Show the repo section nav on CI pages
Assisted-by: Claude Sonnet 4.6 via Claude Code
diff --git a/quire-server/src/quire/web/handlers.rs b/quire-server/src/quire/web/handlers.rs
index 7fada0e..1d946b7 100644
--- a/quire-server/src/quire/web/handlers.rs
+++ b/quire-server/src/quire/web/handlers.rs
@@ -61,6 +61,7 @@ pub async fn repo_home(State(quire): State<Quire>, AxumPath(repo): AxumPath<Stri
tags,
recent_runs,
recent_changes,
+ active_section: "readme".to_string(),
};
render(&tmpl)
}
@@ -262,13 +263,18 @@ fn render_error(repo: String, status: StatusCode, title: &str, detail: String) -
pub async fn run_list(State(quire): State<Quire>, AxumPath(repo): AxumPath<String>) -> Response {
let repo_display = repo.trim_end_matches(".git").to_string();
let repo_name = db::resolve_repo_name(&repo);
- match quire.repo(&repo_name) {
- Ok(r) if r.exists() => {}
+ let git_repo = match quire.repo(&repo_name) {
+ Ok(r) if r.exists() => r,
_ => return StatusCode::NOT_FOUND.into_response(),
};
let q = quire.clone();
- let runs = match tokio::task::spawn_blocking(move || db::load_runs(&q, &repo_name)).await {
+ let rn = repo_name.clone();
+ let runs_handle = tokio::task::spawn_blocking(move || db::load_runs(&q, &rn));
+ let refs_handle =
+ tokio::task::spawn_blocking(move || (read_bookmarks(&git_repo), read_tags(&git_repo)));
+
+ let runs = match runs_handle.await {
Ok(Ok(r)) => r,
Ok(Err(e)) => {
tracing::error!(repo = %repo, error = &e as &(dyn std::error::Error + 'static), "failed to load runs");
@@ -284,6 +290,7 @@ pub async fn run_list(State(quire): State<Quire>, AxumPath(repo): AxumPath<Strin
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
}
};
+ let (bookmarks, tags) = refs_handle.await.unwrap_or_default();
let template_runs: Vec<RunListRow> = runs
.into_iter()
@@ -300,8 +307,11 @@ pub async fn run_list(State(quire): State<Quire>, AxumPath(repo): AxumPath<Strin
let tmpl = RunListTemplate {
repo: repo_display,
- crumbs: vec![Crumb::new("ci")],
+ crumbs: vec![],
runs: template_runs,
+ bookmarks,
+ tags,
+ active_section: "ci".to_string(),
};
render(&tmpl)
}
@@ -312,14 +322,17 @@ pub async fn run_detail(
) -> Response {
let repo_display = repo.trim_end_matches(".git").to_string();
let repo_name = db::resolve_repo_name(&repo);
- match quire.repo(&repo_name) {
- Ok(r) if r.exists() => {}
+ let git_repo = match quire.repo(&repo_name) {
+ Ok(r) if r.exists() => r,
_ => return StatusCode::NOT_FOUND.into_response(),
};
if !db::is_valid_run_id(&run_id) {
return StatusCode::NOT_FOUND.into_response();
}
+ let refs_handle =
+ tokio::task::spawn_blocking(move || (read_bookmarks(&git_repo), read_tags(&git_repo)));
+
let q = quire.clone();
let rn = repo_name.clone();
let ri = run_id.clone();
@@ -438,6 +451,7 @@ pub async fn run_detail(
}
let quire_ci_log = quire_ci_log_handle.await.unwrap_or_default();
+ let (bookmarks, tags) = refs_handle.await.unwrap_or_default();
let crumbs = vec![
Crumb::with_href("ci", format!("/{}/ci", repo_display)),
@@ -449,6 +463,9 @@ pub async fn run_detail(
run: detail_run,
jobs: detail_jobs,
quire_ci_log,
+ bookmarks,
+ tags,
+ active_section: "ci".to_string(),
};
render(&tmpl)
}
diff --git a/quire-server/src/quire/web/templates.rs b/quire-server/src/quire/web/templates.rs
index f50651f..32b140b 100644
--- a/quire-server/src/quire/web/templates.rs
+++ b/quire-server/src/quire/web/templates.rs
@@ -41,6 +41,9 @@ pub struct RunListTemplate {
pub repo: String,
pub crumbs: Vec<Crumb>,
pub runs: Vec<RunListRow>,
+ pub bookmarks: Vec<BookmarkRow>,
+ pub tags: Vec<TagRow>,
+ pub active_section: String,
}
impl RunListTemplate {
@@ -99,6 +102,9 @@ pub struct RunDetailTemplate {
pub run: DetailRun,
pub jobs: Vec<DetailJob>,
pub quire_ci_log: String,
+ pub bookmarks: Vec<BookmarkRow>,
+ pub tags: Vec<TagRow>,
+ pub active_section: String,
}
impl RunDetailTemplate {
@@ -240,6 +246,7 @@ pub struct RepoHomeTemplate {
pub tags: Vec<TagRow>,
pub recent_runs: Vec<RunListRow>,
pub recent_changes: Vec<ChangeRow>,
+ pub active_section: String,
}
impl RepoHomeTemplate {
diff --git a/quire-server/templates/_repo_section_nav.html b/quire-server/templates/_repo_section_nav.html
new file mode 100644
index 0000000..ba760aa
--- /dev/null
+++ b/quire-server/templates/_repo_section_nav.html
@@ -0,0 +1,8 @@
+<nav class="repo-section-nav">
+ <a class="section-link {% if active_section == "readme" %}section-link--active{% endif %}" href="/{{ repo }}">readme</a>
+ <a class="section-link {% if active_section == "tree" %}section-link--active{% endif %}" href="/{{ repo }}/tree">tree</a>
+ <a class="section-link {% if active_section == "log" %}section-link--active{% endif %}" href="/{{ repo }}/log">log</a>
+ <a class="section-link {% if active_section == "bookmarks" %}section-link--active{% endif %}" href="/{{ repo }}/bookmarks">bookmarks{% if !bookmarks.is_empty() %} <span class="section-count">{{ bookmarks.len() }}</span>{% endif %}</a>
+ <a class="section-link {% if active_section == "tags" %}section-link--active{% endif %}" href="/{{ repo }}/tags">tags{% if !tags.is_empty() %} <span class="section-count">{{ tags.len() }}</span>{% endif %}</a>
+ <a class="section-link {% if active_section == "ci" %}section-link--active{% endif %}" href="/{{ repo }}/ci">ci</a>
+</nav>
diff --git a/quire-server/templates/ci/run_detail.html b/quire-server/templates/ci/run_detail.html
index e5f1d79..ef736f6 100644
--- a/quire-server/templates/ci/run_detail.html
+++ b/quire-server/templates/ci/run_detail.html
@@ -6,7 +6,9 @@
{% include "_nav.html" %}
{% endblock %}
-{% block content %}
+{% block fullpage %}
+{% include "_repo_section_nav.html" %}
+<main class="page-main">
<div class="ci-meta">
<div class="ci-meta-primary">
<span class="c-accent">{{ run.sha_short() }}</span>
@@ -52,4 +54,5 @@
<pre class="ci-sh-log">{{ quire_ci_log }}</pre>
</div>
{% endif %}
+</main>
{% endblock %}
diff --git a/quire-server/templates/ci/run_list.html b/quire-server/templates/ci/run_list.html
index 2908486..c6741ac 100644
--- a/quire-server/templates/ci/run_list.html
+++ b/quire-server/templates/ci/run_list.html
@@ -6,7 +6,9 @@
{% include "_nav.html" %}
{% endblock %}
-{% block content %}
+{% block fullpage %}
+{% include "_repo_section_nav.html" %}
+<main class="page-main">
<h2 class="ci-heading">ci runs</h2>
<table class="ci-table">
<thead>
@@ -32,4 +34,5 @@
{% endfor %}
</tbody>
</table>
+</main>
{% endblock %}
diff --git a/quire-server/templates/repo_home.html b/quire-server/templates/repo_home.html
index ffa38f0..70ae532 100644
--- a/quire-server/templates/repo_home.html
+++ b/quire-server/templates/repo_home.html
@@ -54,14 +54,7 @@
</header>
{# ── Section nav ────────────────────────────────────────────── #}
-<nav class="repo-section-nav">
- <a class="section-link section-link--active" href="/{{ repo }}">readme</a>
- <a class="section-link" href="/{{ repo }}/tree">tree</a>
- <a class="section-link" href="/{{ repo }}/log">log</a>
- <a class="section-link" href="/{{ repo }}/bookmarks">bookmarks{% if !bookmarks.is_empty() %} <span class="section-count">{{ bookmarks.len() }}</span>{% endif %}</a>
- <a class="section-link" href="/{{ repo }}/tags">tags{% if !tags.is_empty() %} <span class="section-count">{{ tags.len() }}</span>{% endif %}</a>
- <a class="section-link" href="/{{ repo }}/ci">ci</a>
-</nav>
+{% include "_repo_section_nav.html" %}
{# ── Two-column body ─────────────────────────────────────────── #}
<div class="repo-body">