@masterteam/form-builder 0.0.50 → 0.0.51

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.
@@ -29,10 +29,10 @@ import { DynamicForm } from '@masterteam/forms/dynamic-form';
29
29
  import { ToggleField } from '@masterteam/components/toggle-field';
30
30
  import { ModalRef } from '@masterteam/components/dialog';
31
31
  import { CONDITION_FUNCTION_CATEGORIES, CONDITION_OPERATORS, FormulaToolbar, FormulaEditor, serializeTokens, tokenizeFormulaTemplate, serializeTokensForDisplay } from '@masterteam/components/formula';
32
+ import { of, map, catchError, tap, startWith } from 'rxjs';
32
33
  import { Tooltip } from '@masterteam/components/tooltip';
33
34
  import { ClientForm } from '@masterteam/forms/client-form';
34
35
  import { Table } from '@masterteam/components/table';
35
- import { startWith, of, map, catchError } from 'rxjs';
36
36
  import { RadioCardsField } from '@masterteam/components/radio-cards-field';
37
37
  import { FormulaBuilder } from '@masterteam/formula-builder';
38
38
 
@@ -1227,6 +1227,120 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1227
1227
  args: [{ providedIn: 'root' }]
1228
1228
  }] });
1229
1229
 
1230
+ /**
1231
+ * View types whose values the backend can serve. Matched after lower-casing
1232
+ * and stripping spaces/underscores/dashes, and kept in step with the backend
1233
+ * gate (`PropertyItemsLookupSourceResolver.IsLookupBacked` plus `Status`) —
1234
+ * every other view type is rejected with a validation error.
1235
+ */
1236
+ const VALUE_BACKED_VIEW_TYPES = new Set([
1237
+ 'lookup',
1238
+ 'lookupmultiselect',
1239
+ 'lookupmatrix',
1240
+ 'status',
1241
+ ]);
1242
+ /** Whether a property's values can be picked from a source instead of typed. */
1243
+ function isValueBackedViewType(viewType) {
1244
+ if (!viewType)
1245
+ return false;
1246
+ return VALUE_BACKED_VIEW_TYPES.has(viewType.toLowerCase().replace(/[ _-]/g, ''));
1247
+ }
1248
+ class FormBuilderContextService {
1249
+ http = inject(HttpClient);
1250
+ baseUrl = 'context';
1251
+ propertyItemsCache = new Map();
1252
+ /**
1253
+ * Resolves context data including navigation paths and properties.
1254
+ * No caching - always fetches fresh data.
1255
+ */
1256
+ resolveContext(contextKey, options = {}) {
1257
+ if (!contextKey)
1258
+ return of(null);
1259
+ return this.http
1260
+ .post(`${this.baseUrl}/resolve`, {
1261
+ contextKey,
1262
+ displayTags: options.displayTags,
1263
+ propertyFlags: options.propertyFlags,
1264
+ matchAllTags: options.matchAllTags,
1265
+ includeVirtual: options.includeVirtual,
1266
+ includeNavigationPaths: options.includeNavigationPaths,
1267
+ includeConnectionMetadata: options.includeConnectionMetadata,
1268
+ includeRelatedContextValues: options.includeRelatedContextValues,
1269
+ relatedContextsToInclude: options.relatedContextsToInclude,
1270
+ // Consumer-supplied fields win on collision with any field above.
1271
+ ...options.extraParams,
1272
+ })
1273
+ .pipe(map((response) => this.normalizeResponse(response)), catchError((error) => {
1274
+ console.warn('Failed to resolve context:', error);
1275
+ return of(null);
1276
+ }));
1277
+ }
1278
+ /**
1279
+ * Gets properties for a context.
1280
+ * No caching - always fetches fresh data.
1281
+ */
1282
+ getProperties(contextKey, options = {}) {
1283
+ if (!contextKey)
1284
+ return of([]);
1285
+ return this.resolveContext(contextKey, options).pipe(map((resolved) => resolved?.properties ?? []));
1286
+ }
1287
+ /**
1288
+ * Selectable values of a lookup / lookup-matrix / status property, used by
1289
+ * the condition builder so a compared value is picked rather than typed.
1290
+ *
1291
+ * The backend answers 400 for any other view type, which we swallow into an
1292
+ * empty list — callers already gate on `isValueBackedViewType`, so empty
1293
+ * simply means "nothing to pick".
1294
+ */
1295
+ getPropertyItems(propertyKey) {
1296
+ if (!propertyKey)
1297
+ return of([]);
1298
+ const cached = this.propertyItemsCache.get(propertyKey);
1299
+ if (cached)
1300
+ return of(cached);
1301
+ return this.http
1302
+ .get(`formulas/builder/property-items/${encodeURIComponent(propertyKey)}`)
1303
+ .pipe(map((response) => {
1304
+ const payload = response && 'data' in response ? response.data : response;
1305
+ return payload?.items ?? [];
1306
+ }), tap((items) => this.propertyItemsCache.set(propertyKey, items)), catchError((error) => {
1307
+ console.warn('Failed to load property items:', error);
1308
+ return of([]);
1309
+ }));
1310
+ }
1311
+ normalizeResponse(response) {
1312
+ const payload = response?.data ?? response;
1313
+ if (!payload)
1314
+ return null;
1315
+ const properties = this.normalizeProperties(payload.properties ?? []);
1316
+ return {
1317
+ ...payload,
1318
+ properties,
1319
+ };
1320
+ }
1321
+ normalizeProperties(raw) {
1322
+ return (raw ?? [])
1323
+ .map((prop) => {
1324
+ const key = prop?.key ?? prop?.propertyKey;
1325
+ if (!key)
1326
+ return null;
1327
+ const name = prop?.name ?? prop?.displayName ?? key;
1328
+ return {
1329
+ ...prop,
1330
+ key,
1331
+ name,
1332
+ };
1333
+ })
1334
+ .filter((prop) => Boolean(prop));
1335
+ }
1336
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormBuilderContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1337
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormBuilderContextService, providedIn: 'root' });
1338
+ }
1339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormBuilderContextService, decorators: [{
1340
+ type: Injectable,
1341
+ args: [{ providedIn: 'root' }]
1342
+ }] });
1343
+
1230
1344
  /**
1231
1345
  * Field Conditions Dialog
1232
1346
  *
@@ -1235,6 +1349,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1235
1349
  */
