T4: workstreams.md and dependencies.md now call /state/deps instead of the
full /state/summary — removes 2 heavy 10-table queries per 60 s cycle.
T5: index.md's 4 independent polling loops (summaryState, sbomSnapState,
regsState, wsChartState) consolidated into a single pageState generator
with one Promise.all batch and a shared backoff counter.
T6: config.js gains waitForVisible(ms) — pauses polling entirely while the
tab is hidden and fires immediately on visibilitychange. pollDelay()
simplified (hidden-tab POLL_HIDDEN logic removed). All 16 polling pages
migrated from await sleep(pollDelay(...)) to await waitForVisible(pollDelay(...)).
CUST-WP-0039 complete — all 6 tasks done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
18 KiB
18 KiB
title
| title |
|---|
| Goals |
import {API, apiFetch, pollDelay, waitForVisible} from "./components/config.js";
const POLL = 20_000;
const goalsState = (async function*() {
let failures = 0;
while (true) {
let domains = [], domainGoals = [], repoGoals = [], repos = [], ok = false;
try {
const [rd, rdg, rrg, rr] = await Promise.all([
apiFetch("/domains/?status=active"),
apiFetch("/domain-goals/"),
apiFetch("/repo-goals/"),
apiFetch("/repos/"),
]);
ok = rd.ok && rdg.ok && rrg.ok && rr.ok;
if (ok) {
[domains, domainGoals, repoGoals, repos] = await Promise.all([
rd.json(), rdg.json(), rrg.json(), rr.json(),
]);
}
} catch {}
failures = ok ? 0 : failures + 1;
yield {domains, domainGoals, repoGoals, repos, ok, ts: new Date()};
await waitForVisible(pollDelay({ok, base: POLL, failures}));
}
})();
const domains = goalsState.domains ?? [];
const domainGoals = goalsState.domainGoals ?? [];
const repoGoals = goalsState.repoGoals ?? [];
const repos = goalsState.repos ?? [];
const _ok = goalsState.ok ?? false;
const _ts = goalsState.ts;
// ── Indexes ────────────────────────────────────────────────────────────────────
const repoById = Object.fromEntries(repos.map(r => [r.id, r]));
const domainById = Object.fromEntries(domains.map(d => [d.id, d]));
// Domain goals keyed by domain_id; active first, then superseded, then archived
const goalsByDomain = {};
for (const g of domainGoals) {
if (!goalsByDomain[g.domain_id]) goalsByDomain[g.domain_id] = [];
goalsByDomain[g.domain_id].push(g);
}
const STATUS_ORDER = {active: 0, superseded: 1, archived: 2};
for (const id of Object.keys(goalsByDomain)) {
goalsByDomain[id].sort((a, b) =>
(STATUS_ORDER[a.status] ?? 9) - (STATUS_ORDER[b.status] ?? 9)
);
}
// Repo goals keyed by domain_goal_id (primary) and repo_id (for unlinked)
const repoGoalsByDomainGoal = {};
const unlinkedRepoGoals = []; // active repo goals with no domain_goal_id
for (const rg of repoGoals) {
if (rg.domain_goal_id) {
if (!repoGoalsByDomainGoal[rg.domain_goal_id]) repoGoalsByDomainGoal[rg.domain_goal_id] = [];
repoGoalsByDomainGoal[rg.domain_goal_id].push(rg);
} else if (rg.status === "active") {
unlinkedRepoGoals.push(rg);
}
}
// Sort repo goals within each domain goal by priority asc
for (const id of Object.keys(repoGoalsByDomainGoal)) {
repoGoalsByDomainGoal[id].sort((a, b) => a.priority - b.priority);
}
// KPI
const domainsWithActiveGoal = domains.filter(d => (goalsByDomain[d.id] ?? []).some(g => g.status === "active"));
const domainsWithoutGoal = domains.filter(d => !(goalsByDomain[d.id] ?? []).some(g => g.status === "active"));
const totalActiveRepoGoals = repoGoals.filter(g => g.status === "active").length;
Goals
import {injectTocTop} from "./components/toc-sidebar.js";
import {withDocHelp} from "./components/doc-overlay.js";
// ── Live indicator ─────────────────────────────────────────────────────────────
const _liveEl = html`<div class="live-indicator">
<span style="color:${_ok ? 'var(--theme-foreground-focus)' : 'red'}">●</span>
${_ok
? `Live · updated ${_ts?.toLocaleTimeString()}`
: html`<span style="color:red">Offline — run: <code>make api</code></span>`}
</div>`;
withDocHelp(_liveEl, "/docs/live-data");
// ── KPI sidebar card ────────────────────────────────────────────────────────────
const _kpiBox = html`<div class="kpi-infobox">
<div class="kpi-infobox-title">Goals</div>
<div class="kpi-row">
<span class="kpi-row-label">domains with active goal</span>
<div class="kpi-row-right">
<div class="kpi-row-value">${domainsWithActiveGoal.length} / ${domains.length}</div>
</div>
</div>
<div class="kpi-row">
<span class="kpi-row-label">active repo goals</span>
<div class="kpi-row-right">
<div class="kpi-row-value">${totalActiveRepoGoals}</div>
</div>
</div>
${domainsWithoutGoal.length > 0 ? html`
<div class="kpi-block" style="border-top:1px solid var(--theme-foreground-faint,#eee);padding-top:0.4rem;margin-top:0.1rem">
<div class="kpi-row-label" style="color:#b45309;margin-bottom:0.25rem">no active goal</div>
<div class="kpi-slug-list">${domainsWithoutGoal.map(d => html`<div class="kpi-slug-item">${d.slug}</div>`)}</div>
</div>` : ""}
</div>`;
injectTocTop("goals-kpi-box", _kpiBox);
injectTocTop("live-indicator", _liveEl);
const _h1 = document.querySelector("#observablehq-main h1");
if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/goals"); }
Strategic intent, organised by domain. Each domain has one active goal at a time; prior goals are retained as history. Repository goals inherit from a domain goal and refine it into actionable scope for a specific repo.
// ── Repo goal card renderer ────────────────────────────────────────────────────
function renderRepoGoalCard(rg) {
const repo = repoById[rg.repo_id];
const STATUS_COLORS = {
active: {border: "#3b82f6", badge_bg: "#dbeafe", badge_fg: "#1e40af"},
paused: {border: "#f59e0b", badge_bg: "#fef3c7", badge_fg: "#92400e"},
completed: {border: "#22c55e", badge_bg: "#dcfce7", badge_fg: "#166534"},
archived: {border: "#94a3b8", badge_bg: "#f1f5f9", badge_fg: "#475569"},
};
const c = STATUS_COLORS[rg.status] ?? STATUS_COLORS.archived;
return html`<div class="repo-goal-card" style="border-left-color:${c.border}">
<div class="rg-header">
<span class="rg-priority" title="Priority (lower = higher priority)">#${rg.priority}</span>
<span class="rg-repo">${repo?.slug ?? rg.repo_id.slice(0,8)}</span>
<span class="status-badge" style="background:${c.badge_bg};color:${c.badge_fg}">${rg.status}</span>
</div>
<div class="rg-title">${rg.title}</div>
<div class="rg-desc">${rg.description}</div>
<div class="rg-meta">goal id: <code>${rg.id.slice(0,8)}…</code></div>
</div>`;
}
// ── Domain section renderer ────────────────────────────────────────────────────
function renderDomainSection(domain) {
const goals = goalsByDomain[domain.id] ?? [];
const activeGoal = goals.find(g => g.status === "active");
const secondaryGoals = goals.filter(g => g.status !== "active");
return html`<section class="domain-section">
<div class="domain-header">
<span class="domain-chip">${domain.slug}</span>
<span class="domain-name">${domain.name}</span>
</div>
${activeGoal ? html`
<!-- ── Active domain goal ─────────────────────────────────────────── -->
<div class="domain-goal-card dg-active">
<div class="dg-header">
<span class="dg-level-label">Domain Goal</span>
<span class="status-badge badge-active">active</span>
</div>
<div class="dg-title">${activeGoal.title}</div>
<div class="dg-desc">${activeGoal.description}</div>
<div class="dg-meta">
goal id: <code>${activeGoal.id.slice(0,8)}…</code> ·
set ${new Date(activeGoal.created_at).toLocaleDateString()}
</div>
${(repoGoalsByDomainGoal[activeGoal.id] ?? []).length > 0 ? html`
<div class="rg-section">
<div class="rg-section-label">Repository Goals</div>
${(repoGoalsByDomainGoal[activeGoal.id] ?? []).map(renderRepoGoalCard)}
</div>` : html`
<div class="rg-section rg-empty">No repository goals linked to this domain goal yet.</div>`}
</div>
` : html`
<div class="dg-empty">
<span class="dg-no-goal-label">No active goal set for this domain.</span>
</div>`}
${secondaryGoals.length > 0 ? html`
<!-- ── Secondary goals (superseded / archived) ────────────────────── -->
<details class="secondary-goals-details">
<summary class="secondary-goals-summary">
${secondaryGoals.length} secondary goal${secondaryGoals.length === 1 ? "" : "s"}
(${[...new Set(secondaryGoals.map(g => g.status))].join(", ")})
</summary>
<div class="secondary-goals-list">
${secondaryGoals.map(g => html`
<div class="domain-goal-card dg-secondary">
<div class="dg-header">
<span class="dg-level-label">Domain Goal</span>
<span class="status-badge badge-${g.status}">${g.status}</span>
</div>
<div class="dg-title">${g.title}</div>
<div class="dg-desc">${g.description}</div>
<div class="dg-meta">
goal id: <code>${g.id.slice(0,8)}…</code> ·
set ${new Date(g.created_at).toLocaleDateString()}
</div>
${(repoGoalsByDomainGoal[g.id] ?? []).length > 0 ? html`
<div class="rg-section rg-section-secondary">
<div class="rg-section-label">Repository Goals</div>
${(repoGoalsByDomainGoal[g.id] ?? []).map(renderRepoGoalCard)}
</div>` : ""}
</div>`)}
</div>
</details>` : ""}
</section>`;
}
// ── Main render ────────────────────────────────────────────────────────────────
if (!_ok) {
display(html`<p class="dim">API offline — run <code>make api</code> from state-hub/.</p>`);
} else if (domains.length === 0) {
display(html`<p class="dim">No active domains found.</p>`);
} else {
// Domains with active goal first, then those without
const sorted = [
...domainsWithActiveGoal.sort((a, b) => a.slug.localeCompare(b.slug)),
...domainsWithoutGoal.sort((a, b) => a.slug.localeCompare(b.slug)),
];
display(html`<div class="goals-root">${sorted.map(renderDomainSection)}</div>`);
}
// ── Unlinked active repo goals ─────────────────────────────────────────────────
if (unlinkedRepoGoals.length > 0) {
display(html`
<hr/>
<h2>Unlinked Repository Goals</h2>
<p class="dim" style="margin-bottom:1rem">Active repo goals not yet associated with a domain goal.</p>
<div class="rg-list-unlinked">${unlinkedRepoGoals.map(renderRepoGoalCard)}</div>
`);
}