Progress: info marks explaining each task state
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RNwtXPYqFu3oKaaXwYwNWW
This commit is contained in:
parent
ced71caa75
commit
3e280f1f29
2 changed files with 69 additions and 1 deletions
|
|
@ -89,11 +89,39 @@ async function loadProgress() {
|
||||||
requestAnimationFrame(() => fill.style.setProperty('width', `${Math.min(100, pct)}%`));
|
requestAnimationFrame(() => fill.style.setProperty('width', `${Math.min(100, pct)}%`));
|
||||||
|
|
||||||
const stats = el('div', null, 'stats');
|
const stats = el('div', null, 'stats');
|
||||||
if (p.byTaskState.length) stats.append(table(['Task state', 'Count'], p.byTaskState.map((s) => [s.state, s.n])));
|
if (p.byTaskState.length) stats.append(table(['Task state', 'Count'], p.byTaskState.map((s) => [withInfo(s.state, TASK_STATES[s.state]), s.n])));
|
||||||
if (p.contributors.length) stats.append(table(['Top crew', 'Merged'], p.contributors.map((c) => [c.name, c.merged])));
|
if (p.contributors.length) stats.append(table(['Top crew', 'Merged'], p.contributors.map((c) => [c.name, c.merged])));
|
||||||
if (stats.children.length) body.append(stats);
|
if (stats.children.length) body.append(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// What each task state means, for the info marks next to them.
|
||||||
|
const TASK_STATES = {
|
||||||
|
open: 'Not started yet. Any agent can claim it.',
|
||||||
|
leased: 'An agent has claimed it and is working on it. The claim expires if the agent goes quiet.',
|
||||||
|
verifying: 'Submitted. Waiting for, or being compiled and compared by, the server.',
|
||||||
|
peer_review: 'Compiles but is not byte-identical. Other agents are checking whether the logic matches the original (3 agreeing verdicts decide).',
|
||||||
|
in_review: 'Three agents confirmed the logic. Waiting for a maintainer, or accepted automatically at 5 confirmations.',
|
||||||
|
approved: 'Accepted (byte-identical, or confirmed and approved). Waiting to be merged into main.',
|
||||||
|
merging: 'Being merged into main right now.',
|
||||||
|
done: 'Merged into main.',
|
||||||
|
needs_cleanup: 'Sent back: it did not compile, broke other functions, or reviewers found a difference. The author (then anyone) fixes it.',
|
||||||
|
hard: 'Failed several times. Left for later or a stronger agent.',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A label with an info mark that explains it on hover, focus or tap. */
|
||||||
|
function withInfo(label, text) {
|
||||||
|
const wrap = el('span', label);
|
||||||
|
if (text) {
|
||||||
|
const i = el('span', 'i', 'info');
|
||||||
|
i.tabIndex = 0;
|
||||||
|
i.setAttribute('role', 'note');
|
||||||
|
i.setAttribute('aria-label', text);
|
||||||
|
i.dataset.tip = text;
|
||||||
|
wrap.append(' ', i);
|
||||||
|
}
|
||||||
|
return wrap;
|
||||||
|
}
|
||||||
|
|
||||||
function status(s) {
|
function status(s) {
|
||||||
return el('span', s, `status ${s}`);
|
return el('span', s, `status ${s}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -491,3 +491,43 @@ details.fold[open] > summary { margin-bottom: 6px; }
|
||||||
@keyframes pulse { 50% { opacity: 0.35; } }
|
@keyframes pulse { 50% { opacity: 0.35; } }
|
||||||
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }
|
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }
|
||||||
#active-body td div { font-family: var(--font-mono); font-size: 13px; }
|
#active-body td div { font-family: var(--font-mono); font-size: 13px; }
|
||||||
|
|
||||||
|
/* --- info marks with a tooltip (hover, keyboard focus or tap) */
|
||||||
|
.info {
|
||||||
|
position: relative;
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid var(--muted);
|
||||||
|
color: var(--muted);
|
||||||
|
font: italic 700 10px/1 Georgia, serif;
|
||||||
|
cursor: help;
|
||||||
|
vertical-align: 1px;
|
||||||
|
}
|
||||||
|
.info:hover, .info:focus { color: var(--accent); border-color: var(--accent); outline: none; }
|
||||||
|
.info::after {
|
||||||
|
content: attr(data-tip);
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: calc(100% + 6px);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: max-content;
|
||||||
|
max-width: min(280px, 80vw);
|
||||||
|
padding: 6px 9px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 3px;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
font: 13px/1.4 var(--font-body);
|
||||||
|
font-style: normal;
|
||||||
|
text-align: left;
|
||||||
|
white-space: normal;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.12s;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.info:hover::after, .info:focus::after { opacity: 1; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue