From 267253aaab1135ceea46811a7c1da5d5c6f285ed Mon Sep 17 00:00:00 2001 From: Shiven Ajwaliya Date: Thu, 26 Feb 2026 09:41:12 -0500 Subject: [PATCH 1/4] 3929-Gantt-Chart-Improvements fix work packages to not display duplicates --- src/frontend/src/hooks/work-packages.hooks.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/hooks/work-packages.hooks.ts b/src/frontend/src/hooks/work-packages.hooks.ts index acf0fa7d92..51dcf5ef72 100644 --- a/src/frontend/src/hooks/work-packages.hooks.ts +++ b/src/frontend/src/hooks/work-packages.hooks.ts @@ -36,7 +36,17 @@ export const useAllWorkPackages = (queryParams?: { [field: string]: string }) => export const useAllWorkPackagesPreview = (status?: string) => { return useQuery(['work packages', 'preview', status], async () => { const { data } = await getAllWorkPackagesPreview(status); - return data; + + const seen = new Set(); + + const uniqueData = data.filter((item: WorkPackagePreview) => { + const key = `${item.wbsNum.carNumber}-${item.wbsNum.projectNumber}-${item.wbsNum.workPackageNumber}`; + const isDuplicate = seen.has(key); + seen.add(key); + return !isDuplicate; + }); + + return uniqueData; }); }; From 9eb03d5b1eef29a0752fbf00e5bb3b6b1c6c0764 Mon Sep 17 00:00:00 2001 From: Shiven Ajwaliya Date: Tue, 17 Mar 2026 22:39:23 -0400 Subject: [PATCH 2/4] 3929-Gantt-Chart-Improvements render blocked WPs once with multiple dependency arrows instead of once per dependency --- .../GanttTaskBar/BlockedTaskBarView.tsx | 33 ++++++++++ .../GanttTaskBar/GanttTaskBar.tsx | 66 ++++++++----------- .../GanttTaskBar/GanttTaskBarView.tsx | 1 + .../GanttChart/GanttChartSection.tsx | 49 +++++++------- src/frontend/src/utils/gantt.utils.tsx | 6 +- 5 files changed, 90 insertions(+), 65 deletions(-) diff --git a/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx b/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx index b2401a8ee4..445807380b 100644 --- a/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx +++ b/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx @@ -4,9 +4,11 @@ import { OnMouseOverOptions, RequestEventChange } from '../../../../../utils/gantt.utils'; +import { wbsPipe, WbsNumber } from 'shared'; import GanttTaskBarDisplay from './GanttTaskBarDisplay'; interface BlockedGanttTaskViewProps { + parentTask: GanttTask; task: GanttTask; days: Date[]; getStartCol: (start: Date) => number; @@ -19,7 +21,33 @@ interface BlockedGanttTaskViewProps { highlightSubtaskComparator: HighlightTaskComparator; } +interface TaskWithBlockingInfo { + blockedBy: WbsNumber[]; + wbsNum: WbsNumber; +} + +const hasBlockingInfo = (value: unknown): value is TaskWithBlockingInfo => { + return ( + typeof value === 'object' && + value !== null && + 'blockedBy' in value && + 'wbsNum' in value && + Array.isArray((value as { blockedBy: unknown }).blockedBy) + ); +}; + +const shouldRenderUnderParent = (parentTask: GanttTask, task: GanttTask): boolean => { + if (!hasBlockingInfo(task.element) || !hasBlockingInfo(parentTask.element)) { + return true; + } + + const parentWbs = wbsPipe(parentTask.element.wbsNum); + const canonicalBlockedByParent = task.element.blockedBy.map(wbsPipe).sort()[0]; + return canonicalBlockedByParent === parentWbs; +}; + const BlockedGanttTaskView = ({ + parentTask, task, days, getStartCol, @@ -31,6 +59,10 @@ const BlockedGanttTaskView = ({ highlightSubtaskComparator, highlightTaskComparator }: BlockedGanttTaskViewProps) => { + if (!shouldRenderUnderParent(parentTask, task)) { + return null; + } + return ( <> ({ return ( ({ highlightSubtaskComparator, highlightTaskComparator }: GanttTaskBarProps) => { - const archerRef = useRef(null); - const getStartCol = (start: Date) => { const startCol = days.findIndex((day) => dateToString(day) === dateToString(getMonday(start))) + 1; return startCol; @@ -64,43 +59,36 @@ const GanttTaskBar = ({ const handleChange = (change: GanttChange) => { createChange(change); - setTimeout(() => { - if (archerRef.current) { - archerRef.current.refreshScreen(); - } - }, 100); // wait for the change to be added to the state and the DOM to update }; return ( - -
- {isEditMode ? ( - - ) : ( - - )} -
-
+
+ {isEditMode ? ( + + ) : ( + + )} +
); }; diff --git a/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/GanttTaskBarView.tsx b/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/GanttTaskBarView.tsx index 6e17b69cce..1c433d0acd 100644 --- a/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/GanttTaskBarView.tsx +++ b/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/GanttTaskBarView.tsx @@ -78,6 +78,7 @@ const GanttTaskBarView = ({ return ( { start: Date; @@ -65,29 +66,31 @@ const GanttChartSection = ({ return tasks.length > 0 ? ( - - {tasks.map((task) => { - return ( - - onShowChildrenToggle(task)} - onAddTaskPressed={onAddTaskPressed} - showChildren={shouldShowChildren(task)} - highlightedChange={highlightedChange} - highlightSubtaskComparator={highlightSubtaskComparator} - highlightTaskComparator={highlightTaskComparator} - /> - - ); - })} - + + + {tasks.map((task) => { + return ( + + onShowChildrenToggle(task)} + onAddTaskPressed={onAddTaskPressed} + showChildren={shouldShowChildren(task)} + highlightedChange={highlightedChange} + highlightSubtaskComparator={highlightSubtaskComparator} + highlightTaskComparator={highlightTaskComparator} + /> + + ); + })} + + {currentTooltipOptions && ( ( export const transformTaskToGanttTask = (task: T, end: Date): GanttTask => { return { - id: uuidv4(), + id: `task-${task.taskId}`, element: task, name: task.title, @@ -441,7 +441,7 @@ export const transformWorkPackageToGanttTask = ( allWorkPackages: T[] ): GanttTask => { return { - id: uuidv4(), + id: `work-package-${workPackage.id}`, element: workPackage, name: workPackage.name, @@ -477,7 +477,7 @@ export const transformProjectToGanttTask = ( const taskList = hideTasks ? [] : project.tasks; return { - id: uuidv4(), + id: `project-${project.id}`, element: project, name: project.name, From 0b14292f3881313d1137da365964b028dc2d90d9 Mon Sep 17 00:00:00 2001 From: Shiven Ajwaliya Date: Sat, 28 Mar 2026 00:27:47 -0400 Subject: [PATCH 3/4] 3929-Gantt-Chart-Improvements fix duplicate WP bug after resolving merge conflicts --- src/frontend/src/utils/gantt.utils.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/utils/gantt.utils.tsx b/src/frontend/src/utils/gantt.utils.tsx index df43239c8f..b949a1ebfb 100644 --- a/src/frontend/src/utils/gantt.utils.tsx +++ b/src/frontend/src/utils/gantt.utils.tsx @@ -485,7 +485,9 @@ export const transformProjectToGanttTask = ( end: endDate, blocking: [], children: [ - ...project.workPackages.map((workPackage) => transformWorkPackageToGanttTask(workPackage, project.workPackages)), + ...project.workPackages + .filter((wp) => wp.blockedBy.length === 0) + .map((workPackage) => transformWorkPackageToGanttTask(workPackage, project.workPackages)), ...taskList.map((task) => transformTaskToGanttTask(task, endDate)) ], overlays: [ From cca1ea7da7d20a382fda65d81bddf1d19e4ce252 Mon Sep 17 00:00:00 2001 From: Shiven Ajwaliya Date: Sat, 28 Mar 2026 00:31:54 -0400 Subject: [PATCH 4/4] 3929-Gantt-Chart-Improvements fix linter and prettier errors --- src/frontend/src/hooks/work-packages.hooks.ts | 2 +- .../GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/hooks/work-packages.hooks.ts b/src/frontend/src/hooks/work-packages.hooks.ts index 51dcf5ef72..959fcd0ddb 100644 --- a/src/frontend/src/hooks/work-packages.hooks.ts +++ b/src/frontend/src/hooks/work-packages.hooks.ts @@ -36,7 +36,7 @@ export const useAllWorkPackages = (queryParams?: { [field: string]: string }) => export const useAllWorkPackagesPreview = (status?: string) => { return useQuery(['work packages', 'preview', status], async () => { const { data } = await getAllWorkPackagesPreview(status); - + const seen = new Set(); const uniqueData = data.filter((item: WorkPackagePreview) => { diff --git a/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx b/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx index 445807380b..38ff3829fc 100644 --- a/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx +++ b/src/frontend/src/pages/GanttPage/GanttChart/GanttChartComponents/GanttTaskBar/BlockedTaskBarView.tsx @@ -42,7 +42,7 @@ const shouldRenderUnderParent = (parentTask: GanttTask, task: GanttTask