phonograph/interim-server/src/navbar.rs

109 lines
2.8 KiB
Rust
Raw Normal View History

2025-08-04 13:59:42 -07:00
use std::collections::HashMap;
use anyhow::Result;
use askama::Template;
use derive_builder::Builder;
use interim_models::{base::Base, client::AppDbClient, lens::Lens};
use interim_pgtypes::{
client::BaseClient,
pg_class::{PgClass, PgRelKind},
};
use sqlx::postgres::types::Oid;
use uuid::Uuid;
#[derive(Builder, Clone, Template)]
#[template(path = "navbar.html")]
pub struct Navbar {
pub base: Base,
pub namespaces: Vec<NamespaceItem>,
#[builder(setter(strip_option))]
pub current: Option<NavLocation>,
pub root_path: String,
}
impl Navbar {
pub fn builder() -> NavbarBuilder {
NavbarBuilder::default()
}
}
#[derive(Clone, Debug)]
pub struct NamespaceItem {
pub name: String,
pub rels: Vec<RelItem>,
}
#[derive(Clone, Debug)]
pub struct RelItem {
pub name: String,
pub class_oid: Oid,
pub lenses: Vec<LensItem>,
}
#[derive(Clone, Debug)]
pub struct LensItem {
pub name: String,
pub id: Uuid,
}
#[derive(Clone, Debug, PartialEq)]
pub enum NavLocation {
Rel(Oid, Option<RelLocation>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum RelLocation {
Lens(Uuid),
Rbac,
}
impl NavbarBuilder {
/// Helper function to populate relations and lenses automatically.
pub async fn populate_rels(
&mut self,
app_db: &mut AppDbClient,
base_client: &mut BaseClient,
) -> Result<&mut Self> {
let rels = PgClass::with_kind_in([PgRelKind::OrdinaryTable])
.fetch_all(base_client)
.await?;
let mut namespaces: HashMap<String, Vec<RelItem>> = HashMap::new();
for rel in rels {
if rel.regnamespace.as_str() != "pg_catalog"
&& rel.regnamespace.as_str() != "information_schema"
{
let lenses = Lens::belonging_to_base(
self.base
.as_ref()
.ok_or(NavbarBuilderError::UninitializedField("base"))?
.id,
)
.belonging_to_rel(rel.oid)
.fetch_all(app_db)
.await?;
let rel_items = namespaces.entry(rel.regnamespace).or_default();
rel_items.push(RelItem {
name: rel.relname,
class_oid: rel.oid,
lenses: lenses
.into_iter()
.map(|lens| LensItem {
name: lens.name,
id: lens.id,
})
.collect(),
});
}
}
Ok(self.namespaces(
namespaces
.into_iter()
.map(|(name, rel_items)| NamespaceItem {
name,
rels: rel_items,
})
.collect(),
))
}
}