summaryrefslogtreecommitdiff
path: root/web/app.js
diff options
context:
space:
mode:
authorClaudomator Agent <agent@claudomator>2026-03-15 01:35:13 +0000
committerClaudomator Agent <agent@claudomator>2026-03-15 01:35:13 +0000
commit62068d8335af3b12206a4a867f38c6bf6a0f2325 (patch)
tree69dbd5023e7413f94522021917daa913e0704cc8 /web/app.js
parent4029fdd82bdd657ed862c89f20eb03ff2594cde9 (diff)
feat: add task count badges to interrupted, ready, and running tabs
- Add computeTabBadgeCounts(tasks) exported pure function - Add updateTabBadges(tasks) that updates badge spans in tab buttons - Call updateTabBadges on every poll regardless of active tab - Add .tab-count-badge spans to interrupted/ready/running tab buttons in HTML - Add CSS for .tab-count-badge pill styling (hidden when count is zero) - Add 11 tests in web/test/tab-badges.test.mjs covering all states Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'web/app.js')
-rw-r--r--web/app.js42
1 files changed, 42 insertions, 0 deletions
diff --git a/web/app.js b/web/app.js
index bca41fa..a7c18b6 100644
--- a/web/app.js
+++ b/web/app.js
@@ -339,6 +339,46 @@ export function setTaskFilterTab(tab) {
localStorage.setItem('taskFilterTab', tab);
}
+// ── Tab badge counts ───────────────────────────────────────────────────────────
+
+/**
+ * Computes badge counts for the 'interrupted', 'ready', and 'running' tabs.
+ * Returns { interrupted: N, ready: N, running: N }.
+ */
+export function computeTabBadgeCounts(tasks) {
+ let interrupted = 0;
+ let ready = 0;
+ let running = 0;
+ for (const t of tasks) {
+ if (INTERRUPTED_STATES.has(t.state)) interrupted++;
+ if (t.state === 'READY') ready++;
+ if (t.state === 'RUNNING') running++;
+ }
+ return { interrupted, ready, running };
+}
+
+/**
+ * Updates the badge count spans inside the tab buttons for
+ * 'interrupted', 'ready', and 'running'.
+ * Badge is hidden (display:none) when count is zero.
+ */
+export function updateTabBadges(tasks, doc = (typeof document !== 'undefined' ? document : null)) {
+ if (!doc) return;
+ const counts = computeTabBadgeCounts(tasks);
+ for (const [tab, count] of Object.entries(counts)) {
+ const btn = doc.querySelector(`.tab[data-tab="${tab}"]`);
+ if (!btn) continue;
+ let badge = btn.querySelector('.tab-count-badge');
+ if (!badge) {
+ badge = doc.createElement('span');
+ badge.className = 'tab-count-badge';
+ btn.appendChild(badge);
+ }
+ badge.textContent = String(count);
+ badge.hidden = count === 0;
+ }
+}
+
// ── Stats computations ─────────────────────────────────────────────────────────
/**
@@ -961,6 +1001,8 @@ async function poll() {
const tasks = await fetchTasks();
if (isUserEditing()) return;
+ updateTabBadges(tasks);
+
const activeTab = getActiveTab();
switch (activeTab) {
case 'queue':