1236
1350
  class FBFieldConditions {
1237
1351
  modalService = inject(ModalService);
1352
+ contextService = inject(FormBuilderContextService);
1238
1353
  ref = inject(ModalRef);
1239
1354
  transloco = inject(TranslocoService);
1240
1355
  destroyRef = inject(DestroyRef);
@@ -1253,11 +1368,16 @@ class FBFieldConditions {
1253
1368
  // Condition-specific functions and operators
1254
1369
  functionCategories = CONDITION_FUNCTION_CATEGORIES;
1255
1370
  operators = CONDITION_OPERATORS;
1371
+ /** Values already loaded, keyed by property key. */
1372
+ propertyValues = signal({}, ...(ngDevMode ? [{ debugName: "propertyValues" }] : /* istanbul ignore next */ []));
1373
+ /** Property key whose values are being fetched right now. */
1374
+ loadingValuesFor = signal(null, ...(ngDevMode ? [{ debugName: "loadingValuesFor" }] : /* istanbul ignore next */ []));
1256
1375
  /** Property display items for toolbar; keys remain the persisted formula value. */
1257
1376
  propertyItems = computed(() => this.availableFields().map((field) => ({
1258
1377
  key: field.key,
1259
1378
  name: field.name,
1260
1379
  description: field.type ? `${field.name} (${field.type})` : field.name,
1380
+ hasValues: isValueBackedViewType(field.type),
1261
1381
  })), ...(ngDevMode ? [{ debugName: "propertyItems" }] : /* istanbul ignore next */ []));
1262
1382
  /** Toolbar labels */
1263
1383
  toolbarLabels = computed(() => {
@@ -1267,6 +1387,8 @@ class FBFieldConditions {
1267
1387
  properties: this.transloco.translate('formBuilder.toolbar-fields'),
1268
1388
  operators: this.transloco.translate('formBuilder.toolbar-operators'),
1269
1389
  noPropertiesAvailable: this.transloco.translate('formBuilder.toolbar-no-fields'),
1390
+ values: this.transloco.translate('formBuilder.toolbar-values'),
1391
+ noValuesAvailable: this.transloco.translate('formBuilder.toolbar-no-values'),
1270
1392
  };
1271
1393
  }, ...(ngDevMode ? [{ debugName: "toolbarLabels" }] : /* istanbul ignore next */ []));
1272
1394
  constructor() {
@@ -1289,6 +1411,28 @@ class FBFieldConditions {
1289
1411
  }
1290
1412
  }
1291
1413
  }
1414
+ /**
1415
+ * Load the selectable values of a lookup / status field the first time its
1416
+ * value list is opened, so the compared value is picked from the real source
1417
+ * instead of typed as free text.
1418
+ */
1419
+ onPropertyValuesRequest(propertyKey) {
1420
+ if (this.propertyValues()[propertyKey] !== undefined)
1421
+ return;
1422
+ this.loadingValuesFor.set(propertyKey);
1423
+ this.contextService
1424
+ .getPropertyItems(propertyKey)
1425
+ .pipe(takeUntilDestroyed(this.destroyRef))
1426
+ .subscribe((items) => {
1427
+ this.propertyValues.update((current) => ({
1428
+ ...current,
1429
+ [propertyKey]: items,
1430
+ }));
1431
+ if (this.loadingValuesFor() === propertyKey) {
1432
+ this.loadingValuesFor.set(null);
1433
+ }
1434
+ });
1435
+ }
1292
1436
  /** Handle block insert from toolbar */
1293
1437
  onBlockInsert(block) {
1294
1438
  const editor = this.editorRef();
@@ -1326,7 +1470,7 @@ class FBFieldConditions {
1326
1470
  return raw.trim();
1327
1471
  }
1328
1472
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FBFieldConditions, deps: [], target: i0.ɵɵFactoryTarget.Component });
1329
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", type: FBFieldConditions, isStandalone: true, selector: "mt-fb-field-conditions", inputs: { initialFormula: { classPropertyName: "initialFormula", publicName: "initialFormula", isSignal: true, isRequired: false, transformFunction: null }, availableFields: { classPropertyName: "availableFields", publicName: "availableFields", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div\r\n [class]=\"[\r\n modalService.contentClass,\r\n 'min-w-0',\r\n 'p-4',\r\n 'overflow-y-hidden!',\r\n 'max-[640px]:p-3',\r\n ]\"\r\n >\r\n <div class=\"mt-4 flex h-full min-h-0 flex-col gap-3 overflow-y-auto pb-10\">\r\n <!-- Formula Toolbar -->\r\n <mt-formula-toolbar\r\n [knownProperties]=\"propertyItems()\"\r\n [functionCategories]=\"functionCategories\"\r\n [operators]=\"operators\"\r\n [labels]=\"toolbarLabels()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n />\r\n <!-- Formula Editor -->\r\n <mt-formula-editor\r\n #editor\r\n [placeholder]=\"t('build-condition-formula')\"\r\n [formControl]=\"formulaControl\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div\r\n [class]=\"[\r\n modalService.footerClass,\r\n '!h-auto',\r\n 'min-h-0',\r\n 'flex-col',\r\n 'gap-2',\r\n 'sm:flex-row',\r\n 'sm:items-center',\r\n 'sm:justify-end',\r\n ]\"\r\n >\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"submitting()\"\r\n styleClass=\"w-full sm:w-auto\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n styleClass=\"w-full sm:w-auto\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "visibleTabs", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled", "borderless"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }] });
1473
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", type: FBFieldConditions, isStandalone: true, selector: "mt-fb-field-conditions", inputs: { initialFormula: { classPropertyName: "initialFormula", publicName: "initialFormula", isSignal: true, isRequired: false, transformFunction: null }, availableFields: { classPropertyName: "availableFields", publicName: "availableFields", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\n <div\n [class]=\"[\n modalService.contentClass,\n 'min-w-0',\n 'p-4',\n 'overflow-y-hidden!',\n 'max-[640px]:p-3',\n ]\"\n >\n <div class=\"mt-4 flex h-full min-h-0 flex-col gap-3 overflow-y-auto pb-10\">\n <!-- Formula Toolbar -->\n <mt-formula-toolbar\n [knownProperties]=\"propertyItems()\"\n [propertyValues]=\"propertyValues()\"\n [loadingValuesFor]=\"loadingValuesFor()\"\n [functionCategories]=\"functionCategories\"\n [operators]=\"operators\"\n [labels]=\"toolbarLabels()\"\n (onBlockInsert)=\"onBlockInsert($event)\"\n (onPropertyValuesRequest)=\"onPropertyValuesRequest($event)\"\n />\n <!-- Formula Editor -->\n <mt-formula-editor\n #editor\n [placeholder]=\"t('build-condition-formula')\"\n [formControl]=\"formulaControl\"\n />\n </div>\n </div>\n\n <div\n [class]=\"[\n modalService.footerClass,\n '!h-auto',\n 'min-h-0',\n 'flex-col',\n 'gap-2',\n 'sm:flex-row',\n 'sm:items-center',\n 'sm:justify-end',\n ]\"\n >\n <mt-button\n [label]=\"t('cancel')\"\n variant=\"outlined\"\n [disabled]=\"submitting()\"\n styleClass=\"w-full sm:w-auto\"\n (onClick)=\"onCancel()\"\n />\n <mt-button\n [label]=\"t('save')\"\n severity=\"primary\"\n [loading]=\"submitting()\"\n styleClass=\"w-full sm:w-auto\"\n (onClick)=\"onSave()\"\n />\n </div>\n</ng-container>\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "propertyValues", "loadingValuesFor", "functionCategories", "operators", "initialTab", "visibleTabs", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange", "onPropertyValuesRequest"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled", "borderless"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }] });
1330
1474
  }
1331
1475
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FBFieldConditions, decorators: [{
1332
1476
  type: Component,
@@ -1336,7 +1480,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1336
1480
  Button,
1337
1481
  FormulaToolbar,
1338
1482
  FormulaEditor,
1339
- ], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div\r\n [class]=\"[\r\n modalService.contentClass,\r\n 'min-w-0',\r\n 'p-4',\r\n 'overflow-y-hidden!',\r\n 'max-[640px]:p-3',\r\n ]\"\r\n >\r\n <div class=\"mt-4 flex h-full min-h-0 flex-col gap-3 overflow-y-auto pb-10\">\r\n <!-- Formula Toolbar -->\r\n <mt-formula-toolbar\r\n [knownProperties]=\"propertyItems()\"\r\n [functionCategories]=\"functionCategories\"\r\n [operators]=\"operators\"\r\n [labels]=\"toolbarLabels()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n />\r\n <!-- Formula Editor -->\r\n <mt-formula-editor\r\n #editor\r\n [placeholder]=\"t('build-condition-formula')\"\r\n [formControl]=\"formulaControl\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div\r\n [class]=\"[\r\n modalService.footerClass,\r\n '!h-auto',\r\n 'min-h-0',\r\n 'flex-col',\r\n 'gap-2',\r\n 'sm:flex-row',\r\n 'sm:items-center',\r\n 'sm:justify-end',\r\n ]\"\r\n >\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"submitting()\"\r\n styleClass=\"w-full sm:w-auto\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n styleClass=\"w-full sm:w-auto\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
1483
+ ], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\n <div\n [class]=\"[\n modalService.contentClass,\n 'min-w-0',\n 'p-4',\n 'overflow-y-hidden!',\n 'max-[640px]:p-3',\n ]\"\n >\n <div class=\"mt-4 flex h-full min-h-0 flex-col gap-3 overflow-y-auto pb-10\">\n <!-- Formula Toolbar -->\n <mt-formula-toolbar\n [knownProperties]=\"propertyItems()\"\n [propertyValues]=\"propertyValues()\"\n [loadingValuesFor]=\"loadingValuesFor()\"\n [functionCategories]=\"functionCategories\"\n [operators]=\"operators\"\n [labels]=\"toolbarLabels()\"\n (onBlockInsert)=\"onBlockInsert($event)\"\n (onPropertyValuesRequest)=\"onPropertyValuesRequest($event)\"\n />\n <!-- Formula Editor -->\n <mt-formula-editor\n #editor\n [placeholder]=\"t('build-condition-formula')\"\n [formControl]=\"formulaControl\"\n />\n </div>\n </div>\n\n <div\n [class]=\"[\n modalService.footerClass,\n '!h-auto',\n 'min-h-0',\n 'flex-col',\n 'gap-2',\n 'sm:flex-row',\n 'sm:items-center',\n 'sm:justify-end',\n ]\"\n >\n <mt-button\n [label]=\"t('cancel')\"\n variant=\"outlined\"\n [disabled]=\"submitting()\"\n styleClass=\"w-full sm:w-auto\"\n (onClick)=\"onCancel()\"\n />\n <mt-button\n [label]=\"t('save')\"\n severity=\"primary\"\n [loading]=\"submitting()\"\n styleClass=\"w-full sm:w-auto\"\n (onClick)=\"onSave()\"\n />\n </div>\n</ng-container>\n" }]
1340
1484
  }], ctorParameters: () => [], propDecorators: { initialFormula: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialFormula", required: false }] }], availableFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "availableFields", required: false }] }], editorRef: [{ type: i0.ViewChild, args: ['editor', { isSignal: true }] }] } });
1341
1485
 
1342
1486
  class FBFieldForm {
@@ -2453,77 +2597,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
2453
2597
  args: [{ selector: 'mt-fb-validation-rules', standalone: true, imports: [TranslocoDirective, Table, Button], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div\r\n [class]=\"[\r\n modalService.contentClass,\r\n 'min-w-0',\r\n 'p-4',\r\n 'overflow-y-auto',\r\n 'max-[640px]:p-3',\r\n ]\"\r\n >\r\n <div class=\"flex justify-end pb-4 max-[640px]:justify-stretch\">\r\n <mt-button\r\n [label]=\"t('add-validation-rule')\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n styleClass=\"w-full sm:w-auto\"\r\n (onClick)=\"openCreate()\"\r\n ></mt-button>\r\n </div>\r\n <mt-table\r\n noCard\r\n [data]=\"tableRows()\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n storageKey=\"fb-validation-rules-table\"\r\n (cellChange)=\"onCellChange($event)\"\r\n ></mt-table>\r\n </div>\r\n</ng-container>\r\n" }]
2454
2598
  }], ctorParameters: () => [] });
2455
2599
 
2456
- class FormBuilderContextService {
2457
- http = inject(HttpClient);
2458
- baseUrl = 'context';
2459
- /**
2460
- * Resolves context data including navigation paths and properties.
2461
- * No caching - always fetches fresh data.
2462
- */
2463
- resolveContext(contextKey, options = {}) {
2464
- if (!contextKey)
2465
- return of(null);
2466
- return this.http
2467
- .post(`${this.baseUrl}/resolve`, {
2468
- contextKey,
2469
- displayTags: options.displayTags,
2470
- propertyFlags: options.propertyFlags,
2471
- matchAllTags: options.matchAllTags,
2472
- includeVirtual: options.includeVirtual,
2473
- includeNavigationPaths: options.includeNavigationPaths,
2474
- includeConnectionMetadata: options.includeConnectionMetadata,
2475
- includeRelatedContextValues: options.includeRelatedContextValues,
2476
- relatedContextsToInclude: options.relatedContextsToInclude,
2477
- // Consumer-supplied fields win on collision with any field above.
2478
- ...options.extraParams,
2479
- })
2480
- .pipe(map((response) => this.normalizeResponse(response)), catchError((error) => {
2481
- console.warn('Failed to resolve context:', error);
2482
- return of(null);
2483
- }));
2484
- }
2485
- /**
2486
- * Gets properties for a context.
2487
- * No caching - always fetches fresh data.
2488
- */
2489
- getProperties(contextKey, options = {}) {
2490
- if (!contextKey)
2491
- return of([]);
2492
- return this.resolveContext(contextKey, options).pipe(map((resolved) => resolved?.properties ?? []));
2493
- }
2494
- normalizeResponse(response) {
2495
- const payload = response?.data ?? response;
2496
- if (!payload)
2497
- return null;
2498
- const properties = this.normalizeProperties(payload.properties ?? []);
2499
- return {
2500
- ...payload,
2501
- properties,
2502
- };
2503
- }
2504
- normalizeProperties(raw) {
2505
- return (raw ?? [])
2506
- .map((prop) => {
2507
- const key = prop?.key ?? prop?.propertyKey;
2508
- if (!key)
2509
- return null;
2510
- const name = prop?.name ?? prop?.displayName ?? key;
2511
- return {
2512
- ...prop,
2513
- key,
2514
- name,
2515
- };
2516
- })
2517
- .filter((prop) => Boolean(prop));
2518
- }
2519
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormBuilderContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2520
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormBuilderContextService, providedIn: 'root' });
2521
- }
2522
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormBuilderContextService, decorators: [{
2523
- type: Injectable,
2524
- args: [{ providedIn: 'root' }]
2525
- }] });
2526
-
2527
2600
  const SECTIONS_DROP_LIST_ID = 'sections-list';
2528
2601
  const SCOPE_ORDER = [
2529
2602
  'Current',