diff --git a/frontend/packages/shared/src/jobq-graph/hive-jobq-graph.js b/frontend/packages/shared/src/jobq-graph/hive-jobq-graph.js index 46fd3dc9..c593587d 100644 --- a/frontend/packages/shared/src/jobq-graph/hive-jobq-graph.js +++ b/frontend/packages/shared/src/jobq-graph/hive-jobq-graph.js @@ -6,24 +6,23 @@ // `payload.label` verbatim, and `payload.data` (if present) as a generic // key/value list — this element never branches on what a label or a data // key means, matching the "opaque payload" contract the wire type -// documents. A consumer that wants domain-specific rendering (an agent -// chip, a build-log link, ...) does its own thing on top; this is the -// generic floor every jobq gets for free. +// documents. A consumer wanting domain-specific rendering (an agent chip, +// a build-log link, ...) does its own thing on top; this is the generic +// floor every jobq gets for free. // -// Usage: -// Self-fetches on connect. Call `.refresh()` whenever the host knows the -// graph changed (e.g. on an SSE tick) — the element does not poll or -// subscribe itself, since the right refresh trigger varies per page. -// `.render(nodes)` is also public, for a host that already has a fresh -// `Vec` (e.g. riding its own SSE payload) and wants to skip -// the redundant fetch. +// Usage: — +// self-fetches on connect. `.refresh()` (public) re-fetches + re-renders; +// `.render(nodes)` (public) renders host-pushed data directly, no fetch. +// Fetching lives here, not the host page (per the issue this element was +// built for) — every render dispatches a bubbling/composed `hive-jobq-graph-update` +// event (`detail: { nodes }`) so a host needing the raw list for +// something the tree doesn't show (a count badge, a live-log panel) +// listens instead of running its own parallel fetch. // -// Shadow DOM + own styles (not light-DOM like ): unlike a -// tabbar, this renders a whole subtree of markup nothing else on the page -// needs to select into, so scoping is a win here rather than a cost. -// Theme custom properties (--fg, --red, ...) still apply — they pierce -// the shadow boundary by inheritance, only plain class rules need to be -// local, which is exactly what the own stylesheet is for. +// Shadow DOM + own styles, per instruction — unlike light-DOM +// , this renders a whole subtree nothing else needs to +// select into. Theme custom properties (--fg, --red, ...) still pierce +// the shadow boundary by inheritance; only plain class rules are local. import { el } from '../dom.js'; import { attachShadowCss } from '../shadow-css.js'; @@ -130,10 +129,15 @@ class HiveJobqGraph extends HTMLElement { this._body.replaceChildren(); if (!nodes || !nodes.length) { this._body.append(el('p', { class: 'jg-empty' }, 'empty')); - return; + } else { + const roots = buildTree(nodes); + for (const root of roots) this._body.append(renderNode(root)); } - const roots = buildTree(nodes); - for (const root of roots) this._body.append(renderNode(root)); + this.dispatchEvent(new CustomEvent('hive-jobq-graph-update', { + detail: { nodes: nodes || [] }, + bubbles: true, + composed: true, + })); } } customElements.define('hive-jobq-graph', HiveJobqGraph);