Dashboard: show domain on y-axis, workstream title inside bar

- y-axis tick labels now show domain name (only on the first
  workstream in each domain group, blank for subsequent ones)
- Workstream title rendered as text at x=0 inside the bar
- Titles truncated at 36/24 chars to avoid overflow
- marginLeft reduced to 160 (domain names are shorter than titles)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 00:58:34 +01:00
parent e65d530a5e
commit eeb4faeedd

View File

@@ -139,28 +139,43 @@ const taskRows = openWs.flatMap(w => [
{label: w.title, domain: w.domain, status: "todo", count: w.todo},
]).filter(d => d.count > 0);
// y-axis shows domain (only for the first workstream in each domain group)
const yLabels = {};
const _seenDomains = new Set();
for (const w of openWs) {
yLabels[w.title] = _seenDomains.has(w.domain) ? "" : w.domain;
_seenDomains.add(w.domain);
}
if (openWs.length === 0) {
display(html`<p style="color:gray">No open workstreams.</p>`);
} else {
display(Plot.plot({
y: {label: null, tickSize: 0, domain: openWs.map(w => w.title)},
y: {label: null, tickSize: 0, domain: openWs.map(w => w.title), tickFormat: t => yLabels[t] ?? ""},
x: {label: "Tasks", grid: true},
color: {domain: statusOrder, range: statusColors, legend: true},
marks: [
Plot.barX(taskRows, {y: "label", x: "count", fill: "status", tip: true}),
// Workstream title inside the bar
Plot.text(openWs.filter(w => w.total > 0), {
y: "title", x: 0, dx: 6,
text: d => d.title.length > 36 ? d.title.slice(0, 34) + "…" : d.title,
textAnchor: "start", fontSize: 10, fill: "#333",
}),
Plot.text(openWs.filter(w => w.total === 0), {
y: "title", x: 0, dx: 6,
text: d => `${d.title.length > 24 ? d.title.slice(0, 22) + "…" : d.title} — no tasks yet`,
textAnchor: "start", fontSize: 10, fill: "#aaa",
}),
// "done / total" label after the bar
Plot.text(openWs.filter(w => w.total > 0), {
y: "title", x: "total",
text: d => ` ${d.done}/${d.total}`,
dx: 4, textAnchor: "start", fontSize: 11, fill: "gray",
}),
Plot.text(openWs.filter(w => w.total === 0), {
y: "title", x: 0,
text: () => " no tasks yet",
textAnchor: "start", fontSize: 11, fill: "#aaa",
}),
Plot.ruleX([0]),
],
marginLeft: 200,
marginLeft: 160,
marginRight: 70,
height: Math.max(80, openWs.length * 44 + 50),
width: 700,