@praxisui/crud 9.0.0-beta.3 → 9.0.0-beta.31
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 +1 -1
- package/ai/component-registry.json +3582 -0
- package/fesm2022/praxisui-crud.mjs +64 -33
- package/package.json +12 -8
- package/types/praxisui-crud.d.ts +5 -1
|
@@ -95,22 +95,6 @@ class CrudLauncherService {
|
|
|
95
95
|
await this.router.navigateByUrl(url);
|
|
96
96
|
return { mode };
|
|
97
97
|
}
|
|
98
|
-
if (mode === 'drawer' && this.drawerAdapter) {
|
|
99
|
-
const actionForLaunch = this.resolveActionForLaunch(merged.action, merged.metadata);
|
|
100
|
-
const inputs = this.mapInputs(actionForLaunch, row, merged.metadata, runtime);
|
|
101
|
-
const idField = merged.metadata.resource?.idField ?? 'id';
|
|
102
|
-
if (row && inputs[idField] === undefined && row[idField] !== undefined) {
|
|
103
|
-
inputs[idField] = row[idField];
|
|
104
|
-
}
|
|
105
|
-
await Promise.resolve(this.drawerAdapter.open({
|
|
106
|
-
action: actionForLaunch,
|
|
107
|
-
metadata: merged.metadata,
|
|
108
|
-
inputs,
|
|
109
|
-
onClose: drawerCallbacks?.onClose,
|
|
110
|
-
onResult: drawerCallbacks?.onResult,
|
|
111
|
-
}));
|
|
112
|
-
return { mode };
|
|
113
|
-
}
|
|
114
98
|
const actionForLaunch = this.resolveActionForLaunch(merged.action, merged.metadata);
|
|
115
99
|
if (!actionForLaunch.formId) {
|
|
116
100
|
throw new Error(`formId not provided for action ${actionForLaunch.action}`);
|
|
@@ -123,6 +107,16 @@ class CrudLauncherService {
|
|
|
123
107
|
row[idField] !== undefined) {
|
|
124
108
|
inputs[idField] = row[idField];
|
|
125
109
|
}
|
|
110
|
+
if (mode === 'drawer' && this.drawerAdapter) {
|
|
111
|
+
await Promise.resolve(this.drawerAdapter.open({
|
|
112
|
+
action: actionForLaunch,
|
|
113
|
+
metadata: merged.metadata,
|
|
114
|
+
inputs,
|
|
115
|
+
onClose: drawerCallbacks?.onClose,
|
|
116
|
+
onResult: drawerCallbacks?.onResult,
|
|
117
|
+
}));
|
|
118
|
+
return { mode };
|
|
119
|
+
}
|
|
126
120
|
const modalCfg = { ...(merged.metadata.defaults?.modal || {}) };
|
|
127
121
|
console.debug('[CRUD:Launcher] opening dialog with:', {
|
|
128
122
|
action: merged.action.action,
|
|
@@ -131,10 +125,8 @@ class CrudLauncherService {
|
|
|
131
125
|
modalCfg,
|
|
132
126
|
resourcePath: merged.metadata.resource?.path ?? merged.metadata.table?.resourcePath,
|
|
133
127
|
});
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
panelClasses.push(modalCfg.panelClass);
|
|
137
|
-
}
|
|
128
|
+
const drawerMode = mode === 'drawer';
|
|
129
|
+
const panelClasses = mergeClassList(['pfx-dialog-pane', drawerMode ? 'pfx-drawer-pane' : 'pfx-dialog-frosted'], modalCfg.panelClass);
|
|
138
130
|
// Backdrop style presets
|
|
139
131
|
const backdropClasses = [];
|
|
140
132
|
const style = modalCfg.backdropStyle;
|
|
@@ -147,17 +139,19 @@ class CrudLauncherService {
|
|
|
147
139
|
else if (style === 'transparent') {
|
|
148
140
|
backdropClasses.push('pfx-transparent-backdrop');
|
|
149
141
|
}
|
|
150
|
-
|
|
151
|
-
backdropClasses.push(modalCfg.backdropClass);
|
|
152
|
-
}
|
|
142
|
+
const mergedBackdropClasses = mergeClassList(backdropClasses, modalCfg.backdropClass);
|
|
153
143
|
const ref = await this.dialog.openAsync(() => Promise.resolve().then(function () { return dynamicFormDialogHost_component; }).then((m) => m.DynamicFormDialogHostComponent), {
|
|
154
144
|
...modalCfg,
|
|
155
145
|
panelClass: panelClasses,
|
|
156
|
-
backdropClass:
|
|
146
|
+
backdropClass: mergedBackdropClasses,
|
|
157
147
|
autoFocus: modalCfg.autoFocus ?? true,
|
|
158
148
|
restoreFocus: modalCfg.restoreFocus ?? true,
|
|
159
|
-
minWidth: '360px',
|
|
160
|
-
|
|
149
|
+
minWidth: drawerMode ? (modalCfg.minWidth ?? '0') : '360px',
|
|
150
|
+
width: drawerMode ? (modalCfg.width ?? 'min(560px, 100vw)') : modalCfg.width,
|
|
151
|
+
height: drawerMode ? (modalCfg.height ?? '100dvh') : modalCfg.height,
|
|
152
|
+
maxWidth: drawerMode ? (modalCfg.maxWidth ?? '100vw') : '95vw',
|
|
153
|
+
maxHeight: drawerMode ? (modalCfg.maxHeight ?? '100dvh') : modalCfg.maxHeight,
|
|
154
|
+
position: drawerMode ? (modalCfg.position ?? { right: '0', top: '0' }) : modalCfg.position,
|
|
161
155
|
ariaLabelledBy: 'crudDialogTitle',
|
|
162
156
|
data: { action: actionForLaunch, row, metadata: merged.metadata, inputs },
|
|
163
157
|
});
|
|
@@ -248,6 +242,9 @@ class CrudLauncherService {
|
|
|
248
242
|
if (resolved.apiUrlEntry != null) {
|
|
249
243
|
inputs['apiUrlEntry'] = resolved.apiUrlEntry;
|
|
250
244
|
}
|
|
245
|
+
if (resolved.layoutPolicy != null) {
|
|
246
|
+
inputs['layoutPolicy'] = resolved.layoutPolicy;
|
|
247
|
+
}
|
|
251
248
|
if (action.form?.initialValue != null) {
|
|
252
249
|
inputs['initialValue'] = action.form.initialValue;
|
|
253
250
|
}
|
|
@@ -274,12 +271,14 @@ class CrudLauncherService {
|
|
|
274
271
|
submitMethod: action.form?.submitMethod ?? null,
|
|
275
272
|
apiEndpointKey: action.form?.apiEndpointKey ?? null,
|
|
276
273
|
apiUrlEntry: action.form?.apiUrlEntry ?? null,
|
|
274
|
+
layoutPolicy: action.form?.layoutPolicy ?? null,
|
|
277
275
|
};
|
|
278
276
|
}
|
|
279
277
|
if (!this.isCanonicalCrudAction(action.action)) {
|
|
280
278
|
return {
|
|
281
279
|
apiEndpointKey: action.form?.apiEndpointKey ?? null,
|
|
282
280
|
apiUrlEntry: action.form?.apiUrlEntry ?? null,
|
|
281
|
+
layoutPolicy: action.form?.layoutPolicy ?? null,
|
|
283
282
|
};
|
|
284
283
|
}
|
|
285
284
|
const resourcePath = String(metadata.resource?.path ?? metadata.table?.resourcePath ?? '').trim();
|
|
@@ -309,6 +308,7 @@ class CrudLauncherService {
|
|
|
309
308
|
submitMethod: resolved?.submitMethod ?? null,
|
|
310
309
|
apiEndpointKey: action.form?.apiEndpointKey ?? metadata.resource?.endpointKey ?? null,
|
|
311
310
|
apiUrlEntry: action.form?.apiUrlEntry ?? null,
|
|
311
|
+
layoutPolicy: action.form?.layoutPolicy ?? null,
|
|
312
312
|
};
|
|
313
313
|
}
|
|
314
314
|
resolveRuntimeContract(action, row, metadata, runtime) {
|
|
@@ -392,6 +392,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
392
392
|
type: Injectable,
|
|
393
393
|
args: [{ providedIn: 'root' }]
|
|
394
394
|
}] });
|
|
395
|
+
function mergeClassList(base, extra) {
|
|
396
|
+
if (!extra) {
|
|
397
|
+
return base;
|
|
398
|
+
}
|
|
399
|
+
if (typeof extra === 'string') {
|
|
400
|
+
return [...base, extra];
|
|
401
|
+
}
|
|
402
|
+
if (Array.isArray(extra)) {
|
|
403
|
+
return [...base, ...extra];
|
|
404
|
+
}
|
|
405
|
+
return [
|
|
406
|
+
...base,
|
|
407
|
+
...Object.keys(extra).filter((className) => !!extra[className]),
|
|
408
|
+
];
|
|
409
|
+
}
|
|
395
410
|
|
|
396
411
|
const DOCUMENT_KIND = 'praxis.crud.editor';
|
|
397
412
|
const DOCUMENT_VERSION = 1;
|
|
@@ -4657,7 +4672,7 @@ class PraxisCrudComponent {
|
|
|
4657
4672
|
/>
|
|
4658
4673
|
}
|
|
4659
4674
|
}
|
|
4660
|
-
`, isInline: true, styles: [":host{display:block;width:100%;min-width:0;max-width:100%}\n"], dependencies: [{ kind: "component", type: PraxisTable, selector: "praxis-table", inputs: ["config", "resourcePath", "data", "tableId", "componentInstanceId", "configPersistenceStrategy", "title", "subtitle", "icon", "autoDelete", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "crudContext", "filterCriteria", "queryContext", "aiContext", "aiAssistantVoiceInputMode", "aiAssistantVoiceLanguage", "horizontalScroll", "enableCustomization", "dense"], outputs: ["rowClick", "widgetEvent", "rowDoubleClick", "rowExpansionChange", "rowAction", "toolbarAction", "bulkAction", "exportAction", "columnReorder", "columnReorderAttempt", "beforeDelete", "afterDelete", "deleteError", "beforeBulkDelete", "afterBulkDelete", "bulkDeleteError", "schemaStatusChange", "configChange", "metadataChange", "loadingStateChange", "collectionLinksChange", "selectionChange"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }] });
|
|
4675
|
+
`, isInline: true, styles: [":host{display:block;width:100%;min-width:0;max-width:100%}\n"], dependencies: [{ kind: "component", type: PraxisTable, selector: "praxis-table", inputs: ["config", "resourcePath", "data", "tableId", "componentInstanceId", "configPersistenceStrategy", "title", "subtitle", "icon", "autoDelete", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "crudContext", "filterCriteria", "queryContext", "aiContext", "aiAssistantVoiceInputMode", "aiAssistantVoiceLanguage", "horizontalScroll", "enableCustomization", "dense"], outputs: ["rowClick", "widgetEvent", "rowDoubleClick", "rowExpansionChange", "rowAction", "toolbarAction", "bulkAction", "exportAction", "columnReorder", "columnReorderAttempt", "columnResize", "beforeDelete", "afterDelete", "deleteError", "beforeBulkDelete", "afterBulkDelete", "bulkDeleteError", "schemaStatusChange", "configChange", "metadataChange", "loadingStateChange", "collectionLinksChange", "selectionChange"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }] });
|
|
4661
4676
|
}
|
|
4662
4677
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, decorators: [{
|
|
4663
4678
|
type: Component,
|
|
@@ -4756,6 +4771,7 @@ class DynamicFormDialogHostComponent {
|
|
|
4756
4771
|
submitMethod;
|
|
4757
4772
|
apiEndpointKey;
|
|
4758
4773
|
apiUrlEntry;
|
|
4774
|
+
layoutPolicy;
|
|
4759
4775
|
formActions;
|
|
4760
4776
|
mode = 'create';
|
|
4761
4777
|
backConfig;
|
|
@@ -4812,6 +4828,7 @@ class DynamicFormDialogHostComponent {
|
|
|
4812
4828
|
this.apiUrlEntry = this.data.inputs?.['apiUrlEntry'] ?? null;
|
|
4813
4829
|
const act = this.data.action?.action;
|
|
4814
4830
|
this.mode = act === 'edit' ? 'edit' : act === 'view' ? 'view' : 'create';
|
|
4831
|
+
this.layoutPolicy = this.resolveLayoutPolicy();
|
|
4815
4832
|
this.formActions = this.resolveFormActions();
|
|
4816
4833
|
// Back config: defaults from metadata/action, overridden by saved per-form config
|
|
4817
4834
|
const defaults = (this.data.action?.back || this.data.metadata?.defaults?.back) || {};
|
|
@@ -4857,6 +4874,7 @@ class DynamicFormDialogHostComponent {
|
|
|
4857
4874
|
'apiEndpointKey',
|
|
4858
4875
|
'apiUrlEntry',
|
|
4859
4876
|
'initialValue',
|
|
4877
|
+
'layoutPolicy',
|
|
4860
4878
|
]);
|
|
4861
4879
|
const explicit = inputs['initialValue'] && typeof inputs['initialValue'] === 'object'
|
|
4862
4880
|
? { ...inputs['initialValue'] }
|
|
@@ -4890,6 +4908,15 @@ class DynamicFormDialogHostComponent {
|
|
|
4890
4908
|
},
|
|
4891
4909
|
};
|
|
4892
4910
|
}
|
|
4911
|
+
resolveLayoutPolicy() {
|
|
4912
|
+
const explicit = this.data.inputs?.['layoutPolicy'] ??
|
|
4913
|
+
this.data.action?.form?.layoutPolicy ??
|
|
4914
|
+
this.data.action?.layoutPolicy;
|
|
4915
|
+
if (explicit && typeof explicit === 'object') {
|
|
4916
|
+
return explicit;
|
|
4917
|
+
}
|
|
4918
|
+
return null;
|
|
4919
|
+
}
|
|
4893
4920
|
resolveSubmitLabel() {
|
|
4894
4921
|
const action = this.data.action ?? {};
|
|
4895
4922
|
const explicit = stringOrUndefined(action.form?.submitLabel ??
|
|
@@ -5074,6 +5101,7 @@ class DynamicFormDialogHostComponent {
|
|
|
5074
5101
|
[submitMethod]="submitMethod"
|
|
5075
5102
|
[apiEndpointKey]="apiEndpointKey"
|
|
5076
5103
|
[apiUrlEntry]="apiUrlEntry"
|
|
5104
|
+
[layoutPolicy]="layoutPolicy"
|
|
5077
5105
|
[presentationModeGlobal]="mode === 'view' ? true : null"
|
|
5078
5106
|
[backConfig]="backConfig"
|
|
5079
5107
|
[actions]="formActions"
|
|
@@ -5081,7 +5109,7 @@ class DynamicFormDialogHostComponent {
|
|
|
5081
5109
|
(formCancel)="onCancel()"
|
|
5082
5110
|
></praxis-dynamic-form>
|
|
5083
5111
|
</mat-dialog-content>
|
|
5084
|
-
`, isInline: true, styles: [":host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}:host([data-density=\"compact\"]){--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}.dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);padding:0 var(--dlg-pad);height:var(--dlg-header-h);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)}.dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}.spacer{flex:1}.dialog-content{overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}.dialog-header button.mat-icon-button{color:var(--md-sys-color-on-surface-variant)}.dialog-header button.mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}.dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}\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: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }] });
|
|
5112
|
+
`, isInline: true, styles: [":host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}:host([data-density=\"compact\"]){--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}.dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);padding:0 var(--dlg-pad);height:var(--dlg-header-h);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)}.dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}.spacer{flex:1}.dialog-content{overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}.dialog-header button.mat-icon-button{color:var(--md-sys-color-on-surface-variant)}.dialog-header button.mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}.dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}\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: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "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"] }] });
|
|
5085
5113
|
}
|
|
5086
5114
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
|
|
5087
5115
|
type: Component,
|
|
@@ -5136,6 +5164,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
5136
5164
|
[submitMethod]="submitMethod"
|
|
5137
5165
|
[apiEndpointKey]="apiEndpointKey"
|
|
5138
5166
|
[apiUrlEntry]="apiUrlEntry"
|
|
5167
|
+
[layoutPolicy]="layoutPolicy"
|
|
5139
5168
|
[presentationModeGlobal]="mode === 'view' ? true : null"
|
|
5140
5169
|
[backConfig]="backConfig"
|
|
5141
5170
|
[actions]="formActions"
|
|
@@ -5699,6 +5728,7 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5699
5728
|
{ path: 'actions[].params[].to', category: 'actions', valueKind: 'enum', allowedValues: ENUMS.paramTarget, description: 'Destino do parametro.' },
|
|
5700
5729
|
{ path: 'actions[].params[].name', category: 'actions', valueKind: 'string', description: 'Nome do parametro no destino.' },
|
|
5701
5730
|
{ path: 'actions[].form.initialValue', category: 'actions', valueKind: 'object', description: 'Seed fixo do formulario injetado em inputs.initialValue antes da abertura.' },
|
|
5731
|
+
{ path: 'actions[].form.layoutPolicy', category: 'actions', valueKind: 'object', description: 'Politica schema-driven opt-in encaminhada ao Dynamic Form para materializar detalhe ou command form sem FormConfig.sections local; deve acompanhar schemaUrl compativel, especialmente schemaType=request para comandos.' },
|
|
5702
5732
|
{ path: 'actions[].back', category: 'navigation', valueKind: 'object', description: 'BackConfig por acao.' },
|
|
5703
5733
|
{ path: 'actions[].back.strategy', category: 'navigation', valueKind: 'enum', allowedValues: ENUMS.backStrategy, description: 'Estrategia de retorno da acao (auto, close, navigate).' },
|
|
5704
5734
|
{ path: 'actions[].back.returnTo', category: 'navigation', valueKind: 'string', description: 'Rota ou destino usado quando a estrategia de retorno for navigate.' },
|
|
@@ -5736,6 +5766,7 @@ const surfaceConfigureSchema = {
|
|
|
5736
5766
|
submitMethod: { enum: ['post', 'put', 'patch', 'delete'] },
|
|
5737
5767
|
apiEndpointKey: { type: 'string' },
|
|
5738
5768
|
initialValue: { type: 'object' },
|
|
5769
|
+
layoutPolicy: { type: 'object' },
|
|
5739
5770
|
},
|
|
5740
5771
|
},
|
|
5741
5772
|
params: {
|
|
@@ -6017,14 +6048,14 @@ const PRAXIS_CRUD_AUTHORING_MANIFEST = {
|
|
|
6017
6048
|
target: { kind: 'dialogHost', resolver: 'crud-dialog-host-defaults', ambiguityPolicy: 'fail', required: true },
|
|
6018
6049
|
inputSchema: dialogHostSchema,
|
|
6019
6050
|
effects: [{ kind: 'compile-domain-patch', handler: 'crud-dialog-host-set', handlerContract: {
|
|
6020
|
-
reads: ['CrudMetadata.defaults', 'CrudLauncherService.resolveOpenMode', 'DialogService', 'CRUD_DRAWER_ADAPTER'],
|
|
6051
|
+
reads: ['CrudMetadata.defaults', 'CrudLauncherService.resolveOpenMode', 'DialogService', 'DynamicFormDialogHostComponent', 'CRUD_DRAWER_ADAPTER'],
|
|
6021
6052
|
writes: ['CrudMetadata.defaults.openMode', 'CrudMetadata.defaults.modal', 'CrudMetadata.defaults.back'],
|
|
6022
6053
|
identityKeys: ['crudId'],
|
|
6023
6054
|
inputSchema: dialogHostSchema,
|
|
6024
|
-
failureModes: ['open-mode-unsupported', 'drawer-
|
|
6025
|
-
description: 'Configures CRUD-owned route/modal/drawer defaults consumed by the launcher
|
|
6055
|
+
failureModes: ['open-mode-unsupported', 'drawer-runtime-unavailable', 'modal-size-invalid', 'back-policy-invalid'],
|
|
6056
|
+
description: 'Configures CRUD-owned route/modal/drawer defaults consumed by the launcher, default dialog-backed drawer runtime and optional host drawer adapter.',
|
|
6026
6057
|
} }],
|
|
6027
|
-
validators: ['open-mode-supported', 'modal-size-valid', 'drawer-
|
|
6058
|
+
validators: ['open-mode-supported', 'modal-size-valid', 'drawer-runtime-available', 'back-policy-valid', 'settings-panel-shell-compatible'],
|
|
6028
6059
|
affectedPaths: ['defaults.openMode', 'defaults.modal', 'defaults.back'],
|
|
6029
6060
|
submissionImpact: 'config-only',
|
|
6030
6061
|
preconditions: ['crud-metadata-loaded'],
|
|
@@ -6100,7 +6131,7 @@ const PRAXIS_CRUD_AUTHORING_MANIFEST = {
|
|
|
6100
6131
|
{ validatorId: 'permissions-delete-valid', level: 'error', code: 'CRUD_DELETE_PERMISSION_VALID', description: 'Delete permission cannot bypass resource capabilities or confirmation policy.' },
|
|
6101
6132
|
{ validatorId: 'open-mode-supported', level: 'error', code: 'CRUD_OPEN_MODE_SUPPORTED', description: 'Open mode must be route, modal or drawer.' },
|
|
6102
6133
|
{ validatorId: 'modal-size-valid', level: 'error', code: 'CRUD_MODAL_SIZE_VALID', description: 'Modal sizing defaults must be valid DialogConfig values.' },
|
|
6103
|
-
{ validatorId: 'drawer-
|
|
6134
|
+
{ validatorId: 'drawer-runtime-available', level: 'error', code: 'CRUD_DRAWER_RUNTIME_AVAILABLE', description: 'Drawer open mode uses the default dialog-backed drawer runtime; a host drawer adapter is optional for shell-specific presentation.' },
|
|
6104
6135
|
{ validatorId: 'back-policy-valid', level: 'error', code: 'CRUD_BACK_POLICY_VALID', description: 'Back policy must be valid for route/modal/drawer behavior.' },
|
|
6105
6136
|
{ validatorId: 'settings-panel-shell-compatible', level: 'warning', code: 'CRUD_SETTINGS_PANEL_COMPATIBLE', description: 'Authoring shell must preserve apply/save/reset semantics.' },
|
|
6106
6137
|
{ validatorId: 'action-permission-supported', level: 'error', code: 'CRUD_ACTION_PERMISSION_SUPPORTED', description: 'Action permissions must map to supported resource capabilities.' },
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/crud",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.31",
|
|
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.0-beta.
|
|
9
|
-
"@praxisui/table": "^9.0.0-beta.
|
|
10
|
-
"@praxisui/core": "^9.0.0-beta.
|
|
11
|
-
"@praxisui/dynamic-fields": "^9.0.0-beta.
|
|
12
|
-
"@praxisui/settings-panel": "^9.0.0-beta.
|
|
8
|
+
"@praxisui/dynamic-form": "^9.0.0-beta.31",
|
|
9
|
+
"@praxisui/table": "^9.0.0-beta.31",
|
|
10
|
+
"@praxisui/core": "^9.0.0-beta.31",
|
|
11
|
+
"@praxisui/dynamic-fields": "^9.0.0-beta.31",
|
|
12
|
+
"@praxisui/settings-panel": "^9.0.0-beta.31",
|
|
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.0-beta.
|
|
17
|
+
"@praxisui/ai": "^9.0.0-beta.31",
|
|
18
18
|
"rxjs": "~7.8.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"keywords": [
|
|
29
29
|
"angular",
|
|
30
30
|
"praxisui",
|
|
31
|
+
"praxis",
|
|
31
32
|
"crud",
|
|
32
33
|
"admin",
|
|
33
34
|
"backoffice",
|
|
@@ -48,7 +49,10 @@
|
|
|
48
49
|
"./drawer-adapter": {
|
|
49
50
|
"types": "./types/praxisui-crud-drawer-adapter.d.ts",
|
|
50
51
|
"default": "./fesm2022/praxisui-crud-drawer-adapter.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./ai/component-registry.json": {
|
|
54
|
+
"default": "./ai/component-registry.json"
|
|
51
55
|
}
|
|
52
56
|
},
|
|
53
57
|
"type": "module"
|
|
54
|
-
}
|
|
58
|
+
}
|
package/types/praxisui-crud.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _praxisui_core from '@praxisui/core';
|
|
2
|
-
import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
|
|
2
|
+
import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, DynamicFormLayoutPolicy, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
|
|
3
3
|
export { BackConfig } from '@praxisui/core';
|
|
4
4
|
import * as _angular_core from '@angular/core';
|
|
5
5
|
import { NgZone, OnChanges, EventEmitter, SimpleChanges, OnInit, Provider, AfterViewInit, OnDestroy } from '@angular/core';
|
|
@@ -53,6 +53,7 @@ interface CrudActionFormContract {
|
|
|
53
53
|
apiEndpointKey?: ApiEndpoint | string | null;
|
|
54
54
|
apiUrlEntry?: ApiUrlEntry | null;
|
|
55
55
|
initialValue?: Record<string, unknown> | null;
|
|
56
|
+
layoutPolicy?: DynamicFormLayoutPolicy | null;
|
|
56
57
|
}
|
|
57
58
|
type CrudActionResolutionMode = 'inferred' | 'explicit';
|
|
58
59
|
type CrudAction = (RowAction | ToolbarAction) & {
|
|
@@ -316,6 +317,7 @@ declare class CrudLauncherService {
|
|
|
316
317
|
submitMethod?: string | null;
|
|
317
318
|
apiEndpointKey?: unknown;
|
|
318
319
|
apiUrlEntry?: unknown;
|
|
320
|
+
layoutPolicy?: unknown;
|
|
319
321
|
};
|
|
320
322
|
private buildInferredFormId;
|
|
321
323
|
private isCanonicalCrudAction;
|
|
@@ -347,6 +349,7 @@ declare class DynamicFormDialogHostComponent implements OnInit {
|
|
|
347
349
|
submitMethod?: string | null;
|
|
348
350
|
apiEndpointKey?: ApiEndpoint | string | null;
|
|
349
351
|
apiUrlEntry?: ApiUrlEntry | null;
|
|
352
|
+
layoutPolicy?: DynamicFormLayoutPolicy | null;
|
|
350
353
|
formActions?: FormConfig['actions'];
|
|
351
354
|
mode: 'create' | 'edit' | 'view';
|
|
352
355
|
backConfig?: BackConfig;
|
|
@@ -355,6 +358,7 @@ declare class DynamicFormDialogHostComponent implements OnInit {
|
|
|
355
358
|
constructor(dialogRef: DialogRef<DynamicFormDialogHostComponent>, data: any, dialogService: DialogService, crud: GenericCrudService<any>, configStorage: AsyncConfigStorage);
|
|
356
359
|
private extractInitialValue;
|
|
357
360
|
private resolveFormActions;
|
|
361
|
+
private resolveLayoutPolicy;
|
|
358
362
|
private resolveSubmitLabel;
|
|
359
363
|
ngOnInit(): void;
|
|
360
364
|
onSave(result: unknown): void;
|