Files
steep/front/js/job-card.js
T
qpismont 7493de6952
ci/woodpecker/push/tests Pipeline was successful
Add live dashboard with SSE job events
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.
2026-10-13 16:14:48 +00:00

62 lines
1.8 KiB
JavaScript

// Carte d'un job. Le détail (id, event, date) est replié par défaut ; le
// bouton « Watch activity » remonte un évènement `job-select` que le dashboard
// écoute pour ouvrir le flux d'activité du job.
import { escapeHtml, relativeTime } from "./api.js";
class JobCard extends HTMLElement {
set job(value) {
this._job = value;
this.render();
}
get job() {
return this._job;
}
set selected(value) {
this._selected = Boolean(value);
this.render();
}
connectedCallback() {
this.render();
}
render() {
if (!this._job) return;
const job = this._job;
// Préserve l'état replié/déplié à travers les re-rendus (mises à jour SSE).
const open = this._details?.open ? " open" : "";
this.innerHTML = `
<details class="job" data-selected="${this._selected ? "true" : "false"}"${open}>
<summary class="job-head">
<span class="chev" aria-hidden="true"></span>
<span class="job-repo">${escapeHtml(job.repo)}</span>
<span class="job-pr">#${job.pr}</span>
</summary>
<div class="job-info">
<dl>
<div><dt>Job</dt><dd>${job.id}</dd></div>
${job.event_id != null ? `<div><dt>Event</dt><dd>${job.event_id}</dd></div>` : ""}
<div><dt>Created</dt><dd>${escapeHtml(relativeTime(job.created_at))}</dd></div>
</dl>
<button class="button button-secondary job-watch" type="button">Watch activity</button>
</div>
</details>`;
this._details = this.querySelector("details");
this.querySelector(".job-watch").addEventListener("click", () => this.select());
}
select() {
this.dispatchEvent(
new CustomEvent("job-select", { detail: { id: this._job.id }, bubbles: true }),
);
}
}
customElements.define("steep-job-card", JobCard);