2025-08-04 13:59:42 -07:00
|
|
|
use anyhow::Result;
|
|
|
|
|
use askama::Template;
|
|
|
|
|
use derive_builder::Builder;
|
2025-09-14 16:19:44 -04:00
|
|
|
use interim_models::{client::AppDbClient, portal::Portal, workspace::Workspace};
|
2025-08-04 13:59:42 -07:00
|
|
|
use interim_pgtypes::{
|
2025-09-14 16:19:44 -04:00
|
|
|
client::WorkspaceClient,
|
2025-08-04 13:59:42 -07:00
|
|
|
pg_class::{PgClass, PgRelKind},
|
|
|
|
|
};
|
|
|
|
|
use sqlx::postgres::types::Oid;
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
2025-09-14 16:19:44 -04:00
|
|
|
use crate::navigator::Navigator;
|
2025-08-04 13:59:42 -07:00
|
|
|
|
2025-09-14 16:19:44 -04: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
|
|
|
}
|
|
|
|
|
|
2025-09-14 16:19:44 -04:00
|
|
|
impl WorkspaceNav {
|
|
|
|
|
pub fn builder() -> WorkspaceNavBuilder {
|
|
|
|
|
WorkspaceNavBuilder::default()
|
|
|
|
|
}
|
2025-08-04 13:59:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
2025-09-14 16:19:44 -04:00
|
|
|
pub struct RelationItem {
|
2025-08-04 13:59:42 -07:00
|
|
|
pub name: String,
|
2025-09-14 16:19:44 -04:00
|
|
|
pub oid: Oid,
|
|
|
|
|
pub portals: Vec<PortalItem>,
|
2025-08-04 13:59:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
2025-09-14 16:19:44 -04:00
|
|
|
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 {
|
2025-09-14 16:19:44 -04:00
|
|
|
Portal(Uuid),
|
|
|
|
|
Sharing,
|
2025-08-04 13:59:42 -07:00
|
|
|
}
|
|
|
|
|
|
2025-09-14 16:19:44 -04:00
|
|
|
impl WorkspaceNavBuilder {
|
2025-08-04 13:59:42 -07:00
|
|
|
/// Helper function to populate relations and lenses automatically.
|
2025-09-14 16:19:44 -04:00
|
|
|
/// [`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,
|
2025-09-14 16:19:44 -04:00
|
|
|
workspace_client: &mut WorkspaceClient,
|
2025-08-04 13:59:42 -07:00
|
|
|
) -> Result<&mut Self> {
|
|
|
|
|
let rels = PgClass::with_kind_in([PgRelKind::OrdinaryTable])
|
2025-09-14 16:19:44 -04:00
|
|
|
.fetch_all(workspace_client)
|
2025-08-04 13:59:42 -07:00
|
|
|
.await?;
|
2025-09-14 16:19:44 -04:00
|
|
|
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"
|
|
|
|
|
{
|
2025-09-14 16:19:44 -04:00
|
|
|
let portals = Portal::belonging_to_workspace(
|
|
|
|
|
self.workspace
|
2025-08-04 13:59:42 -07:00
|
|
|
.as_ref()
|
2025-09-14 16:19:44 -04:00
|
|
|
.ok_or(WorkspaceNavBuilderError::UninitializedField("workspace"))?
|
2025-08-04 13:59:42 -07:00
|
|
|
.id,
|
|
|
|
|
)
|
|
|
|
|
.belonging_to_rel(rel.oid)
|
|
|
|
|
.fetch_all(app_db)
|
|
|
|
|
.await?;
|
2025-09-14 16:19:44 -04:00
|
|
|
rel_items.push(RelationItem {
|
2025-08-04 13:59:42 -07:00
|
|
|
name: rel.relname,
|
2025-09-14 16:19:44 -04:00
|
|
|
oid: rel.oid,
|
|
|
|
|
portals: portals
|
2025-08-04 13:59:42 -07:00
|
|
|
.into_iter()
|
2025-09-14 16:19:44 -04:00
|
|
|
.map(|portal| PortalItem {
|
|
|
|
|
name: portal.name,
|
|
|
|
|
id: portal.id,
|
2025-08-04 13:59:42 -07:00
|
|
|
})
|
|
|
|
|
.collect(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-14 16:19:44 -04:00
|
|
|
Ok(self.relations(rel_items))
|
2025-08-04 13:59:42 -07:00
|
|
|
}
|
|
|
|
|
}
|