From 8988f7e18ed0846908b34c35e304da3762790927 Mon Sep 17 00:00:00 2001 From: abccodes Date: Fri, 19 Jun 2026 03:20:30 -0700 Subject: [PATCH] [aidan] feat/schedule-calendar: mark current time with a now line in week view --- .../app/pages/Workflows/ScheduleCalendar.tsx | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/Workflows/ScheduleCalendar.tsx b/frontend/src/app/pages/Workflows/ScheduleCalendar.tsx index 5a220063..dc09a23d 100644 --- a/frontend/src/app/pages/Workflows/ScheduleCalendar.tsx +++ b/frontend/src/app/pages/Workflows/ScheduleCalendar.tsx @@ -35,6 +35,13 @@ export default function ScheduleCalendar({ view, density, onSelectWorkflow, refD const dispatch = useAppDispatch(); const workflows = useAppSelector((s) => Object.values(s.workflows.items)); const allPaused = useAppSelector((s) => s.workflows.paused); + // Live clock for the "now" line; a snapshot would drift and refDate may be + // a navigated week, so it can't double as the current moment. + const [now, setNow] = useState(() => new Date()); + useEffect(() => { + const id = setInterval(() => setNow(new Date()), 60_000); + return () => clearInterval(id); + }, []); // Right-click menu: pinned position + the workflow whose pill was // clicked. Same anchor pattern as MUI's menu examples. const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number; workflow: Workflow } | null>(null); @@ -163,6 +170,8 @@ export default function ScheduleCalendar({ view, density, onSelectWorkflow, refD const start = startOfWeek(today); const days = Array.from({ length: 7 }, (_, i) => addDays(start, i)); const HOURS = HOURS_24; + const nowColIdx = days.findIndex((d) => sameDay(d, now)); + const nowTopPx = (now.getHours() + now.getMinutes() / 60) * SLOT_H; // Prefer the short zone name ("PDT", "EST", "JST") so the label // reads in plain English instead of "GMT-7". formatToParts is wide- // supported; if it ever fails we degrade silently rather than show @@ -194,7 +203,7 @@ export default function ScheduleCalendar({ view, density, onSelectWorkflow, refD ); })} - + {HOURS.map((hour, hourIdx) => ( {/* Hour label sits inside its row (top-aligned) rather than @@ -247,6 +256,17 @@ export default function ScheduleCalendar({ view, density, onSelectWorkflow, refD })} ))} + {nowColIdx >= 0 && ( + + + + )} {ctxMenuEl} @@ -264,7 +284,7 @@ export default function ScheduleCalendar({ view, density, onSelectWorkflow, refD reads cleanly in both light and dark themes. */} {WEEKDAY_LABEL_SHORT.map((l, i) => ( - {l} + {l} ))} @@ -357,7 +377,7 @@ export default function ScheduleCalendar({ view, density, onSelectWorkflow, refD fontSize: '0.88rem', color: c.text.secondary, cursor: 'pointer', '&:hover .ev-title': { color: accent }, }}> - + {e.workflow.title} {formatTime(e.date.getHours(), e.date.getMinutes())} @@ -412,7 +432,7 @@ function EventStack({ events, paused, onSelectWorkflow, eventFontSize, onContext bgcolor: accent + '14', color: c.text.primary, borderLeft: `3px solid ${accent}`, - borderRadius: '4px', + borderRadius: c.radius.sm, px: 0.65, py: 0, fontSize: eventFontSize, fontWeight: 500, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', @@ -435,7 +455,7 @@ function EventStack({ events, paused, onSelectWorkflow, eventFontSize, onContext minWidth: 20, px: 0.4, bgcolor: accent + '22', color: accent, - borderRadius: '4px', + borderRadius: c.radius.sm, fontSize: eventFontSize, fontWeight: 700, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', '&:hover': { bgcolor: accent + '33' },