From 0af85229c2a2327b019c9b99c7ac9dea2ae012ab Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Fri, 23 Feb 2024 18:18:33 -0500 Subject: [PATCH] ui: deep linking and url history --- src/main.rs | 1 + src/routes.rs | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index cea5309..8abd933 100644 --- a/src/main.rs +++ b/src/main.rs @@ -90,6 +90,7 @@ async fn main() -> anyhow::Result<()> { .nest("/api", routes::mk_api_routes(config.clone())) // HTMX ui component endpoints .nest("/ui", routes::mk_ui_routes(config.clone())) + .route("/dash/:dash_idx", get(routes::dashboard_direct)) .route("/", get(routes::index).with_state(State(config.clone()))) .layer(TraceLayer::new_for_http()) .with_state(State(config.clone())); diff --git a/src/routes.rs b/src/routes.rs index fe08553..a5f4bbf 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -96,6 +96,10 @@ pub async fn graph_ui( pub async fn dash_ui(State(config): State, Path(dash_idx): Path) -> Markup { // TODO(zaphar): Should do better http error reporting here. + dash_elements(config, dash_idx) +} + +fn dash_elements(config: State>>, dash_idx: usize) -> maud::PreEscaped { let dash = config.get(dash_idx).expect("No such dashboard"); let graph_iter = dash .graphs @@ -123,7 +127,7 @@ pub fn mk_ui_routes(config: Arc>) -> Router { ) } -pub async fn index(State(config): State) -> Markup { +async fn index_html(config: Config, dash_idx: Option) -> Markup { html! { html { head { @@ -132,15 +136,26 @@ pub async fn index(State(config): State) -> Markup { body { script src="/js/plotly.js" { } script src="/js/htmx.js" { } - script src="/js/lib.js" { } + script defer src="/js/lib.js" { } link rel="stylesheet" href="/static/site.css" { } - (app(State(config.clone())).await) + (app(State(config.clone()), dash_idx).await) } } } } -pub async fn app(State(config): State) -> Markup { +pub async fn index(State(config): State) -> Markup { + index_html(config, None).await +} + +pub async fn dashboard_direct( + State(config): State, + Path(dash_idx): Path, +) -> Markup { + index_html(config, Some(dash_idx)).await +} + +fn render_index(config: State>>, dash_idx: Option) -> Markup { let titles = config .iter() .map(|d| d.title.clone()) @@ -152,15 +167,23 @@ pub async fn app(State(config): State) -> Markup { // Header menu ul { @for title in &titles { - li hx-get=(format!("/ui/dash/{}", title.0)) hx-target="#dashboard" { (title.1) } + li hx-push-url=(format!("/dash/{}", title.0)) hx-get=(format!("/ui/dash/{}", title.0)) hx-target="#dashboard" { (title.1) } } } } - div class="flex-item-grow" id="dashboard" { } + div class="flex-item-grow" id="dashboard" { + @if let Some(dash_idx) = dash_idx { + (dash_elements(config, dash_idx)) + } + } } } } +pub async fn app(State(config): State, dash_idx: Option) -> Markup { + render_index(config, dash_idx) +} + pub fn javascript_response(content: &str) -> Response { Response::builder() .header("Content-Type", "text/javascript")