From 77e409dce6510cf4da5f5724a00d22b8ede56bea Mon Sep 17 00:00:00 2001 From: Filipriec Date: Mon, 24 Aug 2026 09:58:49 +0200 Subject: [PATCH] put table definition2 - name change --- common/proto/table_definition.proto | 4 +++ common/src/proto/descriptor.bin | Bin 194486 -> 194703 bytes common/src/proto/komp_ac.table_definition.rs | 4 +++ server | 2 +- web/CHANGELOG.md | 3 ++- web/locales/en/main.ftl | 4 ++- .../pages/admin/table_definition/loader.rs | 4 ++- web/src/pages/admin/table_definition/logic.rs | 25 +++++++++++++++--- web/src/pages/admin/table_definition/ui.rs | 1 + web/src/schema/mod.rs | 4 +++ .../table_definition/add_columns_panel.html | 7 +++++ 11 files changed, 51 insertions(+), 7 deletions(-) diff --git a/common/proto/table_definition.proto b/common/proto/table_definition.proto index 31a9fd16..73247c71 100644 --- a/common/proto/table_definition.proto +++ b/common/proto/table_definition.proto @@ -224,6 +224,10 @@ message PutTableDefinitionRequest { // Revision returned by GetProfileDetails. Prevents a stale editor from // overwriting a newer structural or presentation change. int64 expected_row_version = 7; + + // New physical/catalog name. Empty, or equal to table_name, keeps the + // current name for backwards-compatible callers. + string new_table_name = 8; } message PutTableDefinitionResponse { diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index a71ec3aeddeb3fe899d12e620196c52279b3515e..3f754625449de26924569167fc425a9f7ccfe55b 100644 GIT binary patch delta 7035 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 delta 6793 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 U8f_|JfA#=Ep)FPR4Lxz`f9+pph5!Hn diff --git a/common/src/proto/komp_ac.table_definition.rs b/common/src/proto/komp_ac.table_definition.rs index 7a498dba..e8163110 100644 --- a/common/src/proto/komp_ac.table_definition.rs +++ b/common/src/proto/komp_ac.table_definition.rs @@ -188,6 +188,10 @@ pub struct PutTableDefinitionRequest { /// overwriting a newer structural or presentation change. #[prost(int64, tag = "7")] pub expected_row_version: i64, + /// New physical/catalog name. Empty, or equal to table_name, keeps the + /// current name for backwards-compatible callers. + #[prost(string, tag = "8")] + pub new_table_name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PutTableDefinitionResponse { diff --git a/server b/server index e4540055..0fd5a16b 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit e454005545d3722d72b50f3a160ae345c44777b9 +Subproject commit 0fd5a16ba6ac0671daabfa5fcbf34bd24c12d80c diff --git a/web/CHANGELOG.md b/web/CHANGELOG.md index b47a30c2..5bb4dd2e 100644 --- a/web/CHANGELOG.md +++ b/web/CHANGELOG.md @@ -22,7 +22,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). the same ISO-4217 autocomplete options as the accounting currency. - **Editable empty-table definitions** — the table-definition column page now calls `PutTableDefinition` to atomically remove selected columns and append - replacements, with stable column identities and optimistic revision checks. + replacements or rename the table, with stable column identities and + optimistic revision checks. It is clearly labelled “Adjust table” only while the table is empty; after data is posted, the page switches to append-only “Add columns” mode. - **The shared profile is named by the backend** — `ProfileTreeResponse` diff --git a/web/locales/en/main.ftl b/web/locales/en/main.ftl index 17288d01..cf387873 100644 --- a/web/locales/en/main.ftl +++ b/web/locales/en/main.ftl @@ -169,6 +169,8 @@ td-add-columns-to = Add columns to td-append-hint = Columns are appended. Nothing that already exists is changed, and the new columns can be indexed as they are added. td-adjust-table-of = Adjust table td-adjust-table-hint = This table has no data, so you can add new columns or select existing columns to remove. The change is saved atomically. +td-table-name = Table name +td-table-name-hint = Rename the table here. Links and its definition continue to point to the same table. td-remove-column = Remove td-remove-column-aria = Remove { $column } td-remove-column-confirm = Remove column "{ $column }"? This can't be undone once you save. @@ -330,7 +332,7 @@ td-err-select-table-first = Select a table first. td-err-profile-gone = Profile `{ $missing }` no longer exists. td-err-not-a-table = `{ $missing }` is not a table of { $scope }. td-err-describe-column = Describe at least one column before adding. -td-err-describe-change = Select a column to remove or stage at least one column to add. +td-err-describe-change = Change the table name, select a column to remove, or stage at least one column to add. td-err-backend-no-columns = The backend did not add the columns. td-err-backend-no-adjustment = The backend did not adjust the table definition. td-err-populated-append-only = This table contains data. Existing columns cannot be removed; only new columns can be added. diff --git a/web/src/pages/admin/table_definition/loader.rs b/web/src/pages/admin/table_definition/loader.rs index d501d205..81debd98 100644 --- a/web/src/pages/admin/table_definition/loader.rs +++ b/web/src/pages/admin/table_definition/loader.rs @@ -279,7 +279,9 @@ pub(crate) async fn load_page( || tables .iter() .any(|table| table.name == inputs.selection.table && table.global); - inputs.columns.table_name = inputs.selection.table.clone(); + if inputs.columns.table_name.is_empty() { + inputs.columns.table_name = inputs.selection.table.clone(); + } Ok(TableDefinitionPageState { nav: crate::ui::Nav::from_authorization(headers, "admin", &authorization), diff --git a/web/src/pages/admin/table_definition/logic.rs b/web/src/pages/admin/table_definition/logic.rs index b8c8eb2f..ef3a33c3 100644 --- a/web/src/pages/admin/table_definition/logic.rs +++ b/web/src/pages/admin/table_definition/logic.rs @@ -27,7 +27,7 @@ use crate::{ PutTableDefinitionRequest, }, {i18n::Locale, tr}, - schema::{ColumnForm, proto_columns}, + schema::{ColumnForm, proto_columns, validate_table_name}, services::{authenticated_request, reject_cross_site}, }; @@ -189,6 +189,7 @@ pub(crate) async fn update_columns( let mut inputs = PageInputs::for_selection(selection); inputs.columns = form.to_draft(catalog, false); + inputs.columns.table_name = form.table_name_input.trim().to_string(); let index = form.index.unwrap_or(0); let locale = Locale::from_headers(&headers); @@ -239,6 +240,7 @@ pub(crate) async fn add_columns( let mut inputs = PageInputs::for_selection(selection); inputs.columns = form.to_draft(catalog.clone(), false); + inputs.columns.table_name = form.table_name_input.trim().to_string(); inputs.remove_column_ids = form.remove_column_ids.clone(); if !inputs.selection.has_table() { @@ -255,7 +257,21 @@ pub(crate) async fn add_columns( ) .await; } - if inputs.columns.is_empty() && inputs.remove_column_ids.is_empty() { + let requested_table_name = if inputs.columns.table_name.is_empty() { + inputs.selection.table.clone() + } else { + inputs.columns.table_name.clone() + }; + let renaming = requested_table_name != inputs.selection.table; + if renaming + && let Some(message) = validate_table_name( + Locale::from_headers(&headers), + &requested_table_name, + ) + { + return refuse(state, headers, inputs, Page::AddColumns, message).await; + } + if inputs.columns.is_empty() && inputs.remove_column_ids.is_empty() && !renaming { let message = tr!( Locale::from_headers(&headers), "td-err-describe-change" @@ -314,6 +330,7 @@ pub(crate) async fn add_columns( add_indexes: inputs.columns.selected_index_names(), generated_aliases: Vec::new(), expected_row_version: form.expected_row_version, + new_table_name: requested_table_name.clone(), }; let Ok(request) = authenticated_request(&headers, request) else { return Redirect::to("/login").into_response(); @@ -330,9 +347,11 @@ pub(crate) async fn add_columns( "td-definition-adjusted", "added" => added as i64, "removed" => removed as i64, - "table" => inputs.selection.table.clone(), + "table" => requested_table_name.clone(), )); + inputs.selection.table = requested_table_name.clone(); inputs.columns = crate::schema::ColumnDraft::for_append(catalog); + inputs.columns.table_name = requested_table_name; inputs.remove_column_ids.clear(); respond(state, headers, inputs, Page::AddColumns, StatusCode::OK).await } diff --git a/web/src/pages/admin/table_definition/ui.rs b/web/src/pages/admin/table_definition/ui.rs index 9706321a..274ebd53 100644 --- a/web/src/pages/admin/table_definition/ui.rs +++ b/web/src/pages/admin/table_definition/ui.rs @@ -456,6 +456,7 @@ mod tests { let add_html = render_add_columns_page(&page()); assert!(add_html.contains(r#"id="column-form""#), "{add_html}"); assert!(add_html.contains(r#"name="expected_row_version" value="1""#), "{add_html}"); + assert!(add_html.contains(r#"name="table_name_input" value="invoice""#), "{add_html}"); assert!(add_html.contains(r#"name="remove_column_ids" value="1""#), "{add_html}"); assert!(add_html.contains("Adjust table"), "{add_html}"); assert!(!add_html.contains(r#"name="alias""#), "{add_html}"); diff --git a/web/src/schema/mod.rs b/web/src/schema/mod.rs index b9a1966d..decde2cd 100644 --- a/web/src/schema/mod.rs +++ b/web/src/schema/mod.rs @@ -1422,6 +1422,10 @@ pub(crate) struct ColumnForm { pub remove_column_ids: Vec, #[serde(default)] pub expected_row_version: i64, + /// The requested name of an existing empty table. The append-only form + /// does not render it, so populated tables decode this as empty. + #[serde(default)] + pub table_name_input: String, #[serde(default)] pub column_name_input: String, diff --git a/web/templates/pages/admin/table_definition/add_columns_panel.html b/web/templates/pages/admin/table_definition/add_columns_panel.html index 6ae70741..2c4a7fe9 100644 --- a/web/templates/pages/admin/table_definition/add_columns_panel.html +++ b/web/templates/pages/admin/table_definition/add_columns_panel.html @@ -10,6 +10,13 @@ {% if page.can_adjust_definition() %}

{{ nav.tr("td-adjust-table-of") }} {{ page.selection.table }}

{{ nav.tr("td-adjust-table-hint") }}

+
+ +
{% else %}

{{ nav.tr("td-add-columns-to") }} {{ page.selection.table }}

{{ nav.tr("td-append-hint") }}