Add live dashboard with SSE job events
ci/woodpecker/push/tests Pipeline was successful

Expose /jobs, /dedup, and /events routes backed by a new EventBus that
broadcasts job lifecycle and per-job progress over SSE. Serve a static
dashboard from front/ that lists pending and in-progress jobs, streams
agent activity, and shows completed reviews.

Also add migrate-apply/migrate-generate scripts that load .env, update
the Containerfile to ship the front assets and use the apply script, and
refresh the roadmap.
This commit is contained in:
qpismont committed 2026-10-13 16:14:48 +00:00
1 parent 8c763786c1
commit 7493de6952
32 files changed
+1681 -61

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
// Liste de jobs (une colonne du tableau). Reçoit un tableau de jobs via la
// propriété `jobs` et l'id sélectionné via `selected`.
import "./job-card.js";
class JobList extends HTMLElement {
set jobs(value) {
this._jobs = Array.isArray(value) ? value : [];
this.render();
}
get jobs() {
return this._jobs ?? [];
}
set selected(value) {
this._selected = value;
this.render();
}
connectedCallback() {
if (this._mounted) return;
this._mounted = true;
this.render();
}
render() {
const jobs = this.jobs;
if (jobs.length === 0) {
this.replaceChildren();
const empty = document.createElement("p");
empty.className = "empty";
empty.textContent = this.getAttribute("empty") || "Nothing here.";
this.append(empty);
return;
}
// Réconciliation par id : on réutilise les cartes existantes pour préserver
// l'état replié/déplié de chacune à travers les mises à jour.
const known = new Map();
for (const card of this.querySelectorAll("steep-job-card")) {
if (card.job) known.set(card.job.id, card);
}
for (const job of jobs) {
const card = known.get(job.id) ?? document.createElement("steep-job-card");
known.delete(job.id);
card.job = job;
card.selected = job.id === this._selected;
this.append(card);
}
for (const card of known.values()) card.remove();
}
}
customElements.define("steep-job-list", JobList);