From 9804dc275b031fb562ce9ef4ddebbc2030a26ae6 Mon Sep 17 00:00:00 2001 From: Kushal Pandya <kushal@gitlab.com> Date: Thu, 25 Jul 2024 15:00:04 -0400 Subject: [PATCH] Fix Roadmap not loading when epics have private parents Fixes a bug where Roadmap breaks if any epic has a parent that's inaccessible to current user to due permissions. EE: true Changelog: fixed --- .../roadmap/components/epics_list_section.vue | 15 +++++++++---- .../components/epics_list_section_spec.js | 12 ++++------ ee/spec/frontend/roadmap/mock_data.js | 22 +++++++++++++++++++ 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ee/app/assets/javascripts/roadmap/components/epics_list_section.vue b/ee/app/assets/javascripts/roadmap/components/epics_list_section.vue index 94fc284721c4e..bf306ec126510 100644 --- a/ee/app/assets/javascripts/roadmap/components/epics_list_section.vue +++ b/ee/app/assets/javascripts/roadmap/components/epics_list_section.vue @@ -84,7 +84,8 @@ export default { epicsWithAssociatedParents() { return this.epics.filter((epic) => { if (epic.hasParent) { - if (epic.parent.startDate && epic.parent.dueDate) { + // In case `epic.parent` is null, user doesn't have access to parent and in that case, we just show current epic as is. + if (epic.parent?.startDate && epic.parent?.dueDate) { return this.epicIds.indexOf(epic.parent.id) < 0; } return epic.ancestors.nodes.every((ancestor) => this.epicIds.indexOf(ancestor.id) < 0); @@ -142,9 +143,15 @@ export default { scrollToCurrentDay(this.$el); }); - if (!Object.keys(this.emptyRowContainerStyles).length) { - this.emptyRowContainerStyles = this.getEmptyRowContainerStyles(); - } + // Without setTimeout (or any form of deferred execution), when `getEmptyRowContainerStyles` function called, + // the props that the function relies on aren't available yet, so props like `bufferSize`, `displayedEpics` + // are still in process of initialization, and in that case, `emptyRowContainerStyles` is never initialised + // causing the element not to get the style definition it needs. Also, using `$nextTick` doesn't help here. + setTimeout(() => { + if (!Object.keys(this.emptyRowContainerStyles).length) { + this.emptyRowContainerStyles = this.getEmptyRowContainerStyles(); + } + }); }); this.syncClientWidth(); diff --git a/ee/spec/frontend/roadmap/components/epics_list_section_spec.js b/ee/spec/frontend/roadmap/components/epics_list_section_spec.js index a6de95534237c..57ca4d8607a9c 100644 --- a/ee/spec/frontend/roadmap/components/epics_list_section_spec.js +++ b/ee/spec/frontend/roadmap/components/epics_list_section_spec.js @@ -107,13 +107,6 @@ describe('EpicsListSectionComponent', () => { expect(findEmptyRowEl().attributes('style')).not.toBeDefined(); }); - it('sets style attribute with `height` on empty row when there epics available to render', async () => { - createComponent(); - await nextTick(); - - expect(findEmptyRowEl().attributes('style')).toBe('height: calc(100vh - 1px);'); - }); - describe('epics with associated parents', () => { it('should return only epics where parent is not present on top level', async () => { createComponent({ epics: mockEpicsWithParents }); @@ -139,8 +132,11 @@ describe('EpicsListSectionComponent', () => { }); describe('when mounted', () => { - beforeEach(() => { + beforeEach(async () => { createComponent(); + + await nextTick(); + jest.runAllTimers(); }); it('calls `setBufferSize` mutation with value based on window.innerHeight and component element position', () => { diff --git a/ee/spec/frontend/roadmap/mock_data.js b/ee/spec/frontend/roadmap/mock_data.js index e95689b4de850..b482a5e26da32 100644 --- a/ee/spec/frontend/roadmap/mock_data.js +++ b/ee/spec/frontend/roadmap/mock_data.js @@ -371,6 +371,28 @@ export const rawEpics = [ }, group: mockGroup2, }, + { + id: 'gid://gitlab/Epic/42', + iid: 18, + description: null, + title: 'Epic with inaccessible parent', + startDate: '2017-12-26', + endDate: '2018-03-10', + webUrl: '/groups/gitlab-org/marketing/-/epics/18', + descendantCounts: defaultDescendantCounts, + hasParent: true, + color: '#ff0000', + textColor: '#ffffff', + parent: null, + ancestors: { + nodes: [ + { + id: 'gid://gitlab/Epic/40', + }, + ], + }, + group: mockGroup2, + }, { id: 'gid://gitlab/Epic/40', iid: 1, -- GitLab