109 lines
2.8 KiB
Rust
109 lines
2.8 KiB
Rust
|
|
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(),
|
||
|
|
))
|
||
|
|
}
|
||
|
|
}
|