@praxisui/crud 9.0.5-rc.8 → 9.0.5

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 CHANGED
@@ -96,19 +96,23 @@ export class EmployeesCrudComponent {
96
96
  - `tableConfigPersistenceStrategy`: controls persistence precedence for the internal table. Keep `local-first` for user-owned workspaces, use `input-first` for an authoritative governed contract, and use `volatile` for previews that must neither read nor write stored preferences.
97
97
  - `context`: host/runtime context passed into table and form flows
98
98
  - `enableCustomization`: enables the package authoring surface
99
+ - `showResourceIdentityKey`: defaults to `true`; set it to `false` when an existing-record modal or drawer should preserve the readable identity title without exposing an opaque or technical public key
99
100
  - `authoringCapability`: optionally requires the exact capability from `EnterpriseRuntimeContext.capabilities` before authoring controls, the CRUD editor, and its internal table authoring are available. This is a UX gate; governed persistence must enforce the same policy server-side.
100
101
 
101
102
  It emits:
102
103
 
103
104
  - `configureRequested`
104
105
  - `afterOpen`, `afterClose`, `afterSave`, `afterDelete`
106
+ - `reactiveDeterminationExecuted` (metadata-only evidence with action context), `reactiveDeterminationPendingChange`, and `reactiveDeterminationStabilityChange`. The aggregate stability output preserves `action` and distinguishes `pending`, `settled-satisfied`, and `settled-unsatisfied`; “settled” alone is never a success signal.
105
107
  - `error`
106
- - `rowClick`, `rowAction`, `selectionChange`. `rowAction` preserves the canonical table envelope (`row`, `action`, `resourceIdentity`) so a governed composition can update task context without forcing visual row selection.
108
+ - `resourceEvent` is the canonical output for governed host composition and preserves `kind`, `resourcePath`, `resourceId`, `payload` and runtime context from the internal table. The legacy `rowClick`, `rowAction` and `selectionChange` outputs remain available; `rowAction` preserves the table envelope (`row`, `action`, `resourceIdentity`) without forcing visual row selection.
107
109
  - `tableRuntimeConfigChange`
108
110
  - `crudAuthoringDocumentApplied`, `crudAuthoringDocumentSaved`
109
111
 
110
112
  The component keeps `crudContext` stable for change detection and refreshes the table after successful save/delete flows.
111
113
 
114
+ Built-in modal, drawer and nested surface-frame form hosts do not close or complete save while a child Reactive Determination is pending or when its latest generation settled unsatisfied; cancel waits for bounded successful stabilization and stays open on timeout/failure. A custom `CrudDrawerAdapter` must bind `onReactiveDetermination`, `onReactiveDeterminationPendingChange`, and `onReactiveDeterminationStabilityChange`, use the child Dynamic Form stability API, and refuse every adapter-owned close/submit while pending or unsatisfied. These callbacks are runtime-only and must never be persisted in CRUD metadata.
115
+
112
116
  ## Metadata Boundaries
113
117
 
114
118
  `resourcePath` and `resourceKey` are intentionally different:
@@ -118,6 +122,16 @@ The component keeps `crudContext` stable for change detection and refreshes the
118
122
 
119
123
  `@praxisui/crud` owns CRUD orchestration: list surface, create/edit/view/delete actions, open mode resolution, parameter mapping, `initialValue`, back policy, and stable handoff to the form host.
120
124
 
125
+ For inferred canonical actions, discovery and launcher resolution are sequential
126
+ decision stages, not equivalent retry mechanisms. The launcher is considered
127
+ only when discovery did not select an executable surface. Once a governed
128
+ surface has been selected, a synchronous or asynchronous open failure is
129
+ fail-closed: the runtime emits the error and a correlated structured diagnostic
130
+ without attempting a second drawer/modal/route path. A table nested in
131
+ `PraxisCrudComponent` always delegates the action to that CRUD owner; a
132
+ standalone table owns its `surface.open` attempt and follows the same
133
+ single-path rule.
134
+
121
135
  Child component semantics stay with their owners:
122
136
 
123
137
  - table configuration belongs to `@praxisui/table`
@@ -193,8 +207,9 @@ above the command form when the table has materialized it. An explicit valid
193
207
  key-only fallback from the valid `x-ui.resource.idField`, without inferring a
194
208
  title from property names. This is read-only context: immutable keys remain
195
209
  outside the request schema and are never added to the update payload. Custom
196
- drawer adapters receive the same `resourceIdentity` context and retain their own
197
- presentation responsibility.
210
+ drawer adapters receive the same `resourceIdentity` context and the
211
+ `showResourceIdentityKey` presentation preference. They must keep the identity
212
+ outside form inputs and retain responsibility for presenting its readable title.
198
213
 
199
214
  Related operations also receive `contextIdentity` when the governed surface
200
215
  publishes `context.operation.taskScope`. The default host labels it as “Related
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-08-12T14:05:00.897Z",
3
+ "generatedAt": "2026-08-18T02:12:19.525Z",
4
4
  "packageName": "@praxisui/crud",
5
- "packageVersion": "9.0.5-rc.8",
5
+ "packageVersion": "9.0.5",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -91,6 +91,13 @@
91
91
  "description": "Habilita modo de customização do layout.",
92
92
  "default": false
93
93
  },
94
+ {
95
+ "name": "showResourceIdentityKey",
96
+ "type": "boolean",
97
+ "required": false,
98
+ "description": "Controla se modal e drawer exibem a chave da identidade canônica do registro. Use false quando a chave pública for opaca ou apenas técnica; o título legível permanece visível.",
99
+ "default": true
100
+ },
94
101
  {
95
102
  "name": "authoringCapability",
96
103
  "type": "string | null",
@@ -124,6 +131,24 @@
124
131
  "required": false,
125
132
  "description": "Emitido ao deletar."
126
133
  },
134
+ {
135
+ "name": "reactiveDeterminationExecuted",
136
+ "type": "{ action: string; event: ReactiveDeterminationExecutionEvent }",
137
+ "required": false,
138
+ "description": "Evidencia metadata-only encaminhada pelo formulario aberto, com contexto da acao CRUD."
139
+ },
140
+ {
141
+ "name": "reactiveDeterminationPendingChange",
142
+ "type": "{ action: string; pending: boolean }",
143
+ "required": false,
144
+ "description": "Estado agregado de estabilizacao do formulario aberto, sem valores sensiveis."
145
+ },
146
+ {
147
+ "name": "reactiveDeterminationStabilityChange",
148
+ "type": "CrudReactiveDeterminationStabilityChange",
149
+ "required": false,
150
+ "description": "Conclusao agregada do formulario aberto, distinguindo settled-satisfied de settled-unsatisfied e preservando o contexto da acao."
151
+ },
127
152
  {
128
153
  "name": "rowClick",
129
154
  "type": "{ row: unknown; index: number }",
@@ -142,6 +167,12 @@
142
167
  "required": false,
143
168
  "description": "Encaminha a mudança de seleção da tabela interna quando o CRUD é usado como widget composto."
144
169
  },
170
+ {
171
+ "name": "resourceEvent",
172
+ "type": "PraxisResourceEvent<unknown>",
173
+ "required": false,
174
+ "description": "Encaminha o envelope canônico da tabela interna com kind, resourcePath, resourceId, payload e contexto para composição governada."
175
+ },
145
176
  {
146
177
  "name": "error",
147
178
  "type": "unknown",
@@ -5043,6 +5074,11 @@
5043
5074
  "type": "boolean",
5044
5075
  "description": "Explicit host opt-in for CRUD authoring surfaces."
5045
5076
  },
5077
+ {
5078
+ "name": "showResourceIdentityKey",
5079
+ "type": "boolean",
5080
+ "description": "Presentation-only control for the canonical key in existing-record modal and drawer headers. Defaults to true; false preserves the readable title while hiding an opaque or technical key."
5081
+ },
5046
5082
  {
5047
5083
  "name": "authoringCapability",
5048
5084
  "type": "string | null",
@@ -5062,6 +5098,11 @@
5062
5098
  "name": "afterDelete",
5063
5099
  "type": "{ id: string | number }",
5064
5100
  "description": "Emitted after delete; CRUD refetches the list."
5101
+ },
5102
+ {
5103
+ "name": "resourceEvent",
5104
+ "type": "PraxisResourceEvent<unknown>",
5105
+ "description": "Canonical resource interaction envelope forwarded from the internal table for governed host composition."
5065
5106
  }
5066
5107
  ],
5067
5108
  "editableTargets": [
@@ -7224,9 +7265,9 @@
7224
7265
  {
7225
7266
  "chunkIndex": 0,
7226
7267
  "chunkKind": "summary",
7227
- "content": "Component ID: praxis-crud\nSelector: praxis-crud\nFriendly Name: Praxis CRUD\nDescription: Tabela com operações de CRUD via metadados.\nLib/Package: @praxisui/crud\nTags: widget, crud, configurable, hasWizard, stable\nInputs:\n - metadata (CrudMetadata | string)\n - crudId (string)\n - componentInstanceId (string)\n - tableConfigPersistenceStrategy ('local-first' | 'input-first' | 'volatile')\n - context (Record<string, unknown>)\n - metadata.queryContext (PraxisDataQueryContext | null)\n - metadata.resource.schemaPath (string | null)\n - metadata.resource.title (string | null)\n - metadata.resource.formTitle (string | null)\n - metadata.filterCriteria (Record<string, unknown> | null)\n - metadata.form (FormConfig)\n - metadata.actions[].form (CrudActionFormContract)\n - enableCustomization (boolean)\n - authoringCapability (string | null)\nOutputs:\n - afterOpen ({ mode: FormOpenMode; action: string })\n - afterClose (void)\n - afterSave ({ id: string | number; data: unknown })\n - afterDelete ({ id: string | number })\n - rowClick ({ row: unknown; index: number })\n - rowAction (CrudActionRuntimeEvent)\n - selectionChange (unknown)\n - error (unknown)\n - configureRequested (void)\n - crudAuthoringDocumentApplied (CrudAuthoringWidgetPersistenceEvent)\n - crudAuthoringDocumentSaved (CrudAuthoringWidgetPersistenceEvent)\n",
7268
+ "content": "Component ID: praxis-crud\nSelector: praxis-crud\nFriendly Name: Praxis CRUD\nDescription: Tabela com operações de CRUD via metadados.\nLib/Package: @praxisui/crud\nTags: widget, crud, configurable, hasWizard, stable\nInputs:\n - metadata (CrudMetadata | string)\n - crudId (string)\n - componentInstanceId (string)\n - tableConfigPersistenceStrategy ('local-first' | 'input-first' | 'volatile')\n - context (Record<string, unknown>)\n - metadata.queryContext (PraxisDataQueryContext | null)\n - metadata.resource.schemaPath (string | null)\n - metadata.resource.title (string | null)\n - metadata.resource.formTitle (string | null)\n - metadata.filterCriteria (Record<string, unknown> | null)\n - metadata.form (FormConfig)\n - metadata.actions[].form (CrudActionFormContract)\n - enableCustomization (boolean)\n - showResourceIdentityKey (boolean)\n - authoringCapability (string | null)\nOutputs:\n - afterOpen ({ mode: FormOpenMode; action: string })\n - afterClose (void)\n - afterSave ({ id: string | number; data: unknown })\n - afterDelete ({ id: string | number })\n - reactiveDeterminationExecuted ({ action: string; event: ReactiveDeterminationExecutionEvent })\n - reactiveDeterminationPendingChange ({ action: string; pending: boolean })\n - reactiveDeterminationStabilityChange (CrudReactiveDeterminationStabilityChange)\n - rowClick ({ row: unknown; index: number })\n - rowAction (CrudActionRuntimeEvent)\n - selectionChange (unknown)\n - resourceEvent (PraxisResourceEvent<unknown>)\n - error (unknown)\n - configureRequested (void)\n - crudAuthoringDocumentApplied (CrudAuthoringWidgetPersistenceEvent)\n - crudAuthoringDocumentSaved (CrudAuthoringWidgetPersistenceEvent)\n",
7228
7269
  "sourcePointer": "projects/praxis-crud/src/lib/praxis-crud.metadata.ts",
7229
- "contentHash": "5f18e01c2da358f033eb9b8ee4616dac8a348addc3ce3e56bcb077b094c13300",
7270
+ "contentHash": "b23b03f710e5ccd9109b534891d97f93780d572005599050d3c9b3ade71d57e2",
7230
7271
  "sourceKind": "component_definition",
7231
7272
  "sourceId": "praxis-crud",
7232
7273
  "corpusVersion": "1.0.0"
@@ -7454,9 +7495,9 @@
7454
7495
  {
7455
7496
  "chunkIndex": 23,
7456
7497
  "chunkKind": "authoring_manifest",
7457
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-crud\",\"ownerPackage\":\"@praxisui/crud\",\"configSchemaId\":\"CrudMetadata\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"name\":\"metadata\",\"type\":\"CrudMetadata | string\",\"description\":\"Canonical CRUD metadata or serialized metadata document.\"},{\"name\":\"crudId\",\"type\":\"string\",\"description\":\"Stable CRUD instance id used for table/form identity and persistence.\"},{\"name\":\"componentInstanceId\",\"type\":\"string\",\"description\":\"Optional stable host instance id for multiple CRUD widgets on the same route.\"},{\"name\":\"tableConfigPersistenceStrategy\",\"type\":\"'local-first' | 'input-first' | 'volatile'\",\"description\":\"Persistence precedence forwarded to the internal Praxis Table. Governed previews should use input-first or volatile explicitly.\"},{\"name\":\"context\",\"type\":\"Record<string, unknown>\",\"description\":\"Opaque host context used for authoring seeds and launcher inputs.\"},{\"name\":\"enableCustomization\",\"type\":\"boolean\",\"description\":\"Explicit host opt-in for CRUD authoring surfaces.\"},{\"name\":\"authoringCapability\",\"type\":\"string | null\",\"description\":\"Public runtime capability required before CRUD and delegated table authoring can open.\"},{\"name\":\"afterOpen\",\"type\":\"{ mode: FormOpenMode; action: string }\",\"description\":\"Emitted after a CRUD action opens.\"},{\"name\":\"afterSave\",\"type\":\"{ id: string | number; data: unknown }\",\"description\":\"Emitted after save; CRUD refetches the list.\"},{\"name\":\"afterDelete\",\"type\":\"{ id: string | number }\",\"description\":\"Emitted after delete; CRUD refetches the list.\"}]}",
7498
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-crud\",\"ownerPackage\":\"@praxisui/crud\",\"configSchemaId\":\"CrudMetadata\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"name\":\"metadata\",\"type\":\"CrudMetadata | string\",\"description\":\"Canonical CRUD metadata or serialized metadata document.\"},{\"name\":\"crudId\",\"type\":\"string\",\"description\":\"Stable CRUD instance id used for table/form identity and persistence.\"},{\"name\":\"componentInstanceId\",\"type\":\"string\",\"description\":\"Optional stable host instance id for multiple CRUD widgets on the same route.\"},{\"name\":\"tableConfigPersistenceStrategy\",\"type\":\"'local-first' | 'input-first' | 'volatile'\",\"description\":\"Persistence precedence forwarded to the internal Praxis Table. Governed previews should use input-first or volatile explicitly.\"},{\"name\":\"context\",\"type\":\"Record<string, unknown>\",\"description\":\"Opaque host context used for authoring seeds and launcher inputs.\"},{\"name\":\"enableCustomization\",\"type\":\"boolean\",\"description\":\"Explicit host opt-in for CRUD authoring surfaces.\"},{\"name\":\"showResourceIdentityKey\",\"type\":\"boolean\",\"description\":\"Presentation-only control for the canonical key in existing-record modal and drawer headers. Defaults to true; false preserves the readable title while hiding an opaque or technical key.\"},{\"name\":\"authoringCapability\",\"type\":\"string | null\",\"description\":\"Public runtime capability required before CRUD and delegated table authoring can open.\"},{\"name\":\"afterOpen\",\"type\":\"{ mode: FormOpenMode; action: string }\",\"description\":\"Emitted after a CRUD action opens.\"},{\"name\":\"afterSave\",\"type\":\"{ id: string | number; data: unknown }\",\"description\":\"Emitted after save; CRUD refetches the list.\"},{\"name\":\"afterDelete\",\"type\":\"{ id: string | number }\",\"description\":\"Emitted after delete; CRUD refetches the list.\"},{\"name\":\"resourceEvent\",\"type\":\"PraxisResourceEvent<unknown>\",\"description\":\"Canonical resource interaction envelope forwarded from the internal table for governed host composition.\"}]}",
7458
7499
  "sourcePointer": "projects/praxis-crud/src/lib/ai/praxis-crud-authoring-manifest.ts",
7459
- "contentHash": "068b8503236aa70e0543cc63c791a5c9cb192983b3e369285bb44732b3b646d8",
7500
+ "contentHash": "8d9479e522f58e71d54dd7654e161b6f84db71c9828dd621458bcd5887fc7cb6",
7460
7501
  "sourceKind": "component_definition",
7461
7502
  "sourceId": "praxis-crud",
7462
7503
  "corpusVersion": "1.0.0"
@@ -11439,6 +11480,18 @@
11439
11480
  "valueKind": "string",
11440
11481
  "description": "Versao persistida esperada, transportada como If-Match quando exigida pela action."
11441
11482
  },
11483
+ {
11484
+ "path": "inputs.submitResourceVersionTargetResourceKey",
11485
+ "category": "inputs",
11486
+ "valueKind": "string",
11487
+ "description": "Resource key canônico materializado pela action para resolver o ETag de outro agregado no momento do submit."
11488
+ },
11489
+ {
11490
+ "path": "inputs.submitResourceVersionTargetIdField",
11491
+ "category": "inputs",
11492
+ "valueKind": "string",
11493
+ "description": "Campo exato do request que identifica o agregado cujo ETag governa a action."
11494
+ },
11442
11495
  {
11443
11496
  "path": "inputs.responseSchemaUrl",
11444
11497
  "category": "inputs",
@@ -12248,9 +12301,9 @@
12248
12301
  {
12249
12302
  "chunkIndex": 10,
12250
12303
  "chunkKind": "capabilities",
12251
- "content": "Schema Capability:\n - Path: fieldMetadata[].transformDisplayValue\n Category: transform\n Kind: expression\n Description: Transforma valor para exibição.\n\nSchema Capability:\n - Path: fieldMetadata[].transformSaveValue\n Category: transform\n Kind: expression\n Description: Transforma valor para salvar.\n\nSchema Capability:\n - Path: fieldMetadata[].textTransformApply\n Category: transform\n Kind: enum\n Description: Quando aplicar transformação de texto.\n\nSchema Capability:\n - Path: fieldMetadata[].inlineEditing\n Category: behavior\n Kind: boolean\n Description: Permite edição inline (tabelas).\n\nSchema Capability:\n - Path: fieldMetadata[].unique\n Category: validation\n Kind: boolean\n Description: Valida unicidade no backend.\n\nSchema Capability:\n - Path: fieldMetadata[].readOnly\n Category: behavior\n Kind: boolean\n Description: Campo somente leitura.\n\nSchema Capability:\n - Path: fieldMetadata[].disabled\n Category: behavior\n Kind: boolean\n Description: Campo desabilitado.\n\nSchema Capability:\n - Path: fieldMetadata[].defaultValue\n Category: data\n Kind: object\n Description: Valor inicial do campo.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaLabel\n Category: accessibility\n Kind: string\n Description: Label para leitores de tela.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaDescribedBy\n Category: accessibility\n Kind: string\n Description: IDs de descrição acessível.\n\nSchema Capability:\n - Path: fieldMetadata[].tabIndex\n Category: accessibility\n Kind: number\n Description: Ordem de tabulacao para teclado.\n\nSchema Capability:\n - Path: fieldMetadata[].accessKey\n Category: accessibility\n Kind: string\n Description: Atalho de teclado (accessKey).\n\nComponent Capability:\n - Path: inputs.resourcePath\n Category: inputs\n Kind: string\n Description: Caminho do recurso para carregar/salvar dados via CRUD.\n\nComponent Capability:\n - Path: inputs.resourceId\n Category: inputs\n Kind: string\n Description: ID do registro atual (string ou number).\n\nComponent Capability:\n - Path: inputs.initialValue\n Category: inputs\n Kind: object\n Description: Valores iniciais locais para campos host-authored ou complementares.\n\nComponent Capability:\n - Path: inputs.mode\n Category: inputs\n Kind: enum\n Description: Modo do formulario (create/edit/view).\n\nComponent Capability:\n - Path: inputs.config\n Category: inputs\n Kind: object\n Description: Configuracao completa do formulario (FormConfig).\n\nComponent Capability:\n - Path: inputs.schemaSource\n Category: inputs\n Kind: enum\n Description: Fonte de schema para construcao automatica (resource/filter).\n\nComponent Capability:\n - Path: inputs.schemaUrl\n Category: inputs\n Kind: string\n Description: Schema canonico explicito publicado pelo backend para hosts que seguem surfaces/actions/capabilities.\n\nComponent Capability:\n - Path: inputs.readUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de leitura publicado por surface VIEW/READ_PROJECTION para hidratar a entidade exibida.\n\nComponent Capability:\n - Path: inputs.apiEndpointKey\n Category: inputs\n Kind: string\n Description: Endpoint canonico usado para resolver schemaUrl, readUrl e submitUrl relativos em hosts destacados.\n\nComponent Capability:\n - Path: inputs.submitUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de submit publicado por surface/action.\n\nComponent Capability:\n - Path: inputs.submitMethod\n Category: inputs\n Kind: enum\n Description: Metodo HTTP canonico para o submit quando o backend publica operacao explicita.\n\nComponent Capability:\n - Path: inputs.submitIdempotencyKey\n Category: inputs\n Kind: string\n Description: Identidade estavel da tentativa de comando, materializada a partir da politica execution da action.\n\nComponent Capability:\n - Path: inputs.submitCorrelationId\n Category: inputs\n Kind: string\n Description: Identificador de correlacao governado para rastreabilidade ponta a ponta do comando.\n\nComponent Capability:\n - Path: inputs.submitResourceVersion\n Category: inputs\n Kind: string\n Description: Versao persistida esperada, transportada como If-Match quando exigida pela action.\n\nComponent Capability:\n - Path: inputs.responseSchemaUrl\n Category: inputs\n Kind: string\n Description: Schema de resposta publicado pelo backend para inspeção diagnostica/read-only do host.\n\nComponent Capability:\n - Path: inputs.enableCustomization\n Category: inputs\n Kind: boolean\n Description: Habilita a edicao de layout/configuracao no editor.\n\nComponent Capability:\n - Path: inputs.showAiAssistant\n Category: inputs\n Kind: boolean\n Description: Mostra os gatilhos do copiloto semantico Praxis para a instancia do formulario.\n\nComponent Capability:\n - Path: inputs.formId\n Category: inputs\n Kind: string\n Description: ID persistente para salvar configuracoes e preferencias.\n\nComponent Capability:\n - Path: inputs.editorialContext\n Category: inputs\n Kind: object\n Description: Override de contexto editorial fornecido pelo host para os blocos hospedados antes/depois do formulario.\n\nComponent Capability:\n - Path: inputs.layout\n Category: inputs\n Kind: object\n Description: Layout legado (FormLayout). Preferir inputs.config + sections.\n\nComponent Capability:\n - Path: inputs.generatedLayoutPreset\n Category: inputs\n Kind: enum\n Description: Preset usado somente na criacao inicial de FormConfig a partir de schema/metadata.\n\nComponent Capability:\n - Path: inputs.configPersistenceStrategy\n Category: inputs\n Kind: enum\n Description: Define se preferências locais persistidas ou o contrato explícito do host governam a materialização corrente.\n\nComponent Capability:\n - Path: inputs.layoutPolicy\n Category: inputs\n Kind: object\n Description: Politica opt-in para materializar layout diretamente do schema atual sem depender de FormConfig.sections authoradas.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.source\n Category: inputs\n Kind: enum\n Description: Define se o layout vem de configuracao authorada ou do schema.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.preset\n Category: inputs\n Kind: enum\n Description: Preset de layout schema-driven. compactPresentation cobre detalhe read-only; groupedCommand cobre create/edit.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.intent\n Category: inputs\n Kind: enum\n Description: Intencao da surface: detalhe/apresentacao ou comando/editavel.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.lifecycle\n Category: inputs\n Kind: enum\n Description: Ciclo de materializacao do layout schema-driven.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.persistence\n Category: inputs\n Kind: enum\n Description: Define se sections geradas sao transient ou podem virar layout authorado apos detach explicito.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.orphanFieldExpansion\n Category: inputs\n Kind: enum\n Description: Define como uma linha groupedCommand com um unico campo usa o espaco restante. O default medium-and-wide expande spans 6 ou 8 e preserva campos compactos.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.contextFields\n Category: inputs\n Kind: array\n Description: Campos canônicos do request cujo valor vem do contexto da surface. Eles permanecem no FormGroup e no payload, sem renderizar controles redundantes.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.partialRowStrategy\n Category: inputs\n Kind: enum\n Description: Define se cada linha visual parcial, depois de resolver visibilidade responsiva, CSS order e wrap, preserva os spans canônicos ou redistribui apenas campos compatíveis para completar 12 colunas no breakpoint atual.",
12304
+ "content": "Schema Capability:\n - Path: fieldMetadata[].transformDisplayValue\n Category: transform\n Kind: expression\n Description: Transforma valor para exibição.\n\nSchema Capability:\n - Path: fieldMetadata[].transformSaveValue\n Category: transform\n Kind: expression\n Description: Transforma valor para salvar.\n\nSchema Capability:\n - Path: fieldMetadata[].textTransformApply\n Category: transform\n Kind: enum\n Description: Quando aplicar transformação de texto.\n\nSchema Capability:\n - Path: fieldMetadata[].inlineEditing\n Category: behavior\n Kind: boolean\n Description: Permite edição inline (tabelas).\n\nSchema Capability:\n - Path: fieldMetadata[].unique\n Category: validation\n Kind: boolean\n Description: Valida unicidade no backend.\n\nSchema Capability:\n - Path: fieldMetadata[].readOnly\n Category: behavior\n Kind: boolean\n Description: Campo somente leitura.\n\nSchema Capability:\n - Path: fieldMetadata[].disabled\n Category: behavior\n Kind: boolean\n Description: Campo desabilitado.\n\nSchema Capability:\n - Path: fieldMetadata[].defaultValue\n Category: data\n Kind: object\n Description: Valor inicial do campo.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaLabel\n Category: accessibility\n Kind: string\n Description: Label para leitores de tela.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaDescribedBy\n Category: accessibility\n Kind: string\n Description: IDs de descrição acessível.\n\nSchema Capability:\n - Path: fieldMetadata[].tabIndex\n Category: accessibility\n Kind: number\n Description: Ordem de tabulacao para teclado.\n\nSchema Capability:\n - Path: fieldMetadata[].accessKey\n Category: accessibility\n Kind: string\n Description: Atalho de teclado (accessKey).\n\nComponent Capability:\n - Path: inputs.resourcePath\n Category: inputs\n Kind: string\n Description: Caminho do recurso para carregar/salvar dados via CRUD.\n\nComponent Capability:\n - Path: inputs.resourceId\n Category: inputs\n Kind: string\n Description: ID do registro atual (string ou number).\n\nComponent Capability:\n - Path: inputs.initialValue\n Category: inputs\n Kind: object\n Description: Valores iniciais locais para campos host-authored ou complementares.\n\nComponent Capability:\n - Path: inputs.mode\n Category: inputs\n Kind: enum\n Description: Modo do formulario (create/edit/view).\n\nComponent Capability:\n - Path: inputs.config\n Category: inputs\n Kind: object\n Description: Configuracao completa do formulario (FormConfig).\n\nComponent Capability:\n - Path: inputs.schemaSource\n Category: inputs\n Kind: enum\n Description: Fonte de schema para construcao automatica (resource/filter).\n\nComponent Capability:\n - Path: inputs.schemaUrl\n Category: inputs\n Kind: string\n Description: Schema canonico explicito publicado pelo backend para hosts que seguem surfaces/actions/capabilities.\n\nComponent Capability:\n - Path: inputs.readUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de leitura publicado por surface VIEW/READ_PROJECTION para hidratar a entidade exibida.\n\nComponent Capability:\n - Path: inputs.apiEndpointKey\n Category: inputs\n Kind: string\n Description: Endpoint canonico usado para resolver schemaUrl, readUrl e submitUrl relativos em hosts destacados.\n\nComponent Capability:\n - Path: inputs.submitUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de submit publicado por surface/action.\n\nComponent Capability:\n - Path: inputs.submitMethod\n Category: inputs\n Kind: enum\n Description: Metodo HTTP canonico para o submit quando o backend publica operacao explicita.\n\nComponent Capability:\n - Path: inputs.submitIdempotencyKey\n Category: inputs\n Kind: string\n Description: Identidade estavel da tentativa de comando, materializada a partir da politica execution da action.\n\nComponent Capability:\n - Path: inputs.submitCorrelationId\n Category: inputs\n Kind: string\n Description: Identificador de correlacao governado para rastreabilidade ponta a ponta do comando.\n\nComponent Capability:\n - Path: inputs.submitResourceVersion\n Category: inputs\n Kind: string\n Description: Versao persistida esperada, transportada como If-Match quando exigida pela action.\n\nComponent Capability:\n - Path: inputs.submitResourceVersionTargetResourceKey\n Category: inputs\n Kind: string\n Description: Resource key canônico materializado pela action para resolver o ETag de outro agregado no momento do submit.\n\nComponent Capability:\n - Path: inputs.submitResourceVersionTargetIdField\n Category: inputs\n Kind: string\n Description: Campo exato do request que identifica o agregado cujo ETag governa a action.\n\nComponent Capability:\n - Path: inputs.responseSchemaUrl\n Category: inputs\n Kind: string\n Description: Schema de resposta publicado pelo backend para inspeção diagnostica/read-only do host.\n\nComponent Capability:\n - Path: inputs.enableCustomization\n Category: inputs\n Kind: boolean\n Description: Habilita a edicao de layout/configuracao no editor.\n\nComponent Capability:\n - Path: inputs.showAiAssistant\n Category: inputs\n Kind: boolean\n Description: Mostra os gatilhos do copiloto semantico Praxis para a instancia do formulario.\n\nComponent Capability:\n - Path: inputs.formId\n Category: inputs\n Kind: string\n Description: ID persistente para salvar configuracoes e preferencias.\n\nComponent Capability:\n - Path: inputs.editorialContext\n Category: inputs\n Kind: object\n Description: Override de contexto editorial fornecido pelo host para os blocos hospedados antes/depois do formulario.\n\nComponent Capability:\n - Path: inputs.layout\n Category: inputs\n Kind: object\n Description: Layout legado (FormLayout). Preferir inputs.config + sections.\n\nComponent Capability:\n - Path: inputs.generatedLayoutPreset\n Category: inputs\n Kind: enum\n Description: Preset usado somente na criacao inicial de FormConfig a partir de schema/metadata.\n\nComponent Capability:\n - Path: inputs.configPersistenceStrategy\n Category: inputs\n Kind: enum\n Description: Define se preferências locais persistidas ou o contrato explícito do host governam a materialização corrente.\n\nComponent Capability:\n - Path: inputs.layoutPolicy\n Category: inputs\n Kind: object\n Description: Politica opt-in para materializar layout diretamente do schema atual sem depender de FormConfig.sections authoradas.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.source\n Category: inputs\n Kind: enum\n Description: Define se o layout vem de configuracao authorada ou do schema.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.preset\n Category: inputs\n Kind: enum\n Description: Preset de layout schema-driven. compactPresentation cobre detalhe read-only; groupedCommand cobre create/edit.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.intent\n Category: inputs\n Kind: enum\n Description: Intencao da surface: detalhe/apresentacao ou comando/editavel.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.lifecycle\n Category: inputs\n Kind: enum\n Description: Ciclo de materializacao do layout schema-driven.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.persistence\n Category: inputs\n Kind: enum\n Description: Define se sections geradas sao transient ou podem virar layout authorado apos detach explicito.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.orphanFieldExpansion\n Category: inputs\n Kind: enum\n Description: Define como uma linha groupedCommand com um unico campo usa o espaco restante. O default medium-and-wide expande spans 6 ou 8 e preserva campos compactos.",
12252
12305
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/form-ai-capabilities.ts",
12253
- "contentHash": "a05a482e5873ff1de353543220891daaa3867cea957150def37ea50539a20c21",
12306
+ "contentHash": "26b2dfdc858e1b0af8adbd4557dec1561120af335ab33688421d1dda98a4281e",
12254
12307
  "sourceKind": "component_definition",
12255
12308
  "sourceId": "praxis-dynamic-form-dialog-host",
12256
12309
  "corpusVersion": "1.0.0"
@@ -12258,9 +12311,9 @@
12258
12311
  {
12259
12312
  "chunkIndex": 11,
12260
12313
  "chunkKind": "capabilities",
12261
- "content": "Component Capability:\n - Path: inputs.layoutPolicy.detailSummary\n Category: inputs\n Kind: object\n Description: Politica declarativa para resumo read-only compacto em compactPresentation, sem FormConfig.sections locais.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.includeFields\n Category: inputs\n Kind: array\n Description: Lista de campos canônicos do schema que devem entrar no resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.excludeFields\n Category: inputs\n Kind: array\n Description: Lista de campos canônicos do schema que devem ficar fora do resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.includeGroups\n Category: inputs\n Kind: array\n Description: Lista de grupos do schema que devem entrar no resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.excludeGroups\n Category: inputs\n Kind: array\n Description: Lista de grupos do schema que devem ficar fora do resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.includeRoles\n Category: inputs\n Kind: array\n Description: Lista de papeis semanticos de campo que devem entrar no resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.excludeRoles\n Category: inputs\n Kind: array\n Description: Lista de papeis semanticos de campo que devem ficar fora do resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.maxFields\n Category: inputs\n Kind: number\n Description: Limite maximo de campos materializados no primeiro painel compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.fieldPriority\n Category: inputs\n Kind: object\n Description: Mapa campo -> prioridade para ordenar campos do resumo quando o schema publica candidatos suficientes.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.groupPriority\n Category: inputs\n Kind: object\n Description: Mapa grupo -> prioridade para ordenar grupos do resumo quando o schema publica agrupamento semantico.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.columns\n Category: inputs\n Kind: number\n Description: Quantidade base de colunas para distribuir campos de resumo schema-driven sem criar FormConfig.sections locais.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.responsiveColumns\n Category: inputs\n Kind: object\n Description: Mapa de colunas por breakpoint xs/sm/md/lg/xl para detalhes read-only compactos em drawers, side sheets e desktop largo.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.widthPrecedence\n Category: inputs\n Kind: enum\n Description: Define se larguras explicitas do schema ou a densidade do resumo controlam os spans no compactPresentation read-only.\n\nComponent Capability:\n - Path: inputs.fieldIconPolicy\n Category: inputs\n Kind: enum\n Description: Controla se icones prefix/suffix dos metadados aparecem em todos os modos, apenas apresentacao, ou nunca.\n\nComponent Capability:\n - Path: inputs.backConfig\n Category: inputs\n Kind: object\n Description: Configuracao de navegacao/retorno (BackConfig).\n\nComponent Capability:\n - Path: inputs.backConfig.strategy\n Category: inputs\n Kind: enum\n Description: Estrategia de retorno (auto/close/navigate).\n\nComponent Capability:\n - Path: inputs.backConfig.returnTo\n Category: inputs\n Kind: string\n Description: Rota para retornar quando strategy=navigate.\n\nComponent Capability:\n - Path: inputs.backConfig.confirmOnDirty\n Category: inputs\n Kind: boolean\n Description: Solicita confirmacao ao sair com mudancas nao salvas.\n\nComponent Capability:\n - Path: inputs.hooks\n Category: inputs\n Kind: object\n Description: Declaracoes de hooks fornecidas diretamente ao componente.\n\nComponent Capability:\n - Path: inputs.hooks.beforeInit[]\n Category: hooks\n Kind: array\n Description: Hooks executados antes da inicializacao.\n\nComponent Capability:\n - Path: inputs.hooks.afterInit[]\n Category: hooks\n Kind: array\n Description: Hooks executados apos a inicializacao.\n\nComponent Capability:\n - Path: inputs.hooks.beforeValidate[]\n Category: hooks\n Kind: array\n Description: Hooks executados antes da validacao.\n\nComponent Capability:\n - Path: inputs.hooks.afterValidate[]\n Category: hooks\n Kind: array\n Description: Hooks executados apos a validacao.\n\nComponent Capability:\n - Path: inputs.hooks.beforeSubmit[]\n Category: hooks\n Kind: array\n Description: Hooks executados antes do submit.\n\nComponent Capability:\n - Path: inputs.hooks.afterSubmit[]\n Category: hooks\n Kind: array\n Description: Hooks executados apos o submit.\n\nComponent Capability:\n - Path: inputs.hooks.onError[]\n Category: hooks\n Kind: array\n Description: Hooks executados em erros de submit/validacao.\n\nComponent Capability:\n - Path: inputs.removeEmptyContainersOnSave\n Category: inputs\n Kind: boolean\n Description: Remove containers vazios ao salvar configuracao.\n\nComponent Capability:\n - Path: inputs.reactiveValidation\n Category: inputs\n Kind: boolean\n Description: Ativa validacao reativa (afterValidate em valueChanges).\n\nComponent Capability:\n - Path: inputs.reactiveValidationDebounceMs\n Category: inputs\n Kind: number\n Description: Debounce em ms para validacao reativa.\n\nComponent Capability:\n - Path: inputs.notifyIfOutdated\n Category: inputs\n Kind: enum\n Description: Canal de notificacao para schema desatualizado.\n\nComponent Capability:\n - Path: inputs.snoozeMs\n Category: inputs\n Kind: number\n Description: Duracao do snooze para alertas de schema.\n\nComponent Capability:\n - Path: inputs.autoOpenSettingsOnOutdated\n Category: inputs\n Kind: boolean\n Description: Abre automaticamente o editor ao detectar schema desatualizado.\n\nComponent Capability:\n - Path: inputs.readonlyModeGlobal\n Category: inputs\n Kind: boolean\n Description: Forca modo somente leitura global.\n\nComponent Capability:\n - Path: inputs.disabledModeGlobal\n Category: inputs\n Kind: boolean\n Description: Forca modo desabilitado global.\n\nComponent Capability:\n - Path: inputs.presentationModeGlobal\n Category: inputs\n Kind: boolean\n Description: Ativa modo de apresentacao global (somente view).\n\nComponent Capability:\n - Path: inputs.visibleGlobal\n Category: inputs\n Kind: boolean\n Description: Forca visibilidade global dos campos.\n\nComponent Capability:\n - Path: inputs.customEndpoints\n Category: inputs\n Kind: object\n Description: Override de endpoints CRUD (EndpointConfig).\n\nComponent Capability:\n - Path: inputs.customEndpoints.getAll\n Category: inputs\n Kind: string\n Description: Endpoint customizado para listar registros.\n\nComponent Capability:\n - Path: inputs.customEndpoints.getById\n Category: inputs\n Kind: string\n Description: Endpoint customizado para obter registro por ID.\n\nComponent Capability:\n - Path: inputs.customEndpoints.create\n Category: inputs\n Kind: string\n Description: Endpoint customizado para criar registro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.update\n Category: inputs\n Kind: string\n Description: Endpoint customizado para atualizar registro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.delete\n Category: inputs\n Kind: string\n Description: Endpoint customizado para deletar registro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.filter\n Category: inputs\n Kind: string\n Description: Endpoint customizado para filtro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.schema\n Category: inputs\n Kind: string\n Description: Endpoint customizado para schemas.",
12314
+ "content": "Component Capability:\n - Path: inputs.layoutPolicy.groupedCommand.contextFields\n Category: inputs\n Kind: array\n Description: Campos canônicos do request cujo valor vem do contexto da surface. Eles permanecem no FormGroup e no payload, sem renderizar controles redundantes.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.partialRowStrategy\n Category: inputs\n Kind: enum\n Description: Define se cada linha visual parcial, depois de resolver visibilidade responsiva, CSS order e wrap, preserva os spans canônicos ou redistribui apenas campos compatíveis para completar 12 colunas no breakpoint atual.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary\n Category: inputs\n Kind: object\n Description: Politica declarativa para resumo read-only compacto em compactPresentation, sem FormConfig.sections locais.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.includeFields\n Category: inputs\n Kind: array\n Description: Lista de campos canônicos do schema que devem entrar no resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.excludeFields\n Category: inputs\n Kind: array\n Description: Lista de campos canônicos do schema que devem ficar fora do resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.includeGroups\n Category: inputs\n Kind: array\n Description: Lista de grupos do schema que devem entrar no resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.excludeGroups\n Category: inputs\n Kind: array\n Description: Lista de grupos do schema que devem ficar fora do resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.includeRoles\n Category: inputs\n Kind: array\n Description: Lista de papeis semanticos de campo que devem entrar no resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.excludeRoles\n Category: inputs\n Kind: array\n Description: Lista de papeis semanticos de campo que devem ficar fora do resumo read-only compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.maxFields\n Category: inputs\n Kind: number\n Description: Limite maximo de campos materializados no primeiro painel compacto.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.fieldPriority\n Category: inputs\n Kind: object\n Description: Mapa campo -> prioridade para ordenar campos do resumo quando o schema publica candidatos suficientes.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.groupPriority\n Category: inputs\n Kind: object\n Description: Mapa grupo -> prioridade para ordenar grupos do resumo quando o schema publica agrupamento semantico.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.columns\n Category: inputs\n Kind: number\n Description: Quantidade base de colunas para distribuir campos de resumo schema-driven sem criar FormConfig.sections locais.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.responsiveColumns\n Category: inputs\n Kind: object\n Description: Mapa de colunas por breakpoint xs/sm/md/lg/xl para detalhes read-only compactos em drawers, side sheets e desktop largo.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.detailSummary.widthPrecedence\n Category: inputs\n Kind: enum\n Description: Define se larguras explicitas do schema ou a densidade do resumo controlam os spans no compactPresentation read-only.\n\nComponent Capability:\n - Path: inputs.fieldIconPolicy\n Category: inputs\n Kind: enum\n Description: Controla se icones prefix/suffix dos metadados aparecem em todos os modos, apenas apresentacao, ou nunca.\n\nComponent Capability:\n - Path: inputs.backConfig\n Category: inputs\n Kind: object\n Description: Configuracao de navegacao/retorno (BackConfig).\n\nComponent Capability:\n - Path: inputs.backConfig.strategy\n Category: inputs\n Kind: enum\n Description: Estrategia de retorno (auto/close/navigate).\n\nComponent Capability:\n - Path: inputs.backConfig.returnTo\n Category: inputs\n Kind: string\n Description: Rota para retornar quando strategy=navigate.\n\nComponent Capability:\n - Path: inputs.backConfig.confirmOnDirty\n Category: inputs\n Kind: boolean\n Description: Solicita confirmacao ao sair com mudancas nao salvas.\n\nComponent Capability:\n - Path: inputs.hooks\n Category: inputs\n Kind: object\n Description: Declaracoes de hooks fornecidas diretamente ao componente.\n\nComponent Capability:\n - Path: inputs.hooks.beforeInit[]\n Category: hooks\n Kind: array\n Description: Hooks executados antes da inicializacao.\n\nComponent Capability:\n - Path: inputs.hooks.afterInit[]\n Category: hooks\n Kind: array\n Description: Hooks executados apos a inicializacao.\n\nComponent Capability:\n - Path: inputs.hooks.beforeValidate[]\n Category: hooks\n Kind: array\n Description: Hooks executados antes da validacao.\n\nComponent Capability:\n - Path: inputs.hooks.afterValidate[]\n Category: hooks\n Kind: array\n Description: Hooks executados apos a validacao.\n\nComponent Capability:\n - Path: inputs.hooks.beforeSubmit[]\n Category: hooks\n Kind: array\n Description: Hooks executados antes do submit.\n\nComponent Capability:\n - Path: inputs.hooks.afterSubmit[]\n Category: hooks\n Kind: array\n Description: Hooks executados apos o submit.\n\nComponent Capability:\n - Path: inputs.hooks.onError[]\n Category: hooks\n Kind: array\n Description: Hooks executados em erros de submit/validacao.\n\nComponent Capability:\n - Path: inputs.removeEmptyContainersOnSave\n Category: inputs\n Kind: boolean\n Description: Remove containers vazios ao salvar configuracao.\n\nComponent Capability:\n - Path: inputs.reactiveValidation\n Category: inputs\n Kind: boolean\n Description: Ativa validacao reativa (afterValidate em valueChanges).\n\nComponent Capability:\n - Path: inputs.reactiveValidationDebounceMs\n Category: inputs\n Kind: number\n Description: Debounce em ms para validacao reativa.\n\nComponent Capability:\n - Path: inputs.notifyIfOutdated\n Category: inputs\n Kind: enum\n Description: Canal de notificacao para schema desatualizado.\n\nComponent Capability:\n - Path: inputs.snoozeMs\n Category: inputs\n Kind: number\n Description: Duracao do snooze para alertas de schema.\n\nComponent Capability:\n - Path: inputs.autoOpenSettingsOnOutdated\n Category: inputs\n Kind: boolean\n Description: Abre automaticamente o editor ao detectar schema desatualizado.\n\nComponent Capability:\n - Path: inputs.readonlyModeGlobal\n Category: inputs\n Kind: boolean\n Description: Forca modo somente leitura global.\n\nComponent Capability:\n - Path: inputs.disabledModeGlobal\n Category: inputs\n Kind: boolean\n Description: Forca modo desabilitado global.\n\nComponent Capability:\n - Path: inputs.presentationModeGlobal\n Category: inputs\n Kind: boolean\n Description: Ativa modo de apresentacao global (somente view).\n\nComponent Capability:\n - Path: inputs.visibleGlobal\n Category: inputs\n Kind: boolean\n Description: Forca visibilidade global dos campos.\n\nComponent Capability:\n - Path: inputs.customEndpoints\n Category: inputs\n Kind: object\n Description: Override de endpoints CRUD (EndpointConfig).\n\nComponent Capability:\n - Path: inputs.customEndpoints.getAll\n Category: inputs\n Kind: string\n Description: Endpoint customizado para listar registros.\n\nComponent Capability:\n - Path: inputs.customEndpoints.getById\n Category: inputs\n Kind: string\n Description: Endpoint customizado para obter registro por ID.\n\nComponent Capability:\n - Path: inputs.customEndpoints.create\n Category: inputs\n Kind: string\n Description: Endpoint customizado para criar registro.",
12262
12315
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/form-ai-capabilities.ts",
12263
- "contentHash": "c276a80957dcb05beb6aaeb7b61d0174156ac89b26e8ba3f18d3da7eb20e4bc6",
12316
+ "contentHash": "d8a5bd44a76042ef92898e9140289bc09495b4ae07573b497e95c9abdc1ab4a7",
12264
12317
  "sourceKind": "component_definition",
12265
12318
  "sourceId": "praxis-dynamic-form-dialog-host",
12266
12319
  "corpusVersion": "1.0.0"
@@ -12268,9 +12321,9 @@
12268
12321
  {
12269
12322
  "chunkIndex": 12,
12270
12323
  "chunkKind": "capabilities",
12271
- "content": "Component Capability:\n - Path: inputs.config.presentation\n Category: appearance\n Kind: object\n Description: Preferencias visuais persistidas no config.\n\nComponent Capability:\n - Path: inputs.config.presentation.labelFontSize\n Category: appearance\n Kind: number\n Description: Tamanho da fonte do label (px).\n\nComponent Capability:\n - Path: inputs.config.presentation.valueFontSize\n Category: appearance\n Kind: number\n Description: Tamanho da fonte do valor (px).\n\nComponent Capability:\n - Path: inputs.config.presentation.labelPosition\n Category: appearance\n Kind: enum\n Description: Posicionamento do label (above/left).\n\nComponent Capability:\n - Path: inputs.config.presentation.compact\n Category: appearance\n Kind: boolean\n Description: Modo compacto de apresentacao.\n\nComponent Capability:\n - Path: inputs.config.presentation.density\n Category: appearance\n Kind: enum\n Description: Densidade visual global.\n\nComponent Capability:\n - Path: inputs.config.presentation.labelWidth\n Category: appearance\n Kind: number\n Description: Largura do label (px).\n\nComponent Capability:\n - Path: inputs.config.presentation.labelAlign\n Category: appearance\n Kind: enum\n Description: Alinhamento do label.\n\nComponent Capability:\n - Path: inputs.config.presentation.valueAlign\n Category: appearance\n Kind: enum\n Description: Alinhamento do valor.\n\nComponent Capability:\n - Path: outputs.formSubmit\n Category: outputs\n Kind: object\n Description: Evento emitido no submit do formulario.\n\nComponent Capability:\n - Path: outputs.formCancel\n Category: outputs\n Kind: object\n Description: Evento emitido ao cancelar.\n\nComponent Capability:\n - Path: outputs.formReset\n Category: outputs\n Kind: object\n Description: Evento emitido ao resetar o formulario.\n\nComponent Capability:\n - Path: outputs.configChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando a configuracao muda.\n\nComponent Capability:\n - Path: outputs.formReady\n Category: outputs\n Kind: object\n Description: Evento emitido quando o formulario esta pronto.\n\nComponent Capability:\n - Path: outputs.valueChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando o valor do formulario muda.\n\nComponent Capability:\n - Path: outputs.syncCompleted\n Category: outputs\n Kind: object\n Description: Evento emitido ao completar sincronizacao com schema.\n\nComponent Capability:\n - Path: outputs.initializationError\n Category: outputs\n Kind: object\n Description: Evento emitido quando ocorre erro na inicializacao.\n\nComponent Capability:\n - Path: outputs.enableCustomizationChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando o modo de customizacao muda.\n\nComponent Capability:\n - Path: outputs.customAction\n Category: outputs\n Kind: object\n Description: Evento emitido ao disparar acao customizada.\n\nComponent Capability:\n - Path: outputs.actionConfirmation\n Category: outputs\n Kind: object\n Description: Evento emitido quando acao requer confirmacao.\n\nComponent Capability:\n - Path: outputs.schemaStatusChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando o status do schema muda.\n\nCapability Note:\n - Este catalogo descreve inputs e outputs do componente.\n\nCapability Note:\n - O objeto inputs.config segue o schema de FormConfig (veja form-ai-capabilities).\n\nCapability Note:\n - inputs.config.presentation e uma extensao de runtime aplicada pelo componente.\n\nCapability Note:\n - Preferir FormConfig (sections/fieldMetadata) em vez do layout legado (fieldsets).\n\nCapability Note:\n - Use inputs.editorialContext apenas para override de contexto editorial do host; a precedencia final e runtime < config.editorialContext < host.\n\nCapability Note:\n - rich content editorial hospedado pelo form pode ser renderizado em tres slots semanticos: before, beforeActions e after.",
12324
+ "content": "Component Capability:\n - Path: inputs.customEndpoints.update\n Category: inputs\n Kind: string\n Description: Endpoint customizado para atualizar registro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.delete\n Category: inputs\n Kind: string\n Description: Endpoint customizado para deletar registro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.filter\n Category: inputs\n Kind: string\n Description: Endpoint customizado para filtro.\n\nComponent Capability:\n - Path: inputs.customEndpoints.schema\n Category: inputs\n Kind: string\n Description: Endpoint customizado para schemas.\n\nComponent Capability:\n - Path: inputs.config.presentation\n Category: appearance\n Kind: object\n Description: Preferencias visuais persistidas no config.\n\nComponent Capability:\n - Path: inputs.config.presentation.labelFontSize\n Category: appearance\n Kind: number\n Description: Tamanho da fonte do label (px).\n\nComponent Capability:\n - Path: inputs.config.presentation.valueFontSize\n Category: appearance\n Kind: number\n Description: Tamanho da fonte do valor (px).\n\nComponent Capability:\n - Path: inputs.config.presentation.labelPosition\n Category: appearance\n Kind: enum\n Description: Posicionamento do label (above/left).\n\nComponent Capability:\n - Path: inputs.config.presentation.compact\n Category: appearance\n Kind: boolean\n Description: Modo compacto de apresentacao.\n\nComponent Capability:\n - Path: inputs.config.presentation.density\n Category: appearance\n Kind: enum\n Description: Densidade visual global.\n\nComponent Capability:\n - Path: inputs.config.presentation.labelWidth\n Category: appearance\n Kind: number\n Description: Largura do label (px).\n\nComponent Capability:\n - Path: inputs.config.presentation.labelAlign\n Category: appearance\n Kind: enum\n Description: Alinhamento do label.\n\nComponent Capability:\n - Path: inputs.config.presentation.valueAlign\n Category: appearance\n Kind: enum\n Description: Alinhamento do valor.\n\nComponent Capability:\n - Path: outputs.formSubmit\n Category: outputs\n Kind: object\n Description: Evento emitido no submit do formulario.\n\nComponent Capability:\n - Path: outputs.formCancel\n Category: outputs\n Kind: object\n Description: Evento emitido ao cancelar.\n\nComponent Capability:\n - Path: outputs.formReset\n Category: outputs\n Kind: object\n Description: Evento emitido ao resetar o formulario.\n\nComponent Capability:\n - Path: outputs.configChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando a configuracao muda.\n\nComponent Capability:\n - Path: outputs.formReady\n Category: outputs\n Kind: object\n Description: Evento emitido quando o formulario esta pronto.\n\nComponent Capability:\n - Path: outputs.valueChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando o valor do formulario muda.\n\nComponent Capability:\n - Path: outputs.syncCompleted\n Category: outputs\n Kind: object\n Description: Evento emitido ao completar sincronizacao com schema.\n\nComponent Capability:\n - Path: outputs.initializationError\n Category: outputs\n Kind: object\n Description: Evento emitido quando ocorre erro na inicializacao.\n\nComponent Capability:\n - Path: outputs.enableCustomizationChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando o modo de customizacao muda.\n\nComponent Capability:\n - Path: outputs.customAction\n Category: outputs\n Kind: object\n Description: Evento emitido ao disparar acao customizada.\n\nComponent Capability:\n - Path: outputs.actionConfirmation\n Category: outputs\n Kind: object\n Description: Evento emitido quando acao requer confirmacao.\n\nComponent Capability:\n - Path: outputs.schemaStatusChange\n Category: outputs\n Kind: object\n Description: Evento emitido quando o status do schema muda.\n\nCapability Note:\n - Este catalogo descreve inputs e outputs do componente.\n\nCapability Note:\n - O objeto inputs.config segue o schema de FormConfig (veja form-ai-capabilities).\n\nCapability Note:\n - inputs.config.presentation e uma extensao de runtime aplicada pelo componente.\n\nCapability Note:\n - Preferir FormConfig (sections/fieldMetadata) em vez do layout legado (fieldsets).\n\nCapability Note:\n - Use inputs.editorialContext apenas para override de contexto editorial do host; a precedencia final e runtime < config.editorialContext < host.\n\nCapability Note:\n - rich content editorial hospedado pelo form pode ser renderizado em tres slots semanticos: before, beforeActions e after.",
12272
12325
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/form-ai-capabilities.ts",
12273
- "contentHash": "142afe9c47e968f78a0b3b3713325507ac1cb3836d759ae02278d2cf188b1d06",
12326
+ "contentHash": "8cde02bbb0100a17feb34ecf1e03642b852a82d237170763ad456693ee7b8789",
12274
12327
  "sourceKind": "component_definition",
12275
12328
  "sourceId": "praxis-dynamic-form-dialog-host",
12276
12329
  "corpusVersion": "1.0.0"
@@ -1,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, inject, input, signal, computed, effect, ChangeDetectionStrategy, Component, EventEmitter, DestroyRef, ChangeDetectorRef, Injector, ViewChild, Output, Input, Optional, Inject, ViewEncapsulation, ENVIRONMENT_INITIALIZER } from '@angular/core';
2
+ import { Injectable, InjectionToken, inject, input, signal, computed, effect, ChangeDetectionStrategy, Component, EventEmitter, output, DestroyRef, ChangeDetectorRef, Injector, ViewChild, Output, Input, Optional, Inject, ViewEncapsulation, ENVIRONMENT_INITIALIZER } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { HttpClient } from '@angular/common/http';
5
5
  import { Router, ActivatedRoute, RouterLink } from '@angular/router';
6
6
  import { MatSnackBar } from '@angular/material/snack-bar';
7
7
  import { firstValueFrom, BehaviorSubject, Subscription } from 'rxjs';
8
8
  import * as i2$1 from '@praxisui/core';
9
- import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, LoggerService, SurfaceNavigationError, fillUndefined, SETTINGS_PANEL_DATA, PraxisI18nService, PraxisIconDirective, providePraxisI18nConfig, createDefaultTableConfig, EnterpriseRuntimeContextService, GLOBAL_SURFACE_SERVICE, SurfaceOutletRegistryService, ComponentKeyService, ResourceDiscoveryService, ResourceActionOpenAdapterService, ResourceSurfaceOpenAdapterService, normalizeSurfaceOperationContext, translateUnavailableWorkflowMessage, isSurfaceNavigationError, translateSurfaceNavigationRejected, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, SURFACE_DRAWER_REF, SURFACE_DRAWER_CONTENT_DATA, PraxisIconButtonComponent, PraxisResourceIdentityComponent, GenericCrudService, ComponentMetadataRegistry } from '@praxisui/core';
9
+ import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, LoggerService, SurfaceNavigationError, fillUndefined, SETTINGS_PANEL_DATA, PraxisI18nService, PraxisIconDirective, providePraxisI18nConfig, createDefaultTableConfig, EnterpriseRuntimeContextService, GLOBAL_SURFACE_SERVICE, SurfaceOutletRegistryService, ComponentKeyService, ResourceDiscoveryService, ResourceActionOpenAdapterService, ResourceSurfaceOpenAdapterService, normalizeSurfaceOperationContext, translateUnavailableWorkflowMessage, isSurfaceNavigationError, translateSurfaceNavigationRejected, normalizeUnknownError, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, SURFACE_DRAWER_REF, SURFACE_DRAWER_CONTENT_DATA, PraxisIconButtonComponent, PraxisResourceIdentityComponent, GenericCrudService, ComponentMetadataRegistry } from '@praxisui/core';
10
10
  import { SettingsPanelService } from '@praxisui/settings-panel';
11
11
  import { PraxisTableInlineAuthoringEditorComponent, PraxisTable } from '@praxisui/table';
12
12
  import { ConfirmDialogComponent } from '@praxisui/dynamic-fields';
@@ -193,6 +193,12 @@ class CrudLauncherService {
193
193
  presentation: mode === 'drawer' ? 'drawer' : 'modal',
194
194
  resourceIdentity,
195
195
  contextIdentity,
196
+ showResourceIdentityKey: runtime?.showResourceIdentityKey !== false,
197
+ reactiveDeterminationCallbacks: {
198
+ onEvent: drawerCallbacks?.onReactiveDetermination,
199
+ onPendingChange: drawerCallbacks?.onReactiveDeterminationPendingChange,
200
+ onStabilityChange: drawerCallbacks?.onReactiveDeterminationStabilityChange,
201
+ },
196
202
  };
197
203
  const modalCfg = { ...(merged.metadata.defaults?.modal || {}) };
198
204
  const restoreFocus = resolveCrudRestoreFocus(modalCfg.restoreFocus, actionFocusOrigin);
@@ -240,9 +246,13 @@ class CrudLauncherService {
240
246
  inputs,
241
247
  resourceIdentity,
242
248
  contextIdentity,
249
+ showResourceIdentityKey: runtime?.showResourceIdentityKey !== false,
243
250
  restoreFocus,
244
251
  onClose: drawerCallbacks?.onClose,
245
252
  onResult: drawerCallbacks?.onResult,
253
+ onReactiveDetermination: drawerCallbacks?.onReactiveDetermination,
254
+ onReactiveDeterminationPendingChange: drawerCallbacks?.onReactiveDeterminationPendingChange,
255
+ onReactiveDeterminationStabilityChange: drawerCallbacks?.onReactiveDeterminationStabilityChange,
246
256
  }));
247
257
  return { mode };
248
258
  }
@@ -3801,6 +3811,8 @@ class PraxisCrudComponent {
3801
3811
  tableConfigPersistenceStrategy = 'local-first';
3802
3812
  context;
3803
3813
  enableCustomization = false;
3814
+ /** Controls whether existing-record hosts expose the canonical identity key. */
3815
+ showResourceIdentityKey = true;
3804
3816
  /** Capability publica exigida para authoring governado do CRUD e da tabela interna. */
3805
3817
  authoringCapability = null;
3806
3818
  configureRequested = new EventEmitter();
@@ -3808,11 +3820,17 @@ class PraxisCrudComponent {
3808
3820
  afterClose = new EventEmitter();
3809
3821
  afterSave = new EventEmitter();
3810
3822
  afterDelete = new EventEmitter();
3823
+ /** Metadata-only Reactive Determination evidence from an open form host. */
3824
+ reactiveDeterminationExecuted = new EventEmitter();
3825
+ reactiveDeterminationPendingChange = new EventEmitter();
3826
+ reactiveDeterminationStabilityChange = new EventEmitter();
3811
3827
  error = new EventEmitter();
3812
3828
  rowClick = new EventEmitter();
3813
3829
  /** Emits the canonical table row-action envelope before the CRUD handles its surface/action. */
3814
3830
  rowAction = new EventEmitter();
3815
3831
  selectionChange = new EventEmitter();
3832
+ /** Forwards the canonical resource interaction envelope emitted by the internal table. */
3833
+ resourceEvent = output();
3816
3834
  tableRuntimeConfigChange = new EventEmitter();
3817
3835
  crudAuthoringDocumentApplied = new EventEmitter();
3818
3836
  crudAuthoringDocumentSaved = new EventEmitter();
@@ -3834,11 +3852,13 @@ class PraxisCrudComponent {
3834
3852
  snack = inject(MatSnackBar);
3835
3853
  dialog = inject(DialogService);
3836
3854
  i18n = inject(PraxisI18nService);
3855
+ logger = inject(LoggerService, { optional: true });
3837
3856
  injector = inject(Injector);
3838
3857
  resourceDiscoveryInstance;
3839
3858
  actionOpenAdapterInstance;
3840
3859
  surfaceOpenAdapterInstance;
3841
3860
  materializedRefreshSequence = 0;
3861
+ surfaceOpenAttemptSequence = 0;
3842
3862
  global = (() => {
3843
3863
  try {
3844
3864
  return inject(GlobalConfigService);
@@ -3922,6 +3942,9 @@ class PraxisCrudComponent {
3922
3942
  this.selectedRow = this.extractSelectedRowFromEvent(event);
3923
3943
  this.selectionChange.emit(event);
3924
3944
  }
3945
+ onTableResourceEvent(event) {
3946
+ this.resourceEvent.emit(event);
3947
+ }
3925
3948
  async onBulkAction(event) {
3926
3949
  const action = String(event?.action || '').trim();
3927
3950
  if (!action) {
@@ -4051,6 +4074,18 @@ class PraxisCrudComponent {
4051
4074
  this.refreshTable();
4052
4075
  }
4053
4076
  },
4077
+ onReactiveDetermination: (event) => this.reactiveDeterminationExecuted.emit({
4078
+ action: effectiveAction.action,
4079
+ event,
4080
+ }),
4081
+ onReactiveDeterminationPendingChange: (pending) => this.reactiveDeterminationPendingChange.emit({
4082
+ action: effectiveAction.action,
4083
+ pending,
4084
+ }),
4085
+ onReactiveDeterminationStabilityChange: (stability) => this.reactiveDeterminationStabilityChange.emit({
4086
+ action: effectiveAction.action,
4087
+ ...stability,
4088
+ }),
4054
4089
  }, {
4055
4090
  capabilities: effectiveAction.action === 'create'
4056
4091
  ? this.collectionCapabilities
@@ -4058,6 +4093,7 @@ class PraxisCrudComponent {
4058
4093
  links: this.resolveCrudRuntimeLinks(effectiveAction.action, contextualRow),
4059
4094
  resourceIdentity,
4060
4095
  contextIdentity,
4096
+ showResourceIdentityKey: this.showResourceIdentityKey,
4061
4097
  focusOrigin: runtimeEvent?.focusOrigin ?? null,
4062
4098
  surfaceRuntime: this.resolveSurfaceRuntime(),
4063
4099
  });
@@ -4324,9 +4360,16 @@ class PraxisCrudComponent {
4324
4360
  const { mode, ref } = await this.launcher.launch(createAction, undefined, this.resolvedMetadata, this.componentKeyId(), {
4325
4361
  onClose: () => emitDrawerClose(),
4326
4362
  onResult: (result) => handleResult(result),
4363
+ onReactiveDetermination: (event) => this.reactiveDeterminationExecuted.emit({ action: normalizedAction, event }),
4364
+ onReactiveDeterminationPendingChange: (pending) => this.reactiveDeterminationPendingChange.emit({ action: normalizedAction, pending }),
4365
+ onReactiveDeterminationStabilityChange: (stability) => this.reactiveDeterminationStabilityChange.emit({
4366
+ action: normalizedAction,
4367
+ ...stability,
4368
+ }),
4327
4369
  }, {
4328
4370
  capabilities: this.collectionCapabilities,
4329
4371
  links: this.tableCollectionLinks,
4372
+ showResourceIdentityKey: this.showResourceIdentityKey,
4330
4373
  surfaceRuntime: this.resolveSurfaceRuntime(),
4331
4374
  });
4332
4375
  this.afterOpen.emit({ mode, action: normalizedAction });
@@ -4582,6 +4625,12 @@ class PraxisCrudComponent {
4582
4625
  return true;
4583
4626
  }
4584
4627
  const focusOrigin = this.resolveRuntimeFocusOrigin(runtimeEvent);
4628
+ const correlationId = [
4629
+ this.componentKeyId() || this.crudId || 'praxis-crud',
4630
+ 'surface.open',
4631
+ surface.id,
4632
+ ++this.surfaceOpenAttemptSequence,
4633
+ ].join(':');
4585
4634
  let openPromise;
4586
4635
  try {
4587
4636
  const surfaceContext = {
@@ -4592,6 +4641,7 @@ class PraxisCrudComponent {
4592
4641
  resourcePath,
4593
4642
  surfaceId: surface.id,
4594
4643
  operationId: surface.operationId,
4644
+ correlationId,
4595
4645
  },
4596
4646
  runtime: {
4597
4647
  row: row ?? null,
@@ -4607,11 +4657,8 @@ class PraxisCrudComponent {
4607
4657
  openPromise = handledInline ? Promise.resolve(undefined) : Promise.resolve(this.surfaceService.open(payload, surfaceContext));
4608
4658
  }
4609
4659
  catch (error) {
4610
- if (this.notifySurfaceNavigationFailure(error)) {
4611
- this.error.emit(error);
4612
- return true;
4613
- }
4614
- return false;
4660
+ this.reportDiscoveredSurfaceOpenFailure(error, normalizedAction, surface, resourcePath, correlationId);
4661
+ return true;
4615
4662
  }
4616
4663
  try {
4617
4664
  this.bindDiscoveredSurfaceLifecycle(await openPromise);
@@ -4621,8 +4668,7 @@ class PraxisCrudComponent {
4621
4668
  });
4622
4669
  }
4623
4670
  catch (err) {
4624
- this.error.emit(err);
4625
- this.notifySurfaceNavigationFailure(err);
4671
+ this.reportDiscoveredSurfaceOpenFailure(err, normalizedAction, surface, resourcePath, correlationId);
4626
4672
  }
4627
4673
  return true;
4628
4674
  }
@@ -4742,6 +4788,31 @@ class PraxisCrudComponent {
4742
4788
  this.snack.open(translateSurfaceNavigationRejected(this.i18n), undefined, { duration: 4500 });
4743
4789
  return true;
4744
4790
  }
4791
+ reportDiscoveredSurfaceOpenFailure(error, action, surface, resourcePath, correlationId) {
4792
+ const normalizedCause = normalizeUnknownError(error);
4793
+ this.error.emit(error);
4794
+ this.notifySurfaceNavigationFailure(error);
4795
+ this.logger?.warn('Discovered CRUD surface failed to open.', {
4796
+ context: {
4797
+ lib: '@praxisui/crud',
4798
+ component: 'PraxisCrudComponent',
4799
+ actionId: action,
4800
+ correlationId,
4801
+ },
4802
+ data: {
4803
+ surfaceId: surface.id,
4804
+ mode: 'drawer',
4805
+ resourcePath,
4806
+ selectedPath: 'surface.open',
4807
+ fallback: 'none',
4808
+ cause: {
4809
+ name: normalizedCause.name,
4810
+ message: normalizedCause.message,
4811
+ },
4812
+ },
4813
+ throttleKey: `crud:surface.open:${action}:${surface.id}`,
4814
+ });
4815
+ }
4745
4816
  async resolveDiscoveredActionCatalog(row) {
4746
4817
  try {
4747
4818
  if (row) {
@@ -5467,7 +5538,7 @@ class PraxisCrudComponent {
5467
5538
  return Object.entries(params).reduce((current, [name, value]) => current.split(`{${name}}`).join(value), text);
5468
5539
  }
5469
5540
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5470
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisCrudComponent, isStandalone: true, selector: "praxis-crud", inputs: { metadata: "metadata", crudId: "crudId", componentInstanceId: "componentInstanceId", tableConfigPersistenceStrategy: "tableConfigPersistenceStrategy", context: "context", enableCustomization: "enableCustomization", authoringCapability: "authoringCapability" }, outputs: { configureRequested: "configureRequested", afterOpen: "afterOpen", afterClose: "afterClose", afterSave: "afterSave", afterDelete: "afterDelete", error: "error", rowClick: "rowClick", rowAction: "rowAction", selectionChange: "selectionChange", tableRuntimeConfigChange: "tableRuntimeConfigChange", crudAuthoringDocumentApplied: "crudAuthoringDocumentApplied", crudAuthoringDocumentSaved: "crudAuthoringDocumentSaved" }, providers: [
5541
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisCrudComponent, isStandalone: true, selector: "praxis-crud", inputs: { metadata: "metadata", crudId: "crudId", componentInstanceId: "componentInstanceId", tableConfigPersistenceStrategy: "tableConfigPersistenceStrategy", context: "context", enableCustomization: "enableCustomization", showResourceIdentityKey: "showResourceIdentityKey", authoringCapability: "authoringCapability" }, outputs: { configureRequested: "configureRequested", afterOpen: "afterOpen", afterClose: "afterClose", afterSave: "afterSave", afterDelete: "afterDelete", reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange", reactiveDeterminationStabilityChange: "reactiveDeterminationStabilityChange", error: "error", rowClick: "rowClick", rowAction: "rowAction", selectionChange: "selectionChange", resourceEvent: "resourceEvent", tableRuntimeConfigChange: "tableRuntimeConfigChange", crudAuthoringDocumentApplied: "crudAuthoringDocumentApplied", crudAuthoringDocumentSaved: "crudAuthoringDocumentSaved" }, providers: [
5471
5542
  providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
5472
5543
  providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
5473
5544
  ], viewQueries: [{ propertyName: "table", first: true, predicate: PraxisTable, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -5492,6 +5563,7 @@ class PraxisCrudComponent {
5492
5563
  [authoringCapability]="authoringCapability"
5493
5564
  (rowClick)="onTableRowClick($event)"
5494
5565
  (selectionChange)="onTableSelectionChange($event)"
5566
+ (resourceEvent)="onTableResourceEvent($event)"
5495
5567
  (rowAction)="onTableRowAction($event)"
5496
5568
  (toolbarAction)="onToolbarAction($event)"
5497
5569
  (bulkAction)="onBulkAction($event)"
@@ -5540,6 +5612,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5540
5612
  [authoringCapability]="authoringCapability"
5541
5613
  (rowClick)="onTableRowClick($event)"
5542
5614
  (selectionChange)="onTableSelectionChange($event)"
5615
+ (resourceEvent)="onTableResourceEvent($event)"
5543
5616
  (rowAction)="onTableRowAction($event)"
5544
5617
  (toolbarAction)="onToolbarAction($event)"
5545
5618
  (bulkAction)="onBulkAction($event)"
@@ -5574,6 +5647,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5574
5647
  type: Input
5575
5648
  }], enableCustomization: [{
5576
5649
  type: Input
5650
+ }], showResourceIdentityKey: [{
5651
+ type: Input
5577
5652
  }], authoringCapability: [{
5578
5653
  type: Input
5579
5654
  }], configureRequested: [{
@@ -5586,6 +5661,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5586
5661
  type: Output
5587
5662
  }], afterDelete: [{
5588
5663
  type: Output
5664
+ }], reactiveDeterminationExecuted: [{
5665
+ type: Output
5666
+ }], reactiveDeterminationPendingChange: [{
5667
+ type: Output
5668
+ }], reactiveDeterminationStabilityChange: [{
5669
+ type: Output
5589
5670
  }], error: [{
5590
5671
  type: Output
5591
5672
  }], rowClick: [{
@@ -5594,7 +5675,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5594
5675
  type: Output
5595
5676
  }], selectionChange: [{
5596
5677
  type: Output
5597
- }], tableRuntimeConfigChange: [{
5678
+ }], resourceEvent: [{ type: i0.Output, args: ["resourceEvent"] }], tableRuntimeConfigChange: [{
5598
5679
  type: Output
5599
5680
  }], crudAuthoringDocumentApplied: [{
5600
5681
  type: Output
@@ -5633,6 +5714,9 @@ class DynamicFormDialogHostComponent {
5633
5714
  configStorage;
5634
5715
  surfaceRef;
5635
5716
  formComp;
5717
+ reactiveDeterminationExecuted = new EventEmitter();
5718
+ reactiveDeterminationPendingChange = new EventEmitter();
5719
+ reactiveDeterminationStabilityChange = new EventEmitter();
5636
5720
  modal = {};
5637
5721
  presentation = 'modal';
5638
5722
  maximized = false;
@@ -5644,11 +5728,13 @@ class DynamicFormDialogHostComponent {
5644
5728
  terminalClose = false;
5645
5729
  destroyRef = inject(DestroyRef);
5646
5730
  i18n = inject(PraxisI18nService);
5731
+ reactiveDeterminationStabilitySignature = '';
5647
5732
  resourcePath;
5648
5733
  resourceId;
5649
5734
  initialValue;
5650
5735
  resourceIdentity = null;
5651
5736
  contextIdentity = null;
5737
+ showResourceIdentityKey = true;
5652
5738
  schemaUrl;
5653
5739
  submitUrl;
5654
5740
  submitMethod;
@@ -5737,6 +5823,7 @@ class DynamicFormDialogHostComponent {
5737
5823
  this.resourceIdentity = this.mode !== 'create' && this.data.resourceIdentity
5738
5824
  ? this.data.resourceIdentity
5739
5825
  : null;
5826
+ this.showResourceIdentityKey = this.data.showResourceIdentityKey !== false;
5740
5827
  this.contextIdentity = this.data.contextIdentity
5741
5828
  ? this.data.contextIdentity
5742
5829
  : null;
@@ -5967,6 +6054,9 @@ class DynamicFormDialogHostComponent {
5967
6054
  if (stage === 'before' || stage === 'error') {
5968
6055
  return;
5969
6056
  }
6057
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6058
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.())
6059
+ return;
5970
6060
  if (this.modal.closeOnSave === false) {
5971
6061
  this.saveState();
5972
6062
  return;
@@ -5982,6 +6072,47 @@ class DynamicFormDialogHostComponent {
5982
6072
  }
5983
6073
  }
5984
6074
  onCancel() {
6075
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6076
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.()) {
6077
+ void this.formComp.waitForReactiveDeterminations().then((stable) => {
6078
+ if (stable)
6079
+ this.continueCancel();
6080
+ });
6081
+ return;
6082
+ }
6083
+ this.continueCancel();
6084
+ }
6085
+ onReactiveDeterminationExecuted(event) {
6086
+ this.reactiveDeterminationExecuted.emit(event);
6087
+ this.data.reactiveDeterminationCallbacks?.onEvent?.(event);
6088
+ this.emitReactiveDeterminationStability();
6089
+ }
6090
+ onReactiveDeterminationPendingChange(pending) {
6091
+ this.reactiveDeterminationPendingChange.emit(pending);
6092
+ this.data.reactiveDeterminationCallbacks?.onPendingChange?.(pending);
6093
+ this.emitReactiveDeterminationStability();
6094
+ }
6095
+ emitReactiveDeterminationStability() {
6096
+ const pending = this.formComp?.hasPendingReactiveDeterminations?.() === true;
6097
+ const unsatisfied = this.formComp?.hasUnsatisfiedReactiveDeterminations?.() === true;
6098
+ const status = pending
6099
+ ? 'pending'
6100
+ : unsatisfied
6101
+ ? 'settled-unsatisfied'
6102
+ : 'settled-satisfied';
6103
+ const signature = `${status}:${pending}:${unsatisfied}`;
6104
+ if (signature === this.reactiveDeterminationStabilitySignature)
6105
+ return;
6106
+ this.reactiveDeterminationStabilitySignature = signature;
6107
+ const stability = {
6108
+ status,
6109
+ pending,
6110
+ unsatisfied,
6111
+ };
6112
+ this.reactiveDeterminationStabilityChange.emit(stability);
6113
+ this.data.reactiveDeterminationCallbacks?.onStabilityChange?.(stability);
6114
+ }
6115
+ continueCancel() {
5985
6116
  if (this.surfaceRef) {
5986
6117
  void this.canLeaveSurfaceFrame().then((allowed) => {
5987
6118
  if (!allowed)
@@ -6018,6 +6149,12 @@ class DynamicFormDialogHostComponent {
6018
6149
  }
6019
6150
  }
6020
6151
  async canLeaveSurfaceFrame() {
6152
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6153
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.()) {
6154
+ const stable = await this.formComp.waitForReactiveDeterminations();
6155
+ if (!stable)
6156
+ return false;
6157
+ }
6021
6158
  if (this.terminalClose || !this.formComp?.form.dirty) {
6022
6159
  return true;
6023
6160
  }
@@ -6157,7 +6294,7 @@ class DynamicFormDialogHostComponent {
6157
6294
  return { ...horizontal, ...vertical };
6158
6295
  }
6159
6296
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, deps: [{ token: MatDialogRef, optional: true }, { token: MAT_DIALOG_DATA, optional: true }, { token: DialogService }, { token: i2$1.GenericCrudService }, { token: ASYNC_CONFIG_STORAGE }, { token: SURFACE_DRAWER_REF, optional: true }, { token: SURFACE_DRAWER_CONTENT_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
6160
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicFormDialogHostComponent, isStandalone: true, selector: "praxis-dynamic-form-dialog-host", host: { properties: { "attr.data-density": "modal.density || \"default\"", "attr.data-presentation": "presentation", "class.praxis-drawer": "presentation === \"drawer\"", "class.praxis-surface-frame": "isSurfaceFrame" }, classAttribute: "praxis-dialog" }, providers: [
6297
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicFormDialogHostComponent, isStandalone: true, selector: "praxis-dynamic-form-dialog-host", outputs: { reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange", reactiveDeterminationStabilityChange: "reactiveDeterminationStabilityChange" }, host: { properties: { "attr.data-density": "modal.density || \"default\"", "attr.data-presentation": "presentation", "class.praxis-drawer": "presentation === \"drawer\"", "class.praxis-surface-frame": "isSurfaceFrame" }, classAttribute: "praxis-dialog" }, providers: [
6161
6298
  GenericCrudService,
6162
6299
  providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
6163
6300
  ], viewQueries: [{ propertyName: "formComp", first: true, predicate: PraxisDynamicForm, descendants: true }], ngImport: i0, template: `
@@ -6229,7 +6366,8 @@ class DynamicFormDialogHostComponent {
6229
6366
  <praxis-resource-identity
6230
6367
  [identity]="resourceIdentity"
6231
6368
  density="compact"
6232
- [showKeyLabel]="true"
6369
+ [showKey]="showResourceIdentityKey"
6370
+ [showKeyLabel]="showResourceIdentityKey"
6233
6371
  [ariaLabel]="resourceIdentityLabel"
6234
6372
  ></praxis-resource-identity>
6235
6373
  </div>
@@ -6256,9 +6394,11 @@ class DynamicFormDialogHostComponent {
6256
6394
  [actions]="formActions"
6257
6395
  (formSubmit)="onSave($event)"
6258
6396
  (formCancel)="onCancel()"
6397
+ (reactiveDeterminationExecuted)="onReactiveDeterminationExecuted($event)"
6398
+ (reactiveDeterminationPendingChange)="onReactiveDeterminationPendingChange($event)"
6259
6399
  ></praxis-dynamic-form>
6260
6400
  </mat-dialog-content>
6261
- `, isInline: true, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);min-height:var(--dlg-header-h);padding:10px var(--dlg-pad);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-heading{display:grid;min-width:0;gap:2px}praxis-dynamic-form-dialog-host .dialog-title-icon{display:inline-grid;flex:0 0 auto;width:36px;height:36px;place-items:center;border-radius:10px;color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}praxis-dynamic-form-dialog-host .dialog-title-icon mat-icon{width:22px;height:22px;font-size:22px}praxis-dynamic-form-dialog-host .dialog-subtitle{display:-webkit-box;overflow:hidden;color:var(--md-sys-color-on-surface-variant);font-size:.82rem;font-weight:400;line-height:1.35;-webkit-box-orient:vertical;-webkit-line-clamp:2}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host .crud-operation-context{position:sticky;top:0;z-index:1;display:grid;gap:.75rem;margin-block-end:var(--dlg-pad);padding-block:.5rem .75rem;background:var(--pfx-form-surface, var(--md-sys-color-surface));border-bottom:1px solid var(--md-sys-color-outline-variant)}praxis-dynamic-form-dialog-host .crud-resource-identity{display:grid;gap:.25rem;min-width:0}praxis-dynamic-form-dialog-host .crud-resource-identity__label{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-label-medium, 500 .75rem/1rem inherit)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 72px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{display:flex;flex-direction:column;max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form{display:block;flex:1 1 auto;min-height:0}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form{min-height:100%}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:auto;padding-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}praxis-dynamic-form-dialog-host.praxis-surface-frame .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button:hover{color:var(--md-sys-color-primary)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;min-width:0;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane.pfx-drawer-maximized{margin:var(--pfx-drawer-edge-gap, 8px)!important}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{min-width:0!important;border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisResourceIdentityComponent, selector: "praxis-resource-identity", inputs: ["identity", "emptyTitle", "density", "showMetadataLabels", "showKeyLabel", "ariaLabel"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }], encapsulation: i0.ViewEncapsulation.None });
6401
+ `, isInline: true, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);min-height:var(--dlg-header-h);padding:10px var(--dlg-pad);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-heading{display:grid;min-width:0;gap:2px}praxis-dynamic-form-dialog-host .dialog-title-icon{display:inline-grid;flex:0 0 auto;width:36px;height:36px;place-items:center;border-radius:10px;color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}praxis-dynamic-form-dialog-host .dialog-title-icon mat-icon{width:22px;height:22px;font-size:22px}praxis-dynamic-form-dialog-host .dialog-subtitle{display:-webkit-box;overflow:hidden;color:var(--md-sys-color-on-surface-variant);font-size:.82rem;font-weight:400;line-height:1.35;-webkit-box-orient:vertical;-webkit-line-clamp:2}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host .crud-operation-context{position:sticky;top:0;z-index:1;display:grid;gap:.75rem;margin-block-end:var(--dlg-pad);padding-block:.5rem .75rem;background:var(--pfx-form-surface, var(--md-sys-color-surface));border-bottom:1px solid var(--md-sys-color-outline-variant)}praxis-dynamic-form-dialog-host .crud-resource-identity{display:grid;gap:.25rem;min-width:0}praxis-dynamic-form-dialog-host .crud-resource-identity__label{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-label-medium, 500 .75rem/1rem inherit)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 72px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{display:flex;flex-direction:column;max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form{display:block;flex:1 1 auto;min-height:0}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form{min-height:100%}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:auto;padding-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}praxis-dynamic-form-dialog-host.praxis-surface-frame .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button:hover{color:var(--md-sys-color-primary)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;min-width:0;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane.pfx-drawer-maximized{margin:var(--pfx-drawer-edge-gap, 8px)!important}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{min-width:0!important;border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisResourceIdentityComponent, selector: "praxis-resource-identity", inputs: ["identity", "emptyTitle", "density", "showMetadataLabels", "showKey", "showKeyLabel", "ariaLabel"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "submitResourceVersionTargetResourceKey", "submitResourceVersionTargetIdField", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange"] }], encapsulation: i0.ViewEncapsulation.None });
6262
6402
  }
6263
6403
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
6264
6404
  type: Component,
@@ -6347,7 +6487,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6347
6487
  <praxis-resource-identity
6348
6488
  [identity]="resourceIdentity"
6349
6489
  density="compact"
6350
- [showKeyLabel]="true"
6490
+ [showKey]="showResourceIdentityKey"
6491
+ [showKeyLabel]="showResourceIdentityKey"
6351
6492
  [ariaLabel]="resourceIdentityLabel"
6352
6493
  ></praxis-resource-identity>
6353
6494
  </div>
@@ -6374,6 +6515,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6374
6515
  [actions]="formActions"
6375
6516
  (formSubmit)="onSave($event)"
6376
6517
  (formCancel)="onCancel()"
6518
+ (reactiveDeterminationExecuted)="onReactiveDeterminationExecuted($event)"
6519
+ (reactiveDeterminationPendingChange)="onReactiveDeterminationPendingChange($event)"
6377
6520
  ></praxis-dynamic-form>
6378
6521
  </mat-dialog-content>
6379
6522
  `, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);min-height:var(--dlg-header-h);padding:10px var(--dlg-pad);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-heading{display:grid;min-width:0;gap:2px}praxis-dynamic-form-dialog-host .dialog-title-icon{display:inline-grid;flex:0 0 auto;width:36px;height:36px;place-items:center;border-radius:10px;color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}praxis-dynamic-form-dialog-host .dialog-title-icon mat-icon{width:22px;height:22px;font-size:22px}praxis-dynamic-form-dialog-host .dialog-subtitle{display:-webkit-box;overflow:hidden;color:var(--md-sys-color-on-surface-variant);font-size:.82rem;font-weight:400;line-height:1.35;-webkit-box-orient:vertical;-webkit-line-clamp:2}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host .crud-operation-context{position:sticky;top:0;z-index:1;display:grid;gap:.75rem;margin-block-end:var(--dlg-pad);padding-block:.5rem .75rem;background:var(--pfx-form-surface, var(--md-sys-color-surface));border-bottom:1px solid var(--md-sys-color-outline-variant)}praxis-dynamic-form-dialog-host .crud-resource-identity{display:grid;gap:.25rem;min-width:0}praxis-dynamic-form-dialog-host .crud-resource-identity__label{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-label-medium, 500 .75rem/1rem inherit)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 72px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{display:flex;flex-direction:column;max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form{display:block;flex:1 1 auto;min-height:0}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form{min-height:100%}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:auto;padding-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}praxis-dynamic-form-dialog-host.praxis-surface-frame .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button:hover{color:var(--md-sys-color-primary)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;min-width:0;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane.pfx-drawer-maximized{margin:var(--pfx-drawer-edge-gap, 8px)!important}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{min-width:0!important;border-radius:0!important}\n"] }]
@@ -6403,6 +6546,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6403
6546
  }] }], propDecorators: { formComp: [{
6404
6547
  type: ViewChild,
6405
6548
  args: [PraxisDynamicForm]
6549
+ }], reactiveDeterminationExecuted: [{
6550
+ type: Output
6551
+ }], reactiveDeterminationPendingChange: [{
6552
+ type: Output
6553
+ }], reactiveDeterminationStabilityChange: [{
6554
+ type: Output
6406
6555
  }] } });
6407
6556
  function getFormSubmitStage(result) {
6408
6557
  if (!result || typeof result !== 'object' || !('stage' in result)) {
@@ -6681,6 +6830,12 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
6681
6830
  default: false,
6682
6831
  description: 'Habilita modo de customização do layout.',
6683
6832
  },
6833
+ {
6834
+ name: 'showResourceIdentityKey',
6835
+ type: 'boolean',
6836
+ default: true,
6837
+ description: 'Controla se modal e drawer exibem a chave da identidade canônica do registro. Use false quando a chave pública for opaca ou apenas técnica; o título legível permanece visível.',
6838
+ },
6684
6839
  {
6685
6840
  name: 'authoringCapability',
6686
6841
  type: 'string | null',
@@ -6709,6 +6864,21 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
6709
6864
  type: '{ id: string | number }',
6710
6865
  description: 'Emitido ao deletar.',
6711
6866
  },
6867
+ {
6868
+ name: 'reactiveDeterminationExecuted',
6869
+ type: '{ action: string; event: ReactiveDeterminationExecutionEvent }',
6870
+ description: 'Evidencia metadata-only encaminhada pelo formulario aberto, com contexto da acao CRUD.',
6871
+ },
6872
+ {
6873
+ name: 'reactiveDeterminationPendingChange',
6874
+ type: '{ action: string; pending: boolean }',
6875
+ description: 'Estado agregado de estabilizacao do formulario aberto, sem valores sensiveis.',
6876
+ },
6877
+ {
6878
+ name: 'reactiveDeterminationStabilityChange',
6879
+ type: 'CrudReactiveDeterminationStabilityChange',
6880
+ description: 'Conclusao agregada do formulario aberto, distinguindo settled-satisfied de settled-unsatisfied e preservando o contexto da acao.',
6881
+ },
6712
6882
  {
6713
6883
  name: 'rowClick',
6714
6884
  type: '{ row: unknown; index: number }',
@@ -6724,6 +6894,11 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
6724
6894
  type: 'unknown',
6725
6895
  description: 'Encaminha a mudança de seleção da tabela interna quando o CRUD é usado como widget composto.',
6726
6896
  },
6897
+ {
6898
+ name: 'resourceEvent',
6899
+ type: 'PraxisResourceEvent<unknown>',
6900
+ description: 'Encaminha o envelope canônico da tabela interna com kind, resourcePath, resourceId, payload e contexto para composição governada.',
6901
+ },
6727
6902
  {
6728
6903
  name: 'error',
6729
6904
  type: 'unknown',
@@ -7218,10 +7393,12 @@ const PRAXIS_CRUD_AUTHORING_MANIFEST = {
7218
7393
  { name: 'tableConfigPersistenceStrategy', type: "'local-first' | 'input-first' | 'volatile'", description: 'Persistence precedence forwarded to the internal Praxis Table. Governed previews should use input-first or volatile explicitly.' },
7219
7394
  { name: 'context', type: 'Record<string, unknown>', description: 'Opaque host context used for authoring seeds and launcher inputs.' },
7220
7395
  { name: 'enableCustomization', type: 'boolean', description: 'Explicit host opt-in for CRUD authoring surfaces.' },
7396
+ { name: 'showResourceIdentityKey', type: 'boolean', description: 'Presentation-only control for the canonical key in existing-record modal and drawer headers. Defaults to true; false preserves the readable title while hiding an opaque or technical key.' },
7221
7397
  { name: 'authoringCapability', type: 'string | null', description: 'Public runtime capability required before CRUD and delegated table authoring can open.' },
7222
7398
  { name: 'afterOpen', type: '{ mode: FormOpenMode; action: string }', description: 'Emitted after a CRUD action opens.' },
7223
7399
  { name: 'afterSave', type: '{ id: string | number; data: unknown }', description: 'Emitted after save; CRUD refetches the list.' },
7224
7400
  { name: 'afterDelete', type: '{ id: string | number }', description: 'Emitted after delete; CRUD refetches the list.' },
7401
+ { name: 'resourceEvent', type: 'PraxisResourceEvent<unknown>', description: 'Canonical resource interaction envelope forwarded from the internal table for governed host composition.' },
7225
7402
  ],
7226
7403
  editableTargets: [
7227
7404
  { kind: 'resourceBinding', resolver: 'crud-resource-by-path-or-key', description: 'Resource path/key, optional schema path template, id field, endpoint key and query context owned by CRUD orchestration.' },
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@praxisui/crud",
3
- "version": "9.0.5-rc.8",
3
+ "version": "9.0.5",
4
4
  "description": "CRUD building blocks for Praxis UI: integrates dynamic forms and tables with unified configuration and services.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
- "@praxisui/dynamic-form": "^9.0.5-rc.8",
9
- "@praxisui/table": "^9.0.5-rc.8",
10
- "@praxisui/core": "^9.0.5-rc.8",
11
- "@praxisui/dynamic-fields": "^9.0.5-rc.8",
12
- "@praxisui/settings-panel": "^9.0.5-rc.8",
8
+ "@praxisui/dynamic-form": "^9.0.5",
9
+ "@praxisui/table": "^9.0.5",
10
+ "@praxisui/core": "^9.0.5",
11
+ "@praxisui/dynamic-fields": "^9.0.5",
12
+ "@praxisui/settings-panel": "^9.0.5",
13
13
  "@angular/cdk": "^21.0.0",
14
14
  "@angular/forms": "^21.0.0",
15
15
  "@angular/material": "^21.0.0",
16
16
  "@angular/router": "^21.0.0",
17
- "@praxisui/ai": "^9.0.5-rc.8",
17
+ "@praxisui/ai": "^9.0.5",
18
18
  "rxjs": "~7.8.0"
19
19
  },
20
20
  "dependencies": {
@@ -51,12 +51,37 @@ interface CrudDrawerResult {
51
51
  type: CrudDrawerResultType;
52
52
  data?: Record<string, unknown>;
53
53
  }
54
+ /** Minimal structural evidence contract kept local to the light entrypoint. */
55
+ interface CrudReactiveDeterminationExecutionEvent {
56
+ determinationId: string;
57
+ operationId: string;
58
+ status: 'pending' | 'success' | 'skipped' | 'error';
59
+ sourcePaths: string[];
60
+ targetPaths: string[];
61
+ appliedTargetPaths?: string[];
62
+ correlationId: string;
63
+ durationMs: number;
64
+ reason?: string;
65
+ provenance: {
66
+ kind: 'platform' | 'host';
67
+ source: string;
68
+ version?: string;
69
+ };
70
+ }
71
+ /** Minimal structural stability contract kept local to the light entrypoint. */
72
+ interface CrudReactiveDeterminationStabilityChange {
73
+ status: 'pending' | 'settled-satisfied' | 'settled-unsatisfied';
74
+ pending: boolean;
75
+ unsatisfied: boolean;
76
+ }
54
77
  interface CrudDrawerOpenConfig {
55
78
  action: CrudAction;
56
79
  metadata: CrudMetadata;
57
80
  inputs: Record<string, unknown>;
58
81
  /** Read-only record context for existing-record drawers. It is never part of form inputs or submit payloads. */
59
82
  resourceIdentity?: MaterializedResourceIdentity | null;
83
+ /** Presentation-only preference. Defaults to true; false hides the record identity key while preserving its title. */
84
+ showResourceIdentityKey?: boolean;
60
85
  /** Read-only task scope for related operations. It is never part of form inputs or submit payloads. */
61
86
  contextIdentity?: MaterializedResourceIdentity | null;
62
87
  /**
@@ -68,6 +93,12 @@ interface CrudDrawerOpenConfig {
68
93
  * Hosts podem propagar `save/delete/close` para sincronizar telemetria/eventos.
69
94
  */
70
95
  onResult?: (result: CrudDrawerResult) => void;
96
+ /** Bind to the child form's metadata-only determination evidence. */
97
+ onReactiveDetermination?: (event: CrudReactiveDeterminationExecutionEvent) => void;
98
+ /** Bind to pending state and refuse every adapter-owned close/submit while true. */
99
+ onReactiveDeterminationPendingChange?: (pending: boolean) => void;
100
+ /** Report aggregate success/unsatisfied stability without form values. */
101
+ onReactiveDeterminationStabilityChange?: (stability: CrudReactiveDeterminationStabilityChange) => void;
71
102
  }
72
103
  interface CrudDrawerAdapter {
73
104
  open(config: CrudDrawerOpenConfig): Promise<void> | void;
@@ -84,4 +115,4 @@ interface DialogConfig<D = any> extends MatDialogConfig<D> {
84
115
  declare const CRUD_DRAWER_ADAPTER: InjectionToken<CrudDrawerAdapter>;
85
116
 
86
117
  export { CRUD_DRAWER_ADAPTER };
87
- export type { CrudAction, CrudDefaults, CrudDrawerAdapter, CrudDrawerOpenConfig, CrudDrawerResult, CrudDrawerResultType, CrudHeaderConfig, CrudMetadata, CrudParamMapping, CrudResource, DialogConfig, FormOpenMode };
118
+ export type { CrudAction, CrudDefaults, CrudDrawerAdapter, CrudDrawerOpenConfig, CrudDrawerResult, CrudDrawerResultType, CrudHeaderConfig, CrudMetadata, CrudParamMapping, CrudReactiveDeterminationExecutionEvent, CrudReactiveDeterminationStabilityChange, CrudResource, DialogConfig, FormOpenMode };
@@ -1,8 +1,8 @@
1
- import * as _angular_core from '@angular/core';
2
- import { NgZone, OnChanges, EventEmitter, SimpleChanges, OnInit, AfterViewInit, Provider, OnDestroy } from '@angular/core';
3
1
  import * as _praxisui_core from '@praxisui/core';
4
- import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, DynamicFormLayoutPolicy, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, MaterializedResourceIdentity, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, SurfaceDrawerRef, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
2
+ import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, DynamicFormLayoutPolicy, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ReactiveDeterminationExecutionEvent, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, MaterializedResourceIdentity, PraxisResourceEvent, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, SurfaceDrawerRef, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
5
3
  export { BackConfig } from '@praxisui/core';
4
+ import * as _angular_core from '@angular/core';
5
+ import { NgZone, OnChanges, EventEmitter, SimpleChanges, OnInit, AfterViewInit, Provider, OnDestroy } from '@angular/core';
6
6
  import { TableConfigPersistenceStrategy } from '@praxisui/table';
7
7
  import { MatDialogConfig, MatDialogRef, MatDialog } from '@angular/material/dialog';
8
8
  export { MAT_DIALOG_DATA as DIALOG_DATA } from '@angular/material/dialog';
@@ -48,6 +48,17 @@ declare class DialogService {
48
48
  }
49
49
 
50
50
  type FormOpenMode = 'route' | 'modal' | 'drawer';
51
+ type CrudReactiveDeterminationStabilityStatus = 'pending' | 'settled-satisfied' | 'settled-unsatisfied';
52
+ /** Value-free stability evidence for the Dynamic Form opened by one CRUD action. */
53
+ interface CrudFormReactiveDeterminationStabilityChange {
54
+ status: CrudReactiveDeterminationStabilityStatus;
55
+ pending: boolean;
56
+ unsatisfied: boolean;
57
+ }
58
+ /** Public CRUD output enriched with the action that owns the open form. */
59
+ interface CrudReactiveDeterminationStabilityChange extends CrudFormReactiveDeterminationStabilityChange {
60
+ action: string;
61
+ }
51
62
  interface CrudParamMapping {
52
63
  from: string;
53
64
  to: 'routeParam' | 'query' | 'input';
@@ -177,6 +188,8 @@ declare class PraxisCrudComponent implements OnChanges {
177
188
  tableConfigPersistenceStrategy: TableConfigPersistenceStrategy;
178
189
  context?: Record<string, unknown>;
179
190
  enableCustomization: boolean;
191
+ /** Controls whether existing-record hosts expose the canonical identity key. */
192
+ showResourceIdentityKey: boolean;
180
193
  /** Capability publica exigida para authoring governado do CRUD e da tabela interna. */
181
194
  authoringCapability: string | null;
182
195
  configureRequested: EventEmitter<void>;
@@ -192,11 +205,23 @@ declare class PraxisCrudComponent implements OnChanges {
192
205
  afterDelete: EventEmitter<{
193
206
  id: string | number;
194
207
  }>;
208
+ /** Metadata-only Reactive Determination evidence from an open form host. */
209
+ reactiveDeterminationExecuted: EventEmitter<{
210
+ action: string;
211
+ event: ReactiveDeterminationExecutionEvent;
212
+ }>;
213
+ reactiveDeterminationPendingChange: EventEmitter<{
214
+ action: string;
215
+ pending: boolean;
216
+ }>;
217
+ reactiveDeterminationStabilityChange: EventEmitter<CrudReactiveDeterminationStabilityChange>;
195
218
  error: EventEmitter<unknown>;
196
219
  rowClick: EventEmitter<unknown>;
197
220
  /** Emits the canonical table row-action envelope before the CRUD handles its surface/action. */
198
221
  rowAction: EventEmitter<CrudActionRuntimeEvent>;
199
222
  selectionChange: EventEmitter<unknown>;
223
+ /** Forwards the canonical resource interaction envelope emitted by the internal table. */
224
+ readonly resourceEvent: _angular_core.OutputEmitterRef<PraxisResourceEvent<unknown>>;
200
225
  tableRuntimeConfigChange: EventEmitter<_praxisui_core.TableConfigModern>;
201
226
  crudAuthoringDocumentApplied: EventEmitter<CrudAuthoringWidgetPersistenceEvent>;
202
227
  crudAuthoringDocumentSaved: EventEmitter<CrudAuthoringWidgetPersistenceEvent>;
@@ -218,11 +243,13 @@ declare class PraxisCrudComponent implements OnChanges {
218
243
  private readonly snack;
219
244
  private readonly dialog;
220
245
  private readonly i18n;
246
+ private readonly logger;
221
247
  private readonly injector;
222
248
  private resourceDiscoveryInstance?;
223
249
  private actionOpenAdapterInstance?;
224
250
  private surfaceOpenAdapterInstance?;
225
251
  private materializedRefreshSequence;
252
+ private surfaceOpenAttemptSequence;
226
253
  private readonly global;
227
254
  private readonly surfaceService;
228
255
  private readonly surfaceOutlets;
@@ -249,6 +276,7 @@ declare class PraxisCrudComponent implements OnChanges {
249
276
  onResetPreferences(): void;
250
277
  onTableRowClick(event: unknown): void;
251
278
  onTableSelectionChange(event: unknown): void;
279
+ onTableResourceEvent(event: PraxisResourceEvent<unknown>): void;
252
280
  onBulkAction(event: CrudActionRuntimeEvent): Promise<void>;
253
281
  onToolbarAction(event: CrudActionRuntimeEvent): Promise<void>;
254
282
  ngOnChanges(changes: SimpleChanges): void;
@@ -302,6 +330,7 @@ declare class PraxisCrudComponent implements OnChanges {
302
330
  private resolveDiscoveredSurfaceCatalog;
303
331
  private tryOpenDiscoveredWorkflowAction;
304
332
  private notifySurfaceNavigationFailure;
333
+ private reportDiscoveredSurfaceOpenFailure;
305
334
  private resolveDiscoveredActionCatalog;
306
335
  private selectDiscoveredWorkflowAction;
307
336
  private resolveProvidedWorkflowAction;
@@ -351,7 +380,7 @@ declare class PraxisCrudComponent implements OnChanges {
351
380
  private txWithParams;
352
381
  private interpolateTranslationParams;
353
382
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<PraxisCrudComponent, never>;
354
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisCrudComponent, "praxis-crud", never, { "metadata": { "alias": "metadata"; "required": true; }; "crudId": { "alias": "crudId"; "required": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "tableConfigPersistenceStrategy": { "alias": "tableConfigPersistenceStrategy"; "required": false; }; "context": { "alias": "context"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "authoringCapability": { "alias": "authoringCapability"; "required": false; }; }, { "configureRequested": "configureRequested"; "afterOpen": "afterOpen"; "afterClose": "afterClose"; "afterSave": "afterSave"; "afterDelete": "afterDelete"; "error": "error"; "rowClick": "rowClick"; "rowAction": "rowAction"; "selectionChange": "selectionChange"; "tableRuntimeConfigChange": "tableRuntimeConfigChange"; "crudAuthoringDocumentApplied": "crudAuthoringDocumentApplied"; "crudAuthoringDocumentSaved": "crudAuthoringDocumentSaved"; }, never, never, true, never>;
383
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisCrudComponent, "praxis-crud", never, { "metadata": { "alias": "metadata"; "required": true; }; "crudId": { "alias": "crudId"; "required": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "tableConfigPersistenceStrategy": { "alias": "tableConfigPersistenceStrategy"; "required": false; }; "context": { "alias": "context"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "showResourceIdentityKey": { "alias": "showResourceIdentityKey"; "required": false; }; "authoringCapability": { "alias": "authoringCapability"; "required": false; }; }, { "configureRequested": "configureRequested"; "afterOpen": "afterOpen"; "afterClose": "afterClose"; "afterSave": "afterSave"; "afterDelete": "afterDelete"; "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "reactiveDeterminationStabilityChange": "reactiveDeterminationStabilityChange"; "error": "error"; "rowClick": "rowClick"; "rowAction": "rowAction"; "selectionChange": "selectionChange"; "resourceEvent": "resourceEvent"; "tableRuntimeConfigChange": "tableRuntimeConfigChange"; "crudAuthoringDocumentApplied": "crudAuthoringDocumentApplied"; "crudAuthoringDocumentSaved": "crudAuthoringDocumentSaved"; }, never, never, true, never>;
355
384
  }
356
385
 
357
386
  type CrudDrawerResultType = 'save' | 'delete' | 'close';
@@ -359,12 +388,48 @@ interface CrudDrawerResult {
359
388
  type: CrudDrawerResultType;
360
389
  data?: Record<string, unknown>;
361
390
  }
391
+ interface CrudDrawerOpenConfig {
392
+ action: CrudAction;
393
+ metadata: CrudMetadata;
394
+ inputs: Record<string, unknown>;
395
+ /** Read-only record context for existing-record drawers. It is never part of form inputs or submit payloads. */
396
+ resourceIdentity?: MaterializedResourceIdentity | null;
397
+ /** Presentation-only preference. Defaults to true; false hides the record identity key while preserving its title. */
398
+ showResourceIdentityKey?: boolean;
399
+ /** Read-only task scope for related operations. It is never part of form inputs or submit payloads. */
400
+ contextIdentity?: MaterializedResourceIdentity | null;
401
+ /**
402
+ * Ephemeral focus policy resolved for this opening. A host adapter must
403
+ * forward it to its native overlay and must never persist, clone, or put it
404
+ * into form inputs or submit payloads. When a responsive render replaces a
405
+ * detached HTMLElement, an adapter should recover the matching
406
+ * `data-praxis-focus-key` element before focusing it.
407
+ */
408
+ restoreFocus?: boolean | string | HTMLElement;
409
+ /**
410
+ * Notifica fechamento do drawer (cancelamento/fechamento externo/resultado finalizado).
411
+ */
412
+ onClose?: () => void;
413
+ /**
414
+ * Notifica resultado semântico do fluxo em drawer.
415
+ * Hosts podem propagar `save/delete/close` para sincronizar telemetria/eventos.
416
+ */
417
+ onResult?: (result: CrudDrawerResult) => void;
418
+ /** Bind to the child Dynamic Form metadata-only execution event. */
419
+ onReactiveDetermination?: (event: ReactiveDeterminationExecutionEvent) => void;
420
+ /** Bind to the child pending event and guard every adapter-owned close/submit. */
421
+ onReactiveDeterminationPendingChange?: (pending: boolean) => void;
422
+ /** Report aggregate settled-success/settled-unsatisfied state without form values. */
423
+ onReactiveDeterminationStabilityChange?: (stability: CrudFormReactiveDeterminationStabilityChange) => void;
424
+ }
362
425
 
363
426
  interface CrudLaunchRuntime {
364
427
  capabilities?: ResourceCapabilitySnapshot | null;
365
428
  links?: RestApiLinks | null;
366
429
  resourceIdentity?: MaterializedResourceIdentity | null;
367
430
  contextIdentity?: MaterializedResourceIdentity | null;
431
+ /** Presentation-only preference for the existing-record identity key. */
432
+ showResourceIdentityKey?: boolean;
368
433
  /** Active runtime drawer session. It is never persisted in CRUD metadata. */
369
434
  surfaceRuntime?: SurfaceDrawerRef | null;
370
435
  /** Stable runtime trigger for restoring focus after a form overlay closes. */
@@ -383,6 +448,9 @@ declare class CrudLauncherService {
383
448
  launch(action: CrudAction, row: Record<string, unknown> | undefined, metadata: CrudMetadata, componentKeyId?: string | null, drawerCallbacks?: {
384
449
  onClose?: () => void;
385
450
  onResult?: (result: CrudDrawerResult) => void;
451
+ onReactiveDetermination?: CrudDrawerOpenConfig['onReactiveDetermination'];
452
+ onReactiveDeterminationPendingChange?: CrudDrawerOpenConfig['onReactiveDeterminationPendingChange'];
453
+ onReactiveDeterminationStabilityChange?: CrudDrawerOpenConfig['onReactiveDeterminationStabilityChange'];
386
454
  }, runtime?: CrudLaunchRuntime): Promise<{
387
455
  mode: FormOpenMode;
388
456
  ref?: DialogRef<any>;
@@ -428,6 +496,9 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
428
496
  private configStorage;
429
497
  private readonly surfaceRef;
430
498
  formComp?: PraxisDynamicForm;
499
+ reactiveDeterminationExecuted: EventEmitter<ReactiveDeterminationExecutionEvent>;
500
+ reactiveDeterminationPendingChange: EventEmitter<boolean>;
501
+ reactiveDeterminationStabilityChange: EventEmitter<CrudFormReactiveDeterminationStabilityChange>;
431
502
  modal: any;
432
503
  presentation: 'modal' | 'drawer' | 'surface-frame';
433
504
  maximized: boolean;
@@ -439,11 +510,13 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
439
510
  private terminalClose;
440
511
  private destroyRef;
441
512
  private readonly i18n;
513
+ private reactiveDeterminationStabilitySignature;
442
514
  resourcePath?: string;
443
515
  resourceId?: string | number;
444
516
  initialValue?: Record<string, unknown> | null;
445
517
  resourceIdentity: MaterializedResourceIdentity | null;
446
518
  contextIdentity: MaterializedResourceIdentity | null;
519
+ showResourceIdentityKey: boolean;
447
520
  schemaUrl?: string | null;
448
521
  submitUrl?: string | null;
449
522
  submitMethod?: string | null;
@@ -479,6 +552,10 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
479
552
  ngAfterViewInit(): void;
480
553
  onSave(result: unknown): void;
481
554
  onCancel(): void;
555
+ onReactiveDeterminationExecuted(event: ReactiveDeterminationExecutionEvent): void;
556
+ onReactiveDeterminationPendingChange(pending: boolean): void;
557
+ private emitReactiveDeterminationStability;
558
+ private continueCancel;
482
559
  private canLeaveSurfaceFrame;
483
560
  toggleMaximize(initial?: boolean): void;
484
561
  private resolveOverlayPane;
@@ -488,7 +565,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
488
565
  private updateHostPosition;
489
566
  private resolveMaximizedDrawerPosition;
490
567
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicFormDialogHostComponent, [{ optional: true; }, { optional: true; }, null, null, null, { optional: true; }, { optional: true; }]>;
491
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicFormDialogHostComponent, "praxis-dynamic-form-dialog-host", never, {}, {}, never, never, true, never>;
568
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicFormDialogHostComponent, "praxis-dynamic-form-dialog-host", never, {}, { "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "reactiveDeterminationStabilityChange": "reactiveDeterminationStabilityChange"; }, never, never, true, never>;
492
569
  }
493
570
 
494
571
  /** Metadata for PraxisCrudComponent */
@@ -770,4 +847,4 @@ type OpenCrudMetadataEditorOptions = {
770
847
  declare function openCrudMetadataEditor(settings: SettingsPanelService, opts?: OpenCrudMetadataEditorOptions): _praxisui_settings_panel.SettingsPanelRef;
771
848
 
772
849
  export { CRUD_AI_CAPABILITIES, CrudLauncherService, CrudMetadataEditorComponent, CrudPageHeaderComponent, DialogService, DynamicFormDialogHostComponent, PRAXIS_CRUD_AUTHORING_MANIFEST, PRAXIS_CRUD_COMPONENT_METADATA, PraxisCrudComponent, PraxisCrudWidgetConfigEditor, assertCrudMetadata, createCrudAuthoringDocument, findCrudAction, normalizeCrudAuthoringDocument, openCrudMetadataEditor, parseLegacyOrCrudDocument, providePraxisCrudMetadata, serializeCrudAuthoringDocument, validateCrudAuthoringDocument };
773
- export type { Capability, CapabilityCatalog, CapabilityCategory, CrudAction, CrudActionFormContract, CrudActionResolutionMode, CrudAuthoringDocument, CrudAuthoringWidgetPersistenceEvent, CrudDefaults, CrudEditorDiagnostic, CrudHeaderConfig, CrudHeaderVariant, CrudMetadata, CrudMetadataAssertionOptions, CrudParamMapping, CrudResource, CrudValidationContext, DialogConfig, DialogRef, FormOpenMode, OpenCrudMetadataEditorOptions, PraxisCrudWidgetEditorInputs, PraxisCrudWidgetEditorValue, ValueKind };
850
+ export type { Capability, CapabilityCatalog, CapabilityCategory, CrudAction, CrudActionFormContract, CrudActionResolutionMode, CrudAuthoringDocument, CrudAuthoringWidgetPersistenceEvent, CrudDefaults, CrudEditorDiagnostic, CrudFormReactiveDeterminationStabilityChange, CrudHeaderConfig, CrudHeaderVariant, CrudMetadata, CrudMetadataAssertionOptions, CrudParamMapping, CrudReactiveDeterminationStabilityChange, CrudReactiveDeterminationStabilityStatus, CrudResource, CrudValidationContext, DialogConfig, DialogRef, FormOpenMode, OpenCrudMetadataEditorOptions, PraxisCrudWidgetEditorInputs, PraxisCrudWidgetEditorValue, ValueKind };