web add table fix in naming

This commit is contained in:
Priec
2026-08-13 22:48:29 +02:00
parent 2b68560359
commit df145c14f7
5 changed files with 89 additions and 21 deletions

View File

@@ -290,6 +290,11 @@ impl TableDraft {
.collect()
}
/// Whether any generated column has been given a name of its own.
pub(crate) fn has_generated_aliases(&self) -> bool {
!self.aliased_generated_columns().is_empty()
}
pub(crate) fn aliased_generated_columns(&self) -> Vec<(String, String)> {
self.aliasable_generated_columns()
.into_iter()
@@ -303,7 +308,7 @@ impl TableDraft {
/// Every alias has to be a legal column name, and has to be free: the table
/// is about to hold the declared columns, the generated ones and the system
/// ones, and two columns cannot share a name.
fn validate_generated_aliases(&self) -> Result<(), String> {
pub(crate) fn validate_generated_aliases(&self) -> Result<(), String> {
let generated = self.aliasable_generated_columns();
let renames = self.aliased_generated_columns();

View File

@@ -60,21 +60,26 @@ pub(crate) async fn load_page(
.into_inner();
let effective_profile = draft.effective_profile_name();
// 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<_, _>>()
.into_iter()
.map(|(name, table_kind)| RelationTableOption {
name,
global: true,
system: table_kind == "system",
})
.collect::<Vec<_>>();
if draft.global {
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<_, _>>()
.into_iter()
.map(|(name, table_kind)| RelationTableOption {
name,
global: true,
system: table_kind == "system",
})
.collect::<Vec<_>>();
draft.existing_profile_tables = tree
.profiles
.iter()
@@ -92,7 +97,7 @@ pub(crate) async fn load_page(
// An existing profile: its tables are the link targets, and their
// names are reserved against duplicate table creation.
Some(profile) => {
let table_options = profile
let mut table_options = profile
.tables
.iter()
.filter(|table| table.name != "accounts")
@@ -102,17 +107,28 @@ pub(crate) async fn load_page(
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 nothing to link to.
// 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.clear();
draft.relation_tables.clear();
draft.relation_table_options.clear();
draft.existing_profile_tables = global_tables
.iter()
.map(|table| table.name.clone())
.collect();
draft.set_available_relation_table_options(global_tables);
}
}}

View File

@@ -159,6 +159,21 @@ fn apply_action(page: &mut AddTablePageState, form: &BuilderForm) {
// in, so moving one is a change to the draft like any other.
"move-column-up" => page.status = page.draft.move_column(index, -1),
"move-column-down" => page.status = page.draft.move_column(index, 1),
// The alias fields carry no `change` trigger of their own — a text
// input fires `change` on blur, which would swap the builder out from
// under the click that is still in flight. This button is what applies
// what was typed, so the column list and the preview say what the
// table will really be called.
"apply-generated-names" => match page.draft.validate_generated_aliases() {
Ok(()) => {
page.status = Some(match page.draft.aliased_generated_columns().len() {
0 => "The generated columns keep their own names.".to_string(),
1 => "1 generated column renamed.".to_string(),
count => format!("{count} generated columns renamed."),
})
}
Err(message) => page.error = Some(message),
},
"toggle-index" => page.draft.columns.toggle_indexed(index),
"toggle-display" => page.draft.toggle_row_display_candidate(index),
_ => {}

View File

@@ -184,6 +184,28 @@ mod tests {
assert!(html.contains(r#"<span class="tag">renamed to md</span>"#), "{html}");
assert!(html.contains(r#"name="generated_alias_names" value="md""#));
// The names only reach the column list when something posts them, and
// the section stays open so the applied names can be read back.
assert!(html.contains(r#""action": "apply-generated-names""#));
assert!(html.contains(r#"<details class="rename-generated" open>"#));
}
/// With no name asked for, the section is the closed default it was.
#[test]
fn the_rename_section_starts_closed() {
let mut page = page();
page.draft.columns.added.push(ColumnDefinition {
name: "accounting".to_string(),
data_type: "accounting".to_string(),
indexed: false,
quantity_ledger: false,
money_mode: MoneyMode::Exact,
currency: "EUR".to_string(),
});
let html = render_builder(&page);
assert!(html.contains(r#"<details class="rename-generated" >"#), "{html}");
}
#[test]