@praxisui/crud 8.0.0-beta.9 → 8.0.0-beta.91
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, runtimeEvent);
|
|
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();
|
|
@@ -3727,7 +3764,7 @@ class PraxisCrudComponent {
|
|
|
3727
3764
|
}
|
|
3728
3765
|
let payload;
|
|
3729
3766
|
try {
|
|
3730
|
-
payload = this.
|
|
3767
|
+
payload = this.getSurfaceOpenAdapter().toPayload(surface, {
|
|
3731
3768
|
resourcePath,
|
|
3732
3769
|
resourceId: this.resolveRowResourceId(row),
|
|
3733
3770
|
endpointKey: this.resolvedMetadata?.resource?.endpointKey,
|
|
@@ -3777,13 +3814,13 @@ class PraxisCrudComponent {
|
|
|
3777
3814
|
if (!this.tableCollectionLinks) {
|
|
3778
3815
|
return null;
|
|
3779
3816
|
}
|
|
3780
|
-
return await firstValueFrom(this.
|
|
3817
|
+
return await firstValueFrom(this.getResourceDiscovery().getSurfaces(this.tableCollectionLinks, this.buildDiscoveryOptions()));
|
|
3781
3818
|
}
|
|
3782
3819
|
const rowLinks = row?._links;
|
|
3783
3820
|
if (!rowLinks) {
|
|
3784
3821
|
return null;
|
|
3785
3822
|
}
|
|
3786
|
-
return await firstValueFrom(this.
|
|
3823
|
+
return await firstValueFrom(this.getResourceDiscovery().getSurfaces(rowLinks, this.buildDiscoveryOptions()));
|
|
3787
3824
|
}
|
|
3788
3825
|
catch {
|
|
3789
3826
|
return null;
|
|
@@ -3807,7 +3844,7 @@ class PraxisCrudComponent {
|
|
|
3807
3844
|
}
|
|
3808
3845
|
let payload;
|
|
3809
3846
|
try {
|
|
3810
|
-
payload = this.
|
|
3847
|
+
payload = this.getActionOpenAdapter().toPayload(discoveredAction, {
|
|
3811
3848
|
resourcePath,
|
|
3812
3849
|
resourceId: this.resolveRowResourceId(row),
|
|
3813
3850
|
endpointKey: this.resolvedMetadata?.resource?.endpointKey,
|
|
@@ -3858,12 +3895,12 @@ class PraxisCrudComponent {
|
|
|
3858
3895
|
if (!rowLinks) {
|
|
3859
3896
|
return null;
|
|
3860
3897
|
}
|
|
3861
|
-
return await firstValueFrom(this.
|
|
3898
|
+
return await firstValueFrom(this.getResourceDiscovery().getActions(rowLinks, this.buildDiscoveryOptions()));
|
|
3862
3899
|
}
|
|
3863
3900
|
if (!this.tableCollectionLinks) {
|
|
3864
3901
|
return null;
|
|
3865
3902
|
}
|
|
3866
|
-
return await firstValueFrom(this.
|
|
3903
|
+
return await firstValueFrom(this.getResourceDiscovery().getActions(this.tableCollectionLinks, this.buildDiscoveryOptions()));
|
|
3867
3904
|
}
|
|
3868
3905
|
catch {
|
|
3869
3906
|
return null;
|
|
@@ -4111,13 +4148,27 @@ class PraxisCrudComponent {
|
|
|
4111
4148
|
});
|
|
4112
4149
|
}
|
|
4113
4150
|
if (rowActions.length) {
|
|
4151
|
+
const rawMaxInline = Number(crudDefaults.rowActionsMaxInline);
|
|
4152
|
+
const maxInline = Number.isFinite(rawMaxInline)
|
|
4153
|
+
? Math.max(0, Math.floor(rawMaxInline))
|
|
4154
|
+
: 2;
|
|
4114
4155
|
cfg.actions = cfg.actions || {};
|
|
4115
4156
|
cfg.actions.row = {
|
|
4116
4157
|
enabled: true,
|
|
4117
4158
|
position: 'end',
|
|
4118
|
-
width: cfg.actions?.row?.width || '
|
|
4159
|
+
width: cfg.actions?.row?.width || crudDefaults.rowActionsWidth || '144px',
|
|
4119
4160
|
display: crudDefaults.rowActionsDisplay || 'icons',
|
|
4120
|
-
trigger: cfg.actions?.row?.trigger || '
|
|
4161
|
+
trigger: cfg.actions?.row?.trigger || crudDefaults.rowActionsTrigger || 'always',
|
|
4162
|
+
menuIcon: crudDefaults.rowActionsMenuIcon || 'more_vert',
|
|
4163
|
+
maxVisibleActions: maxInline,
|
|
4164
|
+
behavior: {
|
|
4165
|
+
enabled: true,
|
|
4166
|
+
maxInline,
|
|
4167
|
+
autoStrategy: 'breakpoints',
|
|
4168
|
+
},
|
|
4169
|
+
discovery: {
|
|
4170
|
+
enabled: crudDefaults.rowActionDiscovery !== false,
|
|
4171
|
+
},
|
|
4121
4172
|
actions: rowActions,
|
|
4122
4173
|
header: { label: cfg.actions?.row?.header?.label || '' },
|
|
4123
4174
|
};
|
|
@@ -4327,7 +4378,7 @@ class PraxisCrudComponent {
|
|
|
4327
4378
|
}
|
|
4328
4379
|
resolveCollectionCapabilitiesHref(links) {
|
|
4329
4380
|
try {
|
|
4330
|
-
return this.
|
|
4381
|
+
return this.getResourceDiscovery().resolveLinkHref(links || undefined, 'capabilities', this.buildDiscoveryOptions());
|
|
4331
4382
|
}
|
|
4332
4383
|
catch {
|
|
4333
4384
|
return null;
|
|
@@ -4347,7 +4398,7 @@ class PraxisCrudComponent {
|
|
|
4347
4398
|
}
|
|
4348
4399
|
resolveDiscoveryApiEntry() {
|
|
4349
4400
|
try {
|
|
4350
|
-
return this.
|
|
4401
|
+
return this.getResourceDiscovery().resolveApiEntry(this.buildDiscoveryOptions());
|
|
4351
4402
|
}
|
|
4352
4403
|
catch {
|
|
4353
4404
|
return null;
|
|
@@ -4407,8 +4458,8 @@ class PraxisCrudComponent {
|
|
|
4407
4458
|
return fallback;
|
|
4408
4459
|
}
|
|
4409
4460
|
}
|
|
4410
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4411
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
4461
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4462
|
+
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: [
|
|
4412
4463
|
providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
|
|
4413
4464
|
providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
|
|
4414
4465
|
], viewQueries: [{ propertyName: "table", first: true, predicate: PraxisTable, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
@@ -4422,6 +4473,8 @@ class PraxisCrudComponent {
|
|
|
4422
4473
|
[tableId]="crudId || 'default'"
|
|
4423
4474
|
[crudContext]="tableCrudContext"
|
|
4424
4475
|
[enableCustomization]="enableCustomization"
|
|
4476
|
+
(rowClick)="onTableRowClick($event)"
|
|
4477
|
+
(selectionChange)="onTableSelectionChange($event)"
|
|
4425
4478
|
(rowAction)="onAction($event.action, $event.row, $event)"
|
|
4426
4479
|
(toolbarAction)="onAction($event.action)"
|
|
4427
4480
|
(collectionLinksChange)="onCollectionLinksChange($event)"
|
|
@@ -4439,9 +4492,9 @@ class PraxisCrudComponent {
|
|
|
4439
4492
|
/>
|
|
4440
4493
|
}
|
|
4441
4494
|
}
|
|
4442
|
-
`, 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"] }] });
|
|
4495
|
+
`, 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"] }] });
|
|
4443
4496
|
}
|
|
4444
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4497
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, decorators: [{
|
|
4445
4498
|
type: Component,
|
|
4446
4499
|
args: [{ selector: 'praxis-crud', standalone: true, imports: [PraxisTable, EmptyStateCardComponent], providers: [
|
|
4447
4500
|
providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
|
|
@@ -4457,6 +4510,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
4457
4510
|
[tableId]="crudId || 'default'"
|
|
4458
4511
|
[crudContext]="tableCrudContext"
|
|
4459
4512
|
[enableCustomization]="enableCustomization"
|
|
4513
|
+
(rowClick)="onTableRowClick($event)"
|
|
4514
|
+
(selectionChange)="onTableSelectionChange($event)"
|
|
4460
4515
|
(rowAction)="onAction($event.action, $event.row, $event)"
|
|
4461
4516
|
(toolbarAction)="onAction($event.action)"
|
|
4462
4517
|
(collectionLinksChange)="onCollectionLinksChange($event)"
|
|
@@ -4499,6 +4554,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
4499
4554
|
type: Output
|
|
4500
4555
|
}], error: [{
|
|
4501
4556
|
type: Output
|
|
4557
|
+
}], rowClick: [{
|
|
4558
|
+
type: Output
|
|
4559
|
+
}], selectionChange: [{
|
|
4560
|
+
type: Output
|
|
4502
4561
|
}], tableRuntimeConfigChange: [{
|
|
4503
4562
|
type: Output
|
|
4504
4563
|
}], crudAuthoringDocumentApplied: [{
|
|
@@ -4807,8 +4866,8 @@ class DynamicFormDialogHostComponent {
|
|
|
4807
4866
|
this.dialogRef.updatePosition();
|
|
4808
4867
|
}
|
|
4809
4868
|
}
|
|
4810
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4811
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
4869
|
+
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 });
|
|
4870
|
+
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: `
|
|
4812
4871
|
<div mat-dialog-title class="dialog-header">
|
|
4813
4872
|
<h2 id="crudDialogTitle" class="dialog-title">
|
|
4814
4873
|
{{ data.action?.label || texts.title }}
|
|
@@ -4857,17 +4916,16 @@ class DynamicFormDialogHostComponent {
|
|
|
4857
4916
|
(formCancel)="onCancel()"
|
|
4858
4917
|
></praxis-dynamic-form>
|
|
4859
4918
|
</mat-dialog-content>
|
|
4860
|
-
`, 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:
|
|
4919
|
+
`, 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", "readUrl", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }] });
|
|
4861
4920
|
}
|
|
4862
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4921
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
|
|
4863
4922
|
type: Component,
|
|
4864
4923
|
args: [{ selector: 'praxis-dynamic-form-dialog-host', standalone: true, imports: [
|
|
4865
|
-
CommonModule,
|
|
4866
4924
|
MatDialogModule,
|
|
4867
4925
|
MatButtonModule,
|
|
4868
4926
|
MatIconModule,
|
|
4869
4927
|
PraxisIconDirective,
|
|
4870
|
-
PraxisDynamicForm
|
|
4928
|
+
PraxisDynamicForm
|
|
4871
4929
|
], providers: [GenericCrudService], host: {
|
|
4872
4930
|
class: 'praxis-dialog',
|
|
4873
4931
|
'[attr.data-density]': 'modal.density || "default"',
|
|
@@ -4963,6 +5021,102 @@ var dynamicFormDialogHost_component = /*#__PURE__*/Object.freeze({
|
|
|
4963
5021
|
DynamicFormDialogHostComponent: DynamicFormDialogHostComponent
|
|
4964
5022
|
});
|
|
4965
5023
|
|
|
5024
|
+
class PraxisCrudWidgetConfigEditor {
|
|
5025
|
+
inputs = null;
|
|
5026
|
+
widgetKey;
|
|
5027
|
+
crudEditor;
|
|
5028
|
+
isDirty$ = new BehaviorSubject(false);
|
|
5029
|
+
isValid$ = new BehaviorSubject(true);
|
|
5030
|
+
isBusy$ = new BehaviorSubject(false);
|
|
5031
|
+
subscription = new Subscription();
|
|
5032
|
+
ngAfterViewInit() {
|
|
5033
|
+
if (!this.crudEditor) {
|
|
5034
|
+
return;
|
|
5035
|
+
}
|
|
5036
|
+
this.subscription.add(this.crudEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
|
|
5037
|
+
this.subscription.add(this.crudEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
|
|
5038
|
+
this.subscription.add(this.crudEditor.isBusy$.subscribe((value) => this.isBusy$.next(value)));
|
|
5039
|
+
}
|
|
5040
|
+
ngOnDestroy() {
|
|
5041
|
+
this.subscription.unsubscribe();
|
|
5042
|
+
}
|
|
5043
|
+
get metadata() {
|
|
5044
|
+
return this.createDocumentFromInputs().metadata;
|
|
5045
|
+
}
|
|
5046
|
+
get effectiveCrudId() {
|
|
5047
|
+
return this.inputs?.crudId ?? this.widgetKey ?? null;
|
|
5048
|
+
}
|
|
5049
|
+
getSettingsValue() {
|
|
5050
|
+
return this.buildValue(this.crudEditor?.getSettingsValue());
|
|
5051
|
+
}
|
|
5052
|
+
onSave() {
|
|
5053
|
+
return this.buildValue(this.crudEditor?.onSave?.() ?? this.crudEditor?.getSettingsValue());
|
|
5054
|
+
}
|
|
5055
|
+
reset() {
|
|
5056
|
+
this.crudEditor?.reset?.();
|
|
5057
|
+
}
|
|
5058
|
+
buildValue(rawPayload) {
|
|
5059
|
+
const document = this.extractDocument(rawPayload);
|
|
5060
|
+
return {
|
|
5061
|
+
inputs: {
|
|
5062
|
+
...(this.inputs ?? {}),
|
|
5063
|
+
metadata: document.metadata,
|
|
5064
|
+
crudId: this.inputs?.crudId ?? this.widgetKey,
|
|
5065
|
+
componentInstanceId: this.inputs?.componentInstanceId ?? this.widgetKey,
|
|
5066
|
+
context: this.inputs?.context,
|
|
5067
|
+
enableCustomization: this.inputs?.enableCustomization ?? false,
|
|
5068
|
+
},
|
|
5069
|
+
};
|
|
5070
|
+
}
|
|
5071
|
+
createDocumentFromInputs() {
|
|
5072
|
+
return parseLegacyOrCrudDocument(this.inputs?.metadata ?? {
|
|
5073
|
+
component: 'praxis-crud',
|
|
5074
|
+
table: { columns: [] },
|
|
5075
|
+
});
|
|
5076
|
+
}
|
|
5077
|
+
extractDocument(rawPayload) {
|
|
5078
|
+
const payload = rawPayload;
|
|
5079
|
+
return parseLegacyOrCrudDocument(payload?.document ??
|
|
5080
|
+
payload?.metadata ??
|
|
5081
|
+
serializeCrudAuthoringDocument(this.createDocumentFromInputs()));
|
|
5082
|
+
}
|
|
5083
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudWidgetConfigEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5084
|
+
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: `
|
|
5085
|
+
<section data-testid="crud-widget-config-editor">
|
|
5086
|
+
<praxis-crud-metadata-editor
|
|
5087
|
+
#crudEditor
|
|
5088
|
+
[metadata]="metadata"
|
|
5089
|
+
[crudId]="effectiveCrudId"
|
|
5090
|
+
/>
|
|
5091
|
+
</section>
|
|
5092
|
+
`, isInline: true, dependencies: [{ kind: "component", type: CrudMetadataEditorComponent, selector: "praxis-crud-metadata-editor", inputs: ["document", "metadata", "crudId", "readonly"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5093
|
+
}
|
|
5094
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudWidgetConfigEditor, decorators: [{
|
|
5095
|
+
type: Component,
|
|
5096
|
+
args: [{
|
|
5097
|
+
selector: 'praxis-crud-widget-config-editor',
|
|
5098
|
+
standalone: true,
|
|
5099
|
+
imports: [CrudMetadataEditorComponent],
|
|
5100
|
+
template: `
|
|
5101
|
+
<section data-testid="crud-widget-config-editor">
|
|
5102
|
+
<praxis-crud-metadata-editor
|
|
5103
|
+
#crudEditor
|
|
5104
|
+
[metadata]="metadata"
|
|
5105
|
+
[crudId]="effectiveCrudId"
|
|
5106
|
+
/>
|
|
5107
|
+
</section>
|
|
5108
|
+
`,
|
|
5109
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
5110
|
+
}]
|
|
5111
|
+
}], propDecorators: { inputs: [{
|
|
5112
|
+
type: Input
|
|
5113
|
+
}], widgetKey: [{
|
|
5114
|
+
type: Input
|
|
5115
|
+
}], crudEditor: [{
|
|
5116
|
+
type: ViewChild,
|
|
5117
|
+
args: ['crudEditor']
|
|
5118
|
+
}] } });
|
|
5119
|
+
|
|
4966
5120
|
/** Metadata for PraxisCrudComponent */
|
|
4967
5121
|
const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
4968
5122
|
id: 'praxis-crud',
|
|
@@ -4971,6 +5125,14 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
|
4971
5125
|
friendlyName: 'Praxis CRUD',
|
|
4972
5126
|
description: 'Tabela com operações de CRUD via metadados.',
|
|
4973
5127
|
icon: 'table_chart',
|
|
5128
|
+
authoringManifestRef: {
|
|
5129
|
+
componentId: 'praxis-crud',
|
|
5130
|
+
source: 'PRAXIS_CRUD_AUTHORING_MANIFEST',
|
|
5131
|
+
},
|
|
5132
|
+
configEditor: {
|
|
5133
|
+
component: PraxisCrudWidgetConfigEditor,
|
|
5134
|
+
title: 'Configurar CRUD',
|
|
5135
|
+
},
|
|
4974
5136
|
inputs: [
|
|
4975
5137
|
{
|
|
4976
5138
|
name: 'metadata',
|
|
@@ -5035,6 +5197,16 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
|
5035
5197
|
type: '{ id: string | number }',
|
|
5036
5198
|
description: 'Emitido ao deletar.',
|
|
5037
5199
|
},
|
|
5200
|
+
{
|
|
5201
|
+
name: 'rowClick',
|
|
5202
|
+
type: '{ row: unknown; index: number }',
|
|
5203
|
+
description: 'Encaminha o clique de linha da tabela interna para composição master-detail e seleção local.',
|
|
5204
|
+
},
|
|
5205
|
+
{
|
|
5206
|
+
name: 'selectionChange',
|
|
5207
|
+
type: 'unknown',
|
|
5208
|
+
description: 'Encaminha a mudança de seleção da tabela interna quando o CRUD é usado como widget composto.',
|
|
5209
|
+
},
|
|
5038
5210
|
{
|
|
5039
5211
|
name: 'error',
|
|
5040
5212
|
type: 'unknown',
|
|
@@ -5141,6 +5313,23 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
|
|
|
5141
5313
|
},
|
|
5142
5314
|
scope: 'shell',
|
|
5143
5315
|
},
|
|
5316
|
+
{
|
|
5317
|
+
id: 'row-click',
|
|
5318
|
+
label: 'Clique em linha',
|
|
5319
|
+
icon: 'ads_click',
|
|
5320
|
+
description: 'Emite evento ao clicar em uma linha da tabela interna do CRUD.',
|
|
5321
|
+
emit: 'rowClick',
|
|
5322
|
+
payloadSchema: {
|
|
5323
|
+
type: 'object',
|
|
5324
|
+
properties: {
|
|
5325
|
+
row: { type: 'object', description: 'Registro clicado.' },
|
|
5326
|
+
index: { type: 'number', description: 'Índice da linha.' },
|
|
5327
|
+
},
|
|
5328
|
+
required: ['row'],
|
|
5329
|
+
example: { row: {}, index: 0 },
|
|
5330
|
+
},
|
|
5331
|
+
scope: 'context',
|
|
5332
|
+
},
|
|
5144
5333
|
{
|
|
5145
5334
|
id: 'close',
|
|
5146
5335
|
label: 'Fechar',
|
|
@@ -5181,64 +5370,66 @@ class CrudPageHeaderComponent {
|
|
|
5181
5370
|
sticky = true;
|
|
5182
5371
|
divider = true;
|
|
5183
5372
|
returnTo;
|
|
5184
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5185
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
5373
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudPageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5374
|
+
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: `
|
|
5186
5375
|
<header
|
|
5187
5376
|
class="crud-header"
|
|
5188
5377
|
[class.sticky]="sticky"
|
|
5189
5378
|
[class.with-divider]="divider"
|
|
5190
|
-
|
|
5379
|
+
>
|
|
5191
5380
|
<div class="left">
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5381
|
+
@if (showBack && returnTo) {
|
|
5382
|
+
<a
|
|
5383
|
+
class="back-btn"
|
|
5384
|
+
[class.ghost]="variant === 'ghost'"
|
|
5385
|
+
[class.tonal]="variant === 'tonal'"
|
|
5386
|
+
[class.outlined]="variant === 'outlined'"
|
|
5387
|
+
[routerLink]="returnTo"
|
|
5388
|
+
[attr.aria-label]="backLabel || 'Voltar'"
|
|
5389
|
+
mat-button
|
|
5390
|
+
>
|
|
5391
|
+
<mat-icon [praxisIcon]="'arrow_back'"></mat-icon>
|
|
5392
|
+
<span class="label" [class.hide-on-narrow]="true">{{ backLabel || 'Voltar' }}</span>
|
|
5393
|
+
</a>
|
|
5394
|
+
}
|
|
5205
5395
|
<h2 class="title" [attr.title]="title">{{ title }}</h2>
|
|
5206
5396
|
</div>
|
|
5207
5397
|
<div class="right">
|
|
5208
5398
|
<ng-content></ng-content>
|
|
5209
5399
|
</div>
|
|
5210
5400
|
</header>
|
|
5211
|
-
|
|
5401
|
+
`, 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"] }] });
|
|
5212
5402
|
}
|
|
5213
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5403
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CrudPageHeaderComponent, decorators: [{
|
|
5214
5404
|
type: Component,
|
|
5215
|
-
args: [{ selector: 'praxis-crud-page-header', standalone: true, imports: [
|
|
5405
|
+
args: [{ selector: 'praxis-crud-page-header', standalone: true, imports: [RouterLink, MatButtonModule, MatIconModule, PraxisIconDirective], template: `
|
|
5216
5406
|
<header
|
|
5217
5407
|
class="crud-header"
|
|
5218
5408
|
[class.sticky]="sticky"
|
|
5219
5409
|
[class.with-divider]="divider"
|
|
5220
|
-
|
|
5410
|
+
>
|
|
5221
5411
|
<div class="left">
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5412
|
+
@if (showBack && returnTo) {
|
|
5413
|
+
<a
|
|
5414
|
+
class="back-btn"
|
|
5415
|
+
[class.ghost]="variant === 'ghost'"
|
|
5416
|
+
[class.tonal]="variant === 'tonal'"
|
|
5417
|
+
[class.outlined]="variant === 'outlined'"
|
|
5418
|
+
[routerLink]="returnTo"
|
|
5419
|
+
[attr.aria-label]="backLabel || 'Voltar'"
|
|
5420
|
+
mat-button
|
|
5421
|
+
>
|
|
5422
|
+
<mat-icon [praxisIcon]="'arrow_back'"></mat-icon>
|
|
5423
|
+
<span class="label" [class.hide-on-narrow]="true">{{ backLabel || 'Voltar' }}</span>
|
|
5424
|
+
</a>
|
|
5425
|
+
}
|
|
5235
5426
|
<h2 class="title" [attr.title]="title">{{ title }}</h2>
|
|
5236
5427
|
</div>
|
|
5237
5428
|
<div class="right">
|
|
5238
5429
|
<ng-content></ng-content>
|
|
5239
5430
|
</div>
|
|
5240
5431
|
</header>
|
|
5241
|
-
|
|
5432
|
+
`, 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"] }]
|
|
5242
5433
|
}], propDecorators: { title: [{
|
|
5243
5434
|
type: Input
|
|
5244
5435
|
}], backLabel: [{
|
|
@@ -5290,6 +5481,12 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5290
5481
|
{ path: 'resource.path', category: 'resource', valueKind: 'string', description: 'Endpoint base do recurso.' },
|
|
5291
5482
|
{ path: 'resource.idField', category: 'resource', valueKind: 'string', description: 'Campo identificador do recurso.' },
|
|
5292
5483
|
{ path: 'resource.endpointKey', category: 'resource', valueKind: 'string', description: 'Chave de endpoint (ApiEndpoint).' },
|
|
5484
|
+
{ path: 'queryContext.meta.domainCatalog', category: 'resource', valueKind: 'object', description: 'Referencia leve para contexto semantico/governanca resolvido via Domain Catalog; nao materializa regras em FormConfig.' },
|
|
5485
|
+
{ path: 'queryContext.meta.domainCatalog.schemaVersion', category: 'resource', valueKind: 'string', description: 'Versao do contrato DomainCatalogContextHint usado em runtime e prompts.' },
|
|
5486
|
+
{ path: 'queryContext.meta.domainCatalog.resourceKey', category: 'resource', valueKind: 'string', description: 'ResourceKey semantico estavel usado para resolver vocabulario/governanca de dominio.' },
|
|
5487
|
+
{ path: 'queryContext.meta.domainCatalog.releaseId', category: 'resource', valueKind: 'string', description: 'Release opcional do Domain Catalog usada como fonte do contexto.' },
|
|
5488
|
+
{ path: 'queryContext.meta.domainCatalog.query', category: 'resource', valueKind: 'string', description: 'Probe de campo/conceito usado para buscar itens relevantes, como cpf, salario ou status.' },
|
|
5489
|
+
{ 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.' },
|
|
5293
5490
|
// --- Table / Form ---
|
|
5294
5491
|
{ path: 'table', category: 'table', valueKind: 'object', description: 'TableConfig completo (usar catalogo de tabela).' },
|
|
5295
5492
|
{ path: 'form', category: 'form', valueKind: 'object', description: 'FormConfig completo (usar catalogo de formulario).' },
|
|
@@ -5346,6 +5543,438 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5346
5543
|
],
|
|
5347
5544
|
};
|
|
5348
5545
|
|
|
5546
|
+
const resourceBindSchema = {
|
|
5547
|
+
type: 'object',
|
|
5548
|
+
required: ['resourcePath'],
|
|
5549
|
+
properties: {
|
|
5550
|
+
resourcePath: { type: 'string' },
|
|
5551
|
+
resourceKey: { type: 'string' },
|
|
5552
|
+
idField: { type: ['string', 'number'] },
|
|
5553
|
+
endpointKey: { type: 'string' },
|
|
5554
|
+
queryContext: { type: 'object' },
|
|
5555
|
+
},
|
|
5556
|
+
};
|
|
5557
|
+
const surfaceConfigureSchema = {
|
|
5558
|
+
type: 'object',
|
|
5559
|
+
required: ['actionId', 'openMode'],
|
|
5560
|
+
properties: {
|
|
5561
|
+
actionId: { enum: ['create', 'edit', 'view'] },
|
|
5562
|
+
openMode: { enum: ['route', 'modal', 'drawer'] },
|
|
5563
|
+
route: { type: 'string' },
|
|
5564
|
+
formId: { type: 'string' },
|
|
5565
|
+
form: {
|
|
5566
|
+
type: 'object',
|
|
5567
|
+
properties: {
|
|
5568
|
+
schemaUrl: { type: 'string' },
|
|
5569
|
+
submitUrl: { type: 'string' },
|
|
5570
|
+
submitMethod: { enum: ['post', 'put', 'patch', 'delete'] },
|
|
5571
|
+
apiEndpointKey: { type: 'string' },
|
|
5572
|
+
initialValue: { type: 'object' },
|
|
5573
|
+
},
|
|
5574
|
+
},
|
|
5575
|
+
params: {
|
|
5576
|
+
type: 'array',
|
|
5577
|
+
items: {
|
|
5578
|
+
type: 'object',
|
|
5579
|
+
required: ['from', 'to', 'name'],
|
|
5580
|
+
properties: {
|
|
5581
|
+
from: { type: 'string' },
|
|
5582
|
+
to: { enum: ['routeParam', 'query', 'input'] },
|
|
5583
|
+
name: { type: 'string' },
|
|
5584
|
+
},
|
|
5585
|
+
},
|
|
5586
|
+
},
|
|
5587
|
+
back: { type: 'object' },
|
|
5588
|
+
},
|
|
5589
|
+
};
|
|
5590
|
+
const listSurfaceSchema = {
|
|
5591
|
+
type: 'object',
|
|
5592
|
+
properties: {
|
|
5593
|
+
tablePatch: { type: 'object' },
|
|
5594
|
+
queryContext: { type: 'object' },
|
|
5595
|
+
filterCriteria: { type: 'object' },
|
|
5596
|
+
},
|
|
5597
|
+
};
|
|
5598
|
+
const deleteBehaviorSchema = {
|
|
5599
|
+
type: 'object',
|
|
5600
|
+
required: ['enabled'],
|
|
5601
|
+
properties: {
|
|
5602
|
+
enabled: { type: 'boolean' },
|
|
5603
|
+
actionId: { type: 'string' },
|
|
5604
|
+
requiresConfirmation: { type: 'boolean' },
|
|
5605
|
+
autoDelete: { type: 'boolean' },
|
|
5606
|
+
form: {
|
|
5607
|
+
type: 'object',
|
|
5608
|
+
properties: {
|
|
5609
|
+
submitUrl: { type: 'string' },
|
|
5610
|
+
submitMethod: { enum: ['delete'] },
|
|
5611
|
+
apiEndpointKey: { type: 'string' },
|
|
5612
|
+
},
|
|
5613
|
+
},
|
|
5614
|
+
},
|
|
5615
|
+
};
|
|
5616
|
+
const dialogHostSchema = {
|
|
5617
|
+
type: 'object',
|
|
5618
|
+
properties: {
|
|
5619
|
+
defaultOpenMode: { enum: ['route', 'modal', 'drawer'] },
|
|
5620
|
+
modal: {
|
|
5621
|
+
type: 'object',
|
|
5622
|
+
properties: {
|
|
5623
|
+
width: { type: 'string' },
|
|
5624
|
+
height: { type: 'string' },
|
|
5625
|
+
minWidth: { type: 'string' },
|
|
5626
|
+
maxWidth: { type: 'string' },
|
|
5627
|
+
density: { type: 'string' },
|
|
5628
|
+
canMaximize: { type: 'boolean' },
|
|
5629
|
+
rememberLastState: { type: 'boolean' },
|
|
5630
|
+
startMaximized: { type: 'boolean' },
|
|
5631
|
+
disableCloseOnEsc: { type: 'boolean' },
|
|
5632
|
+
disableCloseOnBackdrop: { type: 'boolean' },
|
|
5633
|
+
fullscreenBreakpoint: { type: 'string' },
|
|
5634
|
+
},
|
|
5635
|
+
},
|
|
5636
|
+
back: { type: 'object' },
|
|
5637
|
+
},
|
|
5638
|
+
};
|
|
5639
|
+
const permissionsSchema = {
|
|
5640
|
+
type: 'object',
|
|
5641
|
+
properties: {
|
|
5642
|
+
requiredCapabilities: {
|
|
5643
|
+
type: 'array',
|
|
5644
|
+
items: { enum: ['create', 'view', 'edit', 'delete'] },
|
|
5645
|
+
},
|
|
5646
|
+
actionPermissions: { type: 'object' },
|
|
5647
|
+
denyWhenMissingCapability: { type: 'boolean' },
|
|
5648
|
+
},
|
|
5649
|
+
};
|
|
5650
|
+
const domainGovernanceContextSchema = {
|
|
5651
|
+
type: 'object',
|
|
5652
|
+
required: ['resourceKey', 'query'],
|
|
5653
|
+
properties: {
|
|
5654
|
+
resourceKey: { type: 'string' },
|
|
5655
|
+
releaseId: { type: 'string' },
|
|
5656
|
+
query: { type: 'string' },
|
|
5657
|
+
itemTypes: {
|
|
5658
|
+
type: 'array',
|
|
5659
|
+
items: { enum: ['governance', 'vocabulary', 'relationship'] },
|
|
5660
|
+
},
|
|
5661
|
+
intent: { enum: ['authoring', 'explain', 'validate', 'ai-access-control'] },
|
|
5662
|
+
},
|
|
5663
|
+
};
|
|
5664
|
+
const childDelegateSchema = {
|
|
5665
|
+
type: 'object',
|
|
5666
|
+
required: ['childComponentId', 'childOperationId', 'reason'],
|
|
5667
|
+
properties: {
|
|
5668
|
+
childComponentId: { enum: ['praxis-dynamic-form', 'praxis-table', 'praxis-dialog', 'praxis-settings-panel'] },
|
|
5669
|
+
childOperationId: { type: 'string' },
|
|
5670
|
+
reason: { type: 'string' },
|
|
5671
|
+
childTarget: { type: 'object' },
|
|
5672
|
+
childParams: { type: 'object' },
|
|
5673
|
+
},
|
|
5674
|
+
};
|
|
5675
|
+
const PRAXIS_CRUD_AUTHORING_MANIFEST = {
|
|
5676
|
+
schemaVersion: '1.0.0',
|
|
5677
|
+
componentId: 'praxis-crud',
|
|
5678
|
+
ownerPackage: '@praxisui/crud',
|
|
5679
|
+
configSchemaId: 'CrudMetadata',
|
|
5680
|
+
manifestVersion: '1.0.0',
|
|
5681
|
+
runtimeInputs: [
|
|
5682
|
+
{ name: 'metadata', type: 'CrudMetadata | string', description: 'Canonical CRUD metadata or serialized metadata document.' },
|
|
5683
|
+
{ name: 'crudId', type: 'string', description: 'Stable CRUD instance id used for table/form identity and persistence.' },
|
|
5684
|
+
{ name: 'componentInstanceId', type: 'string', description: 'Optional stable host instance id for multiple CRUD widgets on the same route.' },
|
|
5685
|
+
{ name: 'context', type: 'Record<string, unknown>', description: 'Opaque host context used for authoring seeds and launcher inputs.' },
|
|
5686
|
+
{ name: 'afterOpen', type: '{ mode: FormOpenMode; action: string }', description: 'Emitted after a CRUD action opens.' },
|
|
5687
|
+
{ name: 'afterSave', type: '{ id: string | number; data: unknown }', description: 'Emitted after save; CRUD refetches the list.' },
|
|
5688
|
+
{ name: 'afterDelete', type: '{ id: string | number }', description: 'Emitted after delete; CRUD refetches the list.' },
|
|
5689
|
+
],
|
|
5690
|
+
editableTargets: [
|
|
5691
|
+
{ kind: 'resourceBinding', resolver: 'crud-resource-by-path-or-key', description: 'Resource path/key, id field, endpoint key and query context owned by CRUD orchestration.' },
|
|
5692
|
+
{ kind: 'listSurface', resolver: 'crud-list-surface', description: 'CRUD-hosted list surface and table delegation boundary.' },
|
|
5693
|
+
{ kind: 'createSurface', resolver: 'crud-action-by-id:create', description: 'Create action open mode, route/form binding and launcher inputs.' },
|
|
5694
|
+
{ kind: 'editSurface', resolver: 'crud-action-by-id:edit', description: 'Edit action open mode, route/form binding and launcher inputs.' },
|
|
5695
|
+
{ kind: 'viewSurface', resolver: 'crud-action-by-id:view', description: 'View action open mode, route/form binding and launcher inputs.' },
|
|
5696
|
+
{ kind: 'deleteBehavior', resolver: 'crud-action-by-id:delete', description: 'Delete action enablement, confirmation, endpoint and capability policy.' },
|
|
5697
|
+
{ kind: 'dialogHost', resolver: 'crud-dialog-host-defaults', description: 'Route/modal/drawer defaults consumed by CrudLauncherService and DynamicFormDialogHostComponent.' },
|
|
5698
|
+
{ kind: 'formBinding', resolver: 'crud-action-form-contract-by-action-id', description: 'CRUD-owned form binding fields: formId, schemaUrl, submitUrl, submitMethod, params and initialValue.' },
|
|
5699
|
+
{ kind: 'permissions', resolver: 'crud-resource-capabilities', description: 'CRUD action availability derived from resource capabilities and action permissions.' },
|
|
5700
|
+
{ 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.' },
|
|
5701
|
+
{ kind: 'childOperation', resolver: 'child-authoring-manifest-operation', description: 'Delegated form/table/dialog/settings-panel operation owned by the child component manifest.' },
|
|
5702
|
+
],
|
|
5703
|
+
operations: [
|
|
5704
|
+
{
|
|
5705
|
+
operationId: 'resource.bind',
|
|
5706
|
+
title: 'Bind CRUD resource',
|
|
5707
|
+
scope: 'dataBinding',
|
|
5708
|
+
targetKind: 'resourceBinding',
|
|
5709
|
+
target: { kind: 'resourceBinding', resolver: 'crud-resource-by-path-or-key', ambiguityPolicy: 'fail', required: true },
|
|
5710
|
+
inputSchema: resourceBindSchema,
|
|
5711
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-resource-bind', handlerContract: {
|
|
5712
|
+
reads: ['CrudMetadata.resource', 'api_metadata', 'ResourceDiscoveryService', 'GET /{resource}/capabilities'],
|
|
5713
|
+
writes: ['CrudMetadata.resource', 'CrudMetadata.queryContext', 'PraxisCrudComponent.tableCrudContext'],
|
|
5714
|
+
identityKeys: ['resourcePath', 'resourceKey'],
|
|
5715
|
+
inputSchema: resourceBindSchema,
|
|
5716
|
+
failureModes: ['resource-not-found', 'schema-url-not-canonical', 'capabilities-unavailable', 'id-field-missing'],
|
|
5717
|
+
description: 'Binds CRUD to a canonical resource and validates it against api_metadata/resource capabilities before runtime use.',
|
|
5718
|
+
} }],
|
|
5719
|
+
validators: ['resource-exists-in-api-metadata', 'resource-path-canonical', 'resource-key-stable', 'id-field-known', 'resource-capabilities-resolvable'],
|
|
5720
|
+
affectedPaths: ['resource.path', 'resource.idField', 'resource.endpointKey', 'queryContext', 'filterCriteria'],
|
|
5721
|
+
submissionImpact: 'affects-remote-binding',
|
|
5722
|
+
preconditions: ['crud-metadata-loaded', 'api-metadata-available'],
|
|
5723
|
+
},
|
|
5724
|
+
{
|
|
5725
|
+
operationId: 'domain.governanceContext.attach',
|
|
5726
|
+
title: 'Attach Domain Catalog governance context',
|
|
5727
|
+
scope: 'dataBinding',
|
|
5728
|
+
targetKind: 'domainGovernanceContext',
|
|
5729
|
+
target: { kind: 'domainGovernanceContext', resolver: 'domain-catalog-context-by-resource-key', ambiguityPolicy: 'fail', required: true },
|
|
5730
|
+
inputSchema: domainGovernanceContextSchema,
|
|
5731
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-domain-governance-context-attach', handlerContract: {
|
|
5732
|
+
reads: ['CrudMetadata.resource', 'CrudMetadata.queryContext', 'DomainCatalogService.getGovernanceContext', 'DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK', 'api_metadata'],
|
|
5733
|
+
writes: ['CrudMetadata.queryContext.meta.domainCatalog'],
|
|
5734
|
+
identityKeys: ['resourceKey', 'releaseId', 'query'],
|
|
5735
|
+
inputSchema: domainGovernanceContextSchema,
|
|
5736
|
+
failureModes: ['resource-key-missing', 'domain-catalog-release-not-found', 'governance-context-empty', 'ai-usage-forbidden'],
|
|
5737
|
+
description: 'Resolves read-only domain vocabulary/governance context and stores only a lightweight reference/probe under queryContext.meta.domainCatalog.',
|
|
5738
|
+
} }],
|
|
5739
|
+
validators: ['resource-key-stable', 'domain-catalog-context-resolvable', 'domain-catalog-read-only', 'ai-usage-visibility-respected', 'no-form-config-rule-materialization'],
|
|
5740
|
+
affectedPaths: ['queryContext.meta.domainCatalog'],
|
|
5741
|
+
submissionImpact: 'config-only',
|
|
5742
|
+
preconditions: ['crud-metadata-loaded', 'api-metadata-available', 'domain-catalog-service-available'],
|
|
5743
|
+
},
|
|
5744
|
+
{
|
|
5745
|
+
operationId: 'list.surface.configure',
|
|
5746
|
+
title: 'Configure CRUD list surface',
|
|
5747
|
+
scope: 'interaction',
|
|
5748
|
+
targetKind: 'listSurface',
|
|
5749
|
+
target: { kind: 'listSurface', resolver: 'crud-list-surface', ambiguityPolicy: 'fail', required: true },
|
|
5750
|
+
inputSchema: listSurfaceSchema,
|
|
5751
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-list-surface-configure', handlerContract: {
|
|
5752
|
+
reads: ['CrudMetadata.table', 'CrudMetadata.queryContext', 'PRAXIS_TABLE_AUTHORING_MANIFEST', 'CRUD_AI_CAPABILITIES'],
|
|
5753
|
+
writes: ['CrudMetadata.table', 'CrudMetadata.queryContext', 'CrudMetadata.filterCriteria'],
|
|
5754
|
+
identityKeys: ['crudId'],
|
|
5755
|
+
inputSchema: listSurfaceSchema,
|
|
5756
|
+
failureModes: ['table-operation-not-delegated', 'table-patch-not-supported', 'query-context-invalid'],
|
|
5757
|
+
description: 'Configures CRUD-owned list orchestration while routing table semantics to the praxis-table manifest.',
|
|
5758
|
+
} }],
|
|
5759
|
+
validators: ['table-child-operation-delegated', 'query-context-valid', 'filter-criteria-bridge-valid', 'crud-context-stable'],
|
|
5760
|
+
affectedPaths: ['table', 'queryContext', 'filterCriteria'],
|
|
5761
|
+
submissionImpact: 'config-only',
|
|
5762
|
+
preconditions: ['crud-metadata-loaded', 'praxis-table-manifest-available'],
|
|
5763
|
+
},
|
|
5764
|
+
{
|
|
5765
|
+
operationId: 'surface.create.configure',
|
|
5766
|
+
title: 'Configure create surface',
|
|
5767
|
+
scope: 'interaction',
|
|
5768
|
+
targetKind: 'createSurface',
|
|
5769
|
+
target: { kind: 'createSurface', resolver: 'crud-action-by-id:create', ambiguityPolicy: 'fail', required: true },
|
|
5770
|
+
inputSchema: surfaceConfigureSchema,
|
|
5771
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-create-surface-configure', handlerContract: {
|
|
5772
|
+
reads: ['CrudMetadata.actions', 'CrudLauncherService.resolveOpenMode', 'DynamicFormDialogHostComponent', 'api_metadata'],
|
|
5773
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].form', 'CrudMetadata.actions[].params', 'CrudMetadata.actions[].back'],
|
|
5774
|
+
identityKeys: ['actionId'],
|
|
5775
|
+
inputSchema: surfaceConfigureSchema,
|
|
5776
|
+
failureModes: ['action-not-found', 'open-mode-binding-incomplete', 'schema-url-not-canonical', 'submit-url-not-canonical', 'resource-create-not-supported'],
|
|
5777
|
+
description: 'Configures create action binding and launcher inputs without editing the child FormConfig.',
|
|
5778
|
+
} }],
|
|
5779
|
+
validators: ['action-exists', 'open-mode-binding-complete', 'schema-url-canonical', 'submit-url-canonical', 'resource-create-supported', 'form-child-operation-delegated'],
|
|
5780
|
+
affectedPaths: ['actions[].openMode', 'actions[].route', 'actions[].formId', 'actions[].form', 'actions[].params', 'actions[].back'],
|
|
5781
|
+
submissionImpact: 'affects-schema-backed-data',
|
|
5782
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5783
|
+
},
|
|
5784
|
+
{
|
|
5785
|
+
operationId: 'surface.edit.configure',
|
|
5786
|
+
title: 'Configure edit surface',
|
|
5787
|
+
scope: 'interaction',
|
|
5788
|
+
targetKind: 'editSurface',
|
|
5789
|
+
target: { kind: 'editSurface', resolver: 'crud-action-by-id:edit', ambiguityPolicy: 'fail', required: true },
|
|
5790
|
+
inputSchema: surfaceConfigureSchema,
|
|
5791
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-edit-surface-configure', handlerContract: {
|
|
5792
|
+
reads: ['CrudMetadata.actions', 'CrudMetadata.resource.idField', 'CrudLauncherService.resolveOpenMode', 'api_metadata'],
|
|
5793
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].form', 'CrudMetadata.actions[].params', 'CrudMetadata.actions[].back'],
|
|
5794
|
+
identityKeys: ['actionId'],
|
|
5795
|
+
inputSchema: surfaceConfigureSchema,
|
|
5796
|
+
failureModes: ['action-not-found', 'id-param-missing', 'open-mode-binding-incomplete', 'resource-edit-not-supported', 'submit-url-not-canonical'],
|
|
5797
|
+
description: 'Configures edit action routing/form binding and ensures id parameter mapping is available to the launcher.',
|
|
5798
|
+
} }],
|
|
5799
|
+
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'],
|
|
5800
|
+
affectedPaths: ['actions[].openMode', 'actions[].route', 'actions[].formId', 'actions[].form', 'actions[].params', 'actions[].back'],
|
|
5801
|
+
submissionImpact: 'affects-schema-backed-data',
|
|
5802
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5803
|
+
},
|
|
5804
|
+
{
|
|
5805
|
+
operationId: 'surface.view.configure',
|
|
5806
|
+
title: 'Configure view surface',
|
|
5807
|
+
scope: 'interaction',
|
|
5808
|
+
targetKind: 'viewSurface',
|
|
5809
|
+
target: { kind: 'viewSurface', resolver: 'crud-action-by-id:view', ambiguityPolicy: 'fail', required: true },
|
|
5810
|
+
inputSchema: surfaceConfigureSchema,
|
|
5811
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-view-surface-configure', handlerContract: {
|
|
5812
|
+
reads: ['CrudMetadata.actions', 'CrudLauncherService.resolveOpenMode', 'DynamicFormDialogHostComponent', 'api_metadata'],
|
|
5813
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].form', 'CrudMetadata.actions[].params', 'CrudMetadata.actions[].back'],
|
|
5814
|
+
identityKeys: ['actionId'],
|
|
5815
|
+
inputSchema: surfaceConfigureSchema,
|
|
5816
|
+
failureModes: ['action-not-found', 'open-mode-binding-incomplete', 'resource-view-not-supported', 'readonly-form-delegation-missing'],
|
|
5817
|
+
description: 'Configures view action binding and delegates readonly form behavior to the dynamic-form manifest.',
|
|
5818
|
+
} }],
|
|
5819
|
+
validators: ['action-exists', 'open-mode-binding-complete', 'schema-url-canonical', 'resource-view-supported', 'form-child-operation-delegated', 'readonly-form-delegation-valid'],
|
|
5820
|
+
affectedPaths: ['actions[].openMode', 'actions[].route', 'actions[].formId', 'actions[].form', 'actions[].params', 'actions[].back'],
|
|
5821
|
+
submissionImpact: 'config-only',
|
|
5822
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5823
|
+
},
|
|
5824
|
+
{
|
|
5825
|
+
operationId: 'delete.enabled.set',
|
|
5826
|
+
title: 'Configure delete behavior',
|
|
5827
|
+
scope: 'interaction',
|
|
5828
|
+
targetKind: 'deleteBehavior',
|
|
5829
|
+
target: { kind: 'deleteBehavior', resolver: 'crud-action-by-id:delete', ambiguityPolicy: 'fail', required: true },
|
|
5830
|
+
inputSchema: deleteBehaviorSchema,
|
|
5831
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-delete-behavior-set', handlerContract: {
|
|
5832
|
+
reads: ['CrudMetadata.actions', 'CrudMetadata.resource', 'GET /{resource}/{id}/capabilities'],
|
|
5833
|
+
writes: ['CrudMetadata.actions[]', 'CrudMetadata.actions[].requiresConfirmation', 'CrudMetadata.actions[].autoDelete', 'CrudMetadata.actions[].form'],
|
|
5834
|
+
identityKeys: ['actionId'],
|
|
5835
|
+
inputSchema: deleteBehaviorSchema,
|
|
5836
|
+
failureModes: ['delete-action-not-found', 'resource-delete-not-supported', 'destructive-delete-not-confirmed', 'delete-submit-url-not-canonical'],
|
|
5837
|
+
description: 'Enables or disables delete behavior with capability checks and explicit confirmation for destructive changes.',
|
|
5838
|
+
} }],
|
|
5839
|
+
destructive: true,
|
|
5840
|
+
requiresConfirmation: true,
|
|
5841
|
+
validators: ['delete-action-exists', 'resource-delete-supported', 'destructive-delete-confirmed', 'submit-url-canonical', 'permissions-delete-valid'],
|
|
5842
|
+
affectedPaths: ['actions[].disabled', 'actions[].requiresConfirmation', 'actions[].autoDelete', 'actions[].form', 'actions[].form.submitUrl', 'actions[].form.submitMethod', 'actions[].form.apiEndpointKey'],
|
|
5843
|
+
submissionImpact: 'affects-schema-backed-data',
|
|
5844
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved', 'explicit-confirmation-provided'],
|
|
5845
|
+
},
|
|
5846
|
+
{
|
|
5847
|
+
operationId: 'dialog.size.set',
|
|
5848
|
+
title: 'Configure CRUD dialog host defaults',
|
|
5849
|
+
scope: 'interaction',
|
|
5850
|
+
targetKind: 'dialogHost',
|
|
5851
|
+
target: { kind: 'dialogHost', resolver: 'crud-dialog-host-defaults', ambiguityPolicy: 'fail', required: true },
|
|
5852
|
+
inputSchema: dialogHostSchema,
|
|
5853
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-dialog-host-set', handlerContract: {
|
|
5854
|
+
reads: ['CrudMetadata.defaults', 'CrudLauncherService.resolveOpenMode', 'DialogService', 'CRUD_DRAWER_ADAPTER'],
|
|
5855
|
+
writes: ['CrudMetadata.defaults.openMode', 'CrudMetadata.defaults.modal', 'CrudMetadata.defaults.back'],
|
|
5856
|
+
identityKeys: ['crudId'],
|
|
5857
|
+
inputSchema: dialogHostSchema,
|
|
5858
|
+
failureModes: ['open-mode-unsupported', 'drawer-adapter-missing', 'modal-size-invalid', 'back-policy-invalid'],
|
|
5859
|
+
description: 'Configures CRUD-owned route/modal/drawer defaults consumed by the launcher and dialog host.',
|
|
5860
|
+
} }],
|
|
5861
|
+
validators: ['open-mode-supported', 'modal-size-valid', 'drawer-adapter-available-when-needed', 'back-policy-valid', 'settings-panel-shell-compatible'],
|
|
5862
|
+
affectedPaths: ['defaults.openMode', 'defaults.modal', 'defaults.back'],
|
|
5863
|
+
submissionImpact: 'config-only',
|
|
5864
|
+
preconditions: ['crud-metadata-loaded'],
|
|
5865
|
+
},
|
|
5866
|
+
{
|
|
5867
|
+
operationId: 'permissions.set',
|
|
5868
|
+
title: 'Configure CRUD permissions',
|
|
5869
|
+
scope: 'interaction',
|
|
5870
|
+
targetKind: 'permissions',
|
|
5871
|
+
target: { kind: 'permissions', resolver: 'crud-resource-capabilities', ambiguityPolicy: 'fail', required: true },
|
|
5872
|
+
inputSchema: permissionsSchema,
|
|
5873
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-permissions-set', handlerContract: {
|
|
5874
|
+
reads: ['GET /{resource}/capabilities', 'GET /{resource}/{id}/capabilities', 'CrudMetadata.actions'],
|
|
5875
|
+
writes: ['CrudMetadata.actions[].disabled', 'CrudMetadata.actions[].visibleWhen', 'CrudMetadata.actions[].requiresConfirmation'],
|
|
5876
|
+
identityKeys: ['resourcePath'],
|
|
5877
|
+
inputSchema: permissionsSchema,
|
|
5878
|
+
failureModes: ['capability-not-found', 'action-permission-conflict', 'delete-permission-without-confirmation'],
|
|
5879
|
+
description: 'Aligns CRUD action visibility/disablement with resource capabilities without inventing a second permission source.',
|
|
5880
|
+
} }],
|
|
5881
|
+
validators: ['resource-capabilities-resolvable', 'action-permission-supported', 'delete-permission-requires-confirmation', 'permissions-do-not-shadow-backend'],
|
|
5882
|
+
affectedPaths: ['actions[].disabled', 'actions[].visibleWhen', 'actions[].requiresConfirmation'],
|
|
5883
|
+
submissionImpact: 'config-only',
|
|
5884
|
+
preconditions: ['crud-metadata-loaded', 'resource-capabilities-resolved'],
|
|
5885
|
+
},
|
|
5886
|
+
{
|
|
5887
|
+
operationId: 'form.childOperation.delegate',
|
|
5888
|
+
title: 'Delegate child form/table/dialog authoring operation',
|
|
5889
|
+
scope: 'global',
|
|
5890
|
+
targetKind: 'childOperation',
|
|
5891
|
+
target: { kind: 'childOperation', resolver: 'child-authoring-manifest-operation', ambiguityPolicy: 'fail', required: false },
|
|
5892
|
+
inputSchema: childDelegateSchema,
|
|
5893
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'crud-child-operation-delegate', handlerContract: {
|
|
5894
|
+
reads: ['PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST', 'PRAXIS_TABLE_AUTHORING_MANIFEST', 'PRAXIS_DIALOG_AUTHORING_MANIFEST', 'PRAXIS_SETTINGS_PANEL_AUTHORING_MANIFEST'],
|
|
5895
|
+
writes: ['delegatedAuthoringOperations[]'],
|
|
5896
|
+
identityKeys: ['childComponentId', 'childOperationId'],
|
|
5897
|
+
inputSchema: childDelegateSchema,
|
|
5898
|
+
failureModes: ['child-manifest-missing', 'child-operation-not-found', 'attempted-local-child-config-write'],
|
|
5899
|
+
description: 'Records explicit delegation when requested edits belong to child manifests instead of CRUD orchestration.',
|
|
5900
|
+
} }],
|
|
5901
|
+
validators: ['child-manifest-available', 'child-operation-known', 'no-local-form-config-write', 'no-local-table-config-write', 'delegation-target-valid'],
|
|
5902
|
+
affectedPaths: ['delegatedAuthoringOperations'],
|
|
5903
|
+
submissionImpact: 'none',
|
|
5904
|
+
preconditions: ['child-manifest-available'],
|
|
5905
|
+
},
|
|
5906
|
+
],
|
|
5907
|
+
validators: [
|
|
5908
|
+
{ validatorId: 'resource-exists-in-api-metadata', level: 'error', code: 'CRUD_RESOURCE_EXISTS', description: 'Resource must exist in api_metadata or resource discovery.' },
|
|
5909
|
+
{ validatorId: 'resource-path-canonical', level: 'error', code: 'CRUD_RESOURCE_PATH_CANONICAL', description: 'Resource path must be canonical and not a local alias.' },
|
|
5910
|
+
{ validatorId: 'resource-key-stable', level: 'error', code: 'CRUD_RESOURCE_KEY_STABLE', description: 'Resource key must remain stable for surfaces/actions/capabilities.' },
|
|
5911
|
+
{ validatorId: 'id-field-known', level: 'error', code: 'CRUD_ID_FIELD_KNOWN', description: 'CRUD id field must exist for edit/view/delete flows.' },
|
|
5912
|
+
{ validatorId: 'resource-capabilities-resolvable', level: 'error', code: 'CRUD_CAPABILITIES_RESOLVABLE', description: 'Resource capabilities must be resolvable before action enablement is authored.' },
|
|
5913
|
+
{ 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.' },
|
|
5914
|
+
{ 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.' },
|
|
5915
|
+
{ 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.' },
|
|
5916
|
+
{ 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.' },
|
|
5917
|
+
{ validatorId: 'table-child-operation-delegated', level: 'error', code: 'CRUD_TABLE_CHILD_DELEGATED', description: 'Table semantics must be delegated to praxis-table.' },
|
|
5918
|
+
{ validatorId: 'query-context-valid', level: 'error', code: 'CRUD_QUERY_CONTEXT_VALID', description: 'Query context must be valid for the bound resource.' },
|
|
5919
|
+
{ validatorId: 'filter-criteria-bridge-valid', level: 'warning', code: 'CRUD_FILTER_CRITERIA_BRIDGE_VALID', description: 'filterCriteria is a bridge; prefer queryContext for new remote authoring.' },
|
|
5920
|
+
{ validatorId: 'crud-context-stable', level: 'error', code: 'CRUD_CONTEXT_STABLE', description: 'Authoring must not break stable crudContext references.' },
|
|
5921
|
+
{ validatorId: 'action-exists', level: 'error', code: 'CRUD_ACTION_EXISTS', description: 'Target action must exist or be created through CRUD action orchestration.' },
|
|
5922
|
+
{ 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.' },
|
|
5923
|
+
{ validatorId: 'schema-url-canonical', level: 'error', code: 'CRUD_SCHEMA_URL_CANONICAL', description: 'Schema URLs must be canonical for the bound resource/action.' },
|
|
5924
|
+
{ validatorId: 'submit-url-canonical', level: 'error', code: 'CRUD_SUBMIT_URL_CANONICAL', description: 'Submit URL and method must be canonical and declared together.' },
|
|
5925
|
+
{ validatorId: 'resource-create-supported', level: 'error', code: 'CRUD_CREATE_SUPPORTED', description: 'Create surface requires resource create capability.' },
|
|
5926
|
+
{ validatorId: 'resource-edit-supported', level: 'error', code: 'CRUD_EDIT_SUPPORTED', description: 'Edit surface requires resource edit capability.' },
|
|
5927
|
+
{ validatorId: 'resource-view-supported', level: 'error', code: 'CRUD_VIEW_SUPPORTED', description: 'View surface requires resource view capability.' },
|
|
5928
|
+
{ 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.' },
|
|
5929
|
+
{ 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.' },
|
|
5930
|
+
{ validatorId: 'readonly-form-delegation-valid', level: 'error', code: 'CRUD_READONLY_FORM_DELEGATED', description: 'Readonly form behavior belongs to the dynamic-form manifest.' },
|
|
5931
|
+
{ validatorId: 'delete-action-exists', level: 'error', code: 'CRUD_DELETE_ACTION_EXISTS', description: 'Delete behavior requires a delete action target.' },
|
|
5932
|
+
{ validatorId: 'resource-delete-supported', level: 'error', code: 'CRUD_DELETE_SUPPORTED', description: 'Delete behavior requires resource delete capability.' },
|
|
5933
|
+
{ validatorId: 'destructive-delete-confirmed', level: 'error', code: 'CRUD_DELETE_CONFIRMED', description: 'Destructive delete behavior requires explicit confirmation.' },
|
|
5934
|
+
{ validatorId: 'permissions-delete-valid', level: 'error', code: 'CRUD_DELETE_PERMISSION_VALID', description: 'Delete permission cannot bypass resource capabilities or confirmation policy.' },
|
|
5935
|
+
{ validatorId: 'open-mode-supported', level: 'error', code: 'CRUD_OPEN_MODE_SUPPORTED', description: 'Open mode must be route, modal or drawer.' },
|
|
5936
|
+
{ validatorId: 'modal-size-valid', level: 'error', code: 'CRUD_MODAL_SIZE_VALID', description: 'Modal sizing defaults must be valid DialogConfig values.' },
|
|
5937
|
+
{ validatorId: 'drawer-adapter-available-when-needed', level: 'error', code: 'CRUD_DRAWER_ADAPTER_AVAILABLE', description: 'Drawer open mode requires a host-provided drawer adapter.' },
|
|
5938
|
+
{ validatorId: 'back-policy-valid', level: 'error', code: 'CRUD_BACK_POLICY_VALID', description: 'Back policy must be valid for route/modal/drawer behavior.' },
|
|
5939
|
+
{ validatorId: 'settings-panel-shell-compatible', level: 'warning', code: 'CRUD_SETTINGS_PANEL_COMPATIBLE', description: 'Authoring shell must preserve apply/save/reset semantics.' },
|
|
5940
|
+
{ validatorId: 'action-permission-supported', level: 'error', code: 'CRUD_ACTION_PERMISSION_SUPPORTED', description: 'Action permissions must map to supported resource capabilities.' },
|
|
5941
|
+
{ validatorId: 'delete-permission-requires-confirmation', level: 'error', code: 'CRUD_DELETE_PERMISSION_CONFIRMATION', description: 'Delete permission enablement requires confirmation policy.' },
|
|
5942
|
+
{ validatorId: 'permissions-do-not-shadow-backend', level: 'error', code: 'CRUD_PERMISSIONS_NO_BACKEND_SHADOW', description: 'UI permissions must not shadow backend capability denial.' },
|
|
5943
|
+
{ validatorId: 'child-manifest-available', level: 'error', code: 'CRUD_CHILD_MANIFEST_AVAILABLE', description: 'Delegated child manifest must be available.' },
|
|
5944
|
+
{ validatorId: 'child-operation-known', level: 'error', code: 'CRUD_CHILD_OPERATION_KNOWN', description: 'Delegated operation must exist in the child manifest.' },
|
|
5945
|
+
{ validatorId: 'no-local-form-config-write', level: 'error', code: 'CRUD_NO_LOCAL_FORM_CONFIG_WRITE', description: 'CRUD must not locally redefine FormConfig semantics.' },
|
|
5946
|
+
{ validatorId: 'no-local-table-config-write', level: 'error', code: 'CRUD_NO_LOCAL_TABLE_CONFIG_WRITE', description: 'CRUD must not locally redefine TableConfig semantics.' },
|
|
5947
|
+
{ validatorId: 'delegation-target-valid', level: 'error', code: 'CRUD_DELEGATION_TARGET_VALID', description: 'Delegation target must be resolvable by the child manifest.' },
|
|
5948
|
+
],
|
|
5949
|
+
roundTripRequirements: [
|
|
5950
|
+
'CrudMetadata is the canonical CRUD document shape.',
|
|
5951
|
+
'CrudAuthoringDocument wraps CrudMetadata without introducing host-local aliases.',
|
|
5952
|
+
'Resource path and resource key have separate semantics: path is operational, key is discovery/capability identity.',
|
|
5953
|
+
'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.',
|
|
5954
|
+
'Open mode round-trip must preserve route, formId, form contract, params, initialValue and back policy.',
|
|
5955
|
+
'FormConfig and FieldMetadata edits must delegate to dynamic-form or metadata-editor manifests.',
|
|
5956
|
+
'TableConfig edits must delegate to praxis-table; CRUD owns only shell orchestration and list surface binding.',
|
|
5957
|
+
'Delete behavior is destructive and requires explicit confirmation plus backend capability support.',
|
|
5958
|
+
'crudContext must remain reference-stable across change detection cycles.',
|
|
5959
|
+
],
|
|
5960
|
+
examples: [
|
|
5961
|
+
{ 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 },
|
|
5962
|
+
{ 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 },
|
|
5963
|
+
{ 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 },
|
|
5964
|
+
{ 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 },
|
|
5965
|
+
{ 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 },
|
|
5966
|
+
{ 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 },
|
|
5967
|
+
{ 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 },
|
|
5968
|
+
{ 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 },
|
|
5969
|
+
{ 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 },
|
|
5970
|
+
{ 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 },
|
|
5971
|
+
{ 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 },
|
|
5972
|
+
{ 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 },
|
|
5973
|
+
{ 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 },
|
|
5974
|
+
{ 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 },
|
|
5975
|
+
],
|
|
5976
|
+
};
|
|
5977
|
+
|
|
5349
5978
|
/*
|
|
5350
5979
|
* Public API Surface of praxis-crud
|
|
5351
5980
|
*/
|
|
@@ -5354,4 +5983,4 @@ const CRUD_AI_CAPABILITIES = {
|
|
|
5354
5983
|
* Generated bundle index. Do not edit.
|
|
5355
5984
|
*/
|
|
5356
5985
|
|
|
5357
|
-
export { CRUD_AI_CAPABILITIES, CrudLauncherService, CrudMetadataEditorComponent, CrudPageHeaderComponent, DialogService, DynamicFormDialogHostComponent, PRAXIS_CRUD_COMPONENT_METADATA, PraxisCrudComponent, assertCrudMetadata, createCrudAuthoringDocument, findCrudAction, normalizeCrudAuthoringDocument, openCrudMetadataEditor, parseLegacyOrCrudDocument, providePraxisCrudMetadata, serializeCrudAuthoringDocument, validateCrudAuthoringDocument };
|
|
5986
|
+
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 };
|