phonograph/interim-server/src/workspace_nav.rs

96 lines
2.7 KiB
Rust
Raw Normal View History

2025-08-04 13:59:42 -07:00
use anyhow::Result;
use askama::Template;
use derive_builder::Builder;
use interim_models::{client::AppDbClient, portal::Portal, workspace::Workspace};
2025-08-04 13:59:42 -07:00
use interim_pgtypes::{
client::WorkspaceClient,
2025-08-04 13:59:42 -07:00
pg_class::{PgClass, PgRelKind},
};
use sqlx::postgres::types::Oid;
use uuid::Uuid;
use crate::navigator::Navigator;
2025-08-04 13:59:42 -07:00
#[derive(Builder, Clone, Debug, Template)]
#[template(path = "workspace_nav.html")]
pub(crate) struct WorkspaceNav {
workspace: Workspace,
relations: Vec<RelationItem>,
#[builder(default, setter(strip_option))]
current: Option<NavLocation>,
navigator: Navigator,
2025-08-04 13:59:42 -07:00
}
impl WorkspaceNav {
pub fn builder() -> WorkspaceNavBuilder {
WorkspaceNavBuilder::default()
}
2025-08-04 13:59:42 -07:00
}
#[derive(Clone, Debug)]
pub struct RelationItem {
2025-08-04 13:59:42 -07:00
pub name: String,
pub oid: Oid,
pub portals: Vec<PortalItem>,
2025-08-04 13:59:42 -07:00
}
#[derive(Clone, Debug)]
pub struct PortalItem {
2025-08-04 13:59:42 -07:00
pub name: String,
pub id: Uuid,
}
#[derive(Clone, Debug, PartialEq)]
pub enum NavLocation {
Rel(Oid, Option<RelLocation>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum RelLocation {
Portal(Uuid),
Sharing,
2025-08-04 13:59:42 -07:00
}
impl WorkspaceNavBuilder {
2025-08-04 13:59:42 -07:00
/// Helper function to populate relations and lenses automatically.
/// [`WorkspaceNavBuilder::workspace()`] must be called first, or else this
/// method will return an error.
2025-08-04 13:59:42 -07:00
pub async fn populate_rels(
&mut self,
app_db: &mut AppDbClient,
workspace_client: &mut WorkspaceClient,
2025-08-04 13:59:42 -07:00
) -> Result<&mut Self> {
let rels = PgClass::with_kind_in([PgRelKind::OrdinaryTable])
.fetch_all(workspace_client)
2025-08-04 13:59:42 -07:00
.await?;
let mut rel_items = Vec::with_capacity(rels.len());
2025-08-04 13:59:42 -07:00
for rel in rels {
if rel.regnamespace.as_str() != "pg_catalog"
&& rel.regnamespace.as_str() != "information_schema"
{
let portals = Portal::belonging_to_workspace(
self.workspace
2025-08-04 13:59:42 -07:00
.as_ref()
.ok_or(WorkspaceNavBuilderError::UninitializedField("workspace"))?
2025-08-04 13:59:42 -07:00
.id,
)
.belonging_to_rel(rel.oid)
.fetch_all(app_db)
.await?;
rel_items.push(RelationItem {
2025-08-04 13:59:42 -07:00
name: rel.relname,
oid: rel.oid,
portals: portals
2025-08-04 13:59:42 -07:00
.into_iter()
.map(|portal| PortalItem {
name: portal.name,
id: portal.id,
2025-08-04 13:59:42 -07:00
})
.collect(),
});
}
}
Ok(self.relations(rel_items))
2025-08-04 13:59:42 -07:00
}
}