wip: use map instead of object to store projects

This commit is contained in:
kolaente 2023-04-10 17:39:29 +02:00
parent d694f168b2
commit 634af32400
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
6 changed files with 34 additions and 29 deletions

View File

@ -61,6 +61,7 @@
"bulma-css-variables": "0.9.33", "bulma-css-variables": "0.9.33",
"camel-case": "4.1.2", "camel-case": "4.1.2",
"codemirror": "5.65.12", "codemirror": "5.65.12",
"core-js": "^3.30.0",
"date-fns": "2.29.3", "date-fns": "2.29.3",
"dayjs": "1.11.7", "dayjs": "1.11.7",
"dompurify": "3.0.1", "dompurify": "3.0.1",

View File

@ -54,6 +54,9 @@ dependencies:
codemirror: codemirror:
specifier: 5.65.12 specifier: 5.65.12
version: 5.65.12 version: 5.65.12
core-js:
specifier: ^3.30.0
version: 3.30.0
date-fns: date-fns:
specifier: 2.29.3 specifier: 2.29.3
version: 2.29.3 version: 2.29.3
@ -4236,7 +4239,7 @@ packages:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/preset-env': 7.20.2(@babel/core@7.21.3) '@babel/preset-env': 7.20.2(@babel/core@7.21.3)
browserslist: 4.21.5 browserslist: 4.21.5
core-js: 3.29.1 core-js: 3.30.0
magic-string: 0.30.0 magic-string: 0.30.0
regenerator-runtime: 0.13.11 regenerator-runtime: 0.13.11
systemjs: 6.14.0 systemjs: 6.14.0
@ -6081,10 +6084,9 @@ packages:
browserslist: 4.21.5 browserslist: 4.21.5
dev: true dev: true
/core-js@3.29.1: /core-js@3.30.0:
resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==} resolution: {integrity: sha512-hQotSSARoNh1mYPi9O2YaWeiq/cEB95kOrFb4NCrO4RIFt1qqNpKsaE+vy/L3oiqvND5cThqXzUU3r9F7Efztg==}
requiresBuild: true requiresBuild: true
dev: true
/core-util-is@1.0.2: /core-util-is@1.0.2:
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}

View File

@ -42,7 +42,7 @@ import type {IProject} from '@/modelTypes/IProject'
import {useProjectStore} from '@/stores/projects' import {useProjectStore} from '@/stores/projects'
const props = defineProps<{ const props = defineProps<{
modelValue?: IProject[], modelValue?: Map<number, IProject>,
canEditOrder: boolean, canEditOrder: boolean,
canCollapse?: boolean, canCollapse?: boolean,
level?: number, level?: number,
@ -59,11 +59,11 @@ const projectStore = useProjectStore()
// Vue draggable will modify the projects list as it changes their position which will not work on a prop. // Vue draggable will modify the projects list as it changes their position which will not work on a prop.
// Hence, we'll clone the prop and work on the clone. // Hence, we'll clone the prop and work on the clone.
const availableProjects = ref<IProject[]>([]) const availableProjects = ref<Map<number, IProject>>(new Map())
watch( watch(
() => props.modelValue, () => props.modelValue,
projects => { projects => {
availableProjects.value = projects || [] availableProjects.value = projects || new Map<number, IProject>()
}, },
{immediate: true}, {immediate: true},
) )
@ -77,14 +77,14 @@ async function saveProjectPosition(e: SortableEvent) {
// If the project was dragged to the last position, Safari will report e.newIndex as the size of the projectsActive // If the project was dragged to the last position, Safari will report e.newIndex as the size of the projectsActive
// array instead of using the position. Because the index is wrong in that case, dragging the project will fail. // array instead of using the position. Because the index is wrong in that case, dragging the project will fail.
// To work around that we're explicitly checking that case here and decrease the index. // To work around that we're explicitly checking that case here and decrease the index.
const newIndex = e.newIndex === projectsActive.length ? e.newIndex - 1 : e.newIndex const newIndex = e.newIndex === projectsActive.size > 0 ? e.newIndex - 1 : e.newIndex
const projectId = parseInt(e.item.dataset.projectId) const projectId = parseInt(e.item.dataset.projectId)
const project = projectStore.getProjectById(projectId) const project = projectStore.getProjectById(projectId)
const parentProjectId = e.to.parentNode.dataset.projectId ? parseInt(e.to.parentNode.dataset.projectId) : 0 const parentProjectId = e.to.parentNode.dataset.projectId ? parseInt(e.to.parentNode.dataset.projectId) : 0
const projectBefore = projectsActive[newIndex - 1] ?? null const projectBefore = projectsActive.get(newIndex - 1) ?? null
const projectAfter = projectsActive[newIndex + 1] ?? null const projectAfter = projectsActive.get(newIndex + 1) ?? null
projectUpdating.value[project.id] = true projectUpdating.value[project.id] = true
const position = calculateItemPosition( const position = calculateItemPosition(

View File

@ -85,9 +85,11 @@ const menuActive = computed(() => baseStore.menuActive)
const projectsLoading = computed(() => projectStore.isLoading) const projectsLoading = computed(() => projectStore.isLoading)
const projects = computed(() => projectStore.notArchivedRootProjects const projects = computed(() => projectStore.notArchivedRootProjects
.sort((a, b) => a.position - b.position)) // .sort((a, b) => a.position - b.position))
)
const favoriteProjects = computed(() => projectStore.favoriteProjects const favoriteProjects = computed(() => projectStore.favoriteProjects
.sort((a, b) => a.position - b.position)) // .sort((a, b) => a.position - b.position))
)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,3 +1,4 @@
import 'core-js/modules/esnext.map.find'
import {watch, reactive, shallowReactive, unref, toRefs, readonly, ref, computed} from 'vue' import {watch, reactive, shallowReactive, unref, toRefs, readonly, ref, computed} from 'vue'
import {acceptHMRUpdate, defineStore} from 'pinia' import {acceptHMRUpdate, defineStore} from 'pinia'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
@ -28,24 +29,23 @@ export const useProjectStore = defineStore('project', () => {
const isLoading = ref(false) const isLoading = ref(false)
// The projects are stored as an object which has the project ids as keys. // The projects are stored as an object which has the project ids as keys.
const projects = ref<ProjectState>({}) const projects = ref<Map<number, IProject>>(new Map<number, IProject>())
const projectsArray = computed(() => Object.values(projects.value)) const notArchivedRootProjects = computed(() => new Map([...projects.value]
const notArchivedRootProjects = computed(() => projectsArray.value .filter(p => p.parentProjectId === 0 && !p.isArchived)))
.filter(p => p.parentProjectId === 0 && !p.isArchived)) const favoriteProjects = computed(() => new Map([...projects.value]
const favoriteProjects = computed(() => projectsArray.value .filter(p => !p.isArchived && p.isFavorite)))
.filter(p => !p.isArchived && p.isFavorite)) const hasProjects = computed(() => projects.value?.size > 0)
const hasProjects = computed(() => projects.value ? true : false)
const getProjectById = computed(() => { const getProjectById = computed(() => {
return (id: IProject['id']) => typeof projects.value[id] !== 'undefined' ? projects.value[id] : null return (id: IProject['id']) => projects.value?.get(id) ?? null
}) })
const getChildProjects = computed(() => { const getChildProjects = computed(() => {
return (id: IProject['id']) => projectsArray.value.filter(p => p.parentProjectId === id) || [] return (id: IProject['id']) => projects.value.filter(p => p.parentProjectId === id) || []
}) })
const findProjectByExactname = computed(() => { const findProjectByExactname = computed(() => {
return (name: string) => { return (name: string) => {
const project = Object.values(projects.value).find(l => { const project = projects.value.find(l => {
return l.title.toLowerCase() === name.toLowerCase() return l.title.toLowerCase() === name.toLowerCase()
}) })
return typeof project === 'undefined' ? null : project return typeof project === 'undefined' ? null : project
@ -56,7 +56,7 @@ export const useProjectStore = defineStore('project', () => {
return (query: string, includeArchived = false) => { return (query: string, includeArchived = false) => {
return search(query) return search(query)
?.filter(value => value > 0) ?.filter(value => value > 0)
.map(id => projects.value[id]) .map(id => projects.value.get(id))
.filter(project => project.isArchived === includeArchived) .filter(project => project.isArchived === includeArchived)
|| [] || []
} }
@ -67,7 +67,7 @@ export const useProjectStore = defineStore('project', () => {
} }
function setProject(project: IProject) { function setProject(project: IProject) {
projects.value[project.id] = project projects.value?.set(project.id, project)
update(project) update(project)
if (baseStore.currentProject?.id === project.id) { if (baseStore.currentProject?.id === project.id) {
@ -81,7 +81,7 @@ export const useProjectStore = defineStore('project', () => {
function removeProjectById(project: IProject) { function removeProjectById(project: IProject) {
remove(project) remove(project)
delete projects.value[project.id] projects.value?.delete(project.id)
} }
function toggleProjectFavorite(project: IProject) { function toggleProjectFavorite(project: IProject) {
@ -152,7 +152,7 @@ export const useProjectStore = defineStore('project', () => {
const projectService = new ProjectService() const projectService = new ProjectService()
try { try {
const loadedProjects = await projectService.getAll({}, {is_archived: true}) as IProject[] const loadedProjects = await projectService.getAll({}, {is_archived: true}) as IProject[]
projects.value = {} projects.value = new Map<number, IProject>()
setProjects(loadedProjects) setProjects(loadedProjects)
return loadedProjects return loadedProjects
@ -166,7 +166,7 @@ export const useProjectStore = defineStore('project', () => {
return [project] return [project]
} }
const parentProject = projects.value[project.parentProjectId] const parentProject = projects.value?.get(project.parentProjectId)
return [ return [
...getParentProjects(parentProject), ...getParentProjects(parentProject),
project, project,
@ -176,7 +176,6 @@ export const useProjectStore = defineStore('project', () => {
return { return {
isLoading: readonly(isLoading), isLoading: readonly(isLoading),
projects: readonly(projects), projects: readonly(projects),
projectsArray: readonly(projectsArray),
notArchivedRootProjects: readonly(notArchivedRootProjects), notArchivedRootProjects: readonly(notArchivedRootProjects),
favoriteProjects: readonly(favoriteProjects), favoriteProjects: readonly(favoriteProjects),
hasProjects: readonly(hasProjects), hasProjects: readonly(hasProjects),

View File

@ -70,6 +70,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import 'core-js/modules/esnext.map.filter'
import {computed} from 'vue' import {computed} from 'vue'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
@ -91,7 +92,7 @@ const showArchived = useStorage('showArchived', false)
const loading = computed(() => projectStore.isLoading) const loading = computed(() => projectStore.isLoading)
const projects = computed(() => { const projects = computed(() => {
return projectStore.projectsArray.filter(project => showArchived.value return projectStore.projects.filter(project => showArchived.value
? true ? true
: !project.isArchived, : !project.isArchived,
) )