Make ci breadcrumb link back to the run list
Replaced the flat Vec<String> crumbs with a Vec<Crumb> where each entry
carries an optional href. The ci crumb on the run detail page now links
to /<repo>/ci; the sha crumb and other leaf crumbs stay as plain text.
Assisted-by: GLM-5.1 via pi
diff --git a/src/quire/web/handlers.rs b/src/quire/web/handlers.rs
index 69f0323..3672049 100644
--- a/src/quire/web/handlers.rs
+++ b/src/quire/web/handlers.rs
@@ -43,7 +43,7 @@ async fn read_log(path: &std::path::Path) -> String {
fn render_error(repo: String, status: StatusCode, title: &str, detail: String) -> Response {
let tmpl = ErrorTemplate {
repo,
- crumbs: vec!["error".to_string()],
+ crumbs: vec![Crumb::new("error")],
title: title.to_string(),
detail: detail.clone(),
};
@@ -91,7 +91,7 @@ pub async fn run_list(State(quire): State<Quire>, AxumPath(repo): AxumPath<Strin
let tmpl = RunListTemplate {
repo: repo_display,
- crumbs: vec!["ci".to_string()],
+ crumbs: vec![Crumb::new("ci")],
runs: template_runs,
};
render(&tmpl)
@@ -178,7 +178,10 @@ pub async fn run_detail(
});
}
- let crumbs = vec!["ci".to_string(), detail_run.sha_short().to_string()];
+ let crumbs = vec![
+ Crumb::with_href("ci", format!("/{}/ci", repo_display)),
+ Crumb::new(detail_run.sha_short()),
+ ];
let tmpl = RunDetailTemplate {
repo: repo_display,
crumbs,
diff --git a/src/quire/web/templates.rs b/src/quire/web/templates.rs
index 84300e4..6aa337e 100644
--- a/src/quire/web/templates.rs
+++ b/src/quire/web/templates.rs
@@ -9,13 +9,37 @@ fn pkg_version() -> &'static str {
env!("CARGO_PKG_VERSION")
}
+/// A navigation breadcrumb entry.
+///
+/// When `href` is `Some`, the crumb renders as a clickable link.
+pub struct Crumb {
+ pub label: String,
+ pub href: Option<String>,
+}
+
+impl Crumb {
+ pub fn new(label: impl Into<String>) -> Self {
+ Self {
+ label: label.into(),
+ href: None,
+ }
+ }
+
+ pub fn with_href(label: impl Into<String>, href: impl Into<String>) -> Self {
+ Self {
+ label: label.into(),
+ href: Some(href.into()),
+ }
+ }
+}
+
// ── Run list ───────────────────────────────────────────────────────
#[derive(Template)]
#[template(path = "ci/run_list.html")]
pub struct RunListTemplate {
pub repo: String,
- pub crumbs: Vec<String>,
+ pub crumbs: Vec<Crumb>,
pub runs: Vec<RunListRow>,
}
@@ -67,7 +91,7 @@ impl RunListRow {
#[template(path = "ci/run_detail.html")]
pub struct RunDetailTemplate {
pub repo: String,
- pub crumbs: Vec<String>,
+ pub crumbs: Vec<Crumb>,
pub run: DetailRun,
pub jobs: Vec<DetailJob>,
}
@@ -194,7 +218,7 @@ impl DetailShEvent {
#[template(path = "error.html")]
pub struct ErrorTemplate {
pub repo: String,
- pub crumbs: Vec<String>,
+ pub crumbs: Vec<Crumb>,
pub title: String,
pub detail: String,
}
diff --git a/templates/_css.html b/templates/_css.html
index 1274e6a..e155e8f 100644
--- a/templates/_css.html
+++ b/templates/_css.html
@@ -44,6 +44,8 @@ pre { white-space: pre-wrap; word-break: break-word; }
.page-nav .nav-repo { color: var(--ink); text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
.page-nav .q-mark { color: var(--ink); display: block; }
.page-nav .nav-crumb { color: var(--muted); }
+.page-nav a.nav-crumb { text-decoration: none; }
+.page-nav a.nav-crumb:hover { color: var(--accent); }
.page-nav .sep { color: var(--rule2); }
.page-main { padding: 22px 56px 32px; }
diff --git a/templates/_nav.html b/templates/_nav.html
index 0e65aad..3cc725a 100644
--- a/templates/_nav.html
+++ b/templates/_nav.html
@@ -14,7 +14,11 @@
<a class="nav-repo" href="/{{ repo }}/ci">{{ repo }}</a>
{% for crumb in crumbs %}
<span class="sep">/</span>
- <span class="nav-crumb">{{ crumb }}</span>
+ {% if let Some(href) = crumb.href %}
+ <a class="nav-crumb" href="{{ href }}">{{ crumb.label }}</a>
+ {% else %}
+ <span class="nav-crumb">{{ crumb.label }}</span>
+ {% endif %}
{% endfor %}
</div>
</nav>