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

+10 -11
View File
@@ -23,17 +23,14 @@ impl JobQueue {
Self { db }
}
/// Enfile une nouvelle review.
///
/// L'unicité de `event_id` fait échouer l'insertion d'un doublon.
pub async fn push(&self, webhook: WebhookType) -> toasty::Result<()> {
pub async fn push(&self, webhook: WebhookType) -> toasty::Result<Job> {
let event_id = webhook.event_id();
let repo = webhook.repository_full_name().to_string();
let pr = webhook.pull_request_number();
let mut db = self.db.clone();
toasty::create!(Job {
let job = toasty::create!(Job {
event_id,
repo,
pr,
@@ -43,14 +40,9 @@ impl JobQueue {
.exec(&mut db)
.await?;
Ok(())
Ok(job)
}
/// Flux des jobs en attente.
///
/// C'est un `Stream` (et non un `Iterator`) : l'accès à la base est
/// asynchrone. Le flux interroge la table en boucle et met en tampon les
/// jobs trouvés.
pub fn pending(&self) -> impl Stream<Item = Job> {
let db = self.db.clone();
@@ -103,6 +95,13 @@ impl JobQueue {
Ok(())
}
pub async fn list(&self, status: JobStatus) -> toasty::Result<Vec<Job>> {
let mut db = self.db.clone();
let jobs = Job::filter_by_status(status).exec(&mut db).await?;
Ok(jobs)
}
}
#[cfg(test)]