diff --git a/client b/client index 827e6a40..949b8c78 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit 827e6a408a9f3df5f306461d3ade22f08e957c62 +Subproject commit 949b8c784d40e8889fb08b44dc591786412236fd diff --git a/common/proto/table_validation.proto b/common/proto/table_validation.proto index f3278cc8..c6187bc1 100644 --- a/common/proto/table_validation.proto +++ b/common/proto/table_validation.proto @@ -13,7 +13,7 @@ package komp_ac.table_validation; // // Important split: // - limits / pattern / allowed_values / required are validation rules. -// - mask is presentation and input-shaping metadata for clients. +// - mask is presentation/input-shaping metadata plus an optional storage policy. // Request validation rules for a table message GetTableValidationRequest { @@ -44,7 +44,7 @@ message FieldValidation { // Client-side hint that this field participates in external/asynchronous validation UI. bool external_validation_enabled = 13; - // Client-side display mask metadata. The server stores raw data without mask literals. + // Client-side display mask metadata and persisted representation policy. DisplayMask mask = 3; // Field must be provided / treated as required by clients and server enforcement layers. @@ -76,14 +76,18 @@ message CharacterLimits { CountMode countMode = 4; // defaults to CHARS if unspecified } -// Mask for pretty display only. -// -// This is not a validation rule by itself. It exists so clients can render and -// navigate masked input while still storing raw values server-side. +enum MaskStorageMode { + MASK_STORAGE_MODE_RAW = 0; + MASK_STORAGE_MODE_FORMATTED = 1; +} + +// Mask metadata used for rendering, input navigation, and optional persistence +// of reached mask literals. Template placeholders are never persisted. message DisplayMask { string pattern = 1; // e.g., "(###) ###-####" or "####-##-##" string input_char = 2; // e.g., "#" optional string template_char = 3; // e.g., "_" + optional MaskStorageMode storage_mode = 4; // absent/default means raw } // Which positions a pattern rule applies to. diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 9f6fc120..0077d896 100644 Binary files a/common/src/proto/descriptor.bin and b/common/src/proto/descriptor.bin differ diff --git a/common/src/proto/komp_ac.table_validation.rs b/common/src/proto/komp_ac.table_validation.rs index 08603730..e1f8cfa5 100644 --- a/common/src/proto/komp_ac.table_validation.rs +++ b/common/src/proto/komp_ac.table_validation.rs @@ -34,7 +34,7 @@ pub struct FieldValidation { /// Client-side hint that this field participates in external/asynchronous validation UI. #[prost(bool, tag = "13")] pub external_validation_enabled: bool, - /// Client-side display mask metadata. The server stores raw data without mask literals. + /// Client-side display mask metadata and persisted representation policy. #[prost(message, optional, tag = "3")] pub mask: ::core::option::Option, /// Field must be provided / treated as required by clients and server enforcement layers. @@ -63,10 +63,8 @@ pub struct CharacterLimits { #[prost(enumeration = "CountMode", tag = "4")] pub count_mode: i32, } -/// Mask for pretty display only. -/// -/// This is not a validation rule by itself. It exists so clients can render and -/// navigate masked input while still storing raw values server-side. +/// Mask metadata used for rendering, input navigation, and optional persistence +/// of reached mask literals. Template placeholders are never persisted. #[derive(serde::Serialize, serde::Deserialize)] #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DisplayMask { @@ -79,6 +77,9 @@ pub struct DisplayMask { /// e.g., "\_" #[prost(string, optional, tag = "3")] pub template_char: ::core::option::Option<::prost::alloc::string::String>, + /// absent/default means raw + #[prost(enumeration = "MaskStorageMode", optional, tag = "4")] + pub storage_mode: ::core::option::Option, } /// Which positions a pattern rule applies to. /// This exists instead of a string syntax like "0-3" so the server can validate @@ -401,6 +402,32 @@ impl CountMode { } } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum MaskStorageMode { + Raw = 0, + Formatted = 1, +} +impl MaskStorageMode { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Raw => "MASK_STORAGE_MODE_RAW", + Self::Formatted => "MASK_STORAGE_MODE_FORMATTED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "MASK_STORAGE_MODE_RAW" => Some(Self::Raw), + "MASK_STORAGE_MODE_FORMATTED" => Some(Self::Formatted), + _ => None, + } + } +} #[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] diff --git a/server b/server index e8c579bf..65e67fe7 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit e8c579bf55b20fec338507542c2bc7466ddfec9a +Subproject commit 65e67fe785b76a647759ca7d7e3517d251dab235 diff --git a/tui-canvas b/tui-canvas index dbec3130..f9d2a7a3 160000 --- a/tui-canvas +++ b/tui-canvas @@ -1 +1 @@ -Subproject commit dbec3130b35b324737df56140d6b0005f65e9479 +Subproject commit f9d2a7a3121abe68aaa232624035539eaf029240 diff --git a/tui-pages b/tui-pages index 8c66dedc..50e1145a 160000 --- a/tui-pages +++ b/tui-pages @@ -1 +1 @@ -Subproject commit 8c66dedc33d4c384977982b1115cb23a1d39e16c +Subproject commit 50e1145a9ab5cb7374da1b812f243b14e75614d7 diff --git a/web/src/pages/add_validation/state.rs b/web/src/pages/add_validation/state.rs index b4a0d5a5..aea97327 100644 --- a/web/src/pages/add_validation/state.rs +++ b/web/src/pages/add_validation/state.rs @@ -163,6 +163,7 @@ impl ValidationForm { self.mask_input_char.clone() }, template_char: nonempty(&self.mask_template_char), + storage_mode: None, }); let pattern = parse_pattern_rules(&self.pattern_rules, &self.pattern_description)?; Ok(FieldValidation {