@praxisui/crud 8.0.0-beta.8 → 8.0.0-beta.81
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.
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, InjectionToken, inject, input, signal, computed, effect, ChangeDetectionStrategy, Component, EventEmitter, DestroyRef, ChangeDetectorRef, ViewChild, Output, Input, Inject, ENVIRONMENT_INITIALIZER } from '@angular/core';
|
|
2
|
+
import { Injectable, InjectionToken, inject, input, signal, computed, effect, ChangeDetectionStrategy, Component, EventEmitter, DestroyRef, ChangeDetectorRef, Injector, ViewChild, Output, Input, Inject, 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
|
-
import { firstValueFrom, BehaviorSubject } from 'rxjs';
|
|
7
|
+
import { firstValueFrom, BehaviorSubject, Subscription } from 'rxjs';
|
|
8
8
|
import * as i2$1 from '@praxisui/core';
|
|
9
|
-
import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, fillUndefined, SETTINGS_PANEL_DATA, PraxisI18nService, providePraxisI18nConfig, createDefaultTableConfig,
|
|
9
|
+
import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, fillUndefined, SETTINGS_PANEL_DATA, PraxisI18nService, providePraxisI18nConfig, createDefaultTableConfig, GLOBAL_SURFACE_SERVICE, ComponentKeyService, ResourceDiscoveryService, ResourceActionOpenAdapterService, ResourceSurfaceOpenAdapterService, translateUnavailableWorkflowMessage, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, PraxisIconDirective, 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';
|
|
13
13
|
import * as i1 from '@angular/material/dialog';
|
|
14
14
|
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
15
15
|
export { MAT_DIALOG_DATA as DIALOG_DATA } from '@angular/material/dialog';
|
|
16
|
-
import * as i1$2 from '@angular/common';
|
|
17
|
-
import { CommonModule } from '@angular/common';
|
|
18
16
|
import * as i1$1 from '@angular/forms';
|
|
19
17
|
import { FormsModule } from '@angular/forms';
|
|
20
18
|
import * as i2 from '@angular/material/button';
|
|
@@ -50,10 +48,10 @@ class DialogService {
|
|
|
50
48
|
const component = await loader();
|
|
51
49
|
return this.zone.run(() => this.matDialog.open(component, config));
|
|
52
50
|
}
|
|
53
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
54
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
51
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DialogService, deps: [{ token: i1.MatDialog }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
52
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DialogService, providedIn: 'root' });
|
|
55
53
|
}
|
|
56
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DialogService, decorators: [{
|
|
57
55
|
type: Injectable,
|
|
58
56
|
args: [{ providedIn: 'root' }]
|
|
59
57
|
}], ctorParameters: () => [{ type: i1.MatDialog }, { type: i0.NgZone }] });
|
|
@@ -251,6 +249,9 @@ class CrudLauncherService {
|
|
|
251
249
|
if (action.form?.initialValue != null) {
|
|
252
250
|
inputs['initialValue'] = action.form.initialValue;
|
|
253
251
|
}
|
|
252
|
+
else if (action.action !== 'create' && row && typeof row === 'object') {
|
|
253
|
+
inputs['initialValue'] = { ...row };
|
|
254
|
+
}
|
|
254
255
|
return inputs;
|
|
255
256
|
}
|
|
256
257
|
resolveActionForLaunch(action, metadata) {
|
|
@@ -382,10 +383,10 @@ class CrudLauncherService {
|
|
|
382
383
|
return { metadata, action };
|
|
383
384
|
}
|
|
384
385
|
}
|
|
385
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
386
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
386
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudLauncherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
387
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudLauncherService, providedIn: 'root' });
|
|
387
388
|
}
|
|
388
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
389
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudLauncherService, decorators: [{
|
|
389
390
|
type: Injectable,
|
|
390
391
|
args: [{ providedIn: 'root' }]
|
|
391
392
|
}] });
|
|
@@ -1235,10 +1236,10 @@ const MODAL_DENSITIES = ['default', 'compact'];
|
|
|
1235
1236
|
const BACK_STRATEGIES = ['auto', 'close', 'navigate'];
|
|
1236
1237
|
const PARAM_TARGETS = ['routeParam', 'query', 'input'];
|
|
1237
1238
|
class CrudMetadataEditorComponent {
|
|
1238
|
-
documentInput = input(null, ...(ngDevMode ?
|
|
1239
|
-
metadataInput = input(null, ...(ngDevMode ?
|
|
1240
|
-
crudIdInput = input(null, ...(ngDevMode ?
|
|
1241
|
-
readonlyInput = input(false, ...(ngDevMode ?
|
|
1239
|
+
documentInput = input(null, { ...(ngDevMode ? { debugName: "documentInput" } : /* istanbul ignore next */ {}), alias: 'document' });
|
|
1240
|
+
metadataInput = input(null, { ...(ngDevMode ? { debugName: "metadataInput" } : /* istanbul ignore next */ {}), alias: 'metadata' });
|
|
1241
|
+
crudIdInput = input(null, { ...(ngDevMode ? { debugName: "crudIdInput" } : /* istanbul ignore next */ {}), alias: 'crudId' });
|
|
1242
|
+
readonlyInput = input(false, { ...(ngDevMode ? { debugName: "readonlyInput" } : /* istanbul ignore next */ {}), alias: 'readonly' });
|
|
1242
1243
|
isDirty$ = new BehaviorSubject(false);
|
|
1243
1244
|
isValid$ = new BehaviorSubject(true);
|
|
1244
1245
|
isBusy$ = new BehaviorSubject(false);
|
|
@@ -1250,39 +1251,39 @@ class CrudMetadataEditorComponent {
|
|
|
1250
1251
|
modalDensities = MODAL_DENSITIES;
|
|
1251
1252
|
backStrategies = BACK_STRATEGIES;
|
|
1252
1253
|
paramTargets = PARAM_TARGETS;
|
|
1253
|
-
initialValueDrafts = signal({}, ...(ngDevMode ? [{ debugName: "initialValueDrafts" }] : []));
|
|
1254
|
+
initialValueDrafts = signal({}, ...(ngDevMode ? [{ debugName: "initialValueDrafts" }] : /* istanbul ignore next */ []));
|
|
1254
1255
|
injectedData = inject(SETTINGS_PANEL_DATA, { optional: true });
|
|
1255
1256
|
i18n = inject(PraxisI18nService);
|
|
1256
|
-
currentDocument = signal(createCrudAuthoringDocument({}), ...(ngDevMode ? [{ debugName: "currentDocument" }] : []));
|
|
1257
|
-
initialDocument = signal(createCrudAuthoringDocument({}), ...(ngDevMode ? [{ debugName: "initialDocument" }] : []));
|
|
1257
|
+
currentDocument = signal(createCrudAuthoringDocument({}), ...(ngDevMode ? [{ debugName: "currentDocument" }] : /* istanbul ignore next */ []));
|
|
1258
|
+
initialDocument = signal(createCrudAuthoringDocument({}), ...(ngDevMode ? [{ debugName: "initialDocument" }] : /* istanbul ignore next */ []));
|
|
1258
1259
|
lastExternalSignature = null;
|
|
1259
|
-
effectiveCrudId = computed(() => this.crudIdInput() || this.injectedData?.crudId || null, ...(ngDevMode ? [{ debugName: "effectiveCrudId" }] : []));
|
|
1260
|
-
isReadonly = computed(() => !!(this.readonlyInput() || this.injectedData?.readonly), ...(ngDevMode ? [{ debugName: "isReadonly" }] : []));
|
|
1261
|
-
diagnostics = computed(() => validateCrudAuthoringDocument(this.currentDocument(), { requireCanonicalActions: true }), ...(ngDevMode ? [{ debugName: "diagnostics" }] : []));
|
|
1262
|
-
errorCount = computed(() => this.diagnostics().filter((issue) => issue.level === 'error').length, ...(ngDevMode ? [{ debugName: "errorCount" }] : []));
|
|
1263
|
-
warningCount = computed(() => this.diagnostics().filter((issue) => issue.level !== 'error').length, ...(ngDevMode ? [{ debugName: "warningCount" }] : []));
|
|
1264
|
-
serializedDocument = computed(() => JSON.stringify(serializeCrudAuthoringDocument(this.currentDocument()), null, 2), ...(ngDevMode ? [{ debugName: "serializedDocument" }] : []));
|
|
1265
|
-
tableConfig = computed(() => this.currentDocument().metadata.table || { columns: [] }, ...(ngDevMode ? [{ debugName: "tableConfig" }] : []));
|
|
1266
|
-
resourcePath = computed(() => this.currentDocument().metadata.resource?.path || '', ...(ngDevMode ? [{ debugName: "resourcePath" }] : []));
|
|
1267
|
-
resourceIdField = computed(() => String(this.currentDocument().metadata.resource?.idField ?? ''), ...(ngDevMode ? [{ debugName: "resourceIdField" }] : []));
|
|
1268
|
-
resourceEndpointKey = computed(() => String(this.currentDocument().metadata.resource?.endpointKey ?? ''), ...(ngDevMode ? [{ debugName: "resourceEndpointKey" }] : []));
|
|
1269
|
-
defaultsOpenMode = computed(() => this.currentDocument().metadata.defaults?.openMode || 'route', ...(ngDevMode ? [{ debugName: "defaultsOpenMode" }] : []));
|
|
1270
|
-
headerShowBack = computed(() => !!this.currentDocument().metadata.defaults?.header?.showBack, ...(ngDevMode ? [{ debugName: "headerShowBack" }] : []));
|
|
1271
|
-
headerBackLabel = computed(() => this.currentDocument().metadata.defaults?.header?.backLabel || '', ...(ngDevMode ? [{ debugName: "headerBackLabel" }] : []));
|
|
1272
|
-
headerVariant = computed(() => this.currentDocument().metadata.defaults?.header?.variant || 'ghost', ...(ngDevMode ? [{ debugName: "headerVariant" }] : []));
|
|
1273
|
-
headerSticky = computed(() => !!this.currentDocument().metadata.defaults?.header?.sticky, ...(ngDevMode ? [{ debugName: "headerSticky" }] : []));
|
|
1274
|
-
headerBreadcrumbs = computed(() => !!this.currentDocument().metadata.defaults?.header?.breadcrumbs, ...(ngDevMode ? [{ debugName: "headerBreadcrumbs" }] : []));
|
|
1275
|
-
headerDivider = computed(() => !!this.currentDocument().metadata.defaults?.header?.divider, ...(ngDevMode ? [{ debugName: "headerDivider" }] : []));
|
|
1276
|
-
modalDensity = computed(() => String(this.currentDocument().metadata.defaults?.modal?.density ?? 'default'), ...(ngDevMode ? [{ debugName: "modalDensity" }] : []));
|
|
1277
|
-
modalCanMaximize = computed(() => this.currentDocument().metadata.defaults?.modal?.canMaximize ?? true, ...(ngDevMode ? [{ debugName: "modalCanMaximize" }] : []));
|
|
1278
|
-
modalStartMaximized = computed(() => !!this.currentDocument().metadata.defaults?.modal?.startMaximized, ...(ngDevMode ? [{ debugName: "modalStartMaximized" }] : []));
|
|
1279
|
-
modalRememberLastState = computed(() => !!this.currentDocument().metadata.defaults?.modal?.rememberLastState, ...(ngDevMode ? [{ debugName: "modalRememberLastState" }] : []));
|
|
1280
|
-
modalDisableCloseOnEsc = computed(() => !!this.currentDocument().metadata.defaults?.modal?.disableCloseOnEsc, ...(ngDevMode ? [{ debugName: "modalDisableCloseOnEsc" }] : []));
|
|
1281
|
-
modalDisableCloseOnBackdrop = computed(() => !!this.currentDocument().metadata.defaults?.modal?.disableCloseOnBackdrop, ...(ngDevMode ? [{ debugName: "modalDisableCloseOnBackdrop" }] : []));
|
|
1282
|
-
modalFullscreenBreakpoint = computed(() => String(this.currentDocument().metadata.defaults?.modal?.fullscreenBreakpoint ?? ''), ...(ngDevMode ? [{ debugName: "modalFullscreenBreakpoint" }] : []));
|
|
1283
|
-
backStrategy = computed(() => String(this.currentDocument().metadata.defaults?.back?.strategy ?? 'auto'), ...(ngDevMode ? [{ debugName: "backStrategy" }] : []));
|
|
1284
|
-
backReturnTo = computed(() => this.currentDocument().metadata.defaults?.back?.returnTo || '', ...(ngDevMode ? [{ debugName: "backReturnTo" }] : []));
|
|
1285
|
-
backConfirmOnDirty = computed(() => !!this.currentDocument().metadata.defaults?.back?.confirmOnDirty, ...(ngDevMode ? [{ debugName: "backConfirmOnDirty" }] : []));
|
|
1260
|
+
effectiveCrudId = computed(() => this.crudIdInput() || this.injectedData?.crudId || null, ...(ngDevMode ? [{ debugName: "effectiveCrudId" }] : /* istanbul ignore next */ []));
|
|
1261
|
+
isReadonly = computed(() => !!(this.readonlyInput() || this.injectedData?.readonly), ...(ngDevMode ? [{ debugName: "isReadonly" }] : /* istanbul ignore next */ []));
|
|
1262
|
+
diagnostics = computed(() => validateCrudAuthoringDocument(this.currentDocument(), { requireCanonicalActions: true }), ...(ngDevMode ? [{ debugName: "diagnostics" }] : /* istanbul ignore next */ []));
|
|
1263
|
+
errorCount = computed(() => this.diagnostics().filter((issue) => issue.level === 'error').length, ...(ngDevMode ? [{ debugName: "errorCount" }] : /* istanbul ignore next */ []));
|
|
1264
|
+
warningCount = computed(() => this.diagnostics().filter((issue) => issue.level !== 'error').length, ...(ngDevMode ? [{ debugName: "warningCount" }] : /* istanbul ignore next */ []));
|
|
1265
|
+
serializedDocument = computed(() => JSON.stringify(serializeCrudAuthoringDocument(this.currentDocument()), null, 2), ...(ngDevMode ? [{ debugName: "serializedDocument" }] : /* istanbul ignore next */ []));
|
|
1266
|
+
tableConfig = computed(() => this.currentDocument().metadata.table || { columns: [] }, ...(ngDevMode ? [{ debugName: "tableConfig" }] : /* istanbul ignore next */ []));
|
|
1267
|
+
resourcePath = computed(() => this.currentDocument().metadata.resource?.path || '', ...(ngDevMode ? [{ debugName: "resourcePath" }] : /* istanbul ignore next */ []));
|
|
1268
|
+
resourceIdField = computed(() => String(this.currentDocument().metadata.resource?.idField ?? ''), ...(ngDevMode ? [{ debugName: "resourceIdField" }] : /* istanbul ignore next */ []));
|
|
1269
|
+
resourceEndpointKey = computed(() => String(this.currentDocument().metadata.resource?.endpointKey ?? ''), ...(ngDevMode ? [{ debugName: "resourceEndpointKey" }] : /* istanbul ignore next */ []));
|
|
1270
|
+
defaultsOpenMode = computed(() => this.currentDocument().metadata.defaults?.openMode || 'route', ...(ngDevMode ? [{ debugName: "defaultsOpenMode" }] : /* istanbul ignore next */ []));
|
|
1271
|
+
headerShowBack = computed(() => !!this.currentDocument().metadata.defaults?.header?.showBack, ...(ngDevMode ? [{ debugName: "headerShowBack" }] : /* istanbul ignore next */ []));
|
|
1272
|
+
headerBackLabel = computed(() => this.currentDocument().metadata.defaults?.header?.backLabel || '', ...(ngDevMode ? [{ debugName: "headerBackLabel" }] : /* istanbul ignore next */ []));
|
|
1273
|
+
headerVariant = computed(() => this.currentDocument().metadata.defaults?.header?.variant || 'ghost', ...(ngDevMode ? [{ debugName: "headerVariant" }] : /* istanbul ignore next */ []));
|
|
1274
|
+
headerSticky = computed(() => !!this.currentDocument().metadata.defaults?.header?.sticky, ...(ngDevMode ? [{ debugName: "headerSticky" }] : /* istanbul ignore next */ []));
|
|
1275
|
+
headerBreadcrumbs = computed(() => !!this.currentDocument().metadata.defaults?.header?.breadcrumbs, ...(ngDevMode ? [{ debugName: "headerBreadcrumbs" }] : /* istanbul ignore next */ []));
|
|
1276
|
+
headerDivider = computed(() => !!this.currentDocument().metadata.defaults?.header?.divider, ...(ngDevMode ? [{ debugName: "headerDivider" }] : /* istanbul ignore next */ []));
|
|
1277
|
+
modalDensity = computed(() => String(this.currentDocument().metadata.defaults?.modal?.density ?? 'default'), ...(ngDevMode ? [{ debugName: "modalDensity" }] : /* istanbul ignore next */ []));
|
|
1278
|
+
modalCanMaximize = computed(() => this.currentDocument().metadata.defaults?.modal?.canMaximize ?? true, ...(ngDevMode ? [{ debugName: "modalCanMaximize" }] : /* istanbul ignore next */ []));
|
|
1279
|
+
modalStartMaximized = computed(() => !!this.currentDocument().metadata.defaults?.modal?.startMaximized, ...(ngDevMode ? [{ debugName: "modalStartMaximized" }] : /* istanbul ignore next */ []));
|
|
1280
|
+
modalRememberLastState = computed(() => !!this.currentDocument().metadata.defaults?.modal?.rememberLastState, ...(ngDevMode ? [{ debugName: "modalRememberLastState" }] : /* istanbul ignore next */ []));
|
|
1281
|
+
modalDisableCloseOnEsc = computed(() => !!this.currentDocument().metadata.defaults?.modal?.disableCloseOnEsc, ...(ngDevMode ? [{ debugName: "modalDisableCloseOnEsc" }] : /* istanbul ignore next */ []));
|
|
1282
|
+
modalDisableCloseOnBackdrop = computed(() => !!this.currentDocument().metadata.defaults?.modal?.disableCloseOnBackdrop, ...(ngDevMode ? [{ debugName: "modalDisableCloseOnBackdrop" }] : /* istanbul ignore next */ []));
|
|
1283
|
+
modalFullscreenBreakpoint = computed(() => String(this.currentDocument().metadata.defaults?.modal?.fullscreenBreakpoint ?? ''), ...(ngDevMode ? [{ debugName: "modalFullscreenBreakpoint" }] : /* istanbul ignore next */ []));
|
|
1284
|
+
backStrategy = computed(() => String(this.currentDocument().metadata.defaults?.back?.strategy ?? 'auto'), ...(ngDevMode ? [{ debugName: "backStrategy" }] : /* istanbul ignore next */ []));
|
|
1285
|
+
backReturnTo = computed(() => this.currentDocument().metadata.defaults?.back?.returnTo || '', ...(ngDevMode ? [{ debugName: "backReturnTo" }] : /* istanbul ignore next */ []));
|
|
1286
|
+
backConfirmOnDirty = computed(() => !!this.currentDocument().metadata.defaults?.back?.confirmOnDirty, ...(ngDevMode ? [{ debugName: "backConfirmOnDirty" }] : /* istanbul ignore next */ []));
|
|
1286
1287
|
nextFocusSection = computed(() => {
|
|
1287
1288
|
for (const section of ['connection', 'defaults', 'actions', 'table']) {
|
|
1288
1289
|
if (this.sectionStatus(section) === 'invalid') {
|
|
@@ -1295,8 +1296,8 @@ class CrudMetadataEditorComponent {
|
|
|
1295
1296
|
}
|
|
1296
1297
|
}
|
|
1297
1298
|
return 'connection';
|
|
1298
|
-
}, ...(ngDevMode ? [{ debugName: "nextFocusSection" }] : []));
|
|
1299
|
-
nextFocusStatus = computed(() => this.sectionStatus(this.nextFocusSection()), ...(ngDevMode ? [{ debugName: "nextFocusStatus" }] : []));
|
|
1299
|
+
}, ...(ngDevMode ? [{ debugName: "nextFocusSection" }] : /* istanbul ignore next */ []));
|
|
1300
|
+
nextFocusStatus = computed(() => this.sectionStatus(this.nextFocusSection()), ...(ngDevMode ? [{ debugName: "nextFocusStatus" }] : /* istanbul ignore next */ []));
|
|
1300
1301
|
visibleHealthBuckets = computed(() => {
|
|
1301
1302
|
const attentionBuckets = ['invalid', 'pending']
|
|
1302
1303
|
.filter((bucket) => this.hasHealthBucketContent(bucket));
|
|
@@ -1304,8 +1305,8 @@ class CrudMetadataEditorComponent {
|
|
|
1304
1305
|
return attentionBuckets;
|
|
1305
1306
|
}
|
|
1306
1307
|
return this.hasHealthBucketContent('ready') ? ['ready'] : [];
|
|
1307
|
-
}, ...(ngDevMode ? [{ debugName: "visibleHealthBuckets" }] : []));
|
|
1308
|
-
showHealthMap = computed(() => this.visibleHealthBuckets().length > 1, ...(ngDevMode ? [{ debugName: "showHealthMap" }] : []));
|
|
1308
|
+
}, ...(ngDevMode ? [{ debugName: "visibleHealthBuckets" }] : /* istanbul ignore next */ []));
|
|
1309
|
+
showHealthMap = computed(() => this.visibleHealthBuckets().length > 1, ...(ngDevMode ? [{ debugName: "showHealthMap" }] : /* istanbul ignore next */ []));
|
|
1309
1310
|
groupedDiagnostics = computed(() => ['connection', 'defaults', 'actions', 'table']
|
|
1310
1311
|
.map((section) => {
|
|
1311
1312
|
const issues = this.sectionDiagnostics(section);
|
|
@@ -1315,7 +1316,7 @@ class CrudMetadataEditorComponent {
|
|
|
1315
1316
|
hasError: issues.some((issue) => issue.level === 'error'),
|
|
1316
1317
|
};
|
|
1317
1318
|
})
|
|
1318
|
-
.filter((group) => group.issues.length > 0), ...(ngDevMode ? [{ debugName: "groupedDiagnostics" }] : []));
|
|
1319
|
+
.filter((group) => group.issues.length > 0), ...(ngDevMode ? [{ debugName: "groupedDiagnostics" }] : /* istanbul ignore next */ []));
|
|
1319
1320
|
constructor() {
|
|
1320
1321
|
effect(() => {
|
|
1321
1322
|
const seed = this.resolveExternalSeed();
|
|
@@ -2307,8 +2308,8 @@ class CrudMetadataEditorComponent {
|
|
|
2307
2308
|
table: this.tx('crud.authoring.section.table', 'Table'),
|
|
2308
2309
|
}[section];
|
|
2309
2310
|
}
|
|
2310
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2311
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2311
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudMetadataEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2312
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CrudMetadataEditorComponent, isStandalone: true, selector: "praxis-crud-metadata-editor", inputs: { documentInput: { classPropertyName: "documentInput", publicName: "document", isSignal: true, isRequired: false, transformFunction: null }, metadataInput: { classPropertyName: "metadataInput", publicName: "metadata", isSignal: true, isRequired: false, transformFunction: null }, crudIdInput: { classPropertyName: "crudIdInput", publicName: "crudId", isSignal: true, isRequired: false, transformFunction: null }, readonlyInput: { classPropertyName: "readonlyInput", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, providers: [providePraxisI18nConfig(PRAXIS_CRUD_AUTHORING_I18N_CONFIG)], ngImport: i0, template: `
|
|
2312
2313
|
<section class="editor-shell" data-testid="crud-metadata-editor">
|
|
2313
2314
|
<header class="editor-header">
|
|
2314
2315
|
<div>
|
|
@@ -2783,12 +2784,11 @@ class CrudMetadataEditorComponent {
|
|
|
2783
2784
|
<pre data-testid="crud-editor-json">{{ serializedDocument() }}</pre>
|
|
2784
2785
|
</mat-card>
|
|
2785
2786
|
</section>
|
|
2786
|
-
`, isInline: true, styles: [":host{display:block;min-width:0;color:var(--md-sys-color-on-surface,#1a1b20)}.editor-shell{display:grid;gap:16px}.editor-header{display:flex;justify-content:space-between;gap:16px;align-items:start}.editor-overview,.editor-health-map{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.editor-health-card{display:grid;gap:4px;padding:14px;border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.editor-health-card--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.editor-health-card--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.editor-focus{display:flex;gap:12px;align-items:start;padding:14px 16px;border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.editor-focus--success{background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent)}.editor-focus-chip{padding:6px 10px;border-radius:999px;font-size:12px;background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent);white-space:nowrap}.editor-focus-chip--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.editor-focus-chip--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.editor-focus-copy{display:grid;gap:4px}.editor-focus-copy p{margin:0;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-overview-card{display:grid;gap:4px;padding:14px;border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.editor-overview-card--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.editor-overview-card--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.editor-overview-label{font-size:12px;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-overview-value{line-height:1.3;overflow-wrap:anywhere}.editor-overview-note{margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-header h2,.editor-card h3{margin:0}.editor-header p{margin:6px 0 0;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-chip{padding:6px 10px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary,#1263b4) 12%,transparent);font-size:12px}.editor-card{display:grid;gap:14px;padding:16px;border-radius:20px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline,#c5c7ce) 70%,transparent)}.editor-section-header{display:flex;justify-content:space-between;gap:12px;align-items:start}.editor-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.editor-grid--compact{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.editor-toggles{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.editor-actions,.action-grid{display:grid;gap:14px}.action-summary-strip{display:flex;flex-wrap:wrap;gap:8px}.action-summary-chip{padding:6px 10px;border-radius:999px;font-size:12px;background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent)}.action-summary-chip--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.action-summary-chip--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.action-group{display:grid;gap:10px;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 88%,transparent)}.action-group--advanced{background:color-mix(in srgb,var(--md-sys-color-surface-container,#f5f7fb) 90%,transparent)}.action-group__header{display:grid;gap:4px}.action-subgroup{display:grid;gap:10px;padding:10px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low,#fafbfd) 92%,transparent)}.action-subgroup__header{display:grid;gap:4px}.action-param-list{display:grid;gap:12px}.action-param-row{display:grid;gap:8px}.action-advanced-panel{border:1px solid color-mix(in srgb,var(--md-sys-color-outline,#c5c7ce) 65%,transparent);border-radius:16px}.editor-section-note{margin:0;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.diagnostics-groups{display:grid;gap:12px}.diagnostics-group{display:grid;gap:10px;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.diagnostics{display:grid;gap:8px;margin:0;padding-left:18px}.diagnostics .error{color:var(--md-sys-color-error,#b3261e)}pre{margin:0;overflow:auto;max-height:320px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type:
|
|
2787
|
+
`, isInline: true, styles: [":host{display:block;min-width:0;color:var(--md-sys-color-on-surface,#1a1b20)}.editor-shell{display:grid;gap:16px}.editor-header{display:flex;justify-content:space-between;gap:16px;align-items:start}.editor-overview,.editor-health-map{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.editor-health-card{display:grid;gap:4px;padding:14px;border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.editor-health-card--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.editor-health-card--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.editor-focus{display:flex;gap:12px;align-items:start;padding:14px 16px;border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.editor-focus--success{background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent)}.editor-focus-chip{padding:6px 10px;border-radius:999px;font-size:12px;background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent);white-space:nowrap}.editor-focus-chip--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.editor-focus-chip--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.editor-focus-copy{display:grid;gap:4px}.editor-focus-copy p{margin:0;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-overview-card{display:grid;gap:4px;padding:14px;border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.editor-overview-card--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.editor-overview-card--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.editor-overview-label{font-size:12px;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-overview-value{line-height:1.3;overflow-wrap:anywhere}.editor-overview-note{margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-header h2,.editor-card h3{margin:0}.editor-header p{margin:6px 0 0;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.editor-chip{padding:6px 10px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary,#1263b4) 12%,transparent);font-size:12px}.editor-card{display:grid;gap:14px;padding:16px;border-radius:20px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline,#c5c7ce) 70%,transparent)}.editor-section-header{display:flex;justify-content:space-between;gap:12px;align-items:start}.editor-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.editor-grid--compact{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.editor-toggles{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.editor-actions,.action-grid{display:grid;gap:14px}.action-summary-strip{display:flex;flex-wrap:wrap;gap:8px}.action-summary-chip{padding:6px 10px;border-radius:999px;font-size:12px;background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent)}.action-summary-chip--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container,#f8e08e) 78%,transparent)}.action-summary-chip--error{background:color-mix(in srgb,var(--md-sys-color-error-container,#f9dedc) 82%,transparent);color:var(--md-sys-color-on-error-container,#410e0b)}.action-group{display:grid;gap:10px;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 88%,transparent)}.action-group--advanced{background:color-mix(in srgb,var(--md-sys-color-surface-container,#f5f7fb) 90%,transparent)}.action-group__header{display:grid;gap:4px}.action-subgroup{display:grid;gap:10px;padding:10px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low,#fafbfd) 92%,transparent)}.action-subgroup__header{display:grid;gap:4px}.action-param-list{display:grid;gap:12px}.action-param-row{display:grid;gap:8px}.action-advanced-panel{border:1px solid color-mix(in srgb,var(--md-sys-color-outline,#c5c7ce) 65%,transparent);border-radius:16px}.editor-section-note{margin:0;color:var(--md-sys-color-on-surface-variant,#5a5d67)}.diagnostics-groups{display:grid;gap:12px}.diagnostics-group{display:grid;gap:10px;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}.diagnostics{display:grid;gap:8px;margin:0;padding-left:18px}.diagnostics .error{color:var(--md-sys-color-error,#b3261e)}pre{margin:0;overflow:auto;max-height:320px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i4.MatExpansionPanelDescription, selector: "mat-panel-description" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i7.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i7.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i8.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: PraxisTableInlineAuthoringEditorComponent, selector: "praxis-table-inline-authoring-editor", inputs: ["config", "readonly"], outputs: ["configChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2787
2788
|
}
|
|
2788
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2789
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudMetadataEditorComponent, decorators: [{
|
|
2789
2790
|
type: Component,
|
|
2790
2791
|
args: [{ selector: 'praxis-crud-metadata-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
2791
|
-
CommonModule,
|
|
2792
2792
|
FormsModule,
|
|
2793
2793
|
MatButtonModule,
|
|
2794
2794
|
MatCardModule,
|
|
@@ -2797,7 +2797,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
2797
2797
|
MatInputModule,
|
|
2798
2798
|
MatSelectModule,
|
|
2799
2799
|
MatSlideToggleModule,
|
|
2800
|
-
PraxisTableInlineAuthoringEditorComponent
|
|
2800
|
+
PraxisTableInlineAuthoringEditorComponent
|
|
2801
2801
|
], providers: [providePraxisI18nConfig(PRAXIS_CRUD_AUTHORING_I18N_CONFIG)], template: `
|
|
2802
2802
|
<section class="editor-shell" data-testid="crud-metadata-editor">
|
|
2803
2803
|
<header class="editor-header">
|
|
@@ -3308,6 +3308,8 @@ class PraxisCrudComponent {
|
|
|
3308
3308
|
afterSave = new EventEmitter();
|
|
3309
3309
|
afterDelete = new EventEmitter();
|
|
3310
3310
|
error = new EventEmitter();
|
|
3311
|
+
rowClick = new EventEmitter();
|
|
3312
|
+
selectionChange = new EventEmitter();
|
|
3311
3313
|
tableRuntimeConfigChange = new EventEmitter();
|
|
3312
3314
|
crudAuthoringDocumentApplied = new EventEmitter();
|
|
3313
3315
|
crudAuthoringDocumentSaved = new EventEmitter();
|
|
@@ -3327,9 +3329,10 @@ class PraxisCrudComponent {
|
|
|
3327
3329
|
snack = inject(MatSnackBar);
|
|
3328
3330
|
dialog = inject(DialogService);
|
|
3329
3331
|
i18n = inject(PraxisI18nService);
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3332
|
+
injector = inject(Injector);
|
|
3333
|
+
resourceDiscoveryInstance;
|
|
3334
|
+
actionOpenAdapterInstance;
|
|
3335
|
+
surfaceOpenAdapterInstance;
|
|
3333
3336
|
global = (() => {
|
|
3334
3337
|
try {
|
|
3335
3338
|
return inject(GlobalConfigService);
|
|
@@ -3359,6 +3362,18 @@ class PraxisCrudComponent {
|
|
|
3359
3362
|
collectionCapabilitiesResolvedHref = null;
|
|
3360
3363
|
collectionCapabilitiesRequestSeq = 0;
|
|
3361
3364
|
currentAuthoringDocument;
|
|
3365
|
+
getResourceDiscovery() {
|
|
3366
|
+
const assigned = this.resourceDiscovery;
|
|
3367
|
+
return assigned ?? (this.resourceDiscoveryInstance ??= this.injector.get(ResourceDiscoveryService));
|
|
3368
|
+
}
|
|
3369
|
+
getActionOpenAdapter() {
|
|
3370
|
+
const assigned = this.actionOpenAdapter;
|
|
3371
|
+
return assigned ?? (this.actionOpenAdapterInstance ??= this.injector.get(ResourceActionOpenAdapterService));
|
|
3372
|
+
}
|
|
3373
|
+
getSurfaceOpenAdapter() {
|
|
3374
|
+
const assigned = this.surfaceOpenAdapter;
|
|
3375
|
+
return assigned ?? (this.surfaceOpenAdapterInstance ??= this.injector.get(ResourceSurfaceOpenAdapterService));
|
|
3376
|
+
}
|
|
3362
3377
|
onResetPreferences() {
|
|
3363
3378
|
try {
|
|
3364
3379
|
const keyId = this.componentKeyId();
|
|
@@ -3372,6 +3387,12 @@ class PraxisCrudComponent {
|
|
|
3372
3387
|
}
|
|
3373
3388
|
catch { }
|
|
3374
3389
|
}
|
|
3390
|
+
onTableRowClick(event) {
|
|
3391
|
+
this.rowClick.emit(event);
|
|
3392
|
+
}
|
|
3393
|
+
onTableSelectionChange(event) {
|
|
3394
|
+
this.selectionChange.emit(event);
|
|
3395
|
+
}
|
|
3375
3396
|
ngOnChanges(changes) {
|
|
3376
3397
|
if (!changes['metadata'] && !changes['context']) {
|
|
3377
3398
|
return;
|
|
@@ -3409,14 +3430,6 @@ class PraxisCrudComponent {
|
|
|
3409
3430
|
async onAction(action, row, runtimeEvent) {
|
|
3410
3431
|
try {
|
|
3411
3432
|
document.activeElement?.blur();
|
|
3412
|
-
const openedByDiscovery = await this.tryOpenDiscoveredCrudSurface(action, row);
|
|
3413
|
-
if (openedByDiscovery) {
|
|
3414
|
-
return;
|
|
3415
|
-
}
|
|
3416
|
-
const handledByWorkflowAction = await this.tryOpenDiscoveredWorkflowAction(action, row, runtimeEvent);
|
|
3417
|
-
if (handledByWorkflowAction) {
|
|
3418
|
-
return;
|
|
3419
|
-
}
|
|
3420
3433
|
let actionMeta = this.resolvedMetadata.actions?.find((candidate) => candidate.action === action);
|
|
3421
3434
|
if (!actionMeta) {
|
|
3422
3435
|
const ctxAction = this.tableCrudContext?.actions?.find((candidate) => candidate.action === action);
|
|
@@ -3433,6 +3446,16 @@ class PraxisCrudComponent {
|
|
|
3433
3446
|
}
|
|
3434
3447
|
}
|
|
3435
3448
|
const effectiveAction = (actionMeta || { action });
|
|
3449
|
+
if (!this.hasExplicitOpenBinding(effectiveAction)) {
|
|
3450
|
+
const openedByDiscovery = await this.tryOpenDiscoveredCrudSurface(action, row, runtimeEvent);
|
|
3451
|
+
if (openedByDiscovery) {
|
|
3452
|
+
return;
|
|
3453
|
+
}
|
|
3454
|
+
const handledByWorkflowAction = await this.tryOpenDiscoveredWorkflowAction(action, row, runtimeEvent);
|
|
3455
|
+
if (handledByWorkflowAction) {
|
|
3456
|
+
return;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3436
3459
|
const handledByDelete = await this.tryHandleCanonicalDeleteAction(effectiveAction, row);
|
|
3437
3460
|
if (handledByDelete) {
|
|
3438
3461
|
return;
|
|
@@ -3495,6 +3518,19 @@ class PraxisCrudComponent {
|
|
|
3495
3518
|
this.error.emit(err);
|
|
3496
3519
|
}
|
|
3497
3520
|
}
|
|
3521
|
+
hasExplicitOpenBinding(action) {
|
|
3522
|
+
const mode = action.openMode;
|
|
3523
|
+
if (mode === 'route') {
|
|
3524
|
+
return !!String(action.route || '').trim();
|
|
3525
|
+
}
|
|
3526
|
+
if (mode === 'modal' || mode === 'drawer') {
|
|
3527
|
+
return !!String(action.formId || '').trim();
|
|
3528
|
+
}
|
|
3529
|
+
return !!(String(action.route || '').trim() ||
|
|
3530
|
+
String(action.formId || '').trim() ||
|
|
3531
|
+
String(action.form?.schemaUrl || '').trim() ||
|
|
3532
|
+
String(action.form?.submitUrl || '').trim());
|
|
3533
|
+
}
|
|
3498
3534
|
getCurrentTableConfigSnapshot() {
|
|
3499
3535
|
const current = this.table?.config || this.tableConfigForBinding || this.effectiveTableConfig;
|
|
3500
3536
|
if (!current)
|
|
@@ -3537,7 +3573,7 @@ class PraxisCrudComponent {
|
|
|
3537
3573
|
}
|
|
3538
3574
|
const requestSeq = ++this.collectionCapabilitiesRequestSeq;
|
|
3539
3575
|
this.collectionCapabilitiesRequestHref = capabilitiesHref;
|
|
3540
|
-
void firstValueFrom(this.
|
|
3576
|
+
void firstValueFrom(this.getResourceDiscovery().getCapabilities(links || {}, this.buildDiscoveryOptions()))
|
|
3541
3577
|
.then((snapshot) => {
|
|
3542
3578
|
if (requestSeq !== this.collectionCapabilitiesRequestSeq) {
|
|
3543
3579
|
return;
|
|
@@ -3591,6 +3627,7 @@ class PraxisCrudComponent {
|
|
|
3591
3627
|
}
|
|
3592
3628
|
onConfigureRequested() {
|
|
3593
3629
|
this.configureRequested.emit();
|
|
3630
|
+
this.openCrudAuthoringFromTable();
|
|
3594
3631
|
}
|
|
3595
3632
|
async tryHandleCanonicalDeleteAction(action, row) {
|
|
3596
3633
|
const normalizedAction = String(action.action || '').trim().toLowerCase();
|
|
@@ -3704,25 +3741,35 @@ class PraxisCrudComponent {
|
|
|
3704
3741
|
resolveFilterCriteria(meta) {
|
|
3705
3742
|
return this.isRecord(meta?.filterCriteria) ? { ...meta.filterCriteria } : {};
|
|
3706
3743
|
}
|
|
3707
|
-
async tryOpenDiscoveredCrudSurface(action, row) {
|
|
3744
|
+
async tryOpenDiscoveredCrudSurface(action, row, runtimeEvent) {
|
|
3708
3745
|
const normalizedAction = String(action || '').trim().toLowerCase();
|
|
3709
|
-
if (!this.
|
|
3746
|
+
if (!this.surfaceService) {
|
|
3710
3747
|
return false;
|
|
3711
3748
|
}
|
|
3712
|
-
const
|
|
3713
|
-
|
|
3749
|
+
const providedSurface = this.resolveProvidedSurface(normalizedAction, runtimeEvent?.actionConfig);
|
|
3750
|
+
if (!providedSurface && !this.isDiscoveryManagedCrudAction(normalizedAction)) {
|
|
3751
|
+
return false;
|
|
3752
|
+
}
|
|
3753
|
+
const catalog = providedSurface
|
|
3754
|
+
? null
|
|
3755
|
+
: await this.resolveDiscoveredSurfaceCatalog(normalizedAction, row);
|
|
3756
|
+
const surface = providedSurface || this.selectSurfaceForCrudAction(normalizedAction, catalog?.surfaces || []);
|
|
3714
3757
|
const resourcePath = String(catalog?.resourcePath || this.resolveResourcePath(this.resolvedMetadata) || '').trim();
|
|
3715
|
-
if (!
|
|
3758
|
+
if (!surface || !resourcePath) {
|
|
3716
3759
|
return false;
|
|
3717
3760
|
}
|
|
3761
|
+
if (surface.availability?.allowed === false) {
|
|
3762
|
+
this.snack.open(translateUnavailableWorkflowMessage(this.i18n, surface.availability), undefined, { duration: 2500 });
|
|
3763
|
+
return true;
|
|
3764
|
+
}
|
|
3718
3765
|
let payload;
|
|
3719
3766
|
try {
|
|
3720
|
-
payload = this.
|
|
3767
|
+
payload = this.getSurfaceOpenAdapter().toPayload(surface, {
|
|
3721
3768
|
resourcePath,
|
|
3722
3769
|
resourceId: this.resolveRowResourceId(row),
|
|
3723
3770
|
endpointKey: this.resolvedMetadata?.resource?.endpointKey,
|
|
3724
3771
|
apiUrlEntry: this.resolveDiscoveryApiEntry(),
|
|
3725
|
-
group: catalog
|
|
3772
|
+
group: catalog?.group ?? null,
|
|
3726
3773
|
});
|
|
3727
3774
|
}
|
|
3728
3775
|
catch {
|
|
@@ -3767,13 +3814,13 @@ class PraxisCrudComponent {
|
|
|
3767
3814
|
if (!this.tableCollectionLinks) {
|
|
3768
3815
|
return null;
|
|
3769
3816
|
}
|
|
3770
|
-
return await firstValueFrom(this.
|
|
3817
|
+
return await firstValueFrom(this.getResourceDiscovery().getSurfaces(this.tableCollectionLinks, this.buildDiscoveryOptions()));
|
|
3771
3818
|
}
|
|
3772
3819
|
const rowLinks = row?._links;
|
|
3773
3820
|
if (!rowLinks) {
|
|
3774
3821
|
return null;
|
|
3775
3822
|
}
|
|
3776
|
-
return await firstValueFrom(this.
|
|
3823
|
+
return await firstValueFrom(this.getResourceDiscovery().getSurfaces(rowLinks, this.buildDiscoveryOptions()));
|
|
3777
3824
|
}
|
|
3778
3825
|
catch {
|
|
3779
3826
|
return null;
|
|
@@ -3797,7 +3844,7 @@ class PraxisCrudComponent {
|
|
|
3797
3844
|
}
|
|
3798
3845
|
let payload;
|
|
3799
3846
|
try {
|
|
3800
|
-
payload = this.
|
|
3847
|
+
payload = this.getActionOpenAdapter().toPayload(discoveredAction, {
|
|
3801
3848
|
resourcePath,
|
|
3802
3849
|
resourceId: this.resolveRowResourceId(row),
|
|
3803
3850
|
endpointKey: this.resolvedMetadata?.resource?.endpointKey,
|
|
@@ -3848,12 +3895,12 @@ class PraxisCrudComponent {
|
|
|
3848
3895
|
if (!rowLinks) {
|
|
3849
3896
|
return null;
|
|
3850
3897
|
}
|
|
3851
|
-
return await firstValueFrom(this.
|
|
3898
|
+
return await firstValueFrom(this.getResourceDiscovery().getActions(rowLinks, this.buildDiscoveryOptions()));
|
|
3852
3899
|
}
|
|
3853
3900
|
if (!this.tableCollectionLinks) {
|
|
3854
3901
|
return null;
|
|
3855
3902
|
}
|
|
3856
|
-
return await firstValueFrom(this.
|
|
3903
|
+
return await firstValueFrom(this.getResourceDiscovery().getActions(this.tableCollectionLinks, this.buildDiscoveryOptions()));
|
|
3857
3904
|
}
|
|
3858
3905
|
catch {
|
|
3859
3906
|
return null;
|
|
@@ -3880,6 +3927,23 @@ class PraxisCrudComponent {
|
|
|
3880
3927
|
}
|
|
3881
3928
|
return candidate;
|
|
3882
3929
|
}
|
|
3930
|
+
resolveProvidedSurface(action, candidate) {
|
|
3931
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
3932
|
+
return null;
|
|
3933
|
+
}
|
|
3934
|
+
const normalizedId = String(candidate.id || '').trim().toLowerCase();
|
|
3935
|
+
if (!normalizedId || normalizedId !== action) {
|
|
3936
|
+
return null;
|
|
3937
|
+
}
|
|
3938
|
+
const surface = candidate;
|
|
3939
|
+
if (!surface.kind || !surface.scope || !surface.path || !surface.method) {
|
|
3940
|
+
return null;
|
|
3941
|
+
}
|
|
3942
|
+
if (!this.isWritableCrudSurface(surface) && !this.isReadableCrudSurface(surface)) {
|
|
3943
|
+
return null;
|
|
3944
|
+
}
|
|
3945
|
+
return surface;
|
|
3946
|
+
}
|
|
3883
3947
|
selectSurfaceForCrudAction(action, surfaces) {
|
|
3884
3948
|
const candidates = surfaces
|
|
3885
3949
|
.filter((surface) => surface.availability?.allowed !== false)
|
|
@@ -4300,7 +4364,7 @@ class PraxisCrudComponent {
|
|
|
4300
4364
|
}
|
|
4301
4365
|
resolveCollectionCapabilitiesHref(links) {
|
|
4302
4366
|
try {
|
|
4303
|
-
return this.
|
|
4367
|
+
return this.getResourceDiscovery().resolveLinkHref(links || undefined, 'capabilities', this.buildDiscoveryOptions());
|
|
4304
4368
|
}
|
|
4305
4369
|
catch {
|
|
4306
4370
|
return null;
|
|
@@ -4320,7 +4384,7 @@ class PraxisCrudComponent {
|
|
|
4320
4384
|
}
|
|
4321
4385
|
resolveDiscoveryApiEntry() {
|
|
4322
4386
|
try {
|
|
4323
|
-
return this.
|
|
4387
|
+
return this.getResourceDiscovery().resolveApiEntry(this.buildDiscoveryOptions());
|
|
4324
4388
|
}
|
|
4325
4389
|
catch {
|
|
4326
4390
|
return null;
|
|
@@ -4380,8 +4444,8 @@ class PraxisCrudComponent {
|
|
|
4380
4444
|
return fallback;
|
|
4381
4445
|
}
|
|
4382
4446
|
}
|
|
4383
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4384
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
4447
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4448
|
+
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", context: "context", enableCustomization: "enableCustomization" }, outputs: { configureRequested: "configureRequested", afterOpen: "afterOpen", afterClose: "afterClose", afterSave: "afterSave", afterDelete: "afterDelete", error: "error", rowClick: "rowClick", selectionChange: "selectionChange", tableRuntimeConfigChange: "tableRuntimeConfigChange", crudAuthoringDocumentApplied: "crudAuthoringDocumentApplied", crudAuthoringDocumentSaved: "crudAuthoringDocumentSaved" }, providers: [
|
|
4385
4449
|
providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
|
|
4386
4450
|
providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
|
|
4387
4451
|
], viewQueries: [{ propertyName: "table", first: true, predicate: PraxisTable, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
@@ -4395,6 +4459,8 @@ class PraxisCrudComponent {
|
|
|
4395
4459
|
[tableId]="crudId || 'default'"
|
|
4396
4460
|
[crudContext]="tableCrudContext"
|
|
4397
4461
|
[enableCustomization]="enableCustomization"
|
|
4462
|
+
(rowClick)="onTableRowClick($event)"
|
|
4463
|
+
(selectionChange)="onTableSelectionChange($event)"
|
|
4398
4464
|
(rowAction)="onAction($event.action, $event.row, $event)"
|
|
4399
4465
|
(toolbarAction)="onAction($event.action)"
|
|
4400
4466
|
(collectionLinksChange)="onCollectionLinksChange($event)"
|
|
@@ -4412,9 +4478,9 @@ class PraxisCrudComponent {
|
|
|
4412
4478
|
/>
|
|
4413
4479
|
}
|
|
4414
4480
|
}
|
|
4415
|
-
`, 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", "title", "subtitle", "icon", "autoDelete", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "crudContext", "filterCriteria", "queryContext", "enableCustomization", "dense"], outputs: ["rowClick", "rowDoubleClick", "rowExpansionChange", "rowAction", "toolbarAction", "bulkAction", "columnReorder", "columnReorderAttempt", "beforeDelete", "afterDelete", "deleteError", "beforeBulkDelete", "afterBulkDelete", "bulkDeleteError", "schemaStatusChange", "metadataChange", "loadingStateChange", "collectionLinksChange", "selectionChange"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }] });
|
|
4481
|
+
`, 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", "title", "subtitle", "icon", "autoDelete", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "crudContext", "filterCriteria", "queryContext", "aiContext", "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"] }] });
|
|
4416
4482
|
}
|
|
4417
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4483
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, decorators: [{
|
|
4418
4484
|
type: Component,
|
|
4419
4485
|
args: [{ selector: 'praxis-crud', standalone: true, imports: [PraxisTable, EmptyStateCardComponent], providers: [
|
|
4420
4486
|
providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
|
|
@@ -4430,6 +4496,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
4430
4496
|
[tableId]="crudId || 'default'"
|
|
4431
4497
|
[crudContext]="tableCrudContext"
|
|
4432
4498
|
[enableCustomization]="enableCustomization"
|
|
4499
|
+
(rowClick)="onTableRowClick($event)"
|
|
4500
|
+
(selectionChange)="onTableSelectionChange($event)"
|
|
4433
4501
|
(rowAction)="onAction($event.action, $event.row, $event)"
|
|
4434
4502
|
(toolbarAction)="onAction($event.action)"
|
|
4435
4503
|
(collectionLinksChange)="onCollectionLinksChange($event)"
|
|
@@ -4472,6 +4540,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
4472
4540
|
type: Output
|
|
4473
4541
|
}], error: [{
|
|
4474
4542
|
type: Output
|
|
4543
|
+
}], rowClick: [{
|
|
4544
|
+
type: Output
|
|
4545
|
+
}], selectionChange: [{
|
|
4546
|
+
type: Output
|
|
4475
4547
|
}], tableRuntimeConfigChange: [{
|
|
4476
4548
|
type: Output
|
|
4477
4549
|
}], crudAuthoringDocumentApplied: [{
|
|
@@ -4780,8 +4852,8 @@ class DynamicFormDialogHostComponent {
|
|
|
4780
4852
|
this.dialogRef.updatePosition();
|
|
4781
4853
|
}
|
|
4782
4854
|
}
|
|
4783
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4784
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
4855
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, deps: [{ token: MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: DialogService }, { token: i2$1.GenericCrudService }, { token: ASYNC_CONFIG_STORAGE }], target: i0.ɵɵFactoryTarget.Component });
|
|
4856
|
+
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\"" }, classAttribute: "praxis-dialog" }, providers: [GenericCrudService], viewQueries: [{ propertyName: "formComp", first: true, predicate: PraxisDynamicForm, descendants: true }], ngImport: i0, template: `
|
|
4785
4857
|
<div mat-dialog-title class="dialog-header">
|
|
4786
4858
|
<h2 id="crudDialogTitle" class="dialog-title">
|
|
4787
4859
|
{{ data.action?.label || texts.title }}
|
|
@@ -4830,17 +4902,16 @@ class DynamicFormDialogHostComponent {
|
|
|
4830
4902
|
(formCancel)="onCancel()"
|
|
4831
4903
|
></praxis-dynamic-form>
|
|
4832
4904
|
</mat-dialog-content>
|
|
4833
|
-
`, 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:
|
|
4905
|
+
`, 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: i5$1.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", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "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"] }] });
|
|
4834
4906
|
}
|
|
4835
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4907
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
|
|
4836
4908
|
type: Component,
|
|
4837
4909
|
args: [{ selector: 'praxis-dynamic-form-dialog-host', standalone: true, imports: [
|
|
4838
|
-
CommonModule,
|
|
4839
4910
|
MatDialogModule,
|
|
4840
4911
|
MatButtonModule,
|
|
4841
4912
|
MatIconModule,
|
|
4842
4913
|
PraxisIconDirective,
|
|
4843
|
-
PraxisDynamicForm
|
|
4914
|
+
PraxisDynamicForm
|
|
4844
4915
|
], providers: [GenericCrudService], host: {
|
|
4845
4916
|
class: 'praxis-dialog',
|
|
4846
4917
|
'[attr.data-density]': 'modal.density || "default"',
|
|
@@ -4936,6 +5007,102 @@ var dynamicFormDialogHost_component = /*#__PURE__*/Object.freeze({
|
|
|
4936
5007
|
DynamicFormDialogHostComponent: DynamicFormDialogHostComponent
|
|
4937
5008
|
});
|
|
4938
5009
|
|
|
5010
|
+
class PraxisCrudWidgetConfigEditor {
|
|
5011
|
+
inputs = null;
|
|
5012
|
+
widgetKey;
|
|
5013
|
+
crudEditor;
|
|
5014
|
+
isDirty$ = new BehaviorSubject(false);
|
|
5015
|
+
isValid$ = new BehaviorSubject(true);
|
|
5016
|
+
isBusy$ = new BehaviorSubject(false);
|
|
5017
|
+
subscription = new Subscription();
|
|
5018
|
+
ngAfterViewInit() {
|
|
5019
|
+
if (!this.crudEditor) {
|
|
5020
|
+
return;
|
|
5021
|
+
}
|
|
5022
|
+
this.subscription.add(this.crudEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
|
|
5023
|
+
this.subscription.add(this.crudEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
|
|
5024
|
+
this.subscription.add(this.crudEditor.isBusy$.subscribe((value) => this.isBusy$.next(value)));
|
|
5025
|
+
}
|
|
5026
|
+
ngOnDestroy() {
|
|
5027
|
+
this.subscription.unsubscribe();
|
|
5028
|
+
}
|
|
5029
|
+
get metadata() {
|
|
5030
|
+
return this.createDocumentFromInputs().metadata;
|
|
5031
|
+
}
|
|
5032
|
+
get effectiveCrudId() {
|
|
5033
|
+
return this.inputs?.crudId ?? this.widgetKey ?? null;
|
|
5034
|
+
}
|
|
5035
|
+
getSettingsValue() {
|
|
5036
|
+
return this.buildValue(this.crudEditor?.getSettingsValue());
|
|
5037
|
+
}
|
|
5038
|
+
onSave() {
|
|
5039
|
+
return this.buildValue(this.crudEditor?.onSave?.() ?? this.crudEditor?.getSettingsValue());
|
|
5040
|
+
}
|
|
5041
|
+
reset() {
|
|
5042
|
+
this.crudEditor?.reset?.();
|
|
5043
|
+
}
|
|
5044
|
+
buildValue(rawPayload) {
|
|
5045
|
+
const document = this.extractDocument(rawPayload);
|
|
5046
|
+
return {
|
|
5047
|
+
inputs: {
|
|
5048
|
+
...(this.inputs ?? {}),
|
|
5049
|
+
metadata: document.metadata,
|
|
5050
|
+
crudId: this.inputs?.crudId ?? this.widgetKey,
|
|
5051
|
+
componentInstanceId: this.inputs?.componentInstanceId ?? this.widgetKey,
|
|
5052
|
+
context: this.inputs?.context,
|
|
5053
|
+
enableCustomization: this.inputs?.enableCustomization ?? false,
|
|
5054
|
+
},
|
|
5055
|
+
};
|
|
5056
|
+
}
|
|
5057
|
+
createDocumentFromInputs() {
|
|
5058
|
+
return parseLegacyOrCrudDocument(this.inputs?.metadata ?? {
|
|
5059
|
+
component: 'praxis-crud',
|
|
5060
|
+
table: { columns: [] },
|
|
5061
|
+
});
|
|
5062
|
+
}
|
|
5063
|
+
extractDocument(rawPayload) {
|
|
5064
|
+
const payload = rawPayload;
|
|
5065
|
+
return parseLegacyOrCrudDocument(payload?.document ??
|
|
5066
|
+
payload?.metadata ??
|
|
5067
|
+
serializeCrudAuthoringDocument(this.createDocumentFromInputs()));
|
|
5068
|
+
}
|
|
5069
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudWidgetConfigEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5070
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PraxisCrudWidgetConfigEditor, isStandalone: true, selector: "praxis-crud-widget-config-editor", inputs: { inputs: "inputs", widgetKey: "widgetKey" }, viewQueries: [{ propertyName: "crudEditor", first: true, predicate: ["crudEditor"], descendants: true }], ngImport: i0, template: `
|
|
5071
|
+
<section data-testid="crud-widget-config-editor">
|
|
5072
|
+
<praxis-crud-metadata-editor
|
|
5073
|
+
#crudEditor
|
|
5074
|
+
[metadata]="metadata"
|
|
5075
|
+
[crudId]="effectiveCrudId"
|
|
5076
|
+
/>
|
|
5077
|
+
</section>
|
|
5078
|
+
`, isInline: true, dependencies: [{ kind: "component", type: CrudMetadataEditorComponent, selector: "praxis-crud-metadata-editor", inputs: ["document", "metadata", "crudId", "readonly"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5079
|
+
}
|
|
5080
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudWidgetConfigEditor, decorators: [{
|
|
5081
|
+
type: Component,
|
|
5082
|
+
args: [{
|
|
5083
|
+
selector: 'praxis-crud-widget-config-editor',
|
|
5084
|
+
standalone: true,
|
|
5085
|
+
imports: [CrudMetadataEditorComponent],
|
|
5086
|
+
template: `
|
|
5087
|
+
<section data-testid="crud-widget-config-editor">
|
|
5088
|
+
<praxis-crud-metadata-editor
|
|
5089
|
+
#crudEditor
|
|
5090
|
+
[metadata]="metadata"
|
|
5091
|
+
[crudId]="effectiveCrudId"
|
|
5092
|
+
/>
|
|
5093
|
+
</section>
|
|
5094
|
+
`,
|
|
5095
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
5096
|
+
}]
|
|
5097
|
+
}], propDecorators: { inputs: [{
|
|
5098
|
+
type: Input
|
|
5099
|
+
}], widgetKey: [{
|
|
5100
|
+
type: Input
|
|
5101
|
+
}], crudEditor: [{
|
|
5102
|
+
type: ViewChild,
|
|
5103
|
+
args: ['crudEditor']
|
|
5104
|
+
}] } });
|
|
5105
|
+
|
|
4939
5106
|
/** Metadata for PraxisCrudComponent */
|
|
4940
5107
|
const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
4941
5108
|
id: 'praxis-crud',
|
|
@@ -4944,6 +5111,14 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
|
4944
5111
|
friendlyName: 'Praxis CRUD',
|
|
4945
5112
|
description: 'Tabela com operações de CRUD via metadados.',
|
|
4946
5113
|
icon: 'table_chart',
|
|
5114
|
+
authoringManifestRef: {
|
|
5115
|
+
componentId: 'praxis-crud',
|
|
5116
|
+
source: 'PRAXIS_CRUD_AUTHORING_MANIFEST',
|
|
5117
|
+
},
|
|
5118
|
+
configEditor: {
|
|
5119
|
+
component: PraxisCrudWidgetConfigEditor,
|
|
5120
|
+
title: 'Configurar CRUD',
|
|
5121
|
+
},
|
|
4947
5122
|
inputs: [
|
|
4948
5123
|
{
|
|
4949
5124
|
name: 'metadata',
|
|
@@ -5008,6 +5183,16 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
|
5008
5183
|
type: '{ id: string | number }',
|
|
5009
5184
|
description: 'Emitido ao deletar.',
|
|
5010
5185
|
},
|
|
5186
|
+
{
|
|
5187
|
+
name: 'rowClick',
|
|
5188
|
+
type: '{ row: unknown; index: number }',
|
|
5189
|
+
description: 'Encaminha o clique de linha da tabela interna para composição master-detail e seleção local.',
|
|
5190
|
+
},
|
|
5191
|
+
{
|
|
5192
|
+
name: 'selectionChange',
|
|
5193
|
+
type: 'unknown',
|
|
5194
|
+
description: 'Encaminha a mudança de seleção da tabela interna quando o CRUD é usado como widget composto.',
|
|
5195
|
+
},
|
|
5011
5196
|
{
|
|
5012
5197
|
name: 'error',
|
|
5013
5198
|
type: 'unknown',
|
|
@@ -5114,6 +5299,23 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
|
5114
5299
|
},
|
|
5115
5300
|
scope: 'shell',
|
|
5116
5301
|
},
|
|
5302
|
+
{
|
|
5303
|
+
id: 'row-click',
|
|
5304
|
+
label: 'Clique em linha',
|
|
5305
|
+
icon: 'ads_click',
|
|
5306
|
+
description: 'Emite evento ao clicar em uma linha da tabela interna do CRUD.',
|
|
5307
|
+
emit: 'rowClick',
|
|
5308
|
+
payloadSchema: {
|
|
5309
|
+
type: 'object',
|
|
5310
|
+
properties: {
|
|
5311
|
+
row: { type: 'object', description: 'Registro clicado.' },
|
|
5312
|
+
index: { type: 'number', description: 'Índice da linha.' },
|
|
5313
|
+
},
|
|
5314
|
+
required: ['row'],
|
|
5315
|
+
example: { row: {}, index: 0 },
|
|
5316
|
+
},
|
|
5317
|
+
scope: 'context',
|
|
5318
|
+
},
|
|
5117
5319
|
{
|
|
5118
5320
|
id: 'close',
|
|
5119
5321
|
label: 'Fechar',
|
|
@@ -5154,64 +5356,66 @@ class CrudPageHeaderComponent {
|
|
|
5154
5356
|
sticky = true;
|
|
5155
5357
|
divider = true;
|
|
5156
5358
|
returnTo;
|
|
5157
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5158
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
5359
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudPageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5360
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CrudPageHeaderComponent, isStandalone: true, selector: "praxis-crud-page-header", inputs: { title: "title", backLabel: "backLabel", showBack: "showBack", variant: "variant", sticky: "sticky", divider: "divider", returnTo: "returnTo" }, ngImport: i0, template: `
|
|
5159
5361
|
<header
|
|
5160
5362
|
class="crud-header"
|
|
5161
5363
|
[class.sticky]="sticky"
|
|
5162
5364
|
[class.with-divider]="divider"
|
|
5163
|
-
|
|
5365
|
+
>
|
|
5164
5366
|
<div class="left">
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5367
|
+
@if (showBack && returnTo) {
|
|
5368
|
+
<a
|
|
5369
|
+
class="back-btn"
|
|
5370
|
+
[class.ghost]="variant === 'ghost'"
|
|
5371
|
+
[class.tonal]="variant === 'tonal'"
|
|
5372
|
+
[class.outlined]="variant === 'outlined'"
|
|
5373
|
+
[routerLink]="returnTo"
|
|
5374
|
+
[attr.aria-label]="backLabel || 'Voltar'"
|
|
5375
|
+
mat-button
|
|
5376
|
+
>
|
|
5377
|
+
<mat-icon [praxisIcon]="'arrow_back'"></mat-icon>
|
|
5378
|
+
<span class="label" [class.hide-on-narrow]="true">{{ backLabel || 'Voltar' }}</span>
|
|
5379
|
+
</a>
|
|
5380
|
+
}
|
|
5178
5381
|
<h2 class="title" [attr.title]="title">{{ title }}</h2>
|
|
5179
5382
|
</div>
|
|
5180
5383
|
<div class="right">
|
|
5181
5384
|
<ng-content></ng-content>
|
|
5182
5385
|
</div>
|
|
5183
5386
|
</header>
|
|
5184
|
-
|
|
5387
|
+
`, isInline: true, styles: [".crud-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 0;background:var(--md-sys-color-surface)}.crud-header.sticky{position:sticky;top:0;z-index:10;-webkit-backdrop-filter:saturate(110%);backdrop-filter:saturate(110%)}.crud-header.with-divider{border-bottom:1px solid var(--md-sys-color-outline-variant)}.left{display:flex;align-items:center;gap:8px;min-width:0}.right{display:flex;align-items:center;gap:8px}.title{margin:0;font-weight:600;color:var(--md-sys-color-on-surface, currentColor);font:var(--mdc-typography-title-large, 600 20px/28px system-ui);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.back-btn{display:inline-flex;align-items:center;gap:6px;text-decoration:none}.back-btn .mat-mdc-button{padding-left:0}.back-btn mat-icon{color:var(--md-sys-color-on-surface-variant, currentColor)}.back-btn .label{color:var(--md-sys-color-on-surface-variant, currentColor)}.back-btn.ghost{border-radius:20px;padding:4px 8px}.back-btn.ghost:hover{background:var(--md-sys-color-primary-container)}.back-btn.tonal{border-radius:20px;padding:4px 10px;background:var(--md-sys-color-surface-container);box-shadow:inset 0 0 0 1px var(--md-sys-color-outline-variant)}.back-btn.tonal:hover{background:var(--md-sys-color-primary-container)}.back-btn.outlined{border-radius:20px;padding:4px 10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.back-btn.outlined:hover{border-color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}@media(max-width:599px){.label.hide-on-narrow{display:none}}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
|
|
5185
5388
|
}
|
|
5186
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5389
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudPageHeaderComponent, decorators: [{
|
|
5187
5390
|
type: Component,
|
|
5188
|
-
args: [{ selector: 'praxis-crud-page-header', standalone: true, imports: [
|
|
5391
|
+
args: [{ selector: 'praxis-crud-page-header', standalone: true, imports: [RouterLink, MatButtonModule, MatIconModule, PraxisIconDirective], template: `
|
|
5189
5392
|
<header
|
|
5190
5393
|
class="crud-header"
|
|
5191
5394
|
[class.sticky]="sticky"
|
|
5192
5395
|
[class.with-divider]="divider"
|
|
5193
|
-
|
|
5396
|
+
>
|
|
5194
5397
|
<div class="left">
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5398
|
+
@if (showBack && returnTo) {
|
|
5399
|
+
<a
|
|
5400
|
+
class="back-btn"
|
|
5401
|
+
[class.ghost]="variant === 'ghost'"
|
|
5402
|
+
[class.tonal]="variant === 'tonal'"
|
|
5403
|
+
[class.outlined]="variant === 'outlined'"
|
|
5404
|
+
[routerLink]="returnTo"
|
|
5405
|
+
[attr.aria-label]="backLabel || 'Voltar'"
|
|
5406
|
+
mat-button
|
|
5407
|
+
>
|
|
5408
|
+
<mat-icon [praxisIcon]="'arrow_back'"></mat-icon>
|
|
5409
|
+
<span class="label" [class.hide-on-narrow]="true">{{ backLabel || 'Voltar' }}</span>
|
|
5410
|
+
</a>
|
|
5411
|
+
}
|
|
5208
5412
|
<h2 class="title" [attr.title]="title">{{ title }}</h2>
|
|
5209
5413
|
</div>
|
|
5210
5414
|
<div class="right">
|
|
5211
5415
|
<ng-content></ng-content>
|
|
5212
5416
|
</div>
|
|
5213
5417
|
</header>
|
|
5214
|
-
|
|
5418
|
+
`, styles: [".crud-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 0;background:var(--md-sys-color-surface)}.crud-header.sticky{position:sticky;top:0;z-index:10;-webkit-backdrop-filter:saturate(110%);backdrop-filter:saturate(110%)}.crud-header.with-divider{border-bottom:1px solid var(--md-sys-color-outline-variant)}.left{display:flex;align-items:center;gap:8px;min-width:0}.right{display:flex;align-items:center;gap:8px}.title{margin:0;font-weight:600;color:var(--md-sys-color-on-surface, currentColor);font:var(--mdc-typography-title-large, 600 20px/28px system-ui);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.back-btn{display:inline-flex;align-items:center;gap:6px;text-decoration:none}.back-btn .mat-mdc-button{padding-left:0}.back-btn mat-icon{color:var(--md-sys-color-on-surface-variant, currentColor)}.back-btn .label{color:var(--md-sys-color-on-surface-variant, currentColor)}.back-btn.ghost{border-radius:20px;padding:4px 8px}.back-btn.ghost:hover{background:var(--md-sys-color-primary-container)}.back-btn.tonal{border-radius:20px;padding:4px 10px;background:var(--md-sys-color-surface-container);box-shadow:inset 0 0 0 1px var(--md-sys-color-outline-variant)}.back-btn.tonal:hover{background:var(--md-sys-color-primary-container)}.back-btn.outlined{border-radius:20px;padding:4px 10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.back-btn.outlined:hover{border-color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container)}@media(max-width:599px){.label.hide-on-narrow{display:none}}\n"] }]
|
|
5215
5419
|
}], propDecorators: { title: [{
|
|
5216
5420
|
type: Input
|
|
5217
5421
|
}], backLabel: [{
|
|
@@ -5263,6 +5467,12 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5263
5467
|
{ path: 'resource.path', category: 'resource', valueKind: 'string', description: 'Endpoint base do recurso.' },
|
|
5264
5468
|
{ path: 'resource.idField', category: 'resource', valueKind: 'string', description: 'Campo identificador do recurso.' },
|
|
5265
5469
|
{ path: 'resource.endpointKey', category: 'resource', valueKind: 'string', description: 'Chave de endpoint (ApiEndpoint).' },
|
|
5470
|
+
{ path: 'queryContext.meta.domainCatalog', category: 'resource', valueKind: 'object', description: 'Referencia leve para contexto semantico/governanca resolvido via Domain Catalog; nao materializa regras em FormConfig.' },
|
|
5471
|
+
{ path: 'queryContext.meta.domainCatalog.schemaVersion', category: 'resource', valueKind: 'string', description: 'Versao do contrato DomainCatalogContextHint usado em runtime e prompts.' },
|
|
5472
|
+
{ path: 'queryContext.meta.domainCatalog.resourceKey', category: 'resource', valueKind: 'string', description: 'ResourceKey semantico estavel usado para resolver vocabulario/governanca de dominio.' },
|
|
5473
|
+
{ path: 'queryContext.meta.domainCatalog.releaseId', category: 'resource', valueKind: 'string', description: 'Release opcional do Domain Catalog usada como fonte do contexto.' },
|
|
5474
|
+
{ path: 'queryContext.meta.domainCatalog.query', category: 'resource', valueKind: 'string', description: 'Probe de campo/conceito usado para buscar itens relevantes, como cpf, salario ou status.' },
|
|
5475
|
+
{ path: 'queryContext.meta.domainCatalog.intent', category: 'resource', valueKind: 'enum', allowedValues: ['authoring', 'explain', 'validate', 'ai-access-control'], description: 'Intencao de uso do contexto para orientar LLMs e validadores sem expor dados alem do necessario.' },
|
|
5266
5476
|
// --- Table / Form ---
|
|
5267
5477
|
{ path: 'table', category: 'table', valueKind: 'object', description: 'TableConfig completo (usar catalogo de tabela).' },
|
|
5268
5478
|
{ path: 'form', category: 'form', valueKind: 'object', description: 'FormConfig completo (usar catalogo de formulario).' },
|
|
@@ -5319,6 +5529,438 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5319
5529
|
],
|
|
5320
5530
|
};
|
|
5321
5531
|
|
|
5532
|
+
const resourceBindSchema = {
|
|
5533
|
+
type: 'object',
|
|
5534
|
+
required: ['resourcePath'],
|
|
5535
|
+
properties: {
|
|
5536
|
+
resourcePath: { type: 'string' },
|
|
5537
|
+
resourceKey: { type: 'string' },
|
|
5538
|
+
idField: { type: ['string', 'number'] },
|
|
5539
|
+
endpointKey: { type: 'string' },
|
|
5540
|
+
queryContext: { type: 'object' },
|
|
5541
|
+
},
|
|
5542
|
+
};
|
|
5543
|
+
const surfaceConfigureSchema = {
|
|
5544
|
+
type: 'object',
|
|
5545
|
+
required: ['actionId', 'openMode'],
|
|
5546
|
+
properties: {
|
|
5547
|
+
actionId: { enum: ['create', 'edit', 'view'] },
|
|
5548
|
+
openMode: { enum: ['route', 'modal', 'drawer'] },
|
|
5549
|
+
route: { type: 'string' },
|
|
5550
|
+
formId: { type: 'string' },
|
|
5551
|
+
form: {
|
|
5552
|
+
type: 'object',
|
|
5553
|
+
properties: {
|
|
5554
|
+
schemaUrl: { type: 'string' },
|
|
5555
|
+
submitUrl: { type: 'string' },
|
|
5556
|
+
submitMethod: { enum: ['post', 'put', 'patch', 'delete'] },
|
|
5557
|
+
apiEndpointKey: { type: 'string' },
|
|
5558
|
+
initialValue: { type: 'object' },
|
|
5559
|
+
},
|
|
5560
|
+
},
|
|
5561
|
+
params: {
|
|
5562
|
+
type: 'array',
|
|
5563
|
+
items: {
|
|
5564
|
+
type: 'object',
|
|
5565
|
+
required: ['from', 'to', 'name'],
|
|
5566
|
+
properties: {
|
|
5567
|
+
from: { type: 'string' },
|
|
5568
|
+
to: { enum: ['routeParam', 'query', 'input'] },
|
|
5569
|
+
name: { type: 'string' },
|
|
5570
|
+
},
|
|
5571
|
+
},
|
|
5572
|
+
},
|
|
5573
|
+
back: { type: 'object' },
|
|
5574
|
+
},
|
|
5575
|
+
};
|
|
5576
|
+
const listSurfaceSchema = {
|
|
5577
|
+
type: 'object',
|
|
5578
|
+
properties: {
|
|
5579
|
+
tablePatch: { type: 'object' },
|
|
5580
|
+
queryContext: { type: 'object' },
|
|
5581
|
+
filterCriteria: { type: 'object' },
|
|
5582
|
+
},
|
|
5583
|
+
};
|
|
5584
|
+
const deleteBehaviorSchema = {
|
|
5585
|
+
type: 'object',
|
|
5586
|
+
required: ['enabled'],
|
|
5587
|
+
properties: {
|
|
5588
|
+
enabled: { type: 'boolean' },
|
|
5589
|
+
actionId: { type: 'string' },
|
|
5590
|
+
requiresConfirmation: { type: 'boolean' },
|
|
5591
|
+
autoDelete: { type: 'boolean' },
|
|
5592
|
+
form: {
|
|
5593
|
+
type: 'object',
|
|
5594
|
+
properties: {
|
|
5595
|
+
submitUrl: { type: 'string' },
|
|
5596
|
+
submitMethod: { enum: ['delete'] },
|
|
5597
|
+
apiEndpointKey: { type: 'string' },
|
|
5598
|
+
},
|
|
5599
|
+
},
|
|
5600
|
+
},
|
|
5601
|
+
};
|
|
5602
|
+
const dialogHostSchema = {
|
|
5603
|
+
type: 'object',
|
|
5604
|
+
properties: {
|
|
5605
|
+
defaultOpenMode: { enum: ['route', 'modal', 'drawer'] },
|
|
5606
|
+
modal: {
|
|
5607
|
+
type: 'object',
|
|
5608
|
+
properties: {
|
|
5609
|
+
width: { type: 'string' },
|
|
5610
|
+
height: { type: 'string' },
|
|
5611
|
+
minWidth: { type: 'string' },
|
|
5612
|
+
maxWidth: { type: 'string' },
|
|
5613
|
+
density: { type: 'string' },
|
|
5614
|
+
canMaximize: { type: 'boolean' },
|
|
5615
|
+
rememberLastState: { type: 'boolean' },
|
|
5616
|
+
startMaximized: { type: 'boolean' },
|
|
5617
|
+
disableCloseOnEsc: { type: 'boolean' },
|
|
5618
|
+
disableCloseOnBackdrop: { type: 'boolean' },
|
|
5619
|
+
fullscreenBreakpoint: { type: 'string' },
|
|
5620
|
+
},
|
|
5621
|
+
},
|
|
5622
|
+
back: { type: 'object' },
|
|
5623
|
+
},
|
|
5624
|
+
};
|
|
5625
|
+
const permissionsSchema = {
|
|
5626
|
+
type: 'object',
|
|
5627
|
+
properties: {
|
|
5628
|
+
requiredCapabilities: {
|
|
5629
|
+
type: 'array',
|
|
5630
|
+
items: { enum: ['create', 'view', 'edit', 'delete'] },
|
|
5631
|
+
},
|
|
5632
|
+
actionPermissions: { type: 'object' },
|
|
5633
|
+
denyWhenMissingCapability: { type: 'boolean' },
|
|
5634
|
+
},
|
|
5635
|
+
};
|
|
5636
|
+
const domainGovernanceContextSchema = {
|
|
5637
|
+
type: 'object',
|
|
5638
|
+
required: ['resourceKey', 'query'],
|
|
5639
|
+
properties: {
|
|
5640
|
+
resourceKey: { type: 'string' },
|
|
5641
|
+
releaseId: { type: 'string' },
|
|
5642
|
+
query: { type: 'string' },
|
|
5643
|
+
itemTypes: {
|
|
5644
|
+
type: 'array',
|
|
5645
|
+
items: { enum: ['governance', 'vocabulary', 'relationship'] },
|
|
5646
|
+
},
|
|
5647
|
+
intent: { enum: ['authoring', 'explain', 'validate', 'ai-access-control'] },
|
|
5648
|
+
},
|
|
5649
|
+
};
|
|
5650
|
+
const childDelegateSchema = {
|
|
5651
|
+
type: 'object',
|
|
5652
|
+
required: ['childComponentId', 'childOperationId', 'reason'],
|
|
5653
|
+
properties: {
|
|
5654
|
+
childComponentId: { enum: ['praxis-dynamic-form', 'praxis-table', 'praxis-dialog', 'praxis-settings-panel'] },
|
|
5655
|
+
childOperationId: { type: 'string' },
|
|
5656
|
+
reason: { type: 'string' },
|
|
5657
|
+
childTarget: { type: 'object' },
|
|
5658
|
+
childParams: { type: 'object' },
|
|
5659
|
+
},
|
|
5660
|
+
};
|
|
5661
|
+
const PRAXIS_CRUD_AUTHORING_MANIFEST = {
|
|
5662
|
+
schemaVersion: '1.0.0',
|
|
5663
|
+
componentId: 'praxis-crud',
|
|
5664
|
+
ownerPackage: '@praxisui/crud',
|
|
5665
|
+
configSchemaId: 'CrudMetadata',
|
|
5666
|
+
manifestVersion: '1.0.0',
|
|
5667
|
+
runtimeInputs: [
|
|
5668
|
+
{ name: 'metadata', type: 'CrudMetadata | string', description: 'Canonical CRUD metadata or serialized metadata document.' },
|
|
5669
|
+
{ name: 'crudId', type: 'string', description: 'Stable CRUD instance id used for table/form identity and persistence.' },
|
|
5670
|
+
{ name: 'componentInstanceId', type: 'string', description: 'Optional stable host instance id for multiple CRUD widgets on the same route.' },
|
|
5671
|
+
{ name: 'context', type: 'Record<string, unknown>', description: 'Opaque host context used for authoring seeds and launcher inputs.' },
|
|
5672
|
+
{ name: 'afterOpen', type: '{ mode: FormOpenMode; action: string }', description: 'Emitted after a CRUD action opens.' },
|
|
5673
|
+
{ name: 'afterSave', type: '{ id: string | number; data: unknown }', description: 'Emitted after save; CRUD refetches the list.' },
|
|
5674
|
+
{ name: 'afterDelete', type: '{ id: string | number }', description: 'Emitted after delete; CRUD refetches the list.' },
|
|
5675
|
+
],
|
|
5676
|
+
editableTargets: [
|
|
5677
|
+
{ kind: 'resourceBinding', resolver: 'crud-resource-by-path-or-key', description: 'Resource path/key, id field, endpoint key and query context owned by CRUD orchestration.' },
|
|
5678
|
+
{ kind: 'listSurface', resolver: 'crud-list-surface', description: 'CRUD-hosted list surface and table delegation boundary.' },
|
|
5679
|
+
{ kind: 'createSurface', resolver: 'crud-action-by-id:create', description: 'Create action open mode, route/form binding and launcher inputs.' },
|
|
5680
|
+
{ kind: 'editSurface', resolver: 'crud-action-by-id:edit', description: 'Edit action open mode, route/form binding and launcher inputs.' },
|
|
5681
|
+
{ kind: 'viewSurface', resolver: 'crud-action-by-id:view', description: 'View action open mode, route/form binding and launcher inputs.' },
|
|
5682
|
+
{ kind: 'deleteBehavior', resolver: 'crud-action-by-id:delete', description: 'Delete action enablement, confirmation, endpoint and capability policy.' },
|
|
5683
|
+
{ kind: 'dialogHost', resolver: 'crud-dialog-host-defaults', description: 'Route/modal/drawer defaults consumed by CrudLauncherService and DynamicFormDialogHostComponent.' },
|
|
5684
|
+
{ kind: 'formBinding', resolver: 'crud-action-form-contract-by-action-id', description: 'CRUD-owned form binding fields: formId, schemaUrl, submitUrl, submitMethod, params and initialValue.' },
|
|
5685
|
+
{ kind: 'permissions', resolver: 'crud-resource-capabilities', description: 'CRUD action availability derived from resource capabilities and action permissions.' },
|
|
5686
|
+
{ kind: 'domainGovernanceContext', resolver: 'domain-catalog-context-by-resource-key', description: 'Read-only semantic/governance context resolved from Domain Catalog and referenced from CRUD queryContext.meta.' },
|
|
5687
|
+
{ kind: 'childOperation', resolver: 'child-authoring-manifest-operation', description: 'Delegated form/table/dialog/settings-panel operation owned by the child component manifest.' },
|
|
5688
|
+
],
|
|
5689
|
+
operations: [
|
|
5690
|
+
{
|
|
5691
|
+
operationId: 'resource.bind',
|
|
5692
|
+
title: 'Bind CRUD resource',
|
|
5693
|
+
scope: 'dataBinding',
|
|
5694
|
+
targetKind: 'resourceBinding',
|
|
5695
|
+
target: { kind: 'resourceBinding', resolver: 'crud-resource-by-path-or-key', ambiguityPolicy: 'fail', required: true },
|
|
5696
|
+
inputSchema: resourceBindSchema,
|
|
5697
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-resource-bind', handlerContract: {
|
|
5698
|
+
reads: ['CrudMetadata.resource', 'api_metadata', 'ResourceDiscoveryService', 'GET /{resource}/capabilities'],
|
|
5699
|
+
writes: ['CrudMetadata.resource', 'CrudMetadata.queryContext', 'PraxisCrudComponent.tableCrudContext'],
|
|
5700
|
+
identityKeys: ['resourcePath', 'resourceKey'],
|
|
5701
|
+
inputSchema: resourceBindSchema,
|
|
5702
|
+
failureModes: ['resource-not-found', 'schema-url-not-canonical', 'capabilities-unavailable', 'id-field-missing'],
|
|
5703
|
+
description: 'Binds CRUD to a canonical resource and validates it against api_metadata/resource capabilities before runtime use.',
|
|
5704
|
+
} }],
|
|
5705
|
+
validators: ['resource-exists-in-api-metadata', 'resource-path-canonical', 'resource-key-stable', 'id-field-known', 'resource-capabilities-resolvable'],
|
|
5706
|
+
affectedPaths: ['resource.path', 'resource.idField', 'resource.endpointKey', 'queryContext', 'filterCriteria'],
|
|
5707
|
+
submissionImpact: 'affects-remote-binding',
|
|
5708
|
+
preconditions: ['crud-metadata-loaded', 'api-metadata-available'],
|
|
5709
|
+
},
|
|
5710
|
+
{
|
|
5711
|
+
operationId: 'domain.governanceContext.attach',
|
|
5712
|
+
title: 'Attach Domain Catalog governance context',
|
|
5713
|
+
scope: 'dataBinding',
|
|
5714
|
+
targetKind: 'domainGovernanceContext',
|
|
5715
|
+
target: { kind: 'domainGovernanceContext', resolver: 'domain-catalog-context-by-resource-key', ambiguityPolicy: 'fail', required: true },
|
|
5716
|
+
inputSchema: domainGovernanceContextSchema,
|
|
5717
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-domain-governance-context-attach', handlerContract: {
|
|
5718
|
+
reads: ['CrudMetadata.resource', 'CrudMetadata.queryContext', 'DomainCatalogService.getGovernanceContext', 'DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK', 'api_metadata'],
|
|
5719
|
+
writes: ['CrudMetadata.queryContext.meta.domainCatalog'],
|
|
5720
|
+
identityKeys: ['resourceKey', 'releaseId', 'query'],
|
|
5721
|
+
inputSchema: domainGovernanceContextSchema,
|
|
5722
|
+
failureModes: ['resource-key-missing', 'domain-catalog-release-not-found', 'governance-context-empty', 'ai-usage-forbidden'],
|
|
5723
|
+
description: 'Resolves read-only domain vocabulary/governance context and stores only a lightweight reference/probe under queryContext.meta.domainCatalog.',
|
|
5724
|
+
} }],
|
|
5725
|
+
validators: ['resource-key-stable', 'domain-catalog-context-resolvable', 'domain-catalog-read-only', 'ai-usage-visibility-respected', 'no-form-config-rule-materialization'],
|
|
5726
|
+
affectedPaths: ['queryContext.meta.domainCatalog'],
|
|
5727
|
+
submissionImpact: 'config-only',
|
|
5728
|
+
preconditions: ['crud-metadata-loaded', 'api-metadata-available', 'domain-catalog-service-available'],
|
|
5729
|
+
},
|
|
5730
|
+
{
|
|
5731
|
+
operationId: 'list.surface.configure',
|
|
5732
|
+
title: 'Configure CRUD list surface',
|
|
5733
|
+
scope: 'interaction',
|
|
5734
|
+
targetKind: 'listSurface',
|
|
5735
|
+
target: { kind: 'listSurface', resolver: 'crud-list-surface', ambiguityPolicy: 'fail', required: true },
|
|
5736
|
+
inputSchema: listSurfaceSchema,
|
|
5737
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-list-surface-configure', handlerContract: {
|
|
5738
|
+
reads: ['CrudMetadata.table', 'CrudMetadata.queryContext', 'PRAXIS_TABLE_AUTHORING_MANIFEST', 'CRUD_AI_CAPABILITIES'],
|
|
5739
|
+
writes: ['CrudMetadata.table', 'CrudMetadata.queryContext', 'CrudMetadata.filterCriteria'],
|
|
5740
|
+
identityKeys: ['crudId'],
|
|
5741
|
+
inputSchema: listSurfaceSchema,
|
|
5742
|
+
failureModes: ['table-operation-not-delegated', 'table-patch-not-supported', 'query-context-invalid'],
|
|
5743
|
+
description: 'Configures CRUD-owned list orchestration while routing table semantics to the praxis-table manifest.',
|
|
5744
|
+
} }],
|
|
5745
|
+
validators: ['table-child-operation-delegated', 'query-context-valid', 'filter-criteria-bridge-valid', 'crud-context-stable'],
|
|
5746
|
+
affectedPaths: ['table', 'queryContext', 'filterCriteria'],
|
|
5747
|
+
submissionImpact: 'config-only',
|
|
5748
|
+
preconditions: ['crud-metadata-loaded', 'praxis-table-manifest-available'],
|
|
5749
|
+
},
|
|
5750
|
+
{
|
|
5751
|
+
operationId: 'surface.create.configure',
|
|
5752
|
+
title: 'Configure create surface',
|
|
5753
|
+
scope: 'interaction',
|
|
5754
|
+
targetKind: 'createSurface',
|
|
5755
|
+
target: { kind: 'createSurface', resolver: 'crud-action-by-id:create', ambiguityPolicy: 'fail', required: true },
|
|
5756
|
+
inputSchema: surfaceConfigureSchema,
|
|
5757
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-create-surface-configure', handlerContract: {
|
|
5758
|
+
reads: ['CrudMetadata.actions', 'CrudLauncherService.resolveOpenMode', 'DynamicFormDialogHostComponent', 'api_metadata'],
|
|
5759
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].form', 'CrudMetadata.actions[].params', 'CrudMetadata.actions[].back'],
|
|
5760
|
+
identityKeys: ['actionId'],
|
|
5761
|
+
inputSchema: surfaceConfigureSchema,
|
|
5762
|
+
failureModes: ['action-not-found', 'open-mode-binding-incomplete', 'schema-url-not-canonical', 'submit-url-not-canonical', 'resource-create-not-supported'],
|
|
5763
|
+
description: 'Configures create action binding and launcher inputs without editing the child FormConfig.',
|
|
5764
|
+
} }],
|
|
5765
|
+
validators: ['action-exists', 'open-mode-binding-complete', 'schema-url-canonical', 'submit-url-canonical', 'resource-create-supported', 'form-child-operation-delegated'],
|
|
5766
|
+
affectedPaths: ['actions[].openMode', 'actions[].route', 'actions[].formId', 'actions[].form', 'actions[].params', 'actions[].back'],
|
|
5767
|
+
submissionImpact: 'affects-schema-backed-data',
|
|
5768
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5769
|
+
},
|
|
5770
|
+
{
|
|
5771
|
+
operationId: 'surface.edit.configure',
|
|
5772
|
+
title: 'Configure edit surface',
|
|
5773
|
+
scope: 'interaction',
|
|
5774
|
+
targetKind: 'editSurface',
|
|
5775
|
+
target: { kind: 'editSurface', resolver: 'crud-action-by-id:edit', ambiguityPolicy: 'fail', required: true },
|
|
5776
|
+
inputSchema: surfaceConfigureSchema,
|
|
5777
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-edit-surface-configure', handlerContract: {
|
|
5778
|
+
reads: ['CrudMetadata.actions', 'CrudMetadata.resource.idField', 'CrudLauncherService.resolveOpenMode', 'api_metadata'],
|
|
5779
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].form', 'CrudMetadata.actions[].params', 'CrudMetadata.actions[].back'],
|
|
5780
|
+
identityKeys: ['actionId'],
|
|
5781
|
+
inputSchema: surfaceConfigureSchema,
|
|
5782
|
+
failureModes: ['action-not-found', 'id-param-missing', 'open-mode-binding-incomplete', 'resource-edit-not-supported', 'submit-url-not-canonical'],
|
|
5783
|
+
description: 'Configures edit action routing/form binding and ensures id parameter mapping is available to the launcher.',
|
|
5784
|
+
} }],
|
|
5785
|
+
validators: ['action-exists', 'id-field-known', 'id-param-mapping-valid', 'open-mode-binding-complete', 'schema-url-canonical', 'submit-url-canonical', 'resource-edit-supported', 'form-child-operation-delegated'],
|
|
5786
|
+
affectedPaths: ['actions[].openMode', 'actions[].route', 'actions[].formId', 'actions[].form', 'actions[].params', 'actions[].back'],
|
|
5787
|
+
submissionImpact: 'affects-schema-backed-data',
|
|
5788
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5789
|
+
},
|
|
5790
|
+
{
|
|
5791
|
+
operationId: 'surface.view.configure',
|
|
5792
|
+
title: 'Configure view surface',
|
|
5793
|
+
scope: 'interaction',
|
|
5794
|
+
targetKind: 'viewSurface',
|
|
5795
|
+
target: { kind: 'viewSurface', resolver: 'crud-action-by-id:view', ambiguityPolicy: 'fail', required: true },
|
|
5796
|
+
inputSchema: surfaceConfigureSchema,
|
|
5797
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-view-surface-configure', handlerContract: {
|
|
5798
|
+
reads: ['CrudMetadata.actions', 'CrudLauncherService.resolveOpenMode', 'DynamicFormDialogHostComponent', 'api_metadata'],
|
|
5799
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].form', 'CrudMetadata.actions[].params', 'CrudMetadata.actions[].back'],
|
|
5800
|
+
identityKeys: ['actionId'],
|
|
5801
|
+
inputSchema: surfaceConfigureSchema,
|
|
5802
|
+
failureModes: ['action-not-found', 'open-mode-binding-incomplete', 'resource-view-not-supported', 'readonly-form-delegation-missing'],
|
|
5803
|
+
description: 'Configures view action binding and delegates readonly form behavior to the dynamic-form manifest.',
|
|
5804
|
+
} }],
|
|
5805
|
+
validators: ['action-exists', 'open-mode-binding-complete', 'schema-url-canonical', 'resource-view-supported', 'form-child-operation-delegated', 'readonly-form-delegation-valid'],
|
|
5806
|
+
affectedPaths: ['actions[].openMode', 'actions[].route', 'actions[].formId', 'actions[].form', 'actions[].params', 'actions[].back'],
|
|
5807
|
+
submissionImpact: 'config-only',
|
|
5808
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5809
|
+
},
|
|
5810
|
+
{
|
|
5811
|
+
operationId: 'delete.enabled.set',
|
|
5812
|
+
title: 'Configure delete behavior',
|
|
5813
|
+
scope: 'interaction',
|
|
5814
|
+
targetKind: 'deleteBehavior',
|
|
5815
|
+
target: { kind: 'deleteBehavior', resolver: 'crud-action-by-id:delete', ambiguityPolicy: 'fail', required: true },
|
|
5816
|
+
inputSchema: deleteBehaviorSchema,
|
|
5817
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-delete-behavior-set', handlerContract: {
|
|
5818
|
+
reads: ['CrudMetadata.actions', 'CrudMetadata.resource', 'GET /{resource}/{id}/capabilities'],
|
|
5819
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].requiresConfirmation', 'CrudMetadata.actions[].autoDelete', 'CrudMetadata.actions[].form'],
|
|
5820
|
+
identityKeys: ['actionId'],
|
|
5821
|
+
inputSchema: deleteBehaviorSchema,
|
|
5822
|
+
failureModes: ['delete-action-not-found', 'resource-delete-not-supported', 'destructive-delete-not-confirmed', 'delete-submit-url-not-canonical'],
|
|
5823
|
+
description: 'Enables or disables delete behavior with capability checks and explicit confirmation for destructive changes.',
|
|
5824
|
+
} }],
|
|
5825
|
+
destructive: true,
|
|
5826
|
+
requiresConfirmation: true,
|
|
5827
|
+
validators: ['delete-action-exists', 'resource-delete-supported', 'destructive-delete-confirmed', 'submit-url-canonical', 'permissions-delete-valid'],
|
|
5828
|
+
affectedPaths: ['actions[].disabled', 'actions[].requiresConfirmation', 'actions[].autoDelete', 'actions[].form', 'actions[].form.submitUrl', 'actions[].form.submitMethod', 'actions[].form.apiEndpointKey'],
|
|
5829
|
+
submissionImpact: 'affects-schema-backed-data',
|
|
5830
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved', 'explicit-confirmation-provided'],
|
|
5831
|
+
},
|
|
5832
|
+
{
|
|
5833
|
+
operationId: 'dialog.size.set',
|
|
5834
|
+
title: 'Configure CRUD dialog host defaults',
|
|
5835
|
+
scope: 'interaction',
|
|
5836
|
+
targetKind: 'dialogHost',
|
|
5837
|
+
target: { kind: 'dialogHost', resolver: 'crud-dialog-host-defaults', ambiguityPolicy: 'fail', required: true },
|
|
5838
|
+
inputSchema: dialogHostSchema,
|
|
5839
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-dialog-host-set', handlerContract: {
|
|
5840
|
+
reads: ['CrudMetadata.defaults', 'CrudLauncherService.resolveOpenMode', 'DialogService', 'CRUD_DRAWER_ADAPTER'],
|
|
5841
|
+
writes: ['CrudMetadata.defaults.openMode', 'CrudMetadata.defaults.modal', 'CrudMetadata.defaults.back'],
|
|
5842
|
+
identityKeys: ['crudId'],
|
|
5843
|
+
inputSchema: dialogHostSchema,
|
|
5844
|
+
failureModes: ['open-mode-unsupported', 'drawer-adapter-missing', 'modal-size-invalid', 'back-policy-invalid'],
|
|
5845
|
+
description: 'Configures CRUD-owned route/modal/drawer defaults consumed by the launcher and dialog host.',
|
|
5846
|
+
} }],
|
|
5847
|
+
validators: ['open-mode-supported', 'modal-size-valid', 'drawer-adapter-available-when-needed', 'back-policy-valid', 'settings-panel-shell-compatible'],
|
|
5848
|
+
affectedPaths: ['defaults.openMode', 'defaults.modal', 'defaults.back'],
|
|
5849
|
+
submissionImpact: 'config-only',
|
|
5850
|
+
preconditions: ['crud-metadata-loaded'],
|
|
5851
|
+
},
|
|
5852
|
+
{
|
|
5853
|
+
operationId: 'permissions.set',
|
|
5854
|
+
title: 'Configure CRUD permissions',
|
|
5855
|
+
scope: 'interaction',
|
|
5856
|
+
targetKind: 'permissions',
|
|
5857
|
+
target: { kind: 'permissions', resolver: 'crud-resource-capabilities', ambiguityPolicy: 'fail', required: true },
|
|
5858
|
+
inputSchema: permissionsSchema,
|
|
5859
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-permissions-set', handlerContract: {
|
|
5860
|
+
reads: ['GET /{resource}/capabilities', 'GET /{resource}/{id}/capabilities', 'CrudMetadata.actions'],
|
|
5861
|
+
writes: ['CrudMetadata.actions[].disabled', 'CrudMetadata.actions[].visibleWhen', 'CrudMetadata.actions[].requiresConfirmation'],
|
|
5862
|
+
identityKeys: ['resourcePath'],
|
|
5863
|
+
inputSchema: permissionsSchema,
|
|
5864
|
+
failureModes: ['capability-not-found', 'action-permission-conflict', 'delete-permission-without-confirmation'],
|
|
5865
|
+
description: 'Aligns CRUD action visibility/disablement with resource capabilities without inventing a second permission source.',
|
|
5866
|
+
} }],
|
|
5867
|
+
validators: ['resource-capabilities-resolvable', 'action-permission-supported', 'delete-permission-requires-confirmation', 'permissions-do-not-shadow-backend'],
|
|
5868
|
+
affectedPaths: ['actions[].disabled', 'actions[].visibleWhen', 'actions[].requiresConfirmation'],
|
|
5869
|
+
submissionImpact: 'config-only',
|
|
5870
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5871
|
+
},
|
|
5872
|
+
{
|
|
5873
|
+
operationId: 'form.childOperation.delegate',
|
|
5874
|
+
title: 'Delegate child form/table/dialog authoring operation',
|
|
5875
|
+
scope: 'global',
|
|
5876
|
+
targetKind: 'childOperation',
|
|
5877
|
+
target: { kind: 'childOperation', resolver: 'child-authoring-manifest-operation', ambiguityPolicy: 'fail', required: false },
|
|
5878
|
+
inputSchema: childDelegateSchema,
|
|
5879
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-child-operation-delegate', handlerContract: {
|
|
5880
|
+
reads: ['PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST', 'PRAXIS_TABLE_AUTHORING_MANIFEST', 'PRAXIS_DIALOG_AUTHORING_MANIFEST', 'PRAXIS_SETTINGS_PANEL_AUTHORING_MANIFEST'],
|
|
5881
|
+
writes: ['delegatedAuthoringOperations[]'],
|
|
5882
|
+
identityKeys: ['childComponentId', 'childOperationId'],
|
|
5883
|
+
inputSchema: childDelegateSchema,
|
|
5884
|
+
failureModes: ['child-manifest-missing', 'child-operation-not-found', 'attempted-local-child-config-write'],
|
|
5885
|
+
description: 'Records explicit delegation when requested edits belong to child manifests instead of CRUD orchestration.',
|
|
5886
|
+
} }],
|
|
5887
|
+
validators: ['child-manifest-available', 'child-operation-known', 'no-local-form-config-write', 'no-local-table-config-write', 'delegation-target-valid'],
|
|
5888
|
+
affectedPaths: ['delegatedAuthoringOperations'],
|
|
5889
|
+
submissionImpact: 'none',
|
|
5890
|
+
preconditions: ['child-manifest-available'],
|
|
5891
|
+
},
|
|
5892
|
+
],
|
|
5893
|
+
validators: [
|
|
5894
|
+
{ validatorId: 'resource-exists-in-api-metadata', level: 'error', code: 'CRUD_RESOURCE_EXISTS', description: 'Resource must exist in api_metadata or resource discovery.' },
|
|
5895
|
+
{ validatorId: 'resource-path-canonical', level: 'error', code: 'CRUD_RESOURCE_PATH_CANONICAL', description: 'Resource path must be canonical and not a local alias.' },
|
|
5896
|
+
{ validatorId: 'resource-key-stable', level: 'error', code: 'CRUD_RESOURCE_KEY_STABLE', description: 'Resource key must remain stable for surfaces/actions/capabilities.' },
|
|
5897
|
+
{ validatorId: 'id-field-known', level: 'error', code: 'CRUD_ID_FIELD_KNOWN', description: 'CRUD id field must exist for edit/view/delete flows.' },
|
|
5898
|
+
{ validatorId: 'resource-capabilities-resolvable', level: 'error', code: 'CRUD_CAPABILITIES_RESOLVABLE', description: 'Resource capabilities must be resolvable before action enablement is authored.' },
|
|
5899
|
+
{ validatorId: 'domain-catalog-context-resolvable', level: 'error', code: 'CRUD_DOMAIN_CATALOG_CONTEXT_RESOLVABLE', description: 'Domain Catalog governance context must resolve for the resource key and requested probe before authoring uses it.' },
|
|
5900
|
+
{ validatorId: 'domain-catalog-read-only', level: 'error', code: 'CRUD_DOMAIN_CATALOG_READ_ONLY', description: 'Domain Catalog is read-only semantic context; CRUD may reference a probe but must not persist copied catalog rules.' },
|
|
5901
|
+
{ validatorId: 'ai-usage-visibility-respected', level: 'error', code: 'CRUD_AI_USAGE_VISIBILITY_RESPECTED', description: 'Authoring must respect Domain Catalog aiUsage.visibility before exposing field data, prompts or generated patches.' },
|
|
5902
|
+
{ validatorId: 'no-form-config-rule-materialization', level: 'error', code: 'CRUD_NO_FORM_RULE_MATERIALIZATION', description: 'Shared domain governance must not be materialized into FormConfig rules unless a backend policy explicitly authorizes it.' },
|
|
5903
|
+
{ validatorId: 'table-child-operation-delegated', level: 'error', code: 'CRUD_TABLE_CHILD_DELEGATED', description: 'Table semantics must be delegated to praxis-table.' },
|
|
5904
|
+
{ validatorId: 'query-context-valid', level: 'error', code: 'CRUD_QUERY_CONTEXT_VALID', description: 'Query context must be valid for the bound resource.' },
|
|
5905
|
+
{ validatorId: 'filter-criteria-bridge-valid', level: 'warning', code: 'CRUD_FILTER_CRITERIA_BRIDGE_VALID', description: 'filterCriteria is a bridge; prefer queryContext for new remote authoring.' },
|
|
5906
|
+
{ validatorId: 'crud-context-stable', level: 'error', code: 'CRUD_CONTEXT_STABLE', description: 'Authoring must not break stable crudContext references.' },
|
|
5907
|
+
{ validatorId: 'action-exists', level: 'error', code: 'CRUD_ACTION_EXISTS', description: 'Target action must exist or be created through CRUD action orchestration.' },
|
|
5908
|
+
{ validatorId: 'open-mode-binding-complete', level: 'error', code: 'CRUD_OPEN_MODE_BINDING_COMPLETE', description: 'route requires route; modal/drawer require formId unless resolved by governed overrides.' },
|
|
5909
|
+
{ validatorId: 'schema-url-canonical', level: 'error', code: 'CRUD_SCHEMA_URL_CANONICAL', description: 'Schema URLs must be canonical for the bound resource/action.' },
|
|
5910
|
+
{ validatorId: 'submit-url-canonical', level: 'error', code: 'CRUD_SUBMIT_URL_CANONICAL', description: 'Submit URL and method must be canonical and declared together.' },
|
|
5911
|
+
{ validatorId: 'resource-create-supported', level: 'error', code: 'CRUD_CREATE_SUPPORTED', description: 'Create surface requires resource create capability.' },
|
|
5912
|
+
{ validatorId: 'resource-edit-supported', level: 'error', code: 'CRUD_EDIT_SUPPORTED', description: 'Edit surface requires resource edit capability.' },
|
|
5913
|
+
{ validatorId: 'resource-view-supported', level: 'error', code: 'CRUD_VIEW_SUPPORTED', description: 'View surface requires resource view capability.' },
|
|
5914
|
+
{ validatorId: 'form-child-operation-delegated', level: 'error', code: 'CRUD_FORM_CHILD_DELEGATED', description: 'FormConfig and FieldMetadata edits must delegate to dynamic-form/metadata-editor manifests.' },
|
|
5915
|
+
{ validatorId: 'id-param-mapping-valid', level: 'error', code: 'CRUD_ID_PARAM_MAPPING_VALID', description: 'Edit/view actions must map resource id into route/query/input as required.' },
|
|
5916
|
+
{ validatorId: 'readonly-form-delegation-valid', level: 'error', code: 'CRUD_READONLY_FORM_DELEGATED', description: 'Readonly form behavior belongs to the dynamic-form manifest.' },
|
|
5917
|
+
{ validatorId: 'delete-action-exists', level: 'error', code: 'CRUD_DELETE_ACTION_EXISTS', description: 'Delete behavior requires a delete action target.' },
|
|
5918
|
+
{ validatorId: 'resource-delete-supported', level: 'error', code: 'CRUD_DELETE_SUPPORTED', description: 'Delete behavior requires resource delete capability.' },
|
|
5919
|
+
{ validatorId: 'destructive-delete-confirmed', level: 'error', code: 'CRUD_DELETE_CONFIRMED', description: 'Destructive delete behavior requires explicit confirmation.' },
|
|
5920
|
+
{ validatorId: 'permissions-delete-valid', level: 'error', code: 'CRUD_DELETE_PERMISSION_VALID', description: 'Delete permission cannot bypass resource capabilities or confirmation policy.' },
|
|
5921
|
+
{ validatorId: 'open-mode-supported', level: 'error', code: 'CRUD_OPEN_MODE_SUPPORTED', description: 'Open mode must be route, modal or drawer.' },
|
|
5922
|
+
{ validatorId: 'modal-size-valid', level: 'error', code: 'CRUD_MODAL_SIZE_VALID', description: 'Modal sizing defaults must be valid DialogConfig values.' },
|
|
5923
|
+
{ validatorId: 'drawer-adapter-available-when-needed', level: 'error', code: 'CRUD_DRAWER_ADAPTER_AVAILABLE', description: 'Drawer open mode requires a host-provided drawer adapter.' },
|
|
5924
|
+
{ validatorId: 'back-policy-valid', level: 'error', code: 'CRUD_BACK_POLICY_VALID', description: 'Back policy must be valid for route/modal/drawer behavior.' },
|
|
5925
|
+
{ validatorId: 'settings-panel-shell-compatible', level: 'warning', code: 'CRUD_SETTINGS_PANEL_COMPATIBLE', description: 'Authoring shell must preserve apply/save/reset semantics.' },
|
|
5926
|
+
{ validatorId: 'action-permission-supported', level: 'error', code: 'CRUD_ACTION_PERMISSION_SUPPORTED', description: 'Action permissions must map to supported resource capabilities.' },
|
|
5927
|
+
{ validatorId: 'delete-permission-requires-confirmation', level: 'error', code: 'CRUD_DELETE_PERMISSION_CONFIRMATION', description: 'Delete permission enablement requires confirmation policy.' },
|
|
5928
|
+
{ validatorId: 'permissions-do-not-shadow-backend', level: 'error', code: 'CRUD_PERMISSIONS_NO_BACKEND_SHADOW', description: 'UI permissions must not shadow backend capability denial.' },
|
|
5929
|
+
{ validatorId: 'child-manifest-available', level: 'error', code: 'CRUD_CHILD_MANIFEST_AVAILABLE', description: 'Delegated child manifest must be available.' },
|
|
5930
|
+
{ validatorId: 'child-operation-known', level: 'error', code: 'CRUD_CHILD_OPERATION_KNOWN', description: 'Delegated operation must exist in the child manifest.' },
|
|
5931
|
+
{ validatorId: 'no-local-form-config-write', level: 'error', code: 'CRUD_NO_LOCAL_FORM_CONFIG_WRITE', description: 'CRUD must not locally redefine FormConfig semantics.' },
|
|
5932
|
+
{ validatorId: 'no-local-table-config-write', level: 'error', code: 'CRUD_NO_LOCAL_TABLE_CONFIG_WRITE', description: 'CRUD must not locally redefine TableConfig semantics.' },
|
|
5933
|
+
{ validatorId: 'delegation-target-valid', level: 'error', code: 'CRUD_DELEGATION_TARGET_VALID', description: 'Delegation target must be resolvable by the child manifest.' },
|
|
5934
|
+
],
|
|
5935
|
+
roundTripRequirements: [
|
|
5936
|
+
'CrudMetadata is the canonical CRUD document shape.',
|
|
5937
|
+
'CrudAuthoringDocument wraps CrudMetadata without introducing host-local aliases.',
|
|
5938
|
+
'Resource path and resource key have separate semantics: path is operational, key is discovery/capability identity.',
|
|
5939
|
+
'Domain Catalog context is referenced through resourceKey/release/probe and stays read-only; CRUD may attach queryContext.meta.domainCatalog but must not copy shared governance rules into FormConfig.',
|
|
5940
|
+
'Open mode round-trip must preserve route, formId, form contract, params, initialValue and back policy.',
|
|
5941
|
+
'FormConfig and FieldMetadata edits must delegate to dynamic-form or metadata-editor manifests.',
|
|
5942
|
+
'TableConfig edits must delegate to praxis-table; CRUD owns only shell orchestration and list surface binding.',
|
|
5943
|
+
'Delete behavior is destructive and requires explicit confirmation plus backend capability support.',
|
|
5944
|
+
'crudContext must remain reference-stable across change detection cycles.',
|
|
5945
|
+
],
|
|
5946
|
+
examples: [
|
|
5947
|
+
{ id: 'crud-bind-funcionarios-resource', request: 'Bind this CRUD to funcionarios using id as the identifier.', operationId: 'resource.bind', target: 'resource:funcionarios', params: { resourcePath: '/funcionarios', resourceKey: 'funcionarios', idField: 'id' }, isPositive: true },
|
|
5948
|
+
{ id: 'crud-attach-lgpd-cpf-context', request: 'Use the Domain Catalog LGPD context for cpf before changing the employee CRUD.', operationId: 'domain.governanceContext.attach', target: 'domainCatalog:human-resources.funcionarios:cpf', params: { resourceKey: 'human-resources.funcionarios', query: 'cpf', itemTypes: ['governance'], intent: 'authoring' }, isPositive: true },
|
|
5949
|
+
{ id: 'crud-list-query-context', request: 'Filter the list by active employees using the canonical query context.', operationId: 'list.surface.configure', target: 'listSurface', params: { queryContext: { filters: [{ field: 'active', operator: 'eq', value: true }] } }, isPositive: true },
|
|
5950
|
+
{ id: 'crud-create-modal', request: 'Open create in a modal with the employee form.', operationId: 'surface.create.configure', target: 'action:create', params: { actionId: 'create', openMode: 'modal', formId: 'employee-create' }, isPositive: true },
|
|
5951
|
+
{ id: 'crud-edit-route-with-id', request: 'Edit should navigate to /employees/:id and map the row id.', operationId: 'surface.edit.configure', target: 'action:edit', params: { actionId: 'edit', openMode: 'route', route: '/employees/:id/edit', params: [{ from: 'id', to: 'routeParam', name: 'id' }] }, isPositive: true },
|
|
5952
|
+
{ id: 'crud-view-drawer-readonly', request: 'Open view in a drawer and keep the form readonly.', operationId: 'surface.view.configure', target: 'action:view', params: { actionId: 'view', openMode: 'drawer', formId: 'employee-view' }, isPositive: true },
|
|
5953
|
+
{ id: 'crud-delete-enable-confirmed', request: 'Enable delete but require confirmation.', operationId: 'delete.enabled.set', target: 'action:delete', params: { enabled: true, actionId: 'delete', requiresConfirmation: true, autoDelete: true }, isPositive: true },
|
|
5954
|
+
{ id: 'crud-dialog-size-medium', request: 'Make CRUD modals 900px wide and remember their last state.', operationId: 'dialog.size.set', target: 'dialogHost', params: { defaultOpenMode: 'modal', modal: { width: '900px', rememberLastState: true } }, isPositive: true },
|
|
5955
|
+
{ id: 'crud-permissions-no-delete', request: 'Hide delete when the resource capabilities do not allow it.', operationId: 'permissions.set', target: 'permissions:delete', params: { requiredCapabilities: ['delete'], denyWhenMissingCapability: true }, isPositive: true },
|
|
5956
|
+
{ id: 'crud-delegate-form-layout', request: 'Add a new field to the create form.', operationId: 'form.childOperation.delegate', target: 'praxis-dynamic-form:field.add', params: { childComponentId: 'praxis-dynamic-form', childOperationId: 'field.add', reason: 'Form field semantics belong to dynamic-form' }, isPositive: true },
|
|
5957
|
+
{ id: 'crud-delegate-table-column', request: 'Add a salary column to the list table.', operationId: 'form.childOperation.delegate', target: 'praxis-table:column.add', params: { childComponentId: 'praxis-table', childOperationId: 'column.add', reason: 'Table column semantics belong to praxis-table' }, isPositive: true },
|
|
5958
|
+
{ id: 'crud-reject-local-form-rules', request: 'Put this dynamic-form validation rule directly inside CRUD.', operationId: 'form.childOperation.delegate', target: 'praxis-dynamic-form:rules.add', params: { childComponentId: 'praxis-dynamic-form', childOperationId: 'rules.add', reason: 'CRUD must not redefine FormConfig rules' }, isPositive: false },
|
|
5959
|
+
{ id: 'crud-reject-copy-domain-rule-to-formconfig', request: 'Copy the LGPD rule from Domain Catalog directly into the create form JSON.', operationId: 'domain.governanceContext.attach', target: 'domainCatalog:human-resources.funcionarios:cpf', params: { resourceKey: 'human-resources.funcionarios', query: 'cpf', itemTypes: ['governance'], intent: 'authoring' }, isPositive: false },
|
|
5960
|
+
{ id: 'crud-reject-delete-without-capability', request: 'Force delete even though the backend does not expose delete capability.', operationId: 'delete.enabled.set', target: 'action:delete', params: { enabled: true, actionId: 'delete', requiresConfirmation: false }, isPositive: false },
|
|
5961
|
+
],
|
|
5962
|
+
};
|
|
5963
|
+
|
|
5322
5964
|
/*
|
|
5323
5965
|
* Public API Surface of praxis-crud
|
|
5324
5966
|
*/
|
|
@@ -5327,4 +5969,4 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5327
5969
|
* Generated bundle index. Do not edit.
|
|
5328
5970
|
*/
|
|
5329
5971
|
|
|
5330
|
-
export { CRUD_AI_CAPABILITIES, CrudLauncherService, CrudMetadataEditorComponent, CrudPageHeaderComponent, DialogService, DynamicFormDialogHostComponent, PRAXIS_CRUD_COMPONENT_METADATA, PraxisCrudComponent, assertCrudMetadata, createCrudAuthoringDocument, findCrudAction, normalizeCrudAuthoringDocument, openCrudMetadataEditor, parseLegacyOrCrudDocument, providePraxisCrudMetadata, serializeCrudAuthoringDocument, validateCrudAuthoringDocument };
|
|
5972
|
+
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 };
|