Remove old link and show number of builds

In the users locale of course. Without any annoying Accept-Language
parsing or anything like that, just with the beauty of JavaScript.
This commit is contained in:
nora 2025-07-04 22:06:40 +02:00
parent 3f302c7180
commit f6fac25c6f
4 changed files with 94 additions and 35 deletions

View file

@ -82,6 +82,17 @@ pub struct FinishedNightlyWithBroken {
pub broken_error: Option<String>,
}
pub struct BuildStats {
pub pass_count: u32,
pub error_count: u32,
}
impl BuildStats {
pub fn total(&self) -> u32 {
self.pass_count + self.error_count
}
}
impl Db {
pub async fn open(path: &str) -> Result<Self> {
let db_opts = SqliteConnectOptions::from_str(path)
@ -168,6 +179,34 @@ impl Db {
.map(|elems| elems.into_iter().map(|elem| elem.nightly).collect())
}
pub async fn build_count(&self) -> Result<BuildStats> {
#[derive(sqlx::FromRow)]
struct BuildStat {
build_count: u32,
status: Status,
}
let results = sqlx::query_as::<_, BuildStat>(
"SELECT COUNT(status) as build_count, status FROM build_info GROUP BY status",
)
.fetch_all(&self.conn)
.await
.wrap_err("getting list of all targets")?;
let count = |status| {
results
.iter()
.find(|row| row.status == status)
.map(|row| row.build_count)
.unwrap_or(0)
};
Ok(BuildStats {
pass_count: count(Status::Pass),
error_count: count(Status::Error),
})
}
pub async fn build_status_full(
&self,
nightly: &str,

View file

@ -11,7 +11,7 @@ use color_eyre::{eyre::Context, Result};
use serde::{Deserialize, Serialize};
use tracing::{error, info};
use crate::db::{BuildInfo, BuildMode, Db, Status};
use crate::db::{BuildInfo, BuildMode, BuildStats, Db, Status};
#[derive(Clone)]
pub struct AppState {
@ -25,6 +25,7 @@ pub async fn webserver(db: Db) -> Result<()> {
.route("/target", get(web_target))
.route("/nightly", get(web_nightly))
.route("/index.css", get(index_css))
.route("/index.js", get(index_js))
.with_state(AppState { db });
info!("Serving website on port 3000 (commit {})", crate::VERSION);
@ -257,35 +258,37 @@ async fn web_nightly(State(state): State<AppState>, Query(query): Query<NightlyQ
async fn web_root(State(state): State<AppState>) -> impl IntoResponse {
use askama::Template;
#[derive(askama::Template)]
#[template(path = "index.html")]
struct RootPage {
targets: Vec<String>,
nightlies: Vec<String>,
version: &'static str,
}
match state.db.target_list().await {
Ok(targets) => match state.db.nightly_list().await {
Ok(nightlies) => {
let page = RootPage {
targets,
nightlies,
version: crate::VERSION,
};
Html(page.render().unwrap()).into_response()
}
Err(err) => {
error!(?err, "Error loading nightly state");
StatusCode::INTERNAL_SERVER_ERROR.into_response()
}
},
Err(err) => {
error!(?err, "Error loading target state");
StatusCode::INTERNAL_SERVER_ERROR.into_response()
async fn render(state: AppState) -> Result<Response> {
#[derive(askama::Template)]
#[template(path = "index.html")]
struct RootPage {
targets: Vec<String>,
nightlies: Vec<String>,
version: &'static str,
build_count: BuildStats,
}
let targets = state.db.target_list().await?;
let nightlies = state.db.nightly_list().await?;
let build_count = state.db.build_count().await?;
let page = RootPage {
targets,
nightlies,
version: crate::VERSION,
build_count,
};
Ok(Html(page.render().unwrap()).into_response())
}
render(state)
.await
.unwrap_or_else(|err: color_eyre::eyre::Error| {
error!(?err, "Error loading data for root page");
StatusCode::INTERNAL_SERVER_ERROR.into_response()
})
}
async fn index_css() -> impl IntoResponse {
@ -298,6 +301,16 @@ async fn index_css() -> impl IntoResponse {
)
}
async fn index_js() -> impl IntoResponse {
(
[(
axum::http::header::CONTENT_TYPE,
axum::http::HeaderValue::from_static("application/javascript; charset=utf-8"),
)],
include_str!("../static/index.js"),
)
}
#[derive(Serialize, Deserialize)]
struct TriggerBuildBody {
nightly: String,