The builds tab is gone from the nav; its card sits below the jobs card on /jobs. The swarm-builder commit status now links to /jobs?run=<id>, and the old /builds address redirects there with its query so links already on PRs still open the build. Docs and the link test follow.
80 lines
3.3 KiB
TypeScript
80 lines
3.3 KiB
TypeScript
// <JobsPage> — the swarm-level job graph. Reuses the shared JobqGraph
|
|
// component (originally built for the per-hive dashboard's rebuild
|
|
// queue) pointed at swarm-controller's own GET /api/jobq/graph instead
|
|
// of hive-c0re's — same wire shape (Vec<hive_jobq_wire::GraphNode>),
|
|
// different endpoint, no component fork. swarm-controller's graph has
|
|
// no real node kinds wired in yet (see swarm-controller/src/jobq.rs's
|
|
// SwarmNodeKind/SwarmResourceKind), so this renders an empty tree today
|
|
// — the page exists so the wiring is in place before the first real
|
|
// swarm-level job (e.g. CreateAgent) lands.
|
|
//
|
|
// JobqRollup sits above the graph, same "N running / M queued" banner
|
|
// the dashboard's 4G3NTS tab shows — no `queueHref`, since a "view
|
|
// queue →" link back to this same page would be noise.
|
|
//
|
|
// Auto-refresh reuses `HivesCard`'s exact pattern (`RefreshIntervalPicker`
|
|
// in the `Panel`'s `actions` slot, `useRefreshInterval` driving the
|
|
// re-fetch), but ticks a `refreshToken` bump instead of doing its own
|
|
// fetch — both `JobqGraph`/`JobqRollup` already accept that prop
|
|
// (bumping it is their documented "refetch now" lever) since the
|
|
// dashboard's own rebuild-queue view needed the same thing first.
|
|
import { useState } from "preact/hooks";
|
|
import { JobqGraph } from "@hive/shared/jobq-graph.js";
|
|
import { JobqRollup } from "@hive/shared/jobq-rollup.js";
|
|
import { Panel } from "../ui/panel/Panel.js";
|
|
import { BuildsCard } from "./builds/BuildsPage.js";
|
|
import {
|
|
RefreshIntervalPicker,
|
|
useRefreshInterval,
|
|
type RefreshIntervalMs,
|
|
} from "../ui/refresh-interval/RefreshInterval.js";
|
|
import "./JobsPage.css";
|
|
|
|
// Same 30s default + same reasoning as `HivesCard`: no inputs on this
|
|
// page for a refresh to clobber, so the out-of-the-box behaviour should
|
|
// just solve staleness rather than require an opt-in every visit.
|
|
const DEFAULT_INTERVAL_MS: RefreshIntervalMs = 30_000;
|
|
|
|
function JobsCard() {
|
|
const [intervalMs, setIntervalMs] =
|
|
useState<RefreshIntervalMs>(DEFAULT_INTERVAL_MS);
|
|
const [refreshToken, setRefreshToken] = useState(0);
|
|
|
|
// `useRefreshInterval` ticks once immediately on mount (by design —
|
|
// see its own doc comment), which lands on top of `JobqGraph`'s /
|
|
// `JobqRollup`'s own unconditional mount-time fetch and costs one
|
|
// harmless duplicate request on page load. Not worth a special case
|
|
// in the shared hook for: the alternative (skip the first tick) would
|
|
// need every other `useRefreshInterval` caller to reason about
|
|
// whether it's the sole fetcher or not, for a one-page, one-time,
|
|
// zero-user-visible-effect cost here.
|
|
useRefreshInterval(intervalMs, () => setRefreshToken((t) => t + 1));
|
|
|
|
return (
|
|
<Panel
|
|
title="jobs"
|
|
icon="🧩"
|
|
actions={
|
|
<RefreshIntervalPicker
|
|
id="jobs-refresh"
|
|
value={intervalMs}
|
|
onChange={setIntervalMs}
|
|
/>
|
|
}
|
|
>
|
|
<JobqRollup endpoint="/api/jobq/rollup" refreshToken={refreshToken} />
|
|
<JobqGraph endpoint="/api/jobq/graph" refreshToken={refreshToken} />
|
|
</Panel>
|
|
);
|
|
}
|
|
|
|
// The jobs tab holds two cards: the controller's job graph, and the swarm
|
|
// builder's recent builds under it.
|
|
export function JobsPage() {
|
|
return (
|
|
<div class="ui-jobs-page">
|
|
<JobsCard />
|
|
<BuildsCard />
|
|
</div>
|
|
);
|
|
}
|