From 3c0befb7db37f441ee63151c365a77b436afa940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Mon, 23 Mar 2026 07:30:08 +0100 Subject: [PATCH] feat: enhanced timeline hover tooltip with role, dates, status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tooltip shown when hovering over project strips in the timeline now includes additional information: - Role name (e.g. "3D Artist", "Project Manager") - Assignment date range (2026-03-01 → 2026-06-30) - Status badge when not CONFIRMED (shows PROPOSED, DRAFT, etc.) - Lead person and order type on the same line Data comes from already-loaded timeline entries — no extra API calls. Safe change: tooltip is pointer-events-none and read-only. Co-Authored-By: claude-flow --- .../timeline/TimelineResourcePanel.tsx | 12 +++++++ .../components/timeline/TimelineTooltip.tsx | 36 +++++++++++++++---- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/apps/web/src/components/timeline/TimelineResourcePanel.tsx b/apps/web/src/components/timeline/TimelineResourcePanel.tsx index c54b2db..4e3a175 100644 --- a/apps/web/src/components/timeline/TimelineResourcePanel.tsx +++ b/apps/web/src/components/timeline/TimelineResourcePanel.tsx @@ -141,6 +141,10 @@ function TimelineResourcePanelInner({ orderType: string; hoursPerDay: number; responsiblePerson?: string | null; + role?: string | null; + status?: string; + startDate?: string; + endDate?: string; }[]; } | null>(null); @@ -295,6 +299,10 @@ function TimelineResourcePanelInner({ orderType: string; hours: number; responsiblePerson?: string | null; + role?: string | null; + status?: string; + startDate?: string; + endDate?: string; } >(); for (const alloc of a) { @@ -314,6 +322,10 @@ function TimelineResourcePanelInner({ hours: alloc.hoursPerDay, responsiblePerson: (alloc.project as { responsiblePerson?: string | null }).responsiblePerson ?? null, + role: alloc.role ?? alloc.roleEntity?.name ?? null, + status: alloc.status, + startDate: new Date(alloc.startDate).toISOString().slice(0, 10), + endDate: new Date(alloc.endDate).toISOString().slice(0, 10), }); } } diff --git a/apps/web/src/components/timeline/TimelineTooltip.tsx b/apps/web/src/components/timeline/TimelineTooltip.tsx index 0b9a0f0..3281755 100644 --- a/apps/web/src/components/timeline/TimelineTooltip.tsx +++ b/apps/web/src/components/timeline/TimelineTooltip.tsx @@ -13,6 +13,10 @@ export type HeatmapHoverData = { orderType: string; hoursPerDay: number; responsiblePerson?: string | null; + role?: string | null; + status?: string; + startDate?: string; + endDate?: string; }[]; }; @@ -81,10 +85,20 @@ export function TimelineTooltip({ {entry.projectName}
- {entry.responsiblePerson - ? `Lead: ${entry.responsiblePerson}` - : entry.orderType} + {[ + entry.role, + entry.responsiblePerson ? `Lead: ${entry.responsiblePerson}` : null, + entry.orderType, + ].filter(Boolean).join(" · ")}
+ {entry.startDate && entry.endDate && ( +
+ {entry.startDate} → {entry.endDate} + {entry.status && entry.status !== "CONFIRMED" && ( + {entry.status} + )} +
+ )} {entry.hoursPerDay}h @@ -146,10 +160,20 @@ export function TimelineTooltip({ {entry.projectName}
- {entry.responsiblePerson - ? `Lead: ${entry.responsiblePerson}` - : entry.orderType} + {[ + entry.role, + entry.responsiblePerson ? `Lead: ${entry.responsiblePerson}` : null, + entry.orderType, + ].filter(Boolean).join(" · ")}
+ {entry.startDate && entry.endDate && ( +
+ {entry.startDate} → {entry.endDate} + {entry.status && entry.status !== "CONFIRMED" && ( + {entry.status} + )} +
+ )} {entry.hoursPerDay}h