drop the mountJobqRollup wrapper, render(h(...)) directly
mara, on review: expected the plain Preact pattern (render(h(Widget,
props), container), call again to update) rather than a custom
mountX() returning {refresh(), update()}. Preact's own render is
already the re-render/diff entry point, so the wrapper was indirection
this component didn't need - swarm.js (plain .js, no JSX pragma
required for h()/render() either) now calls render(h(JobqRollup,
{...refreshToken}), root) directly, bumping a module-level token to
force a refetch instead of holding a mount handle.
JobqGraph/mountJobqGraph (a separate, already-merged component) is
untouched - out of scope for this PR, flagged as a possible follow-up
if she wants the same simplification there.
Re-verified: npm run build (whole workspace) + swarm-ui typecheck
clean, comment-block + issue-ref lints clean, re-screenshotted the
dashboard SW4RM tab against the same mocked payload - identical
render, spinner now visibly mid-rotation in the frame (confirms the
animation is live, not just present in markup).
This commit is contained in:
parent
348b2f96da
commit
5c9d89dc64
2 changed files with 23 additions and 38 deletions
|
|
@ -9,7 +9,8 @@ import {
|
||||||
} from './common.js';
|
} from './common.js';
|
||||||
import { el } from '@hive/shared/dom.js';
|
import { el } from '@hive/shared/dom.js';
|
||||||
import { themedConfirm, themedToast } from '@hive/shared/modal.js';
|
import { themedConfirm, themedToast } from '@hive/shared/modal.js';
|
||||||
import { mountJobqRollup } from '@hive/shared/jobq-rollup.js';
|
import { h, render } from 'preact';
|
||||||
|
import { JobqRollup } from '@hive/shared/jobq-rollup.js';
|
||||||
import {
|
import {
|
||||||
containersState, questionsState,
|
containersState, questionsState,
|
||||||
} from './state.js';
|
} from './state.js';
|
||||||
|
|
@ -66,27 +67,26 @@ const selectionState = new Set();
|
||||||
// generic graph was itself judged a stopgap). Rendering itself later
|
// generic graph was itself judged a stopgap). Rendering itself later
|
||||||
// moved out to the shared `JobqRollup` Preact component (same one
|
// moved out to the shared `JobqRollup` Preact component (same one
|
||||||
// swarm-ui's /jobs page mounts), which owns its own fetch of
|
// swarm-ui's /jobs page mounts), which owns its own fetch of
|
||||||
// GET /api/jobq/rollup — this file just mounts it once and bumps its
|
// GET /api/jobq/rollup — this file just calls Preact's own
|
||||||
// refresh handle, mirroring builds.js's JobqGraph mount exactly.
|
// `render(h(...))` directly (no `mountX()` wrapper: `render` is
|
||||||
|
// already the re-render/diff entry point, per mara on review) and
|
||||||
|
// bumps a refresh token to force a refetch.
|
||||||
//
|
//
|
||||||
// Mounted into #jobq-rollup-section, a sibling of #containers-section
|
// Rendered into #jobq-rollup-section, a sibling of #containers-section
|
||||||
// kept OUTSIDE that section's per-render `replaceChildren()` wipe (see
|
// kept OUTSIDE that section's per-render `replaceChildren()` wipe (see
|
||||||
// dashboard.html's comment on the mount div) — re-mounting a fresh
|
// dashboard.html's comment on the mount div) — rendering into a
|
||||||
// Preact tree on every container-state tick would work but is wasteful
|
// section that gets wiped on every container-state tick would defeat
|
||||||
// and defeats the component owning its own fetch lifecycle.
|
// the component owning its own fetch lifecycle.
|
||||||
let jobqRollupHandle = null;
|
let jobqRollupToken = 0;
|
||||||
|
|
||||||
// Mounts once; a second call is a no-op (idempotent — matches
|
|
||||||
// `initCall`/`initPermissions`'s "safe to call from cold-load every
|
|
||||||
// time" shape elsewhere in this bundle).
|
|
||||||
export function initJobqRollup() {
|
export function initJobqRollup() {
|
||||||
if (jobqRollupHandle) return;
|
|
||||||
const root = $('jobq-rollup-section');
|
const root = $('jobq-rollup-section');
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
jobqRollupHandle = mountJobqRollup(root, {
|
render(h(JobqRollup, {
|
||||||
endpoint: '/api/jobq/rollup',
|
endpoint: '/api/jobq/rollup',
|
||||||
queueHref: '/builds.html',
|
queueHref: '/builds.html',
|
||||||
});
|
refreshToken: jobqRollupToken,
|
||||||
|
}), root);
|
||||||
}
|
}
|
||||||
// Refetches on cold load (tabs.js's refreshState) and whenever
|
// Refetches on cold load (tabs.js's refreshState) and whenever
|
||||||
// `rebuild_queue_changed` fires — a payload-less push trigger by
|
// `rebuild_queue_changed` fires — a payload-less push trigger by
|
||||||
|
|
@ -95,8 +95,8 @@ export function initJobqRollup() {
|
||||||
// go refetch" treatment builds.js already gives its own JobqGraph mount
|
// go refetch" treatment builds.js already gives its own JobqGraph mount
|
||||||
// handle's .refresh().
|
// handle's .refresh().
|
||||||
export function applyRebuildQueueChanged() {
|
export function applyRebuildQueueChanged() {
|
||||||
|
jobqRollupToken += 1;
|
||||||
initJobqRollup();
|
initJobqRollup();
|
||||||
jobqRollupHandle?.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── transients ─────────────────────────────────────────────────────────────
|
// ─── transients ─────────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,16 @@
|
||||||
// /builds.html; swarm-ui's /jobs page omits it — a link to the page
|
// /builds.html; swarm-ui's /jobs page omits it — a link to the page
|
||||||
// you're already on is noise).
|
// you're already on is noise).
|
||||||
//
|
//
|
||||||
// The glyph carries `.spinner` (`@hive/shared/base.css`, already
|
// The glyph carries `.spinner` (`@hive/shared/base.css`, imported by
|
||||||
// imported by both consumers) for the "actively happening" spin —
|
// both consumers) for the "actively happening" spin — a static
|
||||||
// not redeclared in jobq-rollup.css, since a static screenshot can't
|
// screenshot can't tell a frozen spinner from a missing one.
|
||||||
// tell a frozen spinner from a missing one; caught by argus's review.
|
|
||||||
//
|
//
|
||||||
// Two ways to use this, same shape as JobqGraph: JSX (swarm-ui) —
|
// JSX (swarm-ui) — `<JobqRollup endpoint="..." queueHref="..." />`. Or
|
||||||
// `<JobqRollup endpoint="..." queueHref="..." />`. Or imperative mount
|
// plain `render(h(JobqRollup, props), container)` (dashboard/src/
|
||||||
// (dashboard/src/swarm.js, plain `.js`) — `mountJobqRollup(container,
|
// swarm.js, no JSX pragma needed) — call again with a bumped
|
||||||
// props)` returns `{ refresh(), update(props) }`.
|
// `refreshToken` to force a refetch. No mount wrapper: `render` is
|
||||||
|
// already the re-render/diff entry point.
|
||||||
|
|
||||||
import { h, render } from 'preact';
|
|
||||||
import { useState, useEffect } from 'preact/hooks';
|
import { useState, useEffect } from 'preact/hooks';
|
||||||
|
|
||||||
// Mirrors `hive_jobq_wire::StateSchema` — only the subset this banner
|
// Mirrors `hive_jobq_wire::StateSchema` — only the subset this banner
|
||||||
|
|
@ -89,17 +88,3 @@ export function JobqRollup({ endpoint, queueHref, refreshToken = 0 }: JobqRollup
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Imperative mount helper — same shape as `mountJobqGraph`. Returns
|
|
||||||
// `.refresh()` (bump the refresh token, re-fetch) and `.update(props)`
|
|
||||||
// (merge new props and re-render).
|
|
||||||
export function mountJobqRollup(container: Element, initialProps: JobqRollupProps) {
|
|
||||||
let props = initialProps;
|
|
||||||
let token = 0;
|
|
||||||
const draw = () => render(h(JobqRollup, { ...props, refreshToken: token }), container);
|
|
||||||
draw();
|
|
||||||
return {
|
|
||||||
refresh() { token += 1; draw(); },
|
|
||||||
update(next: Partial<JobqRollupProps>) { props = { ...props, ...next }; draw(); },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue