frontend for the #444 scheduled-prompts feature. backend is
already merged (PR #454 + sibling commits): GET /api/schedules
(snapshot), POST /api/schedules (operator-direct submit), POST
/api/schedules/{id}/cancel (whole or per-target).
new chrome
- SCH3DUL3S tab in the dashboard tab strip, between SYST3M and
the FL0W link. count pill shows the number of schedules with
at least one still-active target.
- pane has two sections: N3W SCH3DUL3 (creation form) +
QU3U3D SCH3DUL3S (list of cards).
creation form
- targets multi-select rendered as chip-style checkboxes;
candidates pulled from containersState plus the special
`operator` and `manager` recipients.
- prompt body textarea (required, non-empty trim).
- first-fire datetime-local input, defaulted to "5 minutes from
now" so the form has a sensible pre-filled future timestamp.
- optional interval (seconds) input — blank = one-shot.
- optional description (one-liner shown on the schedule card).
- mid-typing carry: re-rendering the form preserves field values
+ checkbox state. the operator never loses what they were
typing when the schedule list refreshes underneath them.
- POSTs SchedulePromptPayload JSON to /api/schedules; on success
re-fetches the list to surface the new row.
schedules list
- one card per schedule, active rows first (sorted by
next_fire_at_unix), cancelled tail dimmed.
- header: id, source chip (`operator` or `approval` — reuses
the rebuild-queue rqe-source styling for visual consistency),
next-fire countdown / overdue label, recurring vs one-shot
badge, owner.
- body: prompt text in a styled <pre>-ish block with linkified
path references.
- per-target table: target name, last fire age, last result,
per-row cancel button.
- whole-schedule "✕ cancel all" button.
- per-target cancel posts { targets: ["name"] }; cancel-all
posts no body (== cancel whole row).
no-SSE refresh
- the backend doesn't emit SchedulesChanged dashboard events
yet (damocles flagged this as a follow-up PR C). list
re-fetches on:
- tab activation (so switching to SCH3DUL3S never lands stale)
- cold load via refreshState
- after every submit + cancel POST
the operator's typical interactions all force a refresh; the
remaining gap (worker fires while you're staring at the tab)
is the natural argument for PR C.
files
- frontend/packages/dashboard/src/index.html — new tab + pane
with the two sections.
- frontend/packages/dashboard/src/app.js — schedulesState
cache, refreshSchedules, render*ScheduleNewForm, submit +
cancel helpers, tab routing extended for `schedules`, count
pill wired into refreshTabCounts.
- frontend/packages/dashboard/src/dashboard.css — schedule
form + card styling + chip checkboxes + targets table. small
.btn-inline-small helper for the per-target cancel.
validation
- npm run build --workspace=@hive/dashboard clean. app.js
158 kb → 161 kb. CSS 41.3 kb → 43.9 kb.
- browser smoke test isn't possible from inside iris's container;
endpoints are wire-compatible (backend types unchanged) and
the form serialisation matches SchedulePromptPayload's JSON
shape exactly (targets / body / first_fire_at_unix /
interval_seconds / description).