dashboard: SCH3DUL3S is a read-only list with a removal banner
The tab lists the rows left in the hive's store so the operator can recreate them with `swarmctl schedule add`: no create row, edit form, fire/pause/cancel buttons or schedules_changed subscription. The next column shows the stored next fire time as an absolute UTC timestamp (the value for --at) instead of a countdown. A warning banner says the page is slated for removal and points at swarmctl. The approvals view drops the schedule_prompt card and the approval_added subscription.
This commit is contained in:
parent
c3a54bbdd0
commit
a4a3f81d5c
8 changed files with 68 additions and 1500 deletions
|
|
@ -17,7 +17,7 @@ import { el } from "@hive/shared/dom.js";
|
|||
import { bindAsyncForms } from "@hive/shared/forms.js";
|
||||
import { createTabStrip } from "@hive/shared/tabs.js";
|
||||
import { containersState, syncContainersFromSnapshot } from "./state.js";
|
||||
import { fmtAgo, fmtDuration } from "./util.js";
|
||||
import { fmtAgo } from "./util.js";
|
||||
import {
|
||||
applyCapabilitiesChanged,
|
||||
applyToolGroupsChanged,
|
||||
|
|
@ -25,18 +25,13 @@ import {
|
|||
fetchAndRenderToolGroups,
|
||||
initPermissions,
|
||||
} from "./permissions.js";
|
||||
import {
|
||||
applySchedulesChanged,
|
||||
refreshSchedules,
|
||||
activeScheduleCount,
|
||||
} from "./schedules.js";
|
||||
import { refreshSchedules, activeScheduleCount } from "./schedules.js";
|
||||
import {
|
||||
initCall,
|
||||
refreshOperatorInbox,
|
||||
operatorInboxAppendFromEvent,
|
||||
operatorInboxCount,
|
||||
syncApprovalsFromSnapshot,
|
||||
applyApprovalAdded,
|
||||
applyApprovalResolved,
|
||||
renderApprovals,
|
||||
activeApprovalCount,
|
||||
|
|
@ -95,11 +90,9 @@ window.marked = marked;
|
|||
// opts out via `data-no-refresh` (its mutation arrives via an SSE event).
|
||||
bindAsyncForms(() => refreshState());
|
||||
|
||||
// One ticker feeds two live displays that would otherwise only
|
||||
// update on the next SSE-triggered re-render: approval request-age
|
||||
// chips (`.approval-ts`, flips `.stale` at the 1h mark) and schedule
|
||||
// next-fire countdowns (`.sched-due`, stamped with `data-due-at` by
|
||||
// the renderers so this loop can refresh them without a full re-render).
|
||||
// Refreshes approval request-age chips (`.approval-ts`, flips `.stale`
|
||||
// at the 1h mark), which would otherwise only update on the next
|
||||
// SSE-triggered re-render.
|
||||
setInterval(() => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
document
|
||||
|
|
@ -111,13 +104,6 @@ window.marked = marked;
|
|||
node.textContent = "requested " + fmtAgo(requestedAt);
|
||||
node.classList.toggle("stale", ageSec >= 3600);
|
||||
});
|
||||
document.querySelectorAll(".sched-due[data-due-at]").forEach((node) => {
|
||||
const dueAt = Number(node.getAttribute("data-due-at"));
|
||||
if (!Number.isFinite(dueAt)) return;
|
||||
const dueIn = dueAt - now;
|
||||
node.textContent =
|
||||
dueIn <= 0 ? "overdue " + fmtAgo(dueAt) : fmtDuration(dueIn);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// ─── state polling ──────────────────────────────────────────────────────
|
||||
|
|
@ -284,7 +270,6 @@ window.marked = marked;
|
|||
// and filter client-side — the dashboard ignores broker traffic
|
||||
// and the inbox ignores mutation events.
|
||||
const MUTATION_HANDLERS = {
|
||||
approval_added: applyApprovalAdded,
|
||||
approval_resolved: applyApprovalResolved,
|
||||
transient_set: applyTransientSet,
|
||||
transient_cleared: applyTransientCleared,
|
||||
|
|
@ -295,7 +280,6 @@ window.marked = marked;
|
|||
// /builds.html gives it for its JobqGraph mount handle's .refresh()
|
||||
// (its own separate subscription).
|
||||
rebuild_queue_changed: applyRebuildQueueChanged,
|
||||
schedules_changed: applySchedulesChanged,
|
||||
capabilities_changed: applyCapabilitiesChanged,
|
||||
tool_groups_changed: applyToolGroupsChanged,
|
||||
};
|
||||
|
|
@ -309,15 +293,15 @@ window.marked = marked;
|
|||
//
|
||||
// kinds= matches MUTATION_HANDLERS below verbatim, plus `sent`
|
||||
// (checked separately, just above, for the operator inbox) —
|
||||
// narrows this from all 15 wire kinds down to the 11 this page
|
||||
// narrows this from all 13 wire kinds down to the 9 this page
|
||||
// actually acts on. This page was one of 4 unfiltered
|
||||
// `/api/dashboard/stream` subscribers before this (subscription
|
||||
// discipline, part 1 of the dashboard-event-stream-split issue).
|
||||
const es = openStream(
|
||||
"/api/dashboard/stream?kinds=sent,approval_added,approval_resolved," +
|
||||
"/api/dashboard/stream?kinds=sent,approval_resolved," +
|
||||
"transient_set,transient_cleared," +
|
||||
"container_state_changed,container_removed,rebuild_queue_changed," +
|
||||
"schedules_changed,capabilities_changed,tool_groups_changed",
|
||||
"capabilities_changed,tool_groups_changed",
|
||||
);
|
||||
es.onmessage = (e) => {
|
||||
let ev;
|
||||
|
|
@ -436,8 +420,7 @@ window.marked = marked;
|
|||
const rawTitle = document.title.replace(/^\(\d+\) /, "");
|
||||
document.title = callCount > 0 ? `(${callCount}) ${rawTitle}` : rawTitle;
|
||||
// SCH3DUL3S — count of schedules with at least one still-active
|
||||
// target (whole-schedule cancellation or all-targets-cancelled
|
||||
// means "not waiting on the worker"; those don't pull attention).
|
||||
// target: the ones left to recreate with `swarmctl schedule`.
|
||||
setTabCount("schedules", activeScheduleCount());
|
||||
}
|
||||
// Poll the state stores on a 1s tick to keep the pill counts in
|
||||
|
|
|
|||
Loading…
Reference in a new issue