From f929c5b6afad970f8d68e5e54ca0917e350a2cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=20=E9=A7=BF=E7=94=AB=20=28Shunsuke=20Hayashi=29?= Date: Fri, 10 Apr 2026 10:12:14 +0900 Subject: [PATCH] feat(dashboard): add completion stats panel with progress bar Adds a Completion Stats panel to the Polaris web dashboard showing: - Completion percentage with large display - Visual progress bar (green) - Breakdown of done/active/pending/total tasks Closes #97 Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/miyabi-cli/src/main.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/miyabi-cli/src/main.rs b/crates/miyabi-cli/src/main.rs index bb849dc..132ecf5 100644 --- a/crates/miyabi-cli/src/main.rs +++ b/crates/miyabi-cli/src/main.rs @@ -2128,6 +2128,10 @@ const POLARIS_DASHBOARD_HTML: &str = r##"

Loading...

+
+

Completion Stats

+
Loading stats...
+

Tasks

  • Loading tasks...
@@ -2254,6 +2258,27 @@ const POLARIS_DASHBOARD_HTML: &str = r##" } } + function renderStats(snapshot) { + const tasks = Array.isArray(snapshot.tasks) ? snapshot.tasks : []; + if (tasks.length === 0) { + document.getElementById("stats").innerHTML = 'No tasks'; + return; + } + const done = tasks.filter(t => t.current_state === "done" || t.current_state === "merged").length; + const active = tasks.filter(t => t.current_state === "implementing" || t.current_state === "reviewing").length; + const pending = tasks.filter(t => t.current_state === "pending" || t.current_state === "draft" || t.current_state === "blocked").length; + const total = tasks.length; + const pct = total > 0 ? Math.round(done / total * 100) : 0; + + const bar = '
' + + '
'; + + document.getElementById("stats").innerHTML = + '
' + pct + '%
' + + '
completed
' + bar + + '
' + done + ' done / ' + active + ' active / ' + pending + ' pending / ' + total + ' total
'; + } + async function refresh() { try { const [statusRes, locksRes, dagRes] = await Promise.all([ @@ -2272,6 +2297,7 @@ const POLARIS_DASHBOARD_HTML: &str = r##" dagRes.json() ]); + renderStats(status); renderTasks(status); renderLocks(locks); renderDag(dag); @@ -2281,6 +2307,7 @@ const POLARIS_DASHBOARD_HTML: &str = r##" " | auto-refresh every 3s"; } catch (error) { document.getElementById("meta").textContent = "Refresh failed: " + error.message; + document.getElementById("stats").innerHTML = 'Failed to load'; setEmpty("tasks", "Failed to load tasks"); setEmpty("dag", "Failed to load DAG"); setEmpty("locks", "Failed to load locks");