feat(tasks): adopt canonical task statuses

This commit is contained in:
2026-05-26 01:32:50 +02:00
parent da5aee6e38
commit 38835e9e79
61 changed files with 692 additions and 342 deletions

View File

@@ -57,12 +57,12 @@ const pageState = (async function*() {
const counts = {};
for (const t of taskList) {
const wid = t.workstream_id;
if (!counts[wid]) counts[wid] = {done: 0, in_progress: 0, blocked: 0, todo: 0, total: 0};
if (!counts[wid]) counts[wid] = {done: 0, progress: 0, wait: 0, todo: 0, total: 0};
counts[wid].total++;
if (t.status === "done") counts[wid].done++;
else if (t.status === "in_progress") counts[wid].in_progress++;
else if (t.status === "blocked") counts[wid].blocked++;
else if (t.status === "todo") counts[wid].todo++;
if (t.status === "done") counts[wid].done++;
else if (t.status === "progress") counts[wid].progress++;
else if (t.status === "wait") counts[wid].wait++;
else if (t.status === "todo") counts[wid].todo++;
}
wsAll = wsList.map(w => {
const repo = repoMap[w.repo_id];
@@ -78,7 +78,7 @@ const pageState = (async function*() {
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}),
...(counts[w.id] ?? {done: 0, progress: 0, wait: 0, todo: 0, total: 0}),
};
});
} catch (e) {
@@ -233,13 +233,13 @@ for (const w of chartWs) {
_seen.add(group);
}
const statusOrder = ["done", "in progress", "blocked", "todo"];
const statusColors = ["#4caf50", "steelblue", "#ff7043", "#e0e0e0"];
const statusOrder = ["done", "progress", "wait", "todo"];
const statusColors = ["#4caf50", "#8b5cf6", "#f59e0b", "#e0e0e0"];
const _taskRows = chartWs.flatMap(w => [
{id: w.id, title: w.title, status: "done", count: w.done ?? 0, domain: w.domain, repo: w.repo_label, workplan: w.workplan_filename, href: w.href},
{id: w.id, title: w.title, status: "in progress", count: w.in_progress ?? 0, domain: w.domain, repo: w.repo_label, workplan: w.workplan_filename, href: w.href},
{id: w.id, title: w.title, status: "blocked", count: w.blocked ?? 0, domain: w.domain, repo: w.repo_label, workplan: w.workplan_filename, href: w.href},
{id: w.id, title: w.title, status: "progress", count: w.progress ?? 0, domain: w.domain, repo: w.repo_label, workplan: w.workplan_filename, href: w.href},
{id: w.id, title: w.title, status: "wait", count: w.wait ?? 0, domain: w.domain, repo: w.repo_label, workplan: w.workplan_filename, href: w.href},
{id: w.id, title: w.title, status: "todo", count: w.todo ?? 0, domain: w.domain, repo: w.repo_label, workplan: w.workplan_filename, href: w.href},
]).filter(d => d.count > 0);
@@ -370,7 +370,7 @@ display(html`<div class="grid grid-cols-3" style="gap:1rem;margin-bottom:1.5rem"
## Status
```js
const blockedTasks = summary.blocked_tasks ?? [];
const waitingTasks = summary.waiting_tasks ?? summary.blocked_tasks ?? [];
const wsById = Object.fromEntries((summary.open_workstreams ?? []).map(w => [w.id, w]));
const todayCount = (summary.recent_progress ?? []).filter(e =>
e.created_at?.startsWith(new Date().toISOString().slice(0, 10))).length;
@@ -388,9 +388,9 @@ const statusEl = html`<div>
<p class="big-num">${decCount}</p>
<small>${decisions.escalated ?? 0} escalated</small>
</a>
<div class="card card-link ${blockedTasks.length > 0 ? 'warn' : ''}" data-toggle="blocked-panel">
<h3>Blocked Tasks</h3>
<p class="big-num">${blockedTasks.length}</p>
<div class="card card-link ${waitingTasks.length > 0 ? 'warn' : ''}" data-toggle="waiting-panel">
<h3>Waiting Tasks</h3>
<p class="big-num">${waitingTasks.length}</p>
<small>of ${tasks.total ?? 0} total · click to expand</small>
</div>
<a class="card card-link" href="#recent-activity">
@@ -400,10 +400,10 @@ const statusEl = html`<div>
</a>
</div>
<div id="blocked-panel" style="display:none;margin-bottom:1rem">
${blockedTasks.length === 0
? html`<p class="dim" style="padding:0.5rem 0">No tasks currently blocked.</p>`
: html`<div class="bt-list">${blockedTasks.map(t => {
<div id="waiting-panel" style="display:none;margin-bottom:1rem">
${waitingTasks.length === 0
? html`<p class="dim" style="padding:0.5rem 0">No tasks currently waiting.</p>`
: html`<div class="bt-list">${waitingTasks.map(t => {
const wsName = wsById[t.workstream_id]?.title ?? t.workstream_id?.slice(0,8) ?? "—";
return html`<div class="bt-row">
<div class="bt-meta">${wsName}</div>
@@ -415,11 +415,11 @@ const statusEl = html`<div>
</div>
</div>`;
statusEl.querySelector('[data-toggle="blocked-panel"]').addEventListener('click', () => {
const panel = statusEl.querySelector('#blocked-panel');
statusEl.querySelector('[data-toggle="waiting-panel"]').addEventListener('click', () => {
const panel = statusEl.querySelector('#waiting-panel');
const isOpen = panel.style.display !== 'none';
panel.style.display = isOpen ? 'none' : 'block';
statusEl.querySelector('[data-toggle="blocked-panel"] small').textContent =
statusEl.querySelector('[data-toggle="waiting-panel"] small').textContent =
isOpen ? `of ${tasks.total ?? 0} total · click to expand` : `of ${tasks.total ?? 0} total · click to collapse`;
});