web add table fix in naming
This commit is contained in:
@@ -290,6 +290,11 @@ impl TableDraft {
|
|||||||
.collect()
|
.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)> {
|
pub(crate) fn aliased_generated_columns(&self) -> Vec<(String, String)> {
|
||||||
self.aliasable_generated_columns()
|
self.aliasable_generated_columns()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -303,7 +308,7 @@ impl TableDraft {
|
|||||||
/// Every alias has to be a legal column name, and has to be free: the table
|
/// 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
|
/// is about to hold the declared columns, the generated ones and the system
|
||||||
/// ones, and two columns cannot share a name.
|
/// 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 generated = self.aliasable_generated_columns();
|
||||||
let renames = self.aliased_generated_columns();
|
let renames = self.aliased_generated_columns();
|
||||||
|
|
||||||
|
|||||||
@@ -60,21 +60,26 @@ pub(crate) async fn load_page(
|
|||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
let effective_profile = draft.effective_profile_name();
|
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 {
|
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
|
draft.existing_profile_tables = tree
|
||||||
.profiles
|
.profiles
|
||||||
.iter()
|
.iter()
|
||||||
@@ -92,7 +97,7 @@ pub(crate) async fn load_page(
|
|||||||
// An existing profile: its tables are the link targets, and their
|
// An existing profile: its tables are the link targets, and their
|
||||||
// names are reserved against duplicate table creation.
|
// names are reserved against duplicate table creation.
|
||||||
Some(profile) => {
|
Some(profile) => {
|
||||||
let table_options = profile
|
let mut table_options = profile
|
||||||
.tables
|
.tables
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|table| table.name != "accounts")
|
.filter(|table| table.name != "accounts")
|
||||||
@@ -102,17 +107,28 @@ pub(crate) async fn load_page(
|
|||||||
system: table.table_kind == "system",
|
system: table.table_kind == "system",
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.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
|
draft.existing_profile_tables = table_options
|
||||||
.iter()
|
.iter()
|
||||||
.map(|table| table.name.clone())
|
.map(|table| table.name.clone())
|
||||||
.collect();
|
.collect();
|
||||||
draft.set_available_relation_table_options(table_options);
|
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 => {
|
None => {
|
||||||
draft.existing_profile_tables.clear();
|
draft.existing_profile_tables = global_tables
|
||||||
draft.relation_tables.clear();
|
.iter()
|
||||||
draft.relation_table_options.clear();
|
.map(|table| table.name.clone())
|
||||||
|
.collect();
|
||||||
|
draft.set_available_relation_table_options(global_tables);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
// 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-up" => page.status = page.draft.move_column(index, -1),
|
||||||
"move-column-down" => 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-index" => page.draft.columns.toggle_indexed(index),
|
||||||
"toggle-display" => page.draft.toggle_row_display_candidate(index),
|
"toggle-display" => page.draft.toggle_row_display_candidate(index),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
@@ -184,6 +184,28 @@ mod tests {
|
|||||||
|
|
||||||
assert!(html.contains(r#"<span class="tag">renamed to md</span>"#), "{html}");
|
assert!(html.contains(r#"<span class="tag">renamed to md</span>"#), "{html}");
|
||||||
assert!(html.contains(r#"name="generated_alias_names" value="md""#));
|
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]
|
#[test]
|
||||||
|
|||||||
@@ -338,7 +338,9 @@
|
|||||||
#}
|
#}
|
||||||
{% if !page.alias_rows().is_empty() %}
|
{% if !page.alias_rows().is_empty() %}
|
||||||
<section class="builder-section">
|
<section class="builder-section">
|
||||||
<details class="rename-generated">
|
{# Open once a name has been asked for: the section is where those names are
|
||||||
|
read back, and a swap that closed it would hide what was just applied. #}
|
||||||
|
<details class="rename-generated" {% if page.draft.has_generated_aliases() %}open{% endif %}>
|
||||||
<summary>Rename generated columns</summary>
|
<summary>Rename generated columns</summary>
|
||||||
<p class="hint">These columns come from the definition rows above. Give one a name of your own, or leave it empty to keep the name shown.</p>
|
<p class="hint">These columns come from the definition rows above. Give one a name of your own, or leave it empty to keep the name shown.</p>
|
||||||
<ul class="rename-list">
|
<ul class="rename-list">
|
||||||
@@ -352,6 +354,14 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
{#
|
||||||
|
A text field posts nothing on its own here, so the names typed above are
|
||||||
|
only carried by the next request. This button is that request: it applies
|
||||||
|
them, so the column list and the preview show the renamed columns.
|
||||||
|
#}
|
||||||
|
<button type="button" class="secondary" hx-post="/admin/tables/builder" hx-include="#table-form"
|
||||||
|
hx-target="#builder" hx-swap="innerHTML"
|
||||||
|
hx-vals='{"action": "apply-generated-names"}'>Apply names</button>
|
||||||
</details>
|
</details>
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user