generated from coulomb/repo-seed
Complete workplan state model cleanup
This commit is contained in:
@@ -4,6 +4,13 @@ title: Overview
|
||||
|
||||
```js
|
||||
import {API, POLL_HEAVY, apiFetch, pollDelay, waitForVisible} from "./components/config.js";
|
||||
import {
|
||||
WORKSTREAM_STATUSES,
|
||||
isClosedWorkstream,
|
||||
isStalledWorkstream,
|
||||
needsReviewWorkstream,
|
||||
normalizeWorkstreamStatus,
|
||||
} from "./components/workplan-status.js";
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -52,11 +59,13 @@ const pageState = (async function*() {
|
||||
const workplan = workplanMap[w.id] ?? {};
|
||||
return {
|
||||
...w,
|
||||
status: normalizeWorkstreamStatus(w.status),
|
||||
domain: repo?.domain_slug ?? topic?.domain_slug ?? "unknown",
|
||||
repo_label: repo?.slug ?? workplan.repo_slug ?? "unassigned",
|
||||
workplan_filename: workplan.filename ?? null,
|
||||
workplan_relative_path: workplan.relative_path ?? null,
|
||||
workplan_archived: workplan.archived ?? false,
|
||||
health_labels: workplan.health_labels ?? [],
|
||||
href: `./workstreams/${w.id}`,
|
||||
...(counts[w.id] ?? {done: 0, in_progress: 0, blocked: 0, todo: 0, total: 0}),
|
||||
};
|
||||
@@ -126,13 +135,18 @@ display(html`<div class="warning" style="display:${summary.error ? '' : 'none'}"
|
||||
// view() is the idiomatic Observable Framework reactive input:
|
||||
// it displays the element AND returns a reactive value that re-runs dependent blocks.
|
||||
const _chartMode = view(html`<select class="ws-mode-select">
|
||||
<optgroup label="By Status">
|
||||
<option value="active" selected>active</option>
|
||||
<option value="accepted">accepted</option>
|
||||
<option value="finished">finished</option>
|
||||
<optgroup label="Lifecycle">
|
||||
<option value="ready" selected>ready</option>
|
||||
<option value="active">active</option>
|
||||
<option value="blocked">blocked</option>
|
||||
<option value="proposed">proposed</option>
|
||||
<option value="backlog">backlog</option>
|
||||
<option value="finished">finished</option>
|
||||
<option value="archived">archived</option>
|
||||
</optgroup>
|
||||
<optgroup label="Health">
|
||||
<option value="needs_review">needs review</option>
|
||||
<option value="stalled">stalled</option>
|
||||
<option value="oldies">oldies</option>
|
||||
</optgroup>
|
||||
<optgroup label="Recently Changed">
|
||||
<option value="1h">last 1 hour</option>
|
||||
@@ -150,12 +164,11 @@ const _chartMode = view(html`<select class="ws-mode-select">
|
||||
import * as Plot from "npm:@observablehq/plot";
|
||||
|
||||
// ── Filter workstreams by selected mode ───────────────────────────────────────
|
||||
// "active" matches the DB status field directly.
|
||||
// "accepted" = DB status "completed" (explicitly reviewed and signed off).
|
||||
// "finished" = no open tasks remaining (derived from task counts).
|
||||
// "blocked" = has ≥1 blocked task; "stalled" / "oldies" = activity-based.
|
||||
// Lifecycle modes match stored canonical status values.
|
||||
// Health modes are derived labels; they are not stored lifecycle states.
|
||||
// Time modes filter by updated_at / created_at.
|
||||
const _STATUS_MODES = new Set(["active"]);
|
||||
const _STATUS_MODES = new Set(WORKSTREAM_STATUSES);
|
||||
const _HEALTH_MODES = new Set(["needs_review", "stalled"]);
|
||||
|
||||
function _timeCutoff(mode) {
|
||||
const now = new Date();
|
||||
@@ -175,27 +188,11 @@ function _timeCutoff(mode) {
|
||||
|
||||
const _chartWsFiltered = (
|
||||
_STATUS_MODES.has(_chartMode)
|
||||
? wsAll.filter(w => w.status === _chartMode)
|
||||
: _chartMode === "accepted"
|
||||
? wsAll.filter(w => w.status === "completed")
|
||||
: _chartMode === "finished"
|
||||
? wsAll.filter(w => (w.todo ?? 0) + (w.in_progress ?? 0) + (w.blocked ?? 0) === 0)
|
||||
: _chartMode === "blocked"
|
||||
? wsAll.filter(w => (w.blocked ?? 0) > 0)
|
||||
? wsAll.filter(w => normalizeWorkstreamStatus(w.status) === _chartMode)
|
||||
: _chartMode === "needs_review"
|
||||
? wsAll.filter(needsReviewWorkstream)
|
||||
: _chartMode === "stalled"
|
||||
? wsAll.filter(w => {
|
||||
const staleAt = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
||||
return new Date(w.updated_at) < staleAt
|
||||
&& (w.done ?? 0) > 0
|
||||
&& (w.todo ?? 0) + (w.in_progress ?? 0) + (w.blocked ?? 0) > 0;
|
||||
})
|
||||
: _chartMode === "oldies"
|
||||
? wsAll.filter(w => {
|
||||
const oldAt = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
||||
return new Date(w.created_at) < oldAt
|
||||
&& (w.done ?? 0) === 0
|
||||
&& (w.todo ?? 0) + (w.in_progress ?? 0) + (w.blocked ?? 0) > 0;
|
||||
})
|
||||
? wsAll.filter(isStalledWorkstream)
|
||||
: (() => {
|
||||
const since = _timeCutoff(_chartMode);
|
||||
return wsAll.filter(w =>
|
||||
@@ -215,9 +212,9 @@ const chartWs = [..._chartWsFiltered].sort((a, b) => {
|
||||
});
|
||||
|
||||
// ── Status weight: bold for notable statuses in mixed-status modes ─────────────
|
||||
// Color is NOT used for status — avoids green-on-green when completed bars fill the row.
|
||||
const _isTimeBased = !_STATUS_MODES.has(_chartMode);
|
||||
function _wsWeight(s) { return (s === "accepted" || s === "blocked" || s === "stalled") ? "bold" : "normal"; }
|
||||
// Color is NOT used for status — avoids green-on-green when finished bars fill the row.
|
||||
const _isTimeBased = !_STATUS_MODES.has(_chartMode) && !_HEALTH_MODES.has(_chartMode);
|
||||
function _wsWeight(s) { return (isClosedWorkstream(s) || normalizeWorkstreamStatus(s) === "blocked") ? "bold" : "normal"; }
|
||||
|
||||
// ── y-axis: domain/repo label for first workstream per repository only ────────
|
||||
const _yLabels = {};
|
||||
@@ -251,10 +248,15 @@ function _wsTitle(d) {
|
||||
// ── Render ────────────────────────────────────────────────────────────────────
|
||||
if (chartWs.length === 0) {
|
||||
const _emptyMsg = {
|
||||
active: "No active workstreams.", accepted: "No accepted workstreams.",
|
||||
finished: "No finished workstreams.", blocked: "No blocked workstreams.",
|
||||
proposed: "No proposed workstreams.",
|
||||
ready: "No ready workstreams.",
|
||||
active: "No active workstreams.",
|
||||
blocked: "No blocked workstreams.",
|
||||
backlog: "No backlog workstreams.",
|
||||
finished: "No finished workstreams.",
|
||||
archived: "No archived workstreams.",
|
||||
needs_review: "No ready workstreams need review.",
|
||||
stalled: "No stalled workstreams — everything is moving.",
|
||||
oldies: "No oldies — all older workstreams have at least one task done.",
|
||||
"1h": "No workstreams changed in the last hour.",
|
||||
"1d": "No workstreams changed in the last 24 hours.",
|
||||
"7d": "No workstreams changed in the last 7 days.",
|
||||
|
||||
Reference in New Issue
Block a user