From ab458c3b478d5aa6a9684a66d7af2659760f7c2e Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Fri, 20 Feb 2026 16:52:02 +0545 Subject: [PATCH] fix: hanlding undisclosed and non-existing project parent Signed-off-by: Saw-jan --- src/views/CreateWorkPackageModal.vue | 76 +++++++++++++++++----------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/views/CreateWorkPackageModal.vue b/src/views/CreateWorkPackageModal.vue index d0a81195b..2ccab6493 100644 --- a/src/views/CreateWorkPackageModal.vue +++ b/src/views/CreateWorkPackageModal.vue @@ -450,12 +450,17 @@ export default { } } const url = generateOcsUrl('/apps/integration_openproject/api/v1/projects') + let projects = {} try { + this.availableProjects = [] const response = await axios.get(url, req) - await this.processProjects(response.data.ocs.data) + projects = response.data.ocs.data } catch (e) { - console.error('Couldn\'t fetch openproject projects') + console.error('Could not fetch OpenProject projects:', e.message) } + + this.availableProjects = this.processProjects(projects) + if (this.isFetchingProjectsFromOpenProjectWithQuery === false) { this.initialAvailableProjects = this.availableProjects } @@ -463,37 +468,48 @@ export default { this.state = STATE.OK } }, - async processProjects(projects) { - this.availableProjects = [] - for (const index in projects) { - const project = {} - project.label = projects[index].name - project.id = projects[index].id - project.identifier = projects[index].identifier - project.self = projects[index]._links.self - project.parent = projects[index]._links.parent - project.children = [] - this.availableProjects[index] = project + processProjects(projects) { + const flatProjectsStore = [] + for (const projectId in projects) { + const opProject = projects[projectId] + const project = { + label: opProject.name, + id: opProject.id, + identifier: opProject.identifier, + self: opProject._links.self, + parent: opProject._links.parent, + children: [], + } + flatProjectsStore[projectId] = project } - this.buildNestedStructure() - }, - buildNestedStructure() { - const childId = [] - for (const projectId in this.availableProjects) { - const project = this.availableProjects[projectId] - if (project.parent.href !== null) { - const parentProjectId = project.parent.href.match(/\/(\d+)$/)[1] - if (project.children.length <= 0) { - this.availableProjects[parentProjectId].children.push(project) - childId.push(project.id) + return this.buildNestedProjects(projects, flatProjectsStore).filter(project => !!project) + }, + buildNestedProjects(allProjects, flatProjectsStore) { + const parentProjects = [] + for (const project of Object.values(allProjects)) { + const parentHref = project._links.parent.href + if (parentHref) { + const parentMatch = parentHref.match(/\/(\d+)$/) + if (parentMatch === null) { + // if parent project is undisclosed, we consider it as a top-level project + parentProjects.push(flatProjectsStore[project.id]) + continue } + + const parentId = parentMatch[1] + if (!(parentId in flatProjectsStore)) { + // if parent project is not in the list of projects fetched, we consider it as a top-level project + parentProjects.push(flatProjectsStore[project.id]) + continue + } + + flatProjectsStore[parentId].children.push(flatProjectsStore[project.id]) + } else { + parentProjects.push(flatProjectsStore[project.id]) } } - for (let i = 0; i < childId.length; i++) { - delete this.availableProjects[childId[i]] - } - this.availableProjects = this.availableProjects.filter(item => item !== undefined) + return parentProjects }, onSubjectChange(value) { if (this.error.error) { @@ -603,7 +619,7 @@ export default { this.previousDescriptionTemplate = this.description.raw } } catch (e) { - console.error('Form validation failed') + console.error('Form validation failed:', e.message) } }, setAllowedValues(allowedValuesList) { @@ -637,7 +653,7 @@ export default { try { response = await axios.get(url) } catch (e) { - console.error('Cannot fetch available assignees') + console.error('Cannot fetch available assignees:', e.message) } const assignees = response.data.ocs.data for (const index in assignees) {