From 86efa8229302595ec1c1958c3a19c166f42bbd23 Mon Sep 17 00:00:00 2001 From: Filipriec Date: Sun, 30 Aug 2026 13:00:55 +0200 Subject: [PATCH] hidden columns from clients --- client | 2 +- common/proto/table_definition.proto | 27 ++++ common/src/proto/descriptor.bin | Bin 203675 -> 205480 bytes common/src/proto/komp_ac.table_definition.rs | 127 ++++++++++++++++++ server | 2 +- web/locales/cs/main.ftl | 4 + web/locales/en/main.ftl | 4 + web/locales/sk/main.ftl | 4 + web/src/lib.rs | 5 + .../pages/admin/table_definition/loader.rs | 2 + web/src/pages/admin/table_definition/logic.rs | 49 ++++++- web/src/pages/admin/table_definition/mod.rs | 4 + web/src/pages/admin/table_definition/state.rs | 21 +++ web/src/pages/admin/table_definition/ui.rs | 1 + .../table_definition/presentation_panel.html | 17 ++- 15 files changed, 263 insertions(+), 6 deletions(-) diff --git a/client b/client index 7eaf34d0..2e4b1589 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit 7eaf34d09e49bb0f30225368e20c63fb18c049bf +Subproject commit 2e4b158935ea31e1cf0c8504b6293d36ec703edb diff --git a/common/proto/table_definition.proto b/common/proto/table_definition.proto index 1e7aa49b..67946424 100644 --- a/common/proto/table_definition.proto +++ b/common/proto/table_definition.proto @@ -58,6 +58,11 @@ service TableDefinition { // Physical column names and identities remain unchanged. rpc SetColumnPresentation(SetColumnPresentationRequest) returns (SetColumnPresentationResponse); + // Shows or hides one column in bundled data-entry forms. This is presentation + // metadata only: hidden columns remain available to data APIs, scripts and + // backend calculations. + rpc SetColumnFormVisibility(SetColumnFormVisibilityRequest) returns (SetColumnFormVisibilityResponse); + // Drops a table and its metadata, then deletes the profile if it becomes empty. rpc DeleteTable(DeleteTableRequest) returns (DeleteTableResponse); } @@ -471,6 +476,10 @@ message ColumnBehavior { // Stable public identity used when updating this column's presentation. int64 column_id = 5; + + // True when bundled data-entry clients should not render this column. + // This is not an authorization boundary; data APIs still expose the column. + bool hidden_from_forms = 6; } // A script that targets a specific column in a table. @@ -507,6 +516,24 @@ message SetColumnPresentationResponse { int64 row_version = 4; } +message SetColumnFormVisibilityRequest { + string profile_name = 1; + string table_name = 2; + int64 column_id = 3; + bool hidden_from_forms = 4; + // Row version returned by GetProfileDetails when the column was read. + int64 expected_row_version = 5; +} + +message SetColumnFormVisibilityResponse { + bool success = 1; + string message = 2; + int64 column_id = 3; + bool hidden_from_forms = 4; + // New row version after the update. + int64 row_version = 5; +} + // Request to delete one table definition entirely. message DeleteTableRequest { // Profile (schema) name owning the table (must exist). diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index c073db7793a45303029d670f52e0aff6643472b3..8e339ff04577a10153e741db2bcb63fc8331e4cd 100644 GIT binary patch delta 11309 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