apply the same render(h(...)) simplification to JobqGraph
mara, follow-up on PR#3365: "follow up with the same for jobq". Drops
mountJobqGraph the same way mountJobqRollup was dropped - builds.js
now calls render(h(JobqGraph, {...}), root) directly, split into
mountRebuildQueue() (the one-time replaceChildren() + first render,
called once at page init) and renderRebuildQueue() (the render-only
path the rebuild_queue_changed handler and the cancel flow reuse,
bumping a module-level jobqGraphToken instead of holding a mount
handle). The split matters here specifically: repeating
replaceChildren() on every refresh would wipe Preact's own tracked
children out from under its diffing instead of letting it update them
minimally - JobqRollup's simpler version didn't need this since it
only ever renders into its own dedicated section once per app
lifetime's worth of state, but the rebuild queue refreshes on every
`rebuild_queue_changed` tick.
Re-verified: npm run build (whole workspace) + swarm-ui typecheck
clean (JobqGraph is also used via JSX on swarm-ui's /jobs page,
untouched by this), comment-block + issue-ref lints clean, headless-
chromium screenshot of builds.html's R3BU1LD QU3U3 tab against a
mocked /api/jobq/graph payload - tree, filter checkboxes, and cancel
buttons all render identically to before.
This commit is contained in:
parent
5c9d89dc64
commit
075d1f63e3
2 changed files with 35 additions and 38 deletions
|
|
@ -14,9 +14,10 @@ import { $, fmtAgeSecs, openStream, openBuildLogStream, initServerWarnings } fro
|
|||
import { el } from '@hive/shared/dom.js';
|
||||
import { bindAsyncForms } from '@hive/shared/forms.js';
|
||||
import { themedConfirm } from '@hive/shared/modal.js';
|
||||
import { h, render } from 'preact';
|
||||
import { fmtAgo, fmtDuration, truncate } from './util.js';
|
||||
import '@hive/shared/hive-tab-strip.js';
|
||||
import { mountJobqGraph } from '@hive/shared/jobq-graph.js';
|
||||
import { JobqGraph } from '@hive/shared/jobq-graph.js';
|
||||
|
||||
// ─── derived state ───────────────────────────────────────────────────────────
|
||||
let metaInputsState = [];
|
||||
|
|
@ -26,7 +27,7 @@ let metaUpdateRunning = false;
|
|||
// the tree itself; this flat array exists only for the two things it
|
||||
// doesn't render: the count-pill and the live-log panel.
|
||||
let jobqNodes = [];
|
||||
let jobqGraphHandle = null;
|
||||
let jobqGraphToken = 0;
|
||||
|
||||
function syncFromSnapshot(s) {
|
||||
metaInputsState = (s.meta_inputs || []).slice();
|
||||
|
|
@ -127,27 +128,40 @@ function renderMetaInputs(s) {
|
|||
}
|
||||
|
||||
// ─── rebuild queue ────────────────────────────────────────────────────────────
|
||||
// R3BU1LD QU3U3 is `JobqGraph` (Preact, mounted imperatively — see
|
||||
// mountJobqGraph's own doc comment in @hive/shared/jobq-graph.js for why
|
||||
// this file has no JSX pipeline) directly — no hand-rolled tree/roll-up
|
||||
// rendering here anymore. The component owns fetching GET /api/jobq/graph
|
||||
// and its own refetch (`.refresh()` on the mount handle); this page just
|
||||
// reads its `onUpdate` callback to keep `jobqNodes` (the flat array) in
|
||||
// sync for the two things the generic view doesn't render itself: the
|
||||
// count-pill and the live-log panel below.
|
||||
// R3BU1LD QU3U3 is `JobqGraph` (Preact, rendered via plain `render(h(...))`
|
||||
// — no JSX pragma needed for either call, no mount wrapper: `render` is
|
||||
// already the re-render/diff entry point, per mara on review) directly —
|
||||
// no hand-rolled tree/roll-up rendering here anymore. The component owns
|
||||
// fetching GET /api/jobq/graph and its own refetch (bump `jobqGraphToken`
|
||||
// and render again); this page just reads its `onUpdate` callback to keep
|
||||
// `jobqNodes` (the flat array) in sync for the two things the generic
|
||||
// view doesn't render itself: the count-pill and the live-log panel below.
|
||||
//
|
||||
// Cancel is the one action this page *does* wire up: the `cancellable`
|
||||
// prop turns on the component's own per-node cancel button, which calls
|
||||
// `onCancel(id)` rather than posting anything — the endpoint
|
||||
// (`/api/rebuild-queue/{id}/cancel`) is this page's domain concept, not
|
||||
// the generic component's.
|
||||
// Split from `renderRebuildQueue` below: `replaceChildren()` only
|
||||
// belongs on the *first* render, to clear the static "loading…"
|
||||
// placeholder `#rebuild-queue-section` starts with in `builds.html` —
|
||||
// Preact doesn't know that placeholder is there, so a later render
|
||||
// call must NOT repeat `replaceChildren()` (it would wipe Preact's own
|
||||
// tracked children out from under its diffing rather than let it
|
||||
// update them minimally).
|
||||
function mountRebuildQueue() {
|
||||
const root = $('rebuild-queue-section');
|
||||
if (!root) return;
|
||||
root.replaceChildren();
|
||||
jobqGraphHandle = mountJobqGraph(root, {
|
||||
renderRebuildQueue();
|
||||
}
|
||||
function renderRebuildQueue() {
|
||||
const root = $('rebuild-queue-section');
|
||||
if (!root) return;
|
||||
render(h(JobqGraph, {
|
||||
endpoint: '/api/jobq/graph',
|
||||
cancellable: true,
|
||||
refreshToken: jobqGraphToken,
|
||||
onUpdate: (nodes) => {
|
||||
jobqNodes = nodes || [];
|
||||
renderRebuildLiveLog();
|
||||
|
|
@ -165,12 +179,12 @@ function mountRebuildQueue() {
|
|||
if (!r.ok) throw new Error('http ' + r.status);
|
||||
// No manual refresh: cancel flips node state, which fires
|
||||
// rebuild_queue_changed over SSE — the existing handler below
|
||||
// already calls jobqGraphHandle.refresh() on that tick.
|
||||
// already bumps jobqGraphToken and re-renders on that tick.
|
||||
} catch (err) {
|
||||
console.error('cancel failed', err);
|
||||
}
|
||||
},
|
||||
});
|
||||
}), root);
|
||||
}
|
||||
|
||||
// ─── running-rebuild live log ─────────────────────────────────────────────────
|
||||
|
|
@ -471,7 +485,8 @@ const SSE_HANDLERS = {
|
|||
// queue snapshot on the wire (tabs.js/SW4RM still consumes it for the
|
||||
// swarm badges, untouched by this), this page just treats it as a
|
||||
// refetch trigger. `JobqGraph` owns the actual fetch.
|
||||
if (jobqGraphHandle) jobqGraphHandle.refresh();
|
||||
jobqGraphToken += 1;
|
||||
renderRebuildQueue();
|
||||
// Auto-refresh build log list when the queue changes and BUILD L0GS is active.
|
||||
if (buildTabs && buildTabs.active() === 'buildlogs') {
|
||||
if (buildRefreshTimer) clearTimeout(buildRefreshTimer);
|
||||
|
|
|
|||
Loading…
Reference in a new issue