@praxisui/dynamic-fields 9.0.0-beta.8 → 9.0.0-beta.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/ai/component-registry.json +273462 -0
- package/docs/date-range-rust-host-integration.md +474 -0
- package/docs/dynamic-fields-field-catalog.md +3 -4
- package/docs/dynamic-fields-field-selection-guide.md +27 -3
- package/docs/dynamic-fields-inline-components-guide.md +30 -7
- package/docs/dynamic-fields-inline-filter-catalog.md +18 -1
- package/docs/dynamic-fields-inline-filter-runtime-contract.md +11 -0
- package/fesm2022/praxisui-dynamic-fields.mjs +2776 -983
- package/package.json +8 -4
- package/src/lib/base/pdx-base-input-runtime-contract.json-api.md +16 -0
- package/src/lib/components/field-shell/praxis-field-shell.json-api.md +33 -3
- package/src/lib/components/inline-date/pdx-inline-date.json-api.md +1 -1
- package/src/lib/components/inline-date-range/pdx-inline-date-range.json-api.md +30 -9
- package/src/lib/components/inline-entity-lookup/pdx-inline-entity-lookup.json-api.md +1 -0
- package/src/lib/components/inline-number/pdx-inline-number.json-api.md +1 -0
- package/src/lib/components/inline-rating/pdx-inline-rating.json-api.md +2 -0
- package/src/lib/components/inline-relative-period/pdx-inline-relative-period.json-api.md +2 -2
- package/src/lib/components/inline-time-range/pdx-inline-time-range.json-api.md +2 -2
- package/src/lib/components/material-async-select/pdx-material-async-select.json-api.md +13 -4
- package/src/lib/components/material-checkbox-group/pdx-material-checkbox-group.json-api.md +5 -3
- package/src/lib/components/material-date-range/pdx-material-date-range.json-api.md +20 -2
- package/src/lib/components/material-file-upload/pdx-material-file-upload.json-api.md +58 -27
- package/src/lib/components/material-searchable-select/pdx-material-searchable-select.json-api.md +10 -3
- package/src/lib/components/material-textarea/pdx-material-textarea.json-api.md +1 -1
- package/types/praxisui-dynamic-fields.d.ts +160 -11
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Date Range Rust Host Integration"
|
|
3
|
+
slug: "date-range-rust-host-integration"
|
|
4
|
+
description: "Guia para hosts Rust publicarem atalhos corporativos de date range como metadata JSON resolvida, sem executar regras de negocio no frontend."
|
|
5
|
+
doc_type: "guide"
|
|
6
|
+
document_kind: "host-guide"
|
|
7
|
+
component: "dynamic-fields"
|
|
8
|
+
category: "integration"
|
|
9
|
+
audience:
|
|
10
|
+
- "backend"
|
|
11
|
+
- "host"
|
|
12
|
+
- "frontend"
|
|
13
|
+
- "architect"
|
|
14
|
+
level: "enterprise"
|
|
15
|
+
status: "active"
|
|
16
|
+
owner: "praxis-ui"
|
|
17
|
+
tags:
|
|
18
|
+
- "dynamic-fields"
|
|
19
|
+
- "date-range"
|
|
20
|
+
- "rust"
|
|
21
|
+
- "metadata"
|
|
22
|
+
- "business-periods"
|
|
23
|
+
order: 45
|
|
24
|
+
icon: "calendar_month"
|
|
25
|
+
toc: true
|
|
26
|
+
sidebar: true
|
|
27
|
+
search_boost: 1.2
|
|
28
|
+
reading_time: 24
|
|
29
|
+
estimated_setup_time: 35
|
|
30
|
+
version: "1.0"
|
|
31
|
+
related_docs:
|
|
32
|
+
- "pdx-material-date-range-json-api"
|
|
33
|
+
- "pdx-inline-date-range-json-api"
|
|
34
|
+
- "dynamic-fields-inline-filter-runtime-contract"
|
|
35
|
+
- "date-range-business-shortcuts-evolution-plan"
|
|
36
|
+
keywords:
|
|
37
|
+
- "StaticDateRangePreset"
|
|
38
|
+
- "serde"
|
|
39
|
+
- "inlineQuickPresets.position"
|
|
40
|
+
- "startDate"
|
|
41
|
+
- "endDate"
|
|
42
|
+
- "calculateRange"
|
|
43
|
+
last_updated: "2026-07-11"
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Date Range Rust Host Integration
|
|
47
|
+
|
|
48
|
+
## Objetivo
|
|
49
|
+
|
|
50
|
+
Orientar hosts Rust que publicam metadata Praxis para `pdx-material-date-range`
|
|
51
|
+
e `pdx-inline-date-range` com atalhos corporativos resolvidos pelo dominio.
|
|
52
|
+
|
|
53
|
+
O contrato de runtime Angular aceita built-ins, presets programaticos
|
|
54
|
+
TypeScript e presets estaticos serializaveis. Hosts Rust devem publicar apenas
|
|
55
|
+
os built-ins e os presets estaticos. Funcoes JavaScript como `calculateRange`
|
|
56
|
+
nao pertencem ao JSON publicado pelo backend.
|
|
57
|
+
|
|
58
|
+
## Pre-requisitos
|
|
59
|
+
|
|
60
|
+
- Host Rust responsavel por publicar metadata Praxis para schema, recurso ou
|
|
61
|
+
endpoint equivalente.
|
|
62
|
+
- Dominio capaz de resolver periodos de negocio antes da serializacao JSON.
|
|
63
|
+
- Conhecimento do contrato `pdx-material-date-range` ou
|
|
64
|
+
`pdx-inline-date-range`.
|
|
65
|
+
- Pipeline de testes que consiga validar serializacao Rust e consumir a
|
|
66
|
+
metadata em uma superficie Praxis oficial.
|
|
67
|
+
|
|
68
|
+
## Responsabilidades
|
|
69
|
+
|
|
70
|
+
| Camada | Responsabilidade |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| Rust/backend | Calcular regras eleitorais, legais, fiscais, contratuais, feriados, dias contaveis, autorizacao, confidencialidade e vigencia antes de publicar metadata. |
|
|
73
|
+
| Metadata publicada | Transportar somente intervalos resolvidos, labels, descricoes, icones semanticos, tons semanticos e configuracao de layout. |
|
|
74
|
+
| Angular/Praxis UI | Materializar o catalogo recebido, preservar constraints do campo, teclado, foco, RTL, tema e payload canonico. |
|
|
75
|
+
| Auditoria de negocio | Permanecer no backend/dominio; `shortcutId`/`id` pode apoiar observabilidade de UI, mas nunca substitui as datas. |
|
|
76
|
+
|
|
77
|
+
O frontend nao executa regras fiscais, eleitorais, juridicas ou de dias uteis
|
|
78
|
+
recebidas por JSON. Se a regra muda por calendario, jurisdicao, tenant,
|
|
79
|
+
permissao ou feriado, o Rust publica um novo intervalo ja resolvido.
|
|
80
|
+
|
|
81
|
+
## Contrato JSON
|
|
82
|
+
|
|
83
|
+
### Built-in
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"controlType": "dateRange",
|
|
88
|
+
"shortcuts": ["today", "thisWeek", "thisMonth"]
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Built-ins sao identificadores conhecidos pelo runtime. Use-os apenas quando a
|
|
93
|
+
semantica relativa for aceitavel para o campo.
|
|
94
|
+
|
|
95
|
+
### Preset estatico
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"id": "periodo-votacao-2026",
|
|
100
|
+
"label": "Periodo de votacao 2026",
|
|
101
|
+
"description": "Janela oficial resolvida pelo dominio eleitoral.",
|
|
102
|
+
"startDate": "2026-07-06",
|
|
103
|
+
"endDate": "2026-10-04",
|
|
104
|
+
"timeZone": "America/Sao_Paulo",
|
|
105
|
+
"icon": "how_to_vote",
|
|
106
|
+
"tone": "info",
|
|
107
|
+
"effectiveFrom": "2026-06-01",
|
|
108
|
+
"effectiveTo": "2026-10-04"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Campos suportados:
|
|
113
|
+
|
|
114
|
+
| Campo | Obrigatorio | Semantica |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| `id` | Sim | Identificador estavel do atalho para estado ativo e observabilidade. |
|
|
117
|
+
| `label` | Sim | Texto publicado pelo dominio ou por i18n governado do host. |
|
|
118
|
+
| `startDate` | Sim | Inicio inclusivo do intervalo resolvido. |
|
|
119
|
+
| `endDate` | Sim | Fim inclusivo do intervalo resolvido. |
|
|
120
|
+
| `timeZone` | Nao | Timezone IANA usado pelo dominio ao resolver o periodo. |
|
|
121
|
+
| `icon` | Nao | Nome de icone semantico suportado pelo host/Praxis. |
|
|
122
|
+
| `description` | Nao | Explicacao operacional do periodo. |
|
|
123
|
+
| `tone` | Nao | `neutral`, `info`, `success` ou `warning`; nunca cor arbitraria. |
|
|
124
|
+
| `effectiveFrom` | Nao | Inicio da vigencia da metadata do atalho. |
|
|
125
|
+
| `effectiveTo` | Nao | Fim da vigencia da metadata do atalho. |
|
|
126
|
+
|
|
127
|
+
### Lista mista e composicao inline
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"controlType": "inlineDateRange",
|
|
132
|
+
"label": "Periodo",
|
|
133
|
+
"shortcuts": [
|
|
134
|
+
"today",
|
|
135
|
+
{
|
|
136
|
+
"id": "competencia-fiscal-2026-03",
|
|
137
|
+
"label": "Competencia fiscal 03/2026",
|
|
138
|
+
"description": "Periodo fiscal fechado pelo dominio tributario.",
|
|
139
|
+
"startDate": "2026-03-01",
|
|
140
|
+
"endDate": "2026-03-31",
|
|
141
|
+
"timeZone": "America/Sao_Paulo",
|
|
142
|
+
"icon": "account_balance",
|
|
143
|
+
"tone": "success"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"inlineQuickPresets": {
|
|
147
|
+
"enabled": true,
|
|
148
|
+
"maxVisible": 4,
|
|
149
|
+
"position": "start"
|
|
150
|
+
},
|
|
151
|
+
"inlineOverlay": {
|
|
152
|
+
"applyMode": "explicit",
|
|
153
|
+
"actions": {
|
|
154
|
+
"apply": { "label": "Aplicar", "appearance": "filled", "colorRole": "primary" },
|
|
155
|
+
"cancel": { "label": "Cancelar", "appearance": "text", "colorRole": "neutral" }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`inlineQuickPresets.position` aceita:
|
|
162
|
+
|
|
163
|
+
| Valor | Uso |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `footer` | Atalhos no rodape, antes de Cancelar/Aplicar. |
|
|
166
|
+
| `start` | Rail logica antes do calendario; esquerda em LTR e direita em RTL. |
|
|
167
|
+
| `end` | Rail logica depois do calendario; direita em LTR e esquerda em RTL. |
|
|
168
|
+
| `auto` | Runtime escolhe rail ou rodape conforme espaco, touch e viewport. |
|
|
169
|
+
|
|
170
|
+
Em viewport estreito, por exemplo 390 px, `auto`, `start` e `end` podem cair
|
|
171
|
+
para `footer` para preservar legibilidade, foco e ordem de tabulacao.
|
|
172
|
+
|
|
173
|
+
## Datas, timezone e payload
|
|
174
|
+
|
|
175
|
+
Use `YYYY-MM-DD` para data civil quando o periodo e contado em dias. O runtime
|
|
176
|
+
trata date-only como data local civil e preserva a semantica de intervalo
|
|
177
|
+
inclusivo de inicio/fim.
|
|
178
|
+
|
|
179
|
+
Use datetime somente se o contrato do recurso exigir instantes com hora. Para
|
|
180
|
+
filtros de periodo civil, prefira date-only e deixe o backend traduzir para
|
|
181
|
+
limites de query conforme timezone, banco e regra do dominio.
|
|
182
|
+
|
|
183
|
+
O payload final do filtro continua canonico:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"startDate": "2026-03-01",
|
|
188
|
+
"endDate": "2026-03-31"
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
O `id` do preset pode aparecer em estado interno, destaque visual ou telemetria
|
|
193
|
+
opcional. Ele nao substitui `startDate` e `endDate` no contrato de filtro.
|
|
194
|
+
|
|
195
|
+
## Exemplo Rust reproduzivel
|
|
196
|
+
|
|
197
|
+
Dependencias sugeridas:
|
|
198
|
+
|
|
199
|
+
```toml
|
|
200
|
+
[dependencies]
|
|
201
|
+
chrono = { version = "0.4", features = ["serde"] }
|
|
202
|
+
chrono-tz = "0.10"
|
|
203
|
+
serde = { version = "1", features = ["derive"] }
|
|
204
|
+
serde_json = "1"
|
|
205
|
+
thiserror = "2"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
DTOs serializaveis:
|
|
209
|
+
|
|
210
|
+
```rust
|
|
211
|
+
use chrono::NaiveDate;
|
|
212
|
+
use chrono_tz::Tz;
|
|
213
|
+
use serde::Serialize;
|
|
214
|
+
use thiserror::Error;
|
|
215
|
+
|
|
216
|
+
#[derive(Debug, Clone, Serialize)]
|
|
217
|
+
#[serde(rename_all = "camelCase")]
|
|
218
|
+
pub struct StaticDateRangePresetDto {
|
|
219
|
+
pub id: String,
|
|
220
|
+
pub label: String,
|
|
221
|
+
pub start_date: String,
|
|
222
|
+
pub end_date: String,
|
|
223
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
224
|
+
pub time_zone: Option<String>,
|
|
225
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
226
|
+
pub icon: Option<String>,
|
|
227
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
228
|
+
pub description: Option<String>,
|
|
229
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
230
|
+
pub tone: Option<StaticDateRangePresetToneDto>,
|
|
231
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
232
|
+
pub effective_from: Option<String>,
|
|
233
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
234
|
+
pub effective_to: Option<String>,
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
#[derive(Debug, Clone, Serialize)]
|
|
238
|
+
#[serde(rename_all = "camelCase")]
|
|
239
|
+
pub enum StaticDateRangePresetToneDto {
|
|
240
|
+
Neutral,
|
|
241
|
+
Info,
|
|
242
|
+
Success,
|
|
243
|
+
Warning,
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
#[derive(Debug, Clone, Serialize)]
|
|
247
|
+
#[serde(untagged)]
|
|
248
|
+
pub enum DateRangeShortcutDto {
|
|
249
|
+
BuiltIn(String),
|
|
250
|
+
Static(StaticDateRangePresetDto),
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#[derive(Debug, Clone, Serialize)]
|
|
254
|
+
#[serde(rename_all = "camelCase")]
|
|
255
|
+
pub struct InlineQuickPresetsDto {
|
|
256
|
+
pub enabled: bool,
|
|
257
|
+
pub max_visible: Option<u8>,
|
|
258
|
+
pub position: InlineQuickPresetsPositionDto,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#[derive(Debug, Clone, Serialize)]
|
|
262
|
+
#[serde(rename_all = "camelCase")]
|
|
263
|
+
pub enum InlineQuickPresetsPositionDto {
|
|
264
|
+
Auto,
|
|
265
|
+
Footer,
|
|
266
|
+
Start,
|
|
267
|
+
End,
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#[derive(Debug, Clone, Serialize)]
|
|
271
|
+
#[serde(rename_all = "camelCase")]
|
|
272
|
+
pub struct DateRangeFieldMetadataDto {
|
|
273
|
+
pub control_type: String,
|
|
274
|
+
pub label: String,
|
|
275
|
+
pub shortcuts: Vec<DateRangeShortcutDto>,
|
|
276
|
+
pub inline_quick_presets: InlineQuickPresetsDto,
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#[derive(Debug, Error)]
|
|
280
|
+
pub enum DateRangeMetadataError {
|
|
281
|
+
#[error("invalid date {value}; expected YYYY-MM-DD")]
|
|
282
|
+
InvalidDate { value: String },
|
|
283
|
+
#[error("startDate must be before or equal to endDate")]
|
|
284
|
+
InvertedInterval,
|
|
285
|
+
#[error("invalid IANA timezone {value}")]
|
|
286
|
+
InvalidTimeZone { value: String },
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
fn parse_date(value: &str) -> Result<NaiveDate, DateRangeMetadataError> {
|
|
290
|
+
NaiveDate::parse_from_str(value, "%Y-%m-%d")
|
|
291
|
+
.map_err(|_| DateRangeMetadataError::InvalidDate { value: value.to_owned() })
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
pub fn validate_static_preset(
|
|
295
|
+
preset: &StaticDateRangePresetDto,
|
|
296
|
+
) -> Result<(), DateRangeMetadataError> {
|
|
297
|
+
let start = parse_date(&preset.start_date)?;
|
|
298
|
+
let end = parse_date(&preset.end_date)?;
|
|
299
|
+
if start > end {
|
|
300
|
+
return Err(DateRangeMetadataError::InvertedInterval);
|
|
301
|
+
}
|
|
302
|
+
if let Some(zone) = &preset.time_zone {
|
|
303
|
+
zone.parse::<Tz>()
|
|
304
|
+
.map_err(|_| DateRangeMetadataError::InvalidTimeZone { value: zone.clone() })?;
|
|
305
|
+
}
|
|
306
|
+
Ok(())
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Periodo de negocio resolvido pelo backend:
|
|
311
|
+
|
|
312
|
+
```rust
|
|
313
|
+
pub fn voting_period_metadata() -> Result<DateRangeFieldMetadataDto, DateRangeMetadataError> {
|
|
314
|
+
let voting_period = StaticDateRangePresetDto {
|
|
315
|
+
id: "periodo-votacao-2026".into(),
|
|
316
|
+
label: "Periodo de votacao 2026".into(),
|
|
317
|
+
description: Some("Janela oficial resolvida pelo dominio eleitoral.".into()),
|
|
318
|
+
start_date: "2026-07-06".into(),
|
|
319
|
+
end_date: "2026-10-04".into(),
|
|
320
|
+
time_zone: Some("America/Sao_Paulo".into()),
|
|
321
|
+
icon: Some("how_to_vote".into()),
|
|
322
|
+
tone: Some(StaticDateRangePresetToneDto::Info),
|
|
323
|
+
effective_from: Some("2026-06-01".into()),
|
|
324
|
+
effective_to: Some("2026-10-04".into()),
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
validate_static_preset(&voting_period)?;
|
|
328
|
+
|
|
329
|
+
Ok(DateRangeFieldMetadataDto {
|
|
330
|
+
control_type: "inlineDateRange".into(),
|
|
331
|
+
label: "Periodo".into(),
|
|
332
|
+
shortcuts: vec![
|
|
333
|
+
DateRangeShortcutDto::BuiltIn("today".into()),
|
|
334
|
+
DateRangeShortcutDto::Static(voting_period),
|
|
335
|
+
],
|
|
336
|
+
inline_quick_presets: InlineQuickPresetsDto {
|
|
337
|
+
enabled: true,
|
|
338
|
+
max_visible: Some(4),
|
|
339
|
+
position: InlineQuickPresetsPositionDto::Auto,
|
|
340
|
+
},
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Teste de serializacao:
|
|
346
|
+
|
|
347
|
+
```rust
|
|
348
|
+
#[test]
|
|
349
|
+
fn serializes_resolved_business_period_metadata() {
|
|
350
|
+
let metadata = voting_period_metadata().expect("valid metadata");
|
|
351
|
+
let json = serde_json::to_value(metadata).expect("serializable");
|
|
352
|
+
|
|
353
|
+
assert_eq!(json["controlType"], "inlineDateRange");
|
|
354
|
+
assert_eq!(json["shortcuts"][0], "today");
|
|
355
|
+
assert_eq!(json["shortcuts"][1]["id"], "periodo-votacao-2026");
|
|
356
|
+
assert_eq!(json["shortcuts"][1]["startDate"], "2026-07-06");
|
|
357
|
+
assert_eq!(json["shortcuts"][1]["endDate"], "2026-10-04");
|
|
358
|
+
assert!(json["shortcuts"][1].get("calculateRange").is_none());
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
#[test]
|
|
362
|
+
fn rejects_inverted_interval() {
|
|
363
|
+
let preset = StaticDateRangePresetDto {
|
|
364
|
+
id: "invalid".into(),
|
|
365
|
+
label: "Invalid".into(),
|
|
366
|
+
start_date: "2026-10-04".into(),
|
|
367
|
+
end_date: "2026-07-06".into(),
|
|
368
|
+
time_zone: Some("America/Sao_Paulo".into()),
|
|
369
|
+
icon: None,
|
|
370
|
+
description: None,
|
|
371
|
+
tone: None,
|
|
372
|
+
effective_from: None,
|
|
373
|
+
effective_to: None,
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
assert!(matches!(
|
|
377
|
+
validate_static_preset(&preset),
|
|
378
|
+
Err(DateRangeMetadataError::InvertedInterval)
|
|
379
|
+
));
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
#[test]
|
|
383
|
+
fn rejects_invalid_timezone() {
|
|
384
|
+
let preset = StaticDateRangePresetDto {
|
|
385
|
+
id: "invalid-zone".into(),
|
|
386
|
+
label: "Invalid zone".into(),
|
|
387
|
+
start_date: "2026-07-06".into(),
|
|
388
|
+
end_date: "2026-10-04".into(),
|
|
389
|
+
time_zone: Some("America/Sao_Paulo/BRT".into()),
|
|
390
|
+
icon: None,
|
|
391
|
+
description: None,
|
|
392
|
+
tone: None,
|
|
393
|
+
effective_from: None,
|
|
394
|
+
effective_to: None,
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
assert!(matches!(
|
|
398
|
+
validate_static_preset(&preset),
|
|
399
|
+
Err(DateRangeMetadataError::InvalidTimeZone { .. })
|
|
400
|
+
));
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## Governanca e seguranca
|
|
405
|
+
|
|
406
|
+
- Decida permissao e confidencialidade antes de publicar metadata. Se revelar
|
|
407
|
+
a existencia do periodo ja for sensivel, omita o atalho.
|
|
408
|
+
- O contrato atual de preset estatico nao possui campo publico `disabled`.
|
|
409
|
+
Quando o usuario nao puder usar o periodo, prefira omitir. Publique um item
|
|
410
|
+
indisponivel somente quando existir contrato governado para isso e quando a
|
|
411
|
+
propria existencia do periodo puder ser exibida.
|
|
412
|
+
- Registre no backend a origem do periodo resolvido: calendario, norma,
|
|
413
|
+
tenant, versao de regra, usuario/role e instante de publicacao.
|
|
414
|
+
- Quando a metadata expirar, publique novo snapshot ou remova o atalho. Nao
|
|
415
|
+
conte com o frontend para recalcular vigencia.
|
|
416
|
+
- `tone` e semantico. Use tokens Praxis/host no frontend; nao envie cores
|
|
417
|
+
arbitrarias como parte do preset.
|
|
418
|
+
- `icon`, `label` e `description` devem vir de catalogo governado ou i18n do
|
|
419
|
+
host. Nao use labels como mecanismo primario de roteamento de intencao.
|
|
420
|
+
- Nunca envie callbacks, expressoes JavaScript, snippets, URLs executaveis ou
|
|
421
|
+
`calculateRange` em JSON. Rust publica dados, nao codigo.
|
|
422
|
+
|
|
423
|
+
## Operacao e testes
|
|
424
|
+
|
|
425
|
+
Contrato minimo entre backend e frontend:
|
|
426
|
+
|
|
427
|
+
1. backend publica `shortcuts` como lista ordenada de built-ins e presets
|
|
428
|
+
estaticos;
|
|
429
|
+
2. backend valida datas, timezone, autorizacao, confidencialidade e vigencia;
|
|
430
|
+
3. frontend materializa o catalogo e preserva `minDate`, `maxDate`,
|
|
431
|
+
`dateFilter`, ordem inicio/fim, RTL, teclado, foco e tema;
|
|
432
|
+
4. submit/filtro envia `{ startDate, endDate }`.
|
|
433
|
+
|
|
434
|
+
Testes recomendados:
|
|
435
|
+
|
|
436
|
+
- teste Rust de serializacao com `serde_json`;
|
|
437
|
+
- teste Rust de rejeicao de datas invalidas, intervalos invertidos e timezone
|
|
438
|
+
invalido;
|
|
439
|
+
- spec Angular focal de `@praxisui/core` para normalizacao de presets;
|
|
440
|
+
- spec Angular focal de `@praxisui/dynamic-fields` para materializacao em
|
|
441
|
+
`pdx-material-date-range` e `pdx-inline-date-range`;
|
|
442
|
+
- E2E de consumidor na superficie oficial
|
|
443
|
+
`src/app/features/filter-demo/praxis-filter-e2e-inventory.component.ts`,
|
|
444
|
+
rota `http://localhost:4003/filter-demo-e2e-inventory`, cobrindo built-in,
|
|
445
|
+
periodo corporativo estatico, `footer`, `start`, `end`, fallback `auto`,
|
|
446
|
+
tema claro/escuro, desktop, 390 px, teclado, foco, Cancelar/Aplicar, payload
|
|
447
|
+
e RTL quando houver composicao lateral.
|
|
448
|
+
|
|
449
|
+
## Checklist de publicacao
|
|
450
|
+
|
|
451
|
+
- [ ] O Rust calculou o periodo antes da serializacao.
|
|
452
|
+
- [ ] O JSON nao contem `calculateRange`, funcoes, snippets ou expressoes.
|
|
453
|
+
- [ ] Cada preset estatico tem `id`, `label`, `startDate` e `endDate`.
|
|
454
|
+
- [ ] Datas seguem `YYYY-MM-DD` quando representam periodo civil.
|
|
455
|
+
- [ ] `startDate <= endDate`.
|
|
456
|
+
- [ ] `timeZone`, quando presente, e IANA valido.
|
|
457
|
+
- [ ] Permissao e confidencialidade foram decididas antes de publicar.
|
|
458
|
+
- [ ] O payload observado no consumidor permanece `{ startDate, endDate }`.
|
|
459
|
+
- [ ] `inlineQuickPresets.position` foi validado em `footer`, `start`, `end`
|
|
460
|
+
ou `auto` conforme a superficie usada.
|
|
461
|
+
|
|
462
|
+
## Criterio sobre skill dedicada
|
|
463
|
+
|
|
464
|
+
Esta documentacao nao cria uma skill nova. A evidencia atual mostra um contrato
|
|
465
|
+
publico estabilizado para atalhos estaticos, mas o fluxo Rust ainda e um guia
|
|
466
|
+
de integracao de host, nao uma rotina transversal repetida em multiplos hosts
|
|
467
|
+
Rust versionados no workspace.
|
|
468
|
+
|
|
469
|
+
Criar uma skill canonica somente quando houver evidencia concreta de repeticao:
|
|
470
|
+
mais de um host Rust publicando a mesma familia de metadata, erros recorrentes
|
|
471
|
+
de validacao/serializacao, manifestos em `praxis-codex-skills` atualizados e
|
|
472
|
+
sincronizacao oficial. A eventual skill deve orientar publicacao de metadata
|
|
473
|
+
resolvida pelo backend, sem duplicar a skill de Dynamic Fields nem mover regra
|
|
474
|
+
de negocio para Angular.
|
|
@@ -27,7 +27,6 @@ reading_time: 24
|
|
|
27
27
|
estimated_setup_time: 30
|
|
28
28
|
version: "1.0"
|
|
29
29
|
related_docs:
|
|
30
|
-
- "dynamic-fields-overview"
|
|
31
30
|
- "dynamic-fields-inventory"
|
|
32
31
|
- "dynamic-fields-field-selection-guide"
|
|
33
32
|
- "dynamic-fields-host-custom-field-guide"
|
|
@@ -144,7 +143,7 @@ Use `stateInitialValues` apenas quando o valor do preset precisa continuar coere
|
|
|
144
143
|
| -------------- | ----------------------------------------------- | ----------------------------- | ----------------------------------------------- | ----------------------- | ------------------------------------------------------- | -------------------------------------- |
|
|
145
144
|
| Date input | <span id="dateinput"></span>`dateInput` | integracao com input nativo | quando o host precisa UX Material forte | `string \| Date` | `{ name: 'birthDate', controlType: 'dateInput' }` | `pdx-date-input.json-api.md` |
|
|
146
145
|
| Date picker | <span id="date"></span>`date` | selecao de data no formulario | se o fluxo pede intervalo | `Date \| string` | `{ name: 'startDate', controlType: 'date' }` | `pdx-material-datepicker.json-api.md` |
|
|
147
|
-
| Date range | <span id="daterange"></span>`dateRange` | intervalo de datas
|
|
146
|
+
| Date range | <span id="daterange"></span>`dateRange` | intervalo de datas, incluindo periodos corporativos estaticos publicados por metadata | data unica | `{ startDate,endDate }` | `{ name: 'period', controlType: 'dateRange', shortcuts: ['today'] }` | `pdx-material-date-range.json-api.md` |
|
|
148
147
|
| Datetime local | <span id="datetimelocal"></span>`dateTimeLocal` | data + hora local em um campo | quando o fluxo precisa seletor dedicado de hora | `string` | `{ name: 'appointment', controlType: 'dateTimeLocal' }` | `pdx-datetime-local-input.json-api.md` |
|
|
149
148
|
| Month input | <span id="month"></span>`month` | mes/ano | datas completas | `string` | `{ name: 'competence', controlType: 'month' }` | `pdx-month-input.json-api.md` |
|
|
150
149
|
| Time input | <span id="time"></span>`time` | hora simples | intervalo de horario | `string` | `{ name: 'startAt', controlType: 'time' }` | `pdx-time-input.json-api.md` |
|
|
@@ -180,7 +179,7 @@ Use `stateInitialValues` apenas quando o valor do preset precisa continuar coere
|
|
|
180
179
|
|
|
181
180
|
| Field | controlType | Quando usar | Quando evitar | Valor esperado | Snippet | Detail doc |
|
|
182
181
|
| ------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------- |
|
|
183
|
-
| Checkbox | <span id="checkbox"></span>`checkbox` | booleano simples com `selectionMode: 'boolean'` ou
|
|
182
|
+
| Checkbox | <span id="checkbox"></span>`checkbox` | booleano simples com `selectionMode: 'boolean'` ou múltiplas escolhas com `selectionMode: 'multiple'`; em migrações, flags `S`/`N` e `1`/`0` são normalizadas no modo booleano | contrato novo sem `selectionMode`; escolha única | `boolean \| unknown[]` | `{ name: 'privacyConsent', controlType: 'checkbox', selectionMode: 'boolean' }` | `pdx-material-checkbox-group.json-api.md` |
|
|
184
183
|
| Radio group | <span id="radio"></span>`radio` | escolha unica explicita com `selectionMode: 'single'` | muitas opcoes/espaco restrito | `string \| number \| boolean` | `{ name: 'priority', controlType: 'radio', selectionMode: 'single' }` | `pdx-material-radio-group.json-api.md` |
|
|
185
184
|
| Toggle | <span id="toggle"></span>`toggle` | booleano binario | multiplos estados | `boolean` | `{ name: 'active', controlType: 'toggle' }` | `pdx-material-slide-toggle.json-api.md` |
|
|
186
185
|
| Button toggle | <span id="buttontoggle"></span>`buttonToggle` | escolha segmentada curta | listas longas | `string \| number` | `{ name: 'mode', controlType: 'buttonToggle' }` | `pdx-material-button-toggle.json-api.md` |
|
|
@@ -189,7 +188,7 @@ Use `stateInitialValues` apenas quando o valor do preset precisa continuar coere
|
|
|
189
188
|
|
|
190
189
|
| Field | controlType | Quando usar | Quando evitar | Valor esperado | Snippet | Detail doc |
|
|
191
190
|
| ----------- | --------------------------------- | ------------------- | -------------------------------- | ---------------------------- | ----------------------------------------------- | -------------------------------------- |
|
|
192
|
-
| File upload | <span id="upload"></span>`upload` | anexos e
|
|
191
|
+
| File upload | <span id="upload"></span>`upload` | anexos, documentos e escolha local de imagem com preview | quando o fluxo nao exige arquivo ou exige persistencia operacional completa sem `@praxisui/files-upload` | `File \| File[] \| metadata` | `{ name: 'attachment', controlType: 'upload', accept: 'image/*', imagePreview: true }` | `pdx-material-file-upload.json-api.md` |
|
|
193
192
|
|
|
194
193
|
## Cor
|
|
195
194
|
|
|
@@ -37,7 +37,7 @@ keywords:
|
|
|
37
37
|
- "select vs autocomplete"
|
|
38
38
|
- "custom host field"
|
|
39
39
|
- "inline filter"
|
|
40
|
-
last_updated: "2026-06-
|
|
40
|
+
last_updated: "2026-06-25"
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
# Dynamic Fields Field Selection Guide
|
|
@@ -187,7 +187,29 @@ Se o caso e filtro corporativo compacto, consulte:
|
|
|
187
187
|
- [Dynamic Fields Inline Filter Catalog](./dynamic-fields-inline-filter-catalog.md)
|
|
188
188
|
- [Dynamic Fields Inline Components Guide](./dynamic-fields-inline-components-guide.md)
|
|
189
189
|
|
|
190
|
-
## 6.
|
|
190
|
+
## 6. Presentation mode vs chart widget
|
|
191
|
+
|
|
192
|
+
`presentation.presenter = 'microVisualization'` nao e um `controlType`. Use esse presenter quando o campo ja tem valor no `FormControl`, mas a surface readonly precisa mostrar um indicador compacto e escaneavel.
|
|
193
|
+
|
|
194
|
+
Use `microVisualization` quando:
|
|
195
|
+
|
|
196
|
+
- a surface e `form-presentation`, `table-cell`, `list-item`, `object-header` ou `card-summary`;
|
|
197
|
+
- a leitura precisa caber em celula, linha, drawer ou detalhe compacto;
|
|
198
|
+
- o indicador e pequeno, como `comparison`, `stackedBar`, `bullet` ou `delta`;
|
|
199
|
+
- a mesma semantica deve ser dirigida por `presentationRules` e Json Logic sem mutar o valor do campo.
|
|
200
|
+
|
|
201
|
+
Use `@praxisui/charts` quando:
|
|
202
|
+
|
|
203
|
+
- o usuario precisa interagir com grafico, legenda, tooltip analitico ou drilldown;
|
|
204
|
+
- o grafico ocupa card, dashboard, cockpit ou modal dedicado;
|
|
205
|
+
- a visualizacao depende de series maiores, eixos, zoom ou agregacoes vindas de endpoint analitico.
|
|
206
|
+
|
|
207
|
+
Use `rich-content` quando:
|
|
208
|
+
|
|
209
|
+
- o bloco mistura timeline, record summary, property sheet, progresso, badges e textos;
|
|
210
|
+
- a surface de detalhe precisa composicao editorial, nao apenas um valor de campo.
|
|
211
|
+
|
|
212
|
+
## 7. Decision table
|
|
191
213
|
|
|
192
214
|
| Question | Prefer |
|
|
193
215
|
| --- | --- |
|
|
@@ -211,12 +233,14 @@ Se o caso e filtro corporativo compacto, consulte:
|
|
|
211
233
|
| ha uma colecao repetivel de objetos? | `array` |
|
|
212
234
|
| ha anexos? | `upload` |
|
|
213
235
|
| o controle e acao, nao dado? | `button` |
|
|
236
|
+
| o valor readonly precisa de indicador compacto em celula/lista/formulario? | `presentation.presenter = "microVisualization"` |
|
|
214
237
|
| nada do catalogo resolve sem gambiarra? | field custom do host |
|
|
215
238
|
|
|
216
|
-
##
|
|
239
|
+
## 8. Enterprise recommendations
|
|
217
240
|
|
|
218
241
|
- prefira nomes canonicos de `controlType`; deixe aliases apenas para compatibilidade;
|
|
219
242
|
- nao use inline filter controls em formularios normais para “economizar espaco”;
|
|
243
|
+
- nao crie `controlType` local para indicadores readonly; use `presentation.presenter` e `presentation.visualization` quando a semantica for de apresentacao;
|
|
220
244
|
- para campos remotos, explicite origem de dados e comportamento de busca;
|
|
221
245
|
- para entidades de negocio, use `entityLookup` com `optionSource.type = RESOURCE_ENTITY`, `byIds`, `dependsOn`, `dependencyFilterMap` e `selectionPolicy` quando a selecao depender de status, permissao ou contexto;
|
|
222
246
|
- para colecoes repetiveis, use `array` com `array.itemSchema.fields` em vez de criar campos numerados como `item1`, `item2`, `item3`;
|