summaryrefslogtreecommitdiff
path: root/web/app.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/app.js')
-rw-r--r--web/app.js52
1 files changed, 52 insertions, 0 deletions
diff --git a/web/app.js b/web/app.js
index a7c18b6..77a2d9d 100644
--- a/web/app.js
+++ b/web/app.js
@@ -74,6 +74,24 @@ function formatDate(iso) {
});
}
+// Returns formatted string for changestats, e.g. "5 files, +127 -43".
+// Returns empty string for null/undefined input.
+export function formatChangestats(stats) {
+ if (stats == null) return '';
+ return `${stats.files_changed} files, +${stats.lines_added} -${stats.lines_removed}`;
+}
+
+// Returns a <span class="changestats-badge"> element for the given stats,
+// or null if stats is null/undefined.
+// Accepts an optional doc parameter for testability (defaults to document).
+export function renderChangestatsBadge(stats, doc = (typeof document !== 'undefined' ? document : null)) {
+ if (stats == null || doc == null) return null;
+ const span = doc.createElement('span');
+ span.className = 'changestats-badge';
+ span.textContent = formatChangestats(stats);
+ return span;
+}
+
function createTaskCard(task) {
const card = document.createElement('div');
card.className = 'task-card';
@@ -118,6 +136,13 @@ function createTaskCard(task) {
card.appendChild(desc);
}
+ // Changestats badge for COMPLETED/READY tasks
+ const CHANGESTATS_STATES = new Set(['COMPLETED', 'READY']);
+ if (CHANGESTATS_STATES.has(task.state) && task.changestats != null) {
+ const csBadge = renderChangestatsBadge(task.changestats);
+ if (csBadge) card.appendChild(csBadge);
+ }
+
// Footer: action buttons based on state
// Interrupted states (CANCELLED, FAILED, BUDGET_EXCEEDED) show both Resume and Restart.
// TIMED_OUT shows Resume only. Others show a single action.
@@ -1690,6 +1715,33 @@ function renderTaskPanel(task, executions) {
exitEl.textContent = `exit: ${exec.ExitCode ?? '—'}`;
row.appendChild(exitEl);
+ if (exec.Changestats != null) {
+ const csBadge = renderChangestatsBadge(exec.Changestats);
+ if (csBadge) row.appendChild(csBadge);
+ }
+
+ if (exec.Commits && exec.Commits.length > 0) {
+ const commitList = document.createElement('div');
+ commitList.className = 'execution-commits';
+ for (const commit of exec.Commits) {
+ const item = document.createElement('div');
+ item.className = 'commit-item';
+
+ const hash = document.createElement('span');
+ hash.className = 'commit-hash';
+ hash.textContent = commit.hash.slice(0, 7);
+ item.appendChild(hash);
+
+ const msg = document.createElement('span');
+ msg.className = 'commit-msg';
+ msg.textContent = commit.message;
+ item.appendChild(msg);
+
+ commitList.appendChild(item);
+ }
+ row.appendChild(commitList);
+ }
+
const logsBtn = document.createElement('button');
logsBtn.className = 'btn-view-logs';
logsBtn.textContent = 'View Logs';