diff --git a/src/components/home/ProjectsNavigation.vue b/src/components/home/ProjectsNavigation.vue index 5f5bf9979..225ef8792 100644 --- a/src/components/home/ProjectsNavigation.vue +++ b/src/components/home/ProjectsNavigation.vue @@ -26,7 +26,7 @@ >
@@ -67,7 +67,7 @@
@@ -93,7 +93,7 @@ import {useBaseStore} from '@/stores/base' import {useProjectStore} from '@/stores/projects' const props = defineProps<{ - modelValue: IProject[], + modelValue?: IProject[], canEditOrder: boolean, }>() const emit = defineEmits(['update:modelValue']) @@ -114,11 +114,16 @@ const currentProject = computed(() => baseStore.currentProject) // TODO: child projects const collapsedProjects = ref<{ [id: IProject['id']]: boolean }>({}) const availableProjects = ref([]) +const childProjects = ref<{ [id: IProject['id']]: boolean }>({}) watch( () => props.modelValue, projects => { - availableProjects.value = projects - projects.forEach(p => collapsedProjects.value[p.id] = false) + availableProjects.value = projects || [] + projects?.forEach(p => { + collapsedProjects.value[p.id] = false + childProjects.value[p.id] = projectStore.getChildProjects(p.id) + .sort((a, b) => a.position - b.position) + }) }, {immediate: true}, ) @@ -149,8 +154,8 @@ async function saveProjectPosition(e: SortableEvent) { if (project.parentProjectId !== parentProjectId && project.parentProjectId > 0) { const parentProject = projectStore.getProjectById(project.parentProjectId) - const childProjectIndex = parentProject.childProjects.findIndex(p => p.id === project.id) - parentProject.childProjects.splice(childProjectIndex, 1) + const childProjectIndex = parentProject.childProjectIds.findIndex(pId => pId === project.id) + parentProject.childProjectIds.splice(childProjectIndex, 1) } try { diff --git a/src/components/home/ProjectsNavigationWrapper.vue b/src/components/home/ProjectsNavigationWrapper.vue index d876ae115..de74de2e6 100644 --- a/src/components/home/ProjectsNavigationWrapper.vue +++ b/src/components/home/ProjectsNavigationWrapper.vue @@ -17,14 +17,18 @@ const projectStore = useProjectStore() await projectStore.loadProjects() -const projects = computed(() => projectStore.projectsArray - .filter(p => p.parentProjectId === 0 && !p.isArchived) - .sort((a, b) => a.position - b.position)) +const projects = computed({ + get() { + return projectStore.projectsArray + .filter(p => p.parentProjectId === 0 && !p.isArchived) + .sort((a, b) => a.position - b.position) + }, + set() { }, // Vue will complain about the component not being writable - but we never need to write here. The setter is only here to silence the warning. +}) const favoriteProjects = computed(() => projectStore.projectsArray .filter(p => !p.isArchived && p.isFavorite) .map(p => ({ ...p, - childProjects: [], })) .sort((a, b) => a.position - b.position)) diff --git a/src/modelTypes/IProject.ts b/src/modelTypes/IProject.ts index 8655f0f8d..ca335f3c6 100644 --- a/src/modelTypes/IProject.ts +++ b/src/modelTypes/IProject.ts @@ -18,7 +18,7 @@ export interface IProject extends IAbstract { subscription: ISubscription position: number backgroundBlurHash: string - childProjects: IProject[] | null + childProjectIds: number[] parentProjectId: number created: Date diff --git a/src/models/project.ts b/src/models/project.ts index c672f2468..4ec1dcb53 100644 --- a/src/models/project.ts +++ b/src/models/project.ts @@ -22,7 +22,7 @@ export default class ProjectModel extends AbstractModel implements IPr subscription: ISubscription = null position = 0 backgroundBlurHash = '' - childProjects = [] + childProjectIds = [] parentProjectId = 0 created: Date = null @@ -47,7 +47,7 @@ export default class ProjectModel extends AbstractModel implements IPr this.subscription = new SubscriptionModel(this.subscription) } - this.childProjects = this.childProjects.map(p => new ProjectModel(p)) + this.childProjectIds = this.childProjects?.map(p => p.id) || [] this.created = new Date(this.created) this.updated = new Date(this.updated) diff --git a/src/stores/projects.ts b/src/stores/projects.ts index b54ab8d1a..d40eefe01 100644 --- a/src/stores/projects.ts +++ b/src/stores/projects.ts @@ -34,6 +34,9 @@ export const useProjectStore = defineStore('project', () => { const getProjectById = computed(() => { return (id: IProject['id']) => typeof projects.value[id] !== 'undefined' ? projects.value[id] : null }) + const getChildProjects = computed(() => { + return (id: IProject['id']) => projectsArray.value.filter(p => p.parentProjectId === id) || [] + }) const findProjectByExactname = computed(() => { return (name: string) => { @@ -67,24 +70,27 @@ export const useProjectStore = defineStore('project', () => { } if (updateChildren) { - project.childProjects?.forEach(p => setProject(p)) + // When projects are loaded from the api, they will include child projects + // in the `childProjects` property. We flatten them out into the project store here. + project.childProjects?.forEach(p => setProject(new ProjectModel(p))) + delete project.childProjects } // if the project is a child project, we need to also set it in the parent if (project.parentProjectId) { const parent = projects.value[project.parentProjectId] let foundProject = false - parent.childProjects = parent.childProjects?.map(p => { + parent.childProjectIds = parent.childProjectIds?.forEach(p => { if (p.id === project.id) { foundProject = true - return project } - - return p }) // If we hit this, the project now has a new parent project which it did not have before if (!foundProject) { - parent.childProjects.push(project) + if (!parent.childProjectIds) { + parent.childProjectIds = [] + } + parent.childProjectIds.push(project.id) } setProject(parent, false) } @@ -197,6 +203,7 @@ export const useProjectStore = defineStore('project', () => { hasProjects: readonly(hasProjects), getProjectById, + getChildProjects, findProjectByExactname, searchProject,