From 4919a1ffe15c2ccccb1a58309349b3a1aa135fb8 Mon Sep 17 00:00:00 2001 From: clerie Date: Sat, 1 Feb 2025 19:38:47 +0100 Subject: [PATCH] Display revision info --- src/bin/web.rs | 30 ++++++++++++++++++++++++++++++ src/storage.rs | 26 ++++++++++++++++++++++++++ src/templates.rs | 8 ++++++++ templates/revision.html | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 templates/revision.html diff --git a/src/bin/web.rs b/src/bin/web.rs index 93342ea..c289d5e 100644 --- a/src/bin/web.rs +++ b/src/bin/web.rs @@ -23,11 +23,13 @@ use flake_tracker::{ storage::{ FlakeRevision, FlakeUri, + InputModel, }, templates::{ FlakeInfoTemplate, FlakesTemplate, IndexTemplate, + RevisionTemplate, }, }; use sqlx::{ @@ -97,6 +99,7 @@ async fn main() -> anyhow::Result<()> { .route("/", get(route_index)) .route("/flakes", get(route_flakes)) .route("/f/{uri}", get(route_flake_info)) + .route("/r/{revision_uri}", get(route_revision)) .with_state(state); let listener = tokio::net::TcpListener::bind("[::]:3000") @@ -158,3 +161,30 @@ async fn route_flake_info( flake_revisions: flake_revisions, })?) } + +async fn route_revision( + State(state): State, + Path(revision_uri): Path, +) -> Result { + let inputs: Vec = sqlx::query_as(" + SELECT + flake_revision_uri, + input_name, + revision_uri, + uri, + nar_hash, + last_modified + FROM flake_revisions_inputs + WHERE flake_revision_uri = ? + ORDER BY input_name + ") + .bind(&revision_uri) + .fetch_all(&state.db) + .await + .context("Failed to fetch data from database")?; + + Ok(render_template(&RevisionTemplate { + revision_uri: revision_uri, + inputs: inputs, + })?) +} diff --git a/src/storage.rs b/src/storage.rs index 305b93e..a749f44 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -38,3 +38,29 @@ impl FlakeUri { format!("/f/{}", urlencode(&self.uri)) } } + +#[derive(FromRow)] +pub struct InputModel { + pub flake_revision_uri: String, + pub input_name: String, + pub revision_uri: Option, + pub uri: Option, + pub nar_hash: Option, + pub last_modified: Option, +} + +impl InputModel { + pub fn revision_link(&self) -> String { + match &self.revision_uri { + Some(revision_uri) => format!("/r/{}", urlencode(&revision_uri)), + None => String::from("#"), + } + } + + pub fn flake_link(&self) -> String { + match &self.uri { + Some(uri) => format!("/f/{}", urlencode(&uri)), + None => String::from("#"), + } + } +} diff --git a/src/templates.rs b/src/templates.rs index d214a86..8b8dfd4 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -5,6 +5,7 @@ use crate::{ storage::{ FlakeRevision, FlakeUri, + InputModel, }, }; @@ -25,3 +26,10 @@ pub struct FlakeInfoTemplate { pub uri: String, pub flake_revisions: Vec, } + +#[derive(Template)] +#[template(path = "revision.html")] +pub struct RevisionTemplate { + pub revision_uri: String, + pub inputs: Vec, +} diff --git a/templates/revision.html b/templates/revision.html new file mode 100644 index 0000000..a7b208e --- /dev/null +++ b/templates/revision.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block content %} +

{{ revision_uri }}

+ + + +

Inputs

+ +
    +{% for input in inputs %} +
  • + {{ input.input_name }} +
      + {% match input.uri %} + {% when Some with (uri) %} +
    • Flake: {{ uri }}
    • + {% when None %} + {% endmatch %} + {% match input.revision_uri %} + {% when Some with (revision_uri) %} +
    • Revision: {{ revision_uri }}
    • + {% when None %} + {% endmatch %} +
    +
  • +{% endfor %} +
+{% endblock %} +