From d593d56ef5c960e7f3b584f0d67bfcfc201daa6e Mon Sep 17 00:00:00 2001 From: Brent Schroeter Date: Wed, 26 Feb 2025 13:10:46 -0800 Subject: [PATCH] simplify nav state management, sort of --- src/auth.rs | 2 +- src/main.rs | 1 + src/nav_state.rs | 90 ++++++++++++++++++++++++++++++++++++++ src/router.rs | 39 +++++++++++++---- templates/breadcrumbs.html | 10 +++++ templates/nav.html | 34 +++++++++++--- templates/projects.html | 12 ++--- 7 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 src/nav_state.rs create mode 100644 templates/breadcrumbs.html diff --git a/src/auth.rs b/src/auth.rs index 6072225..3a03387 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -17,7 +17,7 @@ use oauth2::{ ClientSecret, CsrfToken, RedirectUrl, TokenResponse, TokenUrl, }; use serde::{Deserialize, Serialize}; -use tracing::{debug, span, trace_span, Level}; +use tracing::{debug, trace_span}; use crate::{app_error::AppError, app_state::AppState, schema, settings::Settings}; diff --git a/src/main.rs b/src/main.rs index 9f6d7dd..7815ad2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ mod auth; mod csrf; mod guards; mod messages; +mod nav_state; mod projects; mod router; mod schema; diff --git a/src/nav_state.rs b/src/nav_state.rs new file mode 100644 index 0000000..fea4c6c --- /dev/null +++ b/src/nav_state.rs @@ -0,0 +1,90 @@ +use uuid::Uuid; + +use crate::{projects::Project, teams::Team}; + +#[derive(Clone, Debug, Default)] +pub struct Breadcrumb { + pub href: String, + pub label: String, +} + +// TODO: This is a very quick, dirty, and awkward approach to storing +// navigation state. It can and should be scrapped and replaced when time +// allows. + +#[derive(Clone, Debug, Default)] +pub struct NavState { + pub base_path: String, + pub breadcrumbs: Vec, + pub team_id: Option, + pub navbar_active_item: String, +} + +impl NavState { + pub fn new() -> Self { + Self::default() + } + + pub fn set_base_path(mut self, base_path: &str) -> Self { + self.base_path = base_path.to_string(); + self + } + + pub fn push_team(mut self, team: &Team) -> Self { + self.team_id = Some(team.id.clone()); + self.navbar_active_item = "teams".to_string(); + self.breadcrumbs.push(Breadcrumb { + href: format!("{}/teams", self.base_path), + label: "Teams".to_string(), + }); + self.breadcrumbs.push(Breadcrumb { + href: format!("{}/teams/{}", self.base_path, team.id.clone().simple()), + label: team.name.clone(), + }); + self + } + + pub fn push_project(mut self, project: &Project) -> Result { + let team_id = self.team_id.ok_or(anyhow::anyhow!( + "NavState.push_project() called out of order" + ))?; + self.navbar_active_item = "projects".to_string(); + self.breadcrumbs.push(Breadcrumb { + href: format!("{}/teams/{}/projects", self.base_path, team_id), + label: "Projects".to_string(), + }); + self.breadcrumbs.push(Breadcrumb { + href: format!( + "{}/teams/{}/projects/{}", + self.base_path, + team_id, + project.id.clone().simple() + ), + label: project.name.clone(), + }); + Ok(self) + } + + /** + * Add a breadcrumb with an href treated as a child of the previous + * breadcrumb's path (or of the base_path if no breadcrumbs exist). + */ + pub fn push_slug(mut self, breadcrumb: Breadcrumb) -> Self { + let starting_path = self + .breadcrumbs + .iter() + .last() + .map(|breadcrumb| breadcrumb.href.clone()) + .unwrap_or(self.base_path.clone()); + self.breadcrumbs.push(Breadcrumb { + href: format!("{}/{}", starting_path, breadcrumb.href), + label: breadcrumb.label, + }); + self + } + + pub fn set_navbar_active_item(mut self, value: &str) -> Self { + self.navbar_active_item = value.to_string(); + self + } +} diff --git a/src/router.rs b/src/router.rs index 8715967..d85a69d 100644 --- a/src/router.rs +++ b/src/router.rs @@ -23,12 +23,13 @@ use crate::{ auth, csrf::generate_csrf_token, guards, + nav_state::{Breadcrumb, NavState}, projects::Project, schema, settings::Settings, team_memberships::TeamMembership, teams::Team, - users::{CurrentUser, User}, + users::CurrentUser, v0_router, }; @@ -74,17 +75,24 @@ async fn teams_page( .unwrap() .context("failed to load team memberships") .map(|memberships| memberships.into_iter().map(|(_, team)| team).collect())?; + let nav_state = NavState::new() + .set_base_path(&base_path) + .push_slug(Breadcrumb { + href: "teams".to_string(), + label: "New Team".to_string(), + }) + .set_navbar_active_item("teams"); #[derive(Template)] #[template(path = "teams.html")] struct ResponseTemplate { base_path: String, teams: Vec, - current_user: User, + nav_state: NavState, } Ok(Html( ResponseTemplate { base_path, - current_user, + nav_state, teams, } .render()?, @@ -129,18 +137,25 @@ async fn new_team_page( ) -> Result { let csrf_token = generate_csrf_token(&db_conn, Some(current_user.id)).await?; + let nav_state = NavState::new() + .set_base_path(&base_path) + .push_slug(Breadcrumb { + href: "new-team".to_string(), + label: "New Team".to_string(), + }) + .set_navbar_active_item("teams"); #[derive(Template)] #[template(path = "new-team.html")] struct ResponseTemplate { base_path: String, csrf_token: String, - current_user: User, + nav_state: NavState, } Ok(Html( ResponseTemplate { base_path, csrf_token, - current_user, + nav_state, } .render()?, )) @@ -211,18 +226,24 @@ async fn projects_page( base_path: String, csrf_token: String, keys: Vec, + nav_state: NavState, projects: Vec, - team: Team, - current_user: User, } let csrf_token = generate_csrf_token(&db_conn, Some(current_user.id.clone())).await?; + let nav_state = NavState::new() + .set_base_path(&base_path) + .push_team(&team) + .push_slug(Breadcrumb { + href: "projects".to_string(), + label: "Projects".to_string(), + }) + .set_navbar_active_item("projects"); Ok(Html( ResponseTemplate { base_path, csrf_token, - current_user, + nav_state, projects, - team, keys: api_keys, } .render()?, diff --git a/templates/breadcrumbs.html b/templates/breadcrumbs.html new file mode 100644 index 0000000..c34ecb1 --- /dev/null +++ b/templates/breadcrumbs.html @@ -0,0 +1,10 @@ + diff --git a/templates/nav.html b/templates/nav.html index 0ffddb8..da39bfb 100644 --- a/templates/nav.html +++ b/templates/nav.html @@ -15,14 +15,34 @@