fire-planner: UX review pass 2 — health URL, Progress in shell, Gantt
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

single-year drag, Settings highlight, Dashboard empty state

Round 2 of agent-driven UX review.

- api status badge was always "unreachable" because client called
  /api/healthz but FastAPI mounts /healthz at root (so k8s probes
  hit it without the SPA prefix). Client now calls /healthz directly.
- Progress page rendered without the shell sidebar/tabs because its
  route was sibling to ScenarioShell; moved it inside as a nested
  route (also drops the redundant "← Plan" breadcrumb since the tab
  bar handles that now).
- EventGantt: single-year (point) events no longer render edge handles
  since the bar is too narrow to distinguish "edge grab" from "middle
  grab" — for points the whole bar moves; resize via the popover.
  Bars wider than 24px keep their edge handles.
- Settings sub-nav: Milestones now points at /settings/milestones
  (consistent active highlight); /settings index redirects there.
- Dashboard "Last 12 months" chart shows an explainer when the
  history has fewer than 2 snapshots instead of an empty axis.
- Stub tabs that are currently active get a slate-300 underline +
  slate-500 text rather than the bold slate-900 — visually honest
  about what's a placeholder.

Frontend typecheck/test/build green.
This commit is contained in:
Viktor Barzin 2026-05-10 17:49:05 +00:00
parent cd1fc37f25
commit 9fd8389c26
8 changed files with 53 additions and 34 deletions

View file

@ -288,6 +288,12 @@ function Inner({
const fill = CATEGORY_FILL[ev.category] ?? CATEGORY_FILL.essential;
const border =
CATEGORY_BORDER[ev.category] ?? CATEGORY_BORDER.essential;
// Edge handles are only useful on multi-year ranges. For
// single-year (point) events the bar is too narrow to
// distinguish "edge" from "middle" so the whole bar
// moves and the user resizes via the popover.
const showHandles = w >= 24 && yearEnd > ev.year_start;
const handleW = Math.min(8, w / 4);
return (
<g
key={ev.id}
@ -306,28 +312,30 @@ function Inner({
rx={3}
onMouseDown={(e) => startDrag(e, ev, 'move')}
/>
{/* Left handle */}
<rect
x={x - 1}
y={y}
width={6}
height={h}
fill="rgba(0,0,0,0.25)"
rx={3}
onMouseDown={(e) => startDrag(e, ev, 'left')}
style={{ cursor: 'ew-resize' }}
/>
{/* Right handle */}
<rect
x={x + w - 5}
y={y}
width={6}
height={h}
fill="rgba(0,0,0,0.25)"
rx={3}
onMouseDown={(e) => startDrag(e, ev, 'right')}
style={{ cursor: 'ew-resize' }}
/>
{showHandles && (
<>
<rect
x={x - 1}
y={y}
width={handleW}
height={h}
fill="rgba(0,0,0,0.25)"
rx={3}
onMouseDown={(e) => startDrag(e, ev, 'left')}
style={{ cursor: 'ew-resize' }}
/>
<rect
x={x + w - handleW + 1}
y={y}
width={handleW}
height={h}
fill="rgba(0,0,0,0.25)"
rx={3}
onMouseDown={(e) => startDrag(e, ev, 'right')}
style={{ cursor: 'ew-resize' }}
/>
</>
)}
<text
x={x + 6}
y={y + h / 2}