refactor(web): add has_ai_extract flag to all page templates

Propagate has_ai_extract boolean through every template struct and
route handler so nav.html can conditionally show the scan link.
This commit is contained in:
Jon Seager 2026-02-03 19:14:47 +00:00
parent b668d368e7
commit 023ad1ac31
No known key found for this signature in database
10 changed files with 29 additions and 0 deletions

View file

@ -20,6 +20,7 @@ const SESSION_COOKIE_NAME: &str = "brewlog_session";
struct LoginTemplate {
nav_active: &'static str,
is_authenticated: bool,
has_ai_extract: bool,
error: Option<String>,
}
@ -42,6 +43,7 @@ pub(crate) async fn login_page(
let template = LoginTemplate {
nav_active: "login",
is_authenticated: false,
has_ai_extract: false,
error: None,
};
@ -130,6 +132,7 @@ fn show_login_error(message: &str) -> Result<Response, StatusCode> {
let template = LoginTemplate {
nav_active: "login",
is_authenticated: false,
has_ai_extract: false,
error: Some(message.to_string()),
};

View file

@ -99,6 +99,7 @@ pub(crate) async fn bags_page(
let template = BagsTemplate {
nav_active: "bags",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
open_bags,
bags,
roaster_options,

View file

@ -186,6 +186,7 @@ pub(crate) async fn brews_page(
let template = BrewsTemplate {
nav_active: "brews",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
brews,
bag_options,
grinder_options,

View file

@ -69,6 +69,7 @@ pub(crate) async fn cafes_page(
let template = CafesTemplate {
nav_active: "cafes",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
cafes,
navigator,
};
@ -94,6 +95,7 @@ pub(crate) async fn cafe_page(
let template = CafeDetailTemplate {
nav_active: "cafes",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
cafe: cafe_view,
};

View file

@ -74,6 +74,7 @@ pub(crate) async fn cups_page(
let template = CupsTemplate {
nav_active: "cups",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
cups,
roast_options,
cafe_options,

View file

@ -71,6 +71,7 @@ pub(crate) async fn gear_page(
let template = GearTemplate {
nav_active: "gear",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
gear,
navigator,
};

View file

@ -101,6 +101,7 @@ pub(crate) async fn roaster_page(
let template = RoasterDetailTemplate {
nav_active: "roasters",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
roaster: roaster_view,
roasts: roasts.into_iter().map(RoastView::from_list_item).collect(),
};

View file

@ -121,6 +121,7 @@ pub(crate) async fn roast_page(
let template = RoastDetailTemplate {
nav_active: "roasts",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
roast: RoastView::from_domain(roast, &roaster.name, &roaster.slug),
bags: bag_views,
};

View file

@ -93,6 +93,7 @@ pub(crate) async fn timeline_page(
let template = TimelineTemplate {
nav_active: "timeline",
is_authenticated,
has_ai_extract: state.has_ai_extract(),
events: data.events,
navigator: data.navigator,
months: data.months,

View file

@ -37,6 +37,7 @@ pub struct RoasterListTemplate {
pub struct RoasterDetailTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub roaster: RoasterView,
pub roasts: Vec<RoastView>,
}
@ -57,6 +58,7 @@ pub struct RoastsTemplate {
pub struct RoastDetailTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub roast: RoastView,
pub bags: Vec<BagView>,
}
@ -74,6 +76,7 @@ pub struct RoastListTemplate {
pub struct TimelineTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub events: Paginated<TimelineEventView>,
pub navigator: ListNavigator<TimelineSortKey>,
pub months: Vec<TimelineMonthView>,
@ -93,6 +96,7 @@ pub struct TimelineChunkTemplate {
pub struct BagsTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub open_bags: Vec<BagView>,
pub bags: Paginated<BagView>,
pub roaster_options: Vec<RoasterOptionView>,
@ -113,6 +117,7 @@ pub struct BagListTemplate {
pub struct GearTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub gear: Paginated<GearView>,
pub navigator: ListNavigator<GearSortKey>,
}
@ -136,6 +141,7 @@ pub struct RoastOptionsTemplate {
pub struct BrewsTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub brews: Paginated<BrewView>,
pub bag_options: Vec<BagOptionView>,
pub grinder_options: Vec<GearOptionView>,
@ -158,6 +164,7 @@ pub struct BrewListTemplate {
pub struct CafesTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub cafes: Paginated<CafeView>,
pub navigator: ListNavigator<CafeSortKey>,
}
@ -175,6 +182,7 @@ pub struct CafeListTemplate {
pub struct CafeDetailTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub cafe: CafeView,
}
@ -183,6 +191,7 @@ pub struct CafeDetailTemplate {
pub struct CupsTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
pub cups: Paginated<CupView>,
pub roast_options: Vec<RoastOptionView>,
pub cafe_options: Vec<CafeOptionView>,
@ -197,6 +206,14 @@ pub struct CupListTemplate {
pub navigator: ListNavigator<CupSortKey>,
}
#[derive(Template)]
#[template(path = "scan.html")]
pub struct ScanTemplate {
pub nav_active: &'static str,
pub is_authenticated: bool,
pub has_ai_extract: bool,
}
pub fn render_template<T: Template>(template: T) -> Result<String, askama::Error> {
template.render()
}