global is being global and i can select it and so on

This commit is contained in:
Priec
2026-08-13 22:51:57 +02:00
parent df145c14f7
commit 05f29b82f6
7 changed files with 368 additions and 130 deletions

View File

@@ -1,7 +1,10 @@
use axum::http::HeaderMap;
use crate::{
AppState, auth::GetAuthorizationRequest, definitions::common::Empty,
AppState,
auth::GetAuthorizationRequest,
definitions::{common::Empty, table_definition::GetTableCatalogRequest},
pages::table_scope,
services::authenticated_request,
};
@@ -59,78 +62,60 @@ pub(crate) async fn load_page(
.map_err(|error| LoadError::Backend(error.message().to_string()))?
.into_inner();
let effective_profile = draft.effective_profile_name();
// The global scope is the catalog's answer, here as everywhere else, so a
// shared table the admin panel lists is a shared table this page can link
// to — see `crate::pages::table_scope`.
let catalog_tables = definitions
.get_table_catalog(
authenticated_request(headers, GetTableCatalogRequest { profile_name: None })
.map_err(|_| LoadError::Unauthenticated)?,
)
.await
.map_err(|error| LoadError::Backend(error.message().to_string()))?
.into_inner()
.tables;
// A global table belongs to every profile, so it is a link target from
// every scope. It is listed under each profile in the tree, so it is
// collected once here and deduplicated by name.
let global_tables = tree
.profiles
.iter()
.flat_map(|profile| profile.tables.iter())
.filter(|table| table.global)
.map(|table| (table.name.clone(), table.table_kind.clone()))
.collect::<std::collections::BTreeMap<_, _>>()
let effective_profile = draft.effective_profile_name();
// A global table is a link target from every scope, and a global table
// being created may only link to another global one.
let tables = if draft.global {
table_scope::global_tables(&catalog_tables)
} else {
table_scope::linkable_tables(&tree.profiles, &catalog_tables, &effective_profile)
};
let table_options = tables
.into_iter()
.map(|(name, table_kind)| RelationTableOption {
name,
global: true,
system: table_kind == "system",
// The profile's ledger accounts are not a link target of their own: an
// ACCOUNTING column is how a row is posted to one.
.filter(|table| table.name != "accounts")
.map(|table| RelationTableOption {
name: table.name,
global: table.global,
system: table.table_kind == "system",
})
.collect::<Vec<_>>();
if draft.global {
draft.existing_profile_tables = tree
.profiles
// Every table the new one would sit beside holds its name — including the
// shared ones, which exist in every profile, and including in a profile
// that does not exist yet. A global table would land in every profile at
// once, so for that scope every name in the deployment is taken.
draft.existing_profile_tables = if draft.global {
tree.profiles
.iter()
.flat_map(|profile| profile.tables.iter())
.map(|table| table.name.clone())
.chain(catalog_tables.iter().map(|table| table.name.clone()))
.collect::<std::collections::BTreeSet<_>>()
.into_iter()
.collect();
draft.set_available_relation_table_options(global_tables);
} else { match tree
.profiles
.iter()
.find(|profile| profile.name == effective_profile)
{
// An existing profile: its tables are the link targets, and their
// names are reserved against duplicate table creation.
Some(profile) => {
let mut table_options = profile
.tables
.iter()
.filter(|table| table.name != "accounts")
.map(|table| RelationTableOption {
name: table.name.clone(),
global: table.global,
system: table.table_kind == "system",
})
.collect::<Vec<_>>();
// The shared tables belong here whether or not the tree repeated
// them under this profile.
for global in &global_tables {
if !table_options.iter().any(|table| table.name == global.name) {
table_options.push(global.clone());
}
}
draft.existing_profile_tables = table_options
.iter()
.map(|table| table.name.clone())
.collect();
draft.set_available_relation_table_options(table_options);
}
// A brand-new (or not-yet-named) profile has no tables of its own,
// but the shared ones are there to link to — and their names are
// taken, so the new table may not reuse one either.
None => {
draft.existing_profile_tables = global_tables
.iter()
.map(|table| table.name.clone())
.collect();
draft.set_available_relation_table_options(global_tables);
}
}}
.collect()
} else {
table_options
.iter()
.map(|table| table.name.clone())
.collect()
};
draft.set_available_relation_table_options(table_options);
Ok(AddTablePageState {
nav: crate::ui::Nav::new(headers, "admin").with_authorization(&authorization),