fix(web): open project demand strips in demand popover

This commit is contained in:
2026-03-30 13:26:54 +02:00
parent 5a345cd2e4
commit fcfe09ac1d
3 changed files with 31 additions and 5 deletions
@@ -44,7 +44,7 @@ interface TimelineProjectPanelProps {
onRowMouseDown: (e: React.MouseEvent, info: RowMouseDownInfo) => void; onRowMouseDown: (e: React.MouseEvent, info: RowMouseDownInfo) => void;
onRowTouchStart: (e: React.TouchEvent, info: RowMouseDownInfo) => void; onRowTouchStart: (e: React.TouchEvent, info: RowMouseDownInfo) => void;
onOpenPanel: (projectId: string) => void; onOpenPanel: (projectId: string) => void;
onOpenDemandClick: (demand: OpenDemandAssignment) => void; onOpenDemandClick: (demand: TimelineDemandEntry, anchorX: number, anchorY: number) => void;
onAllocationContextMenu: ( onAllocationContextMenu: (
info: { allocationId: string; projectId: string }, info: { allocationId: string; projectId: string },
anchorX: number, anchorX: number,
@@ -911,7 +911,7 @@ function renderOpenDemandRow(
toLeft: (d: Date) => number, toLeft: (d: Date) => number,
toWidth: (s: Date, e: Date) => number, toWidth: (s: Date, e: Date) => number,
rowGridLines: React.ReactNode, rowGridLines: React.ReactNode,
_onOpenDemandClick: (demand: OpenDemandAssignment) => void, onOpenDemandClick: (demand: TimelineDemandEntry, anchorX: number, anchorY: number) => void,
onAllocMouseDown: (e: React.MouseEvent, info: AllocMouseDownInfo) => void, onAllocMouseDown: (e: React.MouseEvent, info: AllocMouseDownInfo) => void,
onAllocTouchStart: (e: React.TouchEvent, info: AllocMouseDownInfo) => void, onAllocTouchStart: (e: React.TouchEvent, info: AllocMouseDownInfo) => void,
onAllocationContextMenu: ( onAllocationContextMenu: (
@@ -1056,6 +1056,22 @@ function renderOpenDemandRow(
); );
}} }}
onMouseMove={(e) => onDemandHoverMove(e, alloc)} onMouseMove={(e) => onDemandHoverMove(e, alloc)}
onClick={(e) => {
e.stopPropagation();
onOpenDemandClick(alloc, e.clientX, e.clientY);
}}
onKeyDown={(e) => {
if (e.key !== "Enter" && e.key !== " ") {
return;
}
e.preventDefault();
e.stopPropagation();
const rect = e.currentTarget.getBoundingClientRect();
onOpenDemandClick(alloc, rect.left + rect.width / 2, rect.top + rect.height / 2);
}}
role="button"
tabIndex={0}
aria-label={`Open demand details for ${roleName} on ${alloc.project.name}`}
> >
{/* Left resize handle */} {/* Left resize handle */}
<div <div
@@ -117,11 +117,15 @@ export function TimelineTooltip({
<div className="mt-2 grid grid-cols-2 gap-x-4 gap-y-1.5 text-[11px]"> <div className="mt-2 grid grid-cols-2 gap-x-4 gap-y-1.5 text-[11px]">
<div> <div>
<div className="text-gray-500">Requested</div> <div className="text-gray-500">Requested</div>
<div className="font-medium text-gray-100">{demandHover.requestedHeadcount}</div> <div className="font-medium text-gray-100">
{demandHover.requestedHeadcount} {demandHover.requestedHeadcount === 1 ? "seat" : "seats"}
</div>
</div> </div>
<div> <div>
<div className="text-gray-500">Open</div> <div className="text-gray-500">Open</div>
<div className="font-medium text-amber-300">{demandHover.unfilledHeadcount}</div> <div className="font-medium text-amber-300">
{demandHover.unfilledHeadcount} {demandHover.unfilledHeadcount === 1 ? "seat" : "seats"}
</div>
</div> </div>
<div> <div>
<div className="text-gray-500">Range</div> <div className="text-gray-500">Range</div>
@@ -153,6 +157,10 @@ export function TimelineTooltip({
</div> </div>
) : null} ) : null}
</div> </div>
<div className="mt-2 border-t border-gray-800/90 pt-2 text-[10px] uppercase tracking-[0.14em] text-gray-500">
Click for details and actions
</div>
</div>, </div>,
); );
} }
@@ -706,7 +706,9 @@ function TimelineViewContent({
onRowMouseDown={isSelfServiceTimeline ? () => undefined : onRowMouseDown} onRowMouseDown={isSelfServiceTimeline ? () => undefined : onRowMouseDown}
onRowTouchStart={isSelfServiceTimeline ? () => undefined : onRowTouchStart} onRowTouchStart={isSelfServiceTimeline ? () => undefined : onRowTouchStart}
onOpenPanel={isSelfServiceTimeline ? () => undefined : setOpenPanelProjectId} onOpenPanel={isSelfServiceTimeline ? () => undefined : setOpenPanelProjectId}
onOpenDemandClick={isSelfServiceTimeline ? () => undefined : setOpenDemandToAssign} onOpenDemandClick={isSelfServiceTimeline ? () => undefined : (demand, anchorX, anchorY) => {
setDemandPopover({ demand, x: anchorX, y: anchorY });
}}
onAllocationContextMenu={isSelfServiceTimeline ? () => undefined : openAllocationPopoverAt} onAllocationContextMenu={isSelfServiceTimeline ? () => undefined : openAllocationPopoverAt}
CELL_WIDTH={CELL_WIDTH} CELL_WIDTH={CELL_WIDTH}
dates={dates} dates={dates}