@masterteam/formula-builder 0.0.8 → 0.0.10

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.
@@ -42,7 +42,7 @@ const ERROR_VALIDATION = {
42
42
  };
43
43
  class FormulaValidatorService {
44
44
  http = inject(HttpClient);
45
- apiUrl = '/formulas';
45
+ apiUrl = 'formulas';
46
46
  getBaseUrl(mode) {
47
47
  return mode === 'current-only'
48
48
  ? `${this.apiUrl}/current-only`
@@ -51,9 +51,9 @@ class FormulaValidatorService {
51
51
  /** Debounce time in ms */
52
52
  DEBOUNCE_MS = 300;
53
53
  /** Current validation result */
54
- _validation = signal(EMPTY_VALIDATION, ...(ngDevMode ? [{ debugName: "_validation" }] : []));
54
+ _validation = signal(EMPTY_VALIDATION, ...(ngDevMode ? [{ debugName: "_validation" }] : /* istanbul ignore next */ []));
55
55
  /** Loading state */
56
- _isValidating = signal(false, ...(ngDevMode ? [{ debugName: "_isValidating" }] : []));
56
+ _isValidating = signal(false, ...(ngDevMode ? [{ debugName: "_isValidating" }] : /* istanbul ignore next */ []));
57
57
  /** Validation subject for debouncing */
58
58
  validateSubject = new Subject();
59
59
  unwrapResponse(response) {
@@ -169,17 +169,17 @@ class FormulaValidatorService {
169
169
  getComplexity() {
170
170
  return this._validation().complexity;
171
171
  }
172
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaValidatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
173
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaValidatorService, providedIn: 'root' });
172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaValidatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
173
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaValidatorService, providedIn: 'root' });
174
174
  }
175
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaValidatorService, decorators: [{
175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaValidatorService, decorators: [{
176
176
  type: Injectable,
177
177
  args: [{ providedIn: 'root' }]
178
178
  }], ctorParameters: () => [] });
179
179
 
180
180
  class FormulaContextService {
181
181
  http = inject(HttpClient);
182
- apiUrl = '/formulas';
182
+ apiUrl = 'formulas';
183
183
  getBaseUrl(mode) {
184
184
  return mode === 'current-only'
185
185
  ? `${this.apiUrl}/current-only`
@@ -227,9 +227,7 @@ class FormulaContextService {
227
227
  }));
228
228
  }
229
229
  getScopeProperties(schemaId, component, tablePath, moduleId, mode = 'default') {
230
- if (!schemaId || !component || !tablePath)
231
- return of([]);
232
- if (mode === 'current-only')
230
+ if (!schemaId || !tablePath)
233
231
  return of([]);
234
232
  const cacheKey = `${mode}:${schemaId}:${moduleId ?? ''}:${component}:${tablePath}`;
235
233
  const cached = this.propertiesCache.get(cacheKey);
@@ -238,9 +236,11 @@ class FormulaContextService {
238
236
  }
239
237
  const params = new URLSearchParams({
240
238
  schemaId: schemaId.toString(),
241
- component,
242
239
  tablePath,
243
240
  });
241
+ if (component) {
242
+ params.set('component', component);
243
+ }
244
244
  if (moduleId !== undefined) {
245
245
  params.set('moduleId', moduleId.toString());
246
246
  }
@@ -256,8 +256,6 @@ class FormulaContextService {
256
256
  getNextTokens(schemaId, component, tablePath, moduleId, mode = 'default') {
257
257
  if (!schemaId || !component || !tablePath)
258
258
  return of(null);
259
- if (mode === 'current-only')
260
- return of(null);
261
259
  const cacheKey = `${mode}:${schemaId}:${moduleId ?? ''}:${component}:${tablePath}`;
262
260
  const cached = this.nextTokensCache.get(cacheKey);
263
261
  if (cached) {
@@ -282,17 +280,17 @@ class FormulaContextService {
282
280
  return of(null);
283
281
  }));
284
282
  }
285
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
286
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaContextService, providedIn: 'root' });
283
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
284
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaContextService, providedIn: 'root' });
287
285
  }
288
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaContextService, decorators: [{
286
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaContextService, decorators: [{
289
287
  type: Injectable,
290
288
  args: [{ providedIn: 'root' }]
291
289
  }] });
292
290
 
293
291
  class FormulaAutocompleteService {
294
292
  http = inject(HttpClient);
295
- apiUrl = '/formulas';
293
+ apiUrl = 'formulas';
296
294
  getBaseUrl(mode) {
297
295
  return mode === 'current-only'
298
296
  ? `${this.apiUrl}/current-only`
@@ -323,10 +321,10 @@ class FormulaAutocompleteService {
323
321
  return of(null);
324
322
  }));
325
323
  }
326
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaAutocompleteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
327
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaAutocompleteService, providedIn: 'root' });
324
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaAutocompleteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
325
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaAutocompleteService, providedIn: 'root' });
328
326
  }
329
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaAutocompleteService, decorators: [{
327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaAutocompleteService, decorators: [{
330
328
  type: Injectable,
331
329
  args: [{ providedIn: 'root' }]
332
330
  }] });
@@ -425,13 +423,14 @@ const DEFAULT_TOOLBAR_TABS = [
425
423
  'properties',
426
424
  'operators',
427
425
  ];
428
- const PROPERTY_SCOPE_ORDER = [
426
+ const PROPERTY_SCOPE_PRIORITY = [
429
427
  'Current',
430
428
  'Host',
431
429
  'Parent',
432
- // 'Children',
433
- // 'Descendants',
434
- // 'Modules',
430
+ 'Children',
431
+ 'Descendants',
432
+ 'Modules',
433
+ 'Schedule',
435
434
  ];
436
435
  const SCOPE_ICON_MAP = {
437
436
  Current: 'map.marker-pin-01',
@@ -441,37 +440,38 @@ const SCOPE_ICON_MAP = {
441
440
  Children: 'user.users-01',
442
441
  Descendants: 'custom.hierarchy-structure',
443
442
  Modules: 'file.folder-closed',
443
+ Schedule: 'general.placeholder',
444
444
  };
445
445
  class FormulaBuilder {
446
446
  validatorService = inject(FormulaValidatorService);
447
447
  contextService = inject(FormulaContextService);
448
448
  autocompleteService = inject(FormulaAutocompleteService);
449
449
  /** Reference to the formula editor */
450
- editor = viewChild('formulaEditor', ...(ngDevMode ? [{ debugName: "editor" }] : []));
451
- codeEditor = viewChild('formulaEditorCode', ...(ngDevMode ? [{ debugName: "codeEditor" }] : []));
450
+ editor = viewChild('formulaEditor', ...(ngDevMode ? [{ debugName: "editor" }] : /* istanbul ignore next */ []));
451
+ codeEditor = viewChild('formulaEditorCode', ...(ngDevMode ? [{ debugName: "codeEditor" }] : /* istanbul ignore next */ []));
452
452
  // ===== INPUTS =====
453
453
  /** Properties per table path (e.g., "Current", "Children.Project") */
454
- propertiesByPath = input({}, ...(ngDevMode ? [{ debugName: "propertiesByPath" }] : []));
454
+ propertiesByPath = input({}, ...(ngDevMode ? [{ debugName: "propertiesByPath" }] : /* istanbul ignore next */ []));
455
455
  /** Level schema ID for validation context */
456
- levelSchemaId = input(...(ngDevMode ? [undefined, { debugName: "levelSchemaId" }] : []));
456
+ levelSchemaId = input(...(ngDevMode ? [undefined, { debugName: "levelSchemaId" }] : /* istanbul ignore next */ []));
457
457
  /** Optional module ID when the formula is scoped inside a level-linked module */
458
- moduleId = input(...(ngDevMode ? [undefined, { debugName: "moduleId" }] : []));
458
+ moduleId = input(...(ngDevMode ? [undefined, { debugName: "moduleId" }] : /* istanbul ignore next */ []));
459
459
  /** Optional current context entity key, e.g. LevelData or Risk */
460
- contextEntityTypeKey = input(...(ngDevMode ? [undefined, { debugName: "contextEntityTypeKey" }] : []));
460
+ contextEntityTypeKey = input(...(ngDevMode ? [undefined, { debugName: "contextEntityTypeKey" }] : /* istanbul ignore next */ []));
461
461
  /** Template ID for validation context */
462
- templateId = input(...(ngDevMode ? [undefined, { debugName: "templateId" }] : []));
462
+ templateId = input(...(ngDevMode ? [undefined, { debugName: "templateId" }] : /* istanbul ignore next */ []));
463
463
  /** Placeholder text */
464
- placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
464
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
465
465
  /** Hide the top toolbar */
466
- hideToolbar = input(false, ...(ngDevMode ? [{ debugName: "hideToolbar" }] : []));
466
+ hideToolbar = input(false, ...(ngDevMode ? [{ debugName: "hideToolbar" }] : /* istanbul ignore next */ []));
467
467
  /** Hide the status bar */
468
- hideStatusBar = input(false, ...(ngDevMode ? [{ debugName: "hideStatusBar" }] : []));
468
+ hideStatusBar = input(false, ...(ngDevMode ? [{ debugName: "hideStatusBar" }] : /* istanbul ignore next */ []));
469
469
  /** Visible toolbar tabs */
470
- toolbarTabs = input(DEFAULT_TOOLBAR_TABS, ...(ngDevMode ? [{ debugName: "toolbarTabs" }] : []));
470
+ toolbarTabs = input(DEFAULT_TOOLBAR_TABS, ...(ngDevMode ? [{ debugName: "toolbarTabs" }] : /* istanbul ignore next */ []));
471
471
  /** Force code editor mode and hide the mode toggle */
472
- codeOnly = input(false, ...(ngDevMode ? [{ debugName: "codeOnly" }] : []));
472
+ codeOnly = input(false, ...(ngDevMode ? [{ debugName: "codeOnly" }] : /* istanbul ignore next */ []));
473
473
  /** Use Process Builder current-only Formula Engine endpoints */
474
- isProcessBuilder = input(false, ...(ngDevMode ? [{ debugName: "isProcessBuilder" }] : []));
474
+ isProcessBuilder = input(false, ...(ngDevMode ? [{ debugName: "isProcessBuilder" }] : /* istanbul ignore next */ []));
475
475
  // ===== OUTPUTS =====
476
476
  /** Emits validation result on change */
477
477
  validationChange = output();
@@ -479,13 +479,13 @@ class FormulaBuilder {
479
479
  tokensChange = output();
480
480
  // ===== STATE =====
481
481
  /** Editor focus state */
482
- hasFocus = signal(false, ...(ngDevMode ? [{ debugName: "hasFocus" }] : []));
482
+ hasFocus = signal(false, ...(ngDevMode ? [{ debugName: "hasFocus" }] : /* istanbul ignore next */ []));
483
483
  /** Form control value */
484
- expressionValue = signal('', ...(ngDevMode ? [{ debugName: "expressionValue" }] : []));
485
- builderValue = signal([], ...(ngDevMode ? [{ debugName: "builderValue" }] : []));
484
+ expressionValue = signal('', ...(ngDevMode ? [{ debugName: "expressionValue" }] : /* istanbul ignore next */ []));
485
+ builderValue = signal([], ...(ngDevMode ? [{ debugName: "builderValue" }] : /* istanbul ignore next */ []));
486
486
  /** Tokens for the editor */
487
- tokens = signal([], ...(ngDevMode ? [{ debugName: "tokens" }] : []));
488
- expression = computed(() => this.expressionValue(), ...(ngDevMode ? [{ debugName: "expression" }] : []));
487
+ tokens = signal([], ...(ngDevMode ? [{ debugName: "tokens" }] : /* istanbul ignore next */ []));
488
+ expression = computed(() => this.expressionValue(), ...(ngDevMode ? [{ debugName: "expression" }] : /* istanbul ignore next */ []));
489
489
  resolvedContextEntityTypeKey = computed(() => {
490
490
  const value = this.contextEntityTypeKey();
491
491
  if (typeof value !== 'string') {
@@ -493,7 +493,7 @@ class FormulaBuilder {
493
493
  }
494
494
  const normalized = value.trim();
495
495
  return normalized.length > 0 ? normalized : undefined;
496
- }, ...(ngDevMode ? [{ debugName: "resolvedContextEntityTypeKey" }] : []));
496
+ }, ...(ngDevMode ? [{ debugName: "resolvedContextEntityTypeKey" }] : /* istanbul ignore next */ []));
497
497
  isModuleContext = computed(() => {
498
498
  const contextType = this.resolvedContextEntityTypeKey() ??
499
499
  this.builderContext()?.contextEntityTypeKey;
@@ -502,7 +502,7 @@ class FormulaBuilder {
502
502
  }
503
503
  const normalized = contextType.trim().toLowerCase();
504
504
  return normalized.length > 0 && normalized !== 'leveldata';
505
- }, ...(ngDevMode ? [{ debugName: "isModuleContext" }] : []));
505
+ }, ...(ngDevMode ? [{ debugName: "isModuleContext" }] : /* istanbul ignore next */ []));
506
506
  autocompleteProvider = (request) => {
507
507
  return this.autocompleteService.getSuggestions({
508
508
  ...request,
@@ -515,37 +515,37 @@ class FormulaBuilder {
515
515
  /** Track last synced builder JSON to avoid loops */
516
516
  lastBuilderJson = '';
517
517
  /** Editor mode */
518
- editorMode = signal('builder', ...(ngDevMode ? [{ debugName: "editorMode" }] : []));
519
- isCodeMode = computed(() => this.editorMode() === 'code', ...(ngDevMode ? [{ debugName: "isCodeMode" }] : []));
520
- isCodeModeLocked = signal(false, ...(ngDevMode ? [{ debugName: "isCodeModeLocked" }] : []));
521
- showModeToggle = computed(() => !this.codeOnly(), ...(ngDevMode ? [{ debugName: "showModeToggle" }] : []));
522
- formulaApiMode = computed(() => this.isProcessBuilder() ? 'current-only' : 'default', ...(ngDevMode ? [{ debugName: "formulaApiMode" }] : []));
518
+ editorMode = signal('builder', ...(ngDevMode ? [{ debugName: "editorMode" }] : /* istanbul ignore next */ []));
519
+ isCodeMode = computed(() => this.editorMode() === 'code', ...(ngDevMode ? [{ debugName: "isCodeMode" }] : /* istanbul ignore next */ []));
520
+ isCodeModeLocked = signal(false, ...(ngDevMode ? [{ debugName: "isCodeModeLocked" }] : /* istanbul ignore next */ []));
521
+ showModeToggle = computed(() => !this.codeOnly(), ...(ngDevMode ? [{ debugName: "showModeToggle" }] : /* istanbul ignore next */ []));
522
+ formulaApiMode = computed(() => this.isProcessBuilder() ? 'current-only' : 'default', ...(ngDevMode ? [{ debugName: "formulaApiMode" }] : /* istanbul ignore next */ []));
523
523
  resolvedToolbarTabs = computed(() => {
524
524
  const tabs = this.toolbarTabs();
525
525
  return tabs.length > 0 ? tabs : DEFAULT_TOOLBAR_TABS;
526
- }, ...(ngDevMode ? [{ debugName: "resolvedToolbarTabs" }] : []));
526
+ }, ...(ngDevMode ? [{ debugName: "resolvedToolbarTabs" }] : /* istanbul ignore next */ []));
527
527
  codeModeSnapshotTokens = [];
528
528
  codeModeSnapshotExpression = '';
529
529
  /** ControlValueAccessor callbacks */
530
530
  onChange = () => { };
531
531
  onTouched = () => { };
532
532
  /** Disabled state */
533
- isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
533
+ isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
534
534
  /** Validation result from service */
535
535
  validation = this.validatorService.validation;
536
536
  /** Is validation in progress */
537
537
  isValidating = this.validatorService.isValidating;
538
538
  /** Builder context from API */
539
- builderContext = signal(null, ...(ngDevMode ? [{ debugName: "builderContext" }] : []));
539
+ builderContext = signal(null, ...(ngDevMode ? [{ debugName: "builderContext" }] : /* istanbul ignore next */ []));
540
540
  /** Function categories from context */
541
- functionCategories = computed(() => this.builderContext()?.functions?.categories ?? [], ...(ngDevMode ? [{ debugName: "functionCategories" }] : []));
541
+ functionCategories = computed(() => this.builderContext()?.functions?.categories ?? [], ...(ngDevMode ? [{ debugName: "functionCategories" }] : /* istanbul ignore next */ []));
542
542
  /** Is builder context loading */
543
- isContextLoading = signal(false, ...(ngDevMode ? [{ debugName: "isContextLoading" }] : []));
543
+ isContextLoading = signal(false, ...(ngDevMode ? [{ debugName: "isContextLoading" }] : /* istanbul ignore next */ []));
544
544
  contextRequestId = 0;
545
545
  /** Properties loaded from API */
546
- propertiesByPathApi = signal({}, ...(ngDevMode ? [{ debugName: "propertiesByPathApi" }] : []));
546
+ propertiesByPathApi = signal({}, ...(ngDevMode ? [{ debugName: "propertiesByPathApi" }] : /* istanbul ignore next */ []));
547
547
  /** Current property list loading path */
548
- propertyLoadingPath = signal(null, ...(ngDevMode ? [{ debugName: "propertyLoadingPath" }] : []));
548
+ propertyLoadingPath = signal(null, ...(ngDevMode ? [{ debugName: "propertyLoadingPath" }] : /* istanbul ignore next */ []));
549
549
  constructor() {
550
550
  // Validate when formula changes
551
551
  effect(() => {
@@ -590,16 +590,9 @@ class FormulaBuilder {
590
590
  return;
591
591
  }
592
592
  if (context.currentProperties?.length) {
593
- const scalarOperators = context.schemaDescriptor?.operators?.filter((operator) => operator.cardinality === 'scalar' &&
594
- !operator.requiresParameter &&
595
- !operator.parameterKind) ?? [];
596
- const scopedProperties = scalarOperators.reduce((acc, operator) => ({
597
- ...acc,
598
- [operator.token]: context.currentProperties,
599
- }), {});
600
593
  this.propertiesByPathApi.update((current) => ({
601
594
  ...current,
602
- ...scopedProperties,
595
+ Current: context.currentProperties,
603
596
  }));
604
597
  }
605
598
  });
@@ -618,15 +611,11 @@ class FormulaBuilder {
618
611
  effect(() => {
619
612
  const schemaId = this.levelSchemaId();
620
613
  const moduleId = this.moduleId();
621
- const isProcessBuilder = this.isProcessBuilder();
614
+ const apiMode = this.formulaApiMode();
622
615
  const tablePath = this.resolvedTablePath();
623
616
  const component = this.propertiesComponent();
624
617
  const context = this.builderContext();
625
- if (isProcessBuilder ||
626
- !schemaId ||
627
- !tablePath ||
628
- !component ||
629
- !context) {
618
+ if (!schemaId || !tablePath || !context) {
630
619
  this.propertyLoadingPath.set(null);
631
620
  return;
632
621
  }
@@ -637,7 +626,7 @@ class FormulaBuilder {
637
626
  }
638
627
  this.propertyLoadingPath.set(tablePath);
639
628
  this.contextService
640
- .getScopeProperties(schemaId, component, tablePath, moduleId)
629
+ .getScopeProperties(schemaId, component, tablePath, moduleId, apiMode)
641
630
  .subscribe((props) => {
642
631
  this.propertiesByPathApi.update((current) => ({
643
632
  ...current,
@@ -922,38 +911,53 @@ class FormulaBuilder {
922
911
  this.codeModeSnapshotExpression = '';
923
912
  }
924
913
  // ===== PROPERTY COMPOSER =====
925
- propertyScope = signal('', ...(ngDevMode ? [{ debugName: "propertyScope" }] : []));
926
- propertyPathSegments = signal([], ...(ngDevMode ? [{ debugName: "propertyPathSegments" }] : []));
927
- propertyFieldKey = signal('', ...(ngDevMode ? [{ debugName: "propertyFieldKey" }] : []));
928
- nextTokenRulesByPath = signal({}, ...(ngDevMode ? [{ debugName: "nextTokenRulesByPath" }] : []));
914
+ propertyScope = signal('', ...(ngDevMode ? [{ debugName: "propertyScope" }] : /* istanbul ignore next */ []));
915
+ propertyPathSegments = signal([], ...(ngDevMode ? [{ debugName: "propertyPathSegments" }] : /* istanbul ignore next */ []));
916
+ propertyFieldKey = signal('', ...(ngDevMode ? [{ debugName: "propertyFieldKey" }] : /* istanbul ignore next */ []));
917
+ nextTokenRulesByPath = signal({}, ...(ngDevMode ? [{ debugName: "nextTokenRulesByPath" }] : /* istanbul ignore next */ []));
929
918
  contextOperators = computed(() => {
930
919
  return this.builderContext()?.schemaDescriptor?.operators ?? [];
931
- }, ...(ngDevMode ? [{ debugName: "contextOperators" }] : []));
932
- baseOperator = computed(() => this.contextOperators().find((op) => op.token === this.propertyScope()), ...(ngDevMode ? [{ debugName: "baseOperator" }] : []));
920
+ }, ...(ngDevMode ? [{ debugName: "contextOperators" }] : /* istanbul ignore next */ []));
921
+ baseOperator = computed(() => this.contextOperators().find((op) => op.token === this.propertyScope()), ...(ngDevMode ? [{ debugName: "baseOperator" }] : /* istanbul ignore next */ []));
933
922
  baseRule = computed(() => {
934
923
  const scope = this.propertyScope();
935
924
  return this.builderContext()?.schemaDescriptor?.nextTokenRules?.[scope];
936
- }, ...(ngDevMode ? [{ debugName: "baseRule" }] : []));
925
+ }, ...(ngDevMode ? [{ debugName: "baseRule" }] : /* istanbul ignore next */ []));
937
926
  availableScopes = computed(() => {
938
927
  const operators = this.contextOperators();
939
928
  if (operators.length === 0)
940
929
  return [];
941
- const operatorsByToken = new Map(operators.map((operator) => [operator.token, operator]));
942
- return PROPERTY_SCOPE_ORDER.map((token) => operatorsByToken.get(token))
943
- .filter((operator) => Boolean(operator))
930
+ const baseRules = this.builderContext()?.schemaDescriptor?.nextTokenRules ?? {};
931
+ const priority = new Map(PROPERTY_SCOPE_PRIORITY.map((token, index) => [token, index]));
932
+ const scopedOperators = operators.filter((operator) => operator.token.trim().length > 0);
933
+ return [...scopedOperators]
934
+ .filter((operator) => {
935
+ const parameterKind = baseRules[operator.token]?.parameterKind ?? operator.parameterKind;
936
+ const requiresParameter = operator.requiresParameter ?? Boolean(parameterKind);
937
+ return ((!parameterKind && !requiresParameter) ||
938
+ getAllowedValues(baseRules[operator.token]).length > 0);
939
+ })
940
+ .sort((a, b) => {
941
+ const aPriority = priority.get(a.token) ?? Number.MAX_SAFE_INTEGER;
942
+ const bPriority = priority.get(b.token) ?? Number.MAX_SAFE_INTEGER;
943
+ if (aPriority !== bPriority) {
944
+ return aPriority - bPriority;
945
+ }
946
+ return a.token.localeCompare(b.token);
947
+ })
944
948
  .map((operator) => ({
945
949
  key: operator.token,
946
950
  label: `@${operator.token}`,
947
951
  requiresParam: operator.requiresParameter ?? false,
948
952
  optional: !operator.requiresParameter,
949
953
  }));
950
- }, ...(ngDevMode ? [{ debugName: "availableScopes" }] : []));
954
+ }, ...(ngDevMode ? [{ debugName: "availableScopes" }] : /* istanbul ignore next */ []));
951
955
  /** Radio card options for scope selection */
952
956
  scopeOptions = computed(() => this.availableScopes().map((scope) => ({
953
957
  id: scope.key,
954
958
  name: this.getOperatorDisplayName(scope.key),
955
959
  icon: SCOPE_ICON_MAP[scope.key] ?? DEFAULT_SCOPE_ICON,
956
- })), ...(ngDevMode ? [{ debugName: "scopeOptions" }] : []));
960
+ })), ...(ngDevMode ? [{ debugName: "scopeOptions" }] : /* istanbul ignore next */ []));
957
961
  /** Handle scope selection from radio cards */
958
962
  onScopeChange(item) {
959
963
  this.setPropertyScope(String(item.id));
@@ -967,20 +971,20 @@ class FormulaBuilder {
967
971
  baseRule: this.baseRule(),
968
972
  rulesByPath: this.nextTokenRulesByPath(),
969
973
  });
970
- }, ...(ngDevMode ? [{ debugName: "pathSegments" }] : []));
974
+ }, ...(ngDevMode ? [{ debugName: "pathSegments" }] : /* istanbul ignore next */ []));
971
975
  isDirectAccess = computed(() => {
972
976
  const operator = this.baseOperator();
973
977
  const needsParameter = Boolean(operator?.parameterKind) || Boolean(operator?.requiresParameter);
974
978
  return !needsParameter && this.pathSegments().length === 0;
975
- }, ...(ngDevMode ? [{ debugName: "isDirectAccess" }] : []));
976
- propertyTablePath = computed(() => buildTablePath(this.propertyScope(), this.pathSegments(), this.baseOperator(), false), ...(ngDevMode ? [{ debugName: "propertyTablePath" }] : []));
977
- resolvedTablePath = computed(() => buildTablePath(this.propertyScope(), this.pathSegments(), this.baseOperator(), true), ...(ngDevMode ? [{ debugName: "resolvedTablePath" }] : []));
979
+ }, ...(ngDevMode ? [{ debugName: "isDirectAccess" }] : /* istanbul ignore next */ []));
980
+ propertyTablePath = computed(() => buildTablePath(this.propertyScope(), this.pathSegments(), this.baseOperator(), false), ...(ngDevMode ? [{ debugName: "propertyTablePath" }] : /* istanbul ignore next */ []));
981
+ resolvedTablePath = computed(() => buildTablePath(this.propertyScope(), this.pathSegments(), this.baseOperator(), true), ...(ngDevMode ? [{ debugName: "resolvedTablePath" }] : /* istanbul ignore next */ []));
978
982
  currentNextTokenRules = computed(() => {
979
983
  const path = this.resolvedTablePath();
980
984
  if (!path)
981
985
  return {};
982
986
  return this.nextTokenRulesByPath()[path] ?? {};
983
- }, ...(ngDevMode ? [{ debugName: "currentNextTokenRules" }] : []));
987
+ }, ...(ngDevMode ? [{ debugName: "currentNextTokenRules" }] : /* istanbul ignore next */ []));
984
988
  nextOperatorOptions = computed(() => {
985
989
  const rules = this.currentNextTokenRules();
986
990
  const operators = this.contextOperators();
@@ -999,7 +1003,7 @@ class FormulaBuilder {
999
1003
  };
1000
1004
  })
1001
1005
  .filter((option) => option.allowedValues.length > 0 || !option.requiresParameter);
1002
- }, ...(ngDevMode ? [{ debugName: "nextOperatorOptions" }] : []));
1006
+ }, ...(ngDevMode ? [{ debugName: "nextOperatorOptions" }] : /* istanbul ignore next */ []));
1003
1007
  canAddNextSegment = computed(() => {
1004
1008
  if (this.nextOperatorOptions().length === 0)
1005
1009
  return false;
@@ -1008,14 +1012,10 @@ class FormulaBuilder {
1008
1012
  return false;
1009
1013
  }
1010
1014
  return segments.every((segment) => !segment.requiresParameter || Boolean(segment.value));
1011
- }, ...(ngDevMode ? [{ debugName: "canAddNextSegment" }] : []));
1015
+ }, ...(ngDevMode ? [{ debugName: "canAddNextSegment" }] : /* istanbul ignore next */ []));
1012
1016
  propertiesComponent = computed(() => {
1013
- if (this.isProcessBuilder()) {
1014
- return undefined;
1015
- }
1016
- const contextKey = this.builderContext()?.contextEntityTypeKey;
1017
- return contextKey;
1018
- }, ...(ngDevMode ? [{ debugName: "propertiesComponent" }] : []));
1017
+ return this.builderContext()?.contextEntityTypeKey;
1018
+ }, ...(ngDevMode ? [{ debugName: "propertiesComponent" }] : /* istanbul ignore next */ []));
1019
1019
  mergedPropertiesByPath = computed(() => {
1020
1020
  const merged = {
1021
1021
  ...this.propertiesByPath(),
@@ -1027,11 +1027,11 @@ class FormulaBuilder {
1027
1027
  }
1028
1028
  });
1029
1029
  return merged;
1030
- }, ...(ngDevMode ? [{ debugName: "mergedPropertiesByPath" }] : []));
1030
+ }, ...(ngDevMode ? [{ debugName: "mergedPropertiesByPath" }] : /* istanbul ignore next */ []));
1031
1031
  isPropertyLoading = computed(() => {
1032
1032
  const path = this.resolvedTablePath();
1033
1033
  return Boolean(path) && this.propertyLoadingPath() === path;
1034
- }, ...(ngDevMode ? [{ debugName: "isPropertyLoading" }] : []));
1034
+ }, ...(ngDevMode ? [{ debugName: "isPropertyLoading" }] : /* istanbul ignore next */ []));
1035
1035
  propertyOptions = computed(() => {
1036
1036
  const path = this.resolvedTablePath();
1037
1037
  if (!path)
@@ -1042,16 +1042,16 @@ class FormulaBuilder {
1042
1042
  key: prop.key,
1043
1043
  name: prop.name ?? prop.key,
1044
1044
  }));
1045
- }, ...(ngDevMode ? [{ debugName: "propertyOptions" }] : []));
1045
+ }, ...(ngDevMode ? [{ debugName: "propertyOptions" }] : /* istanbul ignore next */ []));
1046
1046
  selectedProperty = computed(() => {
1047
1047
  const key = this.propertyFieldKey();
1048
1048
  return this.propertyOptions().find((prop) => prop.key === key) ?? null;
1049
- }, ...(ngDevMode ? [{ debugName: "selectedProperty" }] : []));
1049
+ }, ...(ngDevMode ? [{ debugName: "selectedProperty" }] : /* istanbul ignore next */ []));
1050
1050
  canInsertProperty = computed(() => {
1051
1051
  if (!this.selectedProperty())
1052
1052
  return false;
1053
1053
  return Boolean(this.resolvedTablePath());
1054
- }, ...(ngDevMode ? [{ debugName: "canInsertProperty" }] : []));
1054
+ }, ...(ngDevMode ? [{ debugName: "canInsertProperty" }] : /* istanbul ignore next */ []));
1055
1055
  setPropertyScope(scope) {
1056
1056
  if (this.propertyScope() === scope) {
1057
1057
  return;
@@ -1111,16 +1111,16 @@ class FormulaBuilder {
1111
1111
  }
1112
1112
  return token;
1113
1113
  }
1114
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
1115
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormulaBuilder, isStandalone: true, selector: "mt-formula-builder", inputs: { propertiesByPath: { classPropertyName: "propertiesByPath", publicName: "propertiesByPath", isSignal: true, isRequired: false, transformFunction: null }, levelSchemaId: { classPropertyName: "levelSchemaId", publicName: "levelSchemaId", isSignal: true, isRequired: false, transformFunction: null }, moduleId: { classPropertyName: "moduleId", publicName: "moduleId", isSignal: true, isRequired: false, transformFunction: null }, contextEntityTypeKey: { classPropertyName: "contextEntityTypeKey", publicName: "contextEntityTypeKey", isSignal: true, isRequired: false, transformFunction: null }, templateId: { classPropertyName: "templateId", publicName: "templateId", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hideToolbar: { classPropertyName: "hideToolbar", publicName: "hideToolbar", isSignal: true, isRequired: false, transformFunction: null }, hideStatusBar: { classPropertyName: "hideStatusBar", publicName: "hideStatusBar", isSignal: true, isRequired: false, transformFunction: null }, toolbarTabs: { classPropertyName: "toolbarTabs", publicName: "toolbarTabs", isSignal: true, isRequired: false, transformFunction: null }, codeOnly: { classPropertyName: "codeOnly", publicName: "codeOnly", isSignal: true, isRequired: false, transformFunction: null }, isProcessBuilder: { classPropertyName: "isProcessBuilder", publicName: "isProcessBuilder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validationChange: "validationChange", tokensChange: "tokensChange" }, host: { classAttribute: "block" }, providers: [
1114
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
1115
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: FormulaBuilder, isStandalone: true, selector: "mt-formula-builder", inputs: { propertiesByPath: { classPropertyName: "propertiesByPath", publicName: "propertiesByPath", isSignal: true, isRequired: false, transformFunction: null }, levelSchemaId: { classPropertyName: "levelSchemaId", publicName: "levelSchemaId", isSignal: true, isRequired: false, transformFunction: null }, moduleId: { classPropertyName: "moduleId", publicName: "moduleId", isSignal: true, isRequired: false, transformFunction: null }, contextEntityTypeKey: { classPropertyName: "contextEntityTypeKey", publicName: "contextEntityTypeKey", isSignal: true, isRequired: false, transformFunction: null }, templateId: { classPropertyName: "templateId", publicName: "templateId", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hideToolbar: { classPropertyName: "hideToolbar", publicName: "hideToolbar", isSignal: true, isRequired: false, transformFunction: null }, hideStatusBar: { classPropertyName: "hideStatusBar", publicName: "hideStatusBar", isSignal: true, isRequired: false, transformFunction: null }, toolbarTabs: { classPropertyName: "toolbarTabs", publicName: "toolbarTabs", isSignal: true, isRequired: false, transformFunction: null }, codeOnly: { classPropertyName: "codeOnly", publicName: "codeOnly", isSignal: true, isRequired: false, transformFunction: null }, isProcessBuilder: { classPropertyName: "isProcessBuilder", publicName: "isProcessBuilder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validationChange: "validationChange", tokensChange: "tokensChange" }, host: { classAttribute: "block" }, providers: [
1116
1116
  {
1117
1117
  provide: NG_VALUE_ACCESSOR,
1118
1118
  useExisting: forwardRef(() => FormulaBuilder),
1119
1119
  multi: true,
1120
1120
  },
1121
- ], viewQueries: [{ propertyName: "editor", first: true, predicate: ["formulaEditor"], descendants: true, isSignal: true }, { propertyName: "codeEditor", first: true, predicate: ["formulaEditorCode"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-card\r\n headless\r\n [class.ring-2]=\"hasFocus()\"\r\n [class.ring-primary]=\"hasFocus()\"\r\n [paddingless]=\"true\"\r\n>\r\n <div\r\n *transloco=\"let t; prefix: 'formulaBuilder'\"\r\n class=\"flex flex-col overflow-hidden\"\r\n >\r\n <!-- Toolbar - Pass data via inputs (pure component) -->\r\n @if (!hideToolbar()) {\r\n <mt-formula-toolbar\r\n [functionCategories]=\"functionCategories()\"\r\n [visibleTabs]=\"resolvedToolbarTabs()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n >\r\n <ng-template #properties let-insertBlock=\"insertBlock\">\r\n @if (isContextLoading()) {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <p-skeleton\r\n width=\"18rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <p-skeleton\r\n width=\"7rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div class=\"flex items-center gap-4\">\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <!-- Scope Selection - Full width, centered -->\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <mt-radio-cards\r\n [options]=\"scopeOptions()\"\r\n [activeId]=\"propertyScope()\"\r\n (selectionChange)=\"onScopeChange($event)\"\r\n size=\"small\"\r\n />\r\n </div>\r\n\r\n <!-- Path + Field + Preview Row -->\r\n <div class=\"flex items-center gap-4\">\r\n <!-- Path Container - Flexible -->\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.path\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (isDirectAccess()) {\r\n <span\r\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\r\n >\r\n \u2713 {{ t(\"properties.direct-access\") }}\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\">{{\r\n t(\"properties.no-path-configured\")\r\n }}</span>\r\n } @else {\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\r\n >\r\n @for (\r\n segment of pathSegments();\r\n track $index;\r\n let segmentIndex = $index\r\n ) {\r\n @if (segmentIndex > 0) {\r\n <span\r\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\r\n >\u203A</span\r\n >\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"\n segment.value ||\n t('properties.select') +\n ' ' +\n getOperatorDisplayName(segment.operatorToken)\n \"\n icon=\"arrow.chevron-down\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [severity]=\"\r\n segment.value ? 'primary' : 'secondary'\r\n \"\r\n [iconPos]=\"'end'\"\r\n (onClick)=\"pathPopover.toggle($event)\"\r\n ></mt-button>\r\n\r\n <p-popover\r\n #pathPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.select\") }}\n {{ getOperatorDisplayName(segment.operatorToken) }}\n </div>\n <div class=\"flex flex-col gap-1\">\r\n @for (\r\n option of segmentOptions(segmentIndex);\r\n track option.key\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"option.name\"\r\n [icon]=\"\r\n segment.value === option.key\r\n ? 'general.check'\r\n : 'general.minus'\r\n \"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n [styleClass]=\"\r\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\r\n (segment.value === option.key\r\n ? 'bg-primary text-white'\r\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\r\n \"\r\n (onClick)=\"\r\n setPathSegmentValue(\r\n segmentIndex,\r\n option.key\r\n );\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n @if (segment.optional) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.clear')\"\r\n [outlined]=\"true\"\r\n icon=\"general.x-close\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\r\n (onClick)=\"\r\n setPathSegmentValue(segmentIndex, null);\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </p-popover>\r\n\r\n @if (\r\n segment.canRemove &&\r\n segmentIndex === pathSegments().length - 1\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.x-close\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\r\n (onClick)=\"removePathSegment(segmentIndex)\"\r\n ></mt-button>\r\n }\r\n }\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [disabled]=\"!canAddNextSegment()\"\r\n [class.hidden]=\"!canAddNextSegment()\"\r\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\r\n (onClick)=\"nextOperatorPopover.toggle($event)\"\r\n ></mt-button>\r\n </div>\r\n }\r\n <p-popover\r\n #nextOperatorPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.add-segment\") }}\r\n </div>\r\n <div class=\"flex flex-col gap-1\">\r\n @for (\r\n option of nextOperatorOptions();\r\n track option.token\r\n ) {\r\n <mt-button\n type=\"button\"\n [label]=\"getOperatorDisplayName(option.token)\"\n icon=\"general.plus\"\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\r\n (onClick)=\"\r\n onAddSegmentSelection(\r\n option.token,\r\n nextOperatorPopover\r\n )\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n </div>\r\n </div>\r\n\r\n <!-- Field Selection - Under Path -->\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.field\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isPropertyLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select')\"\r\n [(ngModel)]=\"propertyFieldKey\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n <div\r\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\r\n [mtTooltip]=\"\r\n '@' +\r\n propertyTablePath() +\r\n '::' +\r\n (selectedProperty()?.key ?? '...')\r\n \"\r\n tooltipPosition=\"top\"\r\n >\r\n @{{ propertyTablePath() }}::{{\r\n selectedProperty()?.key ?? \"...\"\r\n }}\r\n </div>\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert')\"\r\n icon=\"general.plus\"\r\n severity=\"primary\"\r\n [disabled]=\"!canInsertProperty()\"\r\n (onClick)=\"insertSelectedProperty(insertBlock)\"\r\n ></mt-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-formula-toolbar>\r\n }\r\n\r\n <!-- Editor Area -->\r\n <div class=\"p-3\">\r\n <div\r\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\r\n >\r\n @if (showModeToggle()) {\r\n <div\r\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\r\n >\r\n <mt-toggle-field\r\n [label]=\"t('codeMode')\"\r\n labelPosition=\"end\"\r\n size=\"small\"\r\n [ngModel]=\"isCodeMode()\"\r\n [readonly]=\"isCodeModeLocked()\"\r\n [pInputs]=\"{ disabled: isCodeModeLocked() }\"\r\n (ngModelChange)=\"onModeToggle($event)\"\r\n />\r\n </div>\r\n }\r\n <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialFormula]=\"expression()\"\r\n [borderless]=\"true\"\r\n [autocompleteProvider]=\"autocompleteProvider\"\r\n (formulaChange)=\"onCodeFormulaChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n } @else {\r\n <mt-formula-editor\r\n #formulaEditor\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialTokens]=\"tokens()\"\r\n [borderless]=\"true\"\r\n (formulaChange)=\"onFormulaChange($event)\"\r\n (tokensChange)=\"onTokensChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Status Bar - Pass data via inputs (pure component) -->\r\n @if (!hideStatusBar()) {\r\n <mt-formula-status-bar [validation]=\"validation()\" />\r\n }\r\n </div>\r\n</mt-card>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { 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"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "component", type: RadioCards, selector: "mt-radio-cards", inputs: ["circle", "color", "size", "columns", "options", "activeId", "itemTemplate"], outputs: ["optionsChange", "activeIdChange", "selectionChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "visibleTabs", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaStatusBar, selector: "mt-formula-status-bar", inputs: ["validation", "labels"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled", "borderless"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }, { kind: "component", type: FormulaEditorCode, selector: "mt-formula-editor-code", inputs: ["placeholder", "initialFormula", "disabled", "language", "theme", "borderless", "autocompleteProvider", "autocompleteDebounceMs"], outputs: ["formulaChange", "onBlur", "onFocus"] }] });
1121
+ ], viewQueries: [{ propertyName: "editor", first: true, predicate: ["formulaEditor"], descendants: true, isSignal: true }, { propertyName: "codeEditor", first: true, predicate: ["formulaEditorCode"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-card\r\n headless\r\n [class.ring-2]=\"hasFocus()\"\r\n [class.ring-primary]=\"hasFocus()\"\r\n [paddingless]=\"true\"\r\n>\r\n <div\r\n *transloco=\"let t; prefix: 'formulaBuilder'\"\r\n class=\"flex flex-col overflow-hidden\"\r\n >\r\n <!-- Toolbar - Pass data via inputs (pure component) -->\r\n @if (!hideToolbar()) {\r\n <mt-formula-toolbar\r\n [functionCategories]=\"functionCategories()\"\r\n [visibleTabs]=\"resolvedToolbarTabs()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n >\r\n <ng-template #properties let-insertBlock=\"insertBlock\">\r\n @if (isContextLoading()) {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <p-skeleton\r\n width=\"18rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <p-skeleton\r\n width=\"7rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div class=\"flex items-center gap-4\">\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <!-- Scope Selection - Full width, centered -->\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <mt-radio-cards\r\n [options]=\"scopeOptions()\"\r\n [activeId]=\"propertyScope()\"\r\n (selectionChange)=\"onScopeChange($event)\"\r\n size=\"small\"\r\n />\r\n </div>\r\n\r\n <!-- Path + Field + Preview Row -->\r\n <div class=\"flex items-center gap-4\">\r\n <!-- Path Container - Flexible -->\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.path\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (isDirectAccess()) {\r\n <span\r\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\r\n >\r\n \u2713 {{ t(\"properties.direct-access\") }}\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\">{{\r\n t(\"properties.no-path-configured\")\r\n }}</span>\r\n } @else {\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\r\n >\r\n @for (\r\n segment of pathSegments();\r\n track $index;\r\n let segmentIndex = $index\r\n ) {\r\n @if (segmentIndex > 0) {\r\n <span\r\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\r\n >\u203A</span\r\n >\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"\r\n segment.value ||\r\n t('properties.select') +\r\n ' ' +\r\n getOperatorDisplayName(segment.operatorToken)\r\n \"\r\n icon=\"arrow.chevron-down\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [severity]=\"\r\n segment.value ? 'primary' : 'secondary'\r\n \"\r\n [iconPos]=\"'end'\"\r\n (onClick)=\"pathPopover.toggle($event)\"\r\n ></mt-button>\r\n\r\n <p-popover\r\n #pathPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.select\") }}\r\n {{\r\n getOperatorDisplayName(\r\n segment.operatorToken\r\n )\r\n }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of segmentOptions(segmentIndex);\r\n track option.key\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"option.name\"\r\n [icon]=\"\r\n segment.value === option.key\r\n ? 'general.check'\r\n : 'general.minus'\r\n \"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n [styleClass]=\"\r\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\r\n (segment.value === option.key\r\n ? 'bg-primary text-white'\r\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\r\n \"\r\n (onClick)=\"\r\n setPathSegmentValue(\r\n segmentIndex,\r\n option.key\r\n );\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n @if (segment.optional) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.clear')\"\r\n [outlined]=\"true\"\r\n icon=\"general.x-close\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\r\n (onClick)=\"\r\n setPathSegmentValue(segmentIndex, null);\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </p-popover>\r\n\r\n @if (\r\n segment.canRemove &&\r\n segmentIndex === pathSegments().length - 1\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.x-close\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\r\n (onClick)=\"removePathSegment(segmentIndex)\"\r\n ></mt-button>\r\n }\r\n }\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [disabled]=\"!canAddNextSegment()\"\r\n [class.hidden]=\"!canAddNextSegment()\"\r\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\r\n (onClick)=\"nextOperatorPopover.toggle($event)\"\r\n ></mt-button>\r\n </div>\r\n }\r\n <p-popover\r\n #nextOperatorPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.add-segment\") }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of nextOperatorOptions();\r\n track option.token\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"getOperatorDisplayName(option.token)\"\r\n icon=\"general.plus\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\r\n (onClick)=\"\r\n onAddSegmentSelection(\r\n option.token,\r\n nextOperatorPopover\r\n )\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n </div>\r\n </div>\r\n\r\n <!-- Field Selection - Under Path -->\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.field\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isPropertyLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select')\"\r\n [(ngModel)]=\"propertyFieldKey\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n <div\r\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\r\n [mtTooltip]=\"\r\n '@' +\r\n propertyTablePath() +\r\n '::' +\r\n (selectedProperty()?.key ?? '...')\r\n \"\r\n tooltipPosition=\"top\"\r\n >\r\n @{{ propertyTablePath() }}::{{\r\n selectedProperty()?.key ?? \"...\"\r\n }}\r\n </div>\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert')\"\r\n icon=\"general.plus\"\r\n severity=\"primary\"\r\n [disabled]=\"!canInsertProperty()\"\r\n (onClick)=\"insertSelectedProperty(insertBlock)\"\r\n ></mt-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-formula-toolbar>\r\n }\r\n\r\n <!-- Editor Area -->\r\n <div class=\"p-3\">\r\n <div\r\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\r\n >\r\n @if (showModeToggle()) {\r\n <div\r\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\r\n >\r\n <mt-toggle-field\r\n [label]=\"t('codeMode')\"\r\n labelPosition=\"end\"\r\n size=\"small\"\r\n [ngModel]=\"isCodeMode()\"\r\n [readonly]=\"isCodeModeLocked()\"\r\n [pInputs]=\"{ disabled: isCodeModeLocked() }\"\r\n (ngModelChange)=\"onModeToggle($event)\"\r\n />\r\n </div>\r\n }\r\n <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialFormula]=\"expression()\"\r\n [borderless]=\"true\"\r\n [autocompleteProvider]=\"autocompleteProvider\"\r\n (formulaChange)=\"onCodeFormulaChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n } @else {\r\n <mt-formula-editor\r\n #formulaEditor\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialTokens]=\"tokens()\"\r\n [borderless]=\"true\"\r\n (formulaChange)=\"onFormulaChange($event)\"\r\n (tokensChange)=\"onTokensChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Status Bar - Pass data via inputs (pure component) -->\r\n @if (!hideStatusBar()) {\r\n <mt-formula-status-bar [validation]=\"validation()\" />\r\n }\r\n </div>\r\n</mt-card>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { 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"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "component", type: RadioCards, selector: "mt-radio-cards", inputs: ["circle", "color", "size", "columns", "options", "activeId", "itemTemplate"], outputs: ["optionsChange", "activeIdChange", "selectionChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "visibleTabs", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaStatusBar, selector: "mt-formula-status-bar", inputs: ["validation", "labels"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled", "borderless"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }, { kind: "component", type: FormulaEditorCode, selector: "mt-formula-editor-code", inputs: ["placeholder", "initialFormula", "disabled", "language", "theme", "borderless", "autocompleteProvider", "autocompleteDebounceMs"], outputs: ["formulaChange", "onBlur", "onFocus"] }] });
1122
1122
  }
1123
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaBuilder, decorators: [{
1123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaBuilder, decorators: [{
1124
1124
  type: Component,
1125
1125
  args: [{ selector: 'mt-formula-builder', standalone: true, imports: [
1126
1126
  CommonModule,
@@ -1146,7 +1146,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1146
1146
  useExisting: forwardRef(() => FormulaBuilder),
1147
1147
  multi: true,
1148
1148
  },
1149
- ], template: "<mt-card\r\n headless\r\n [class.ring-2]=\"hasFocus()\"\r\n [class.ring-primary]=\"hasFocus()\"\r\n [paddingless]=\"true\"\r\n>\r\n <div\r\n *transloco=\"let t; prefix: 'formulaBuilder'\"\r\n class=\"flex flex-col overflow-hidden\"\r\n >\r\n <!-- Toolbar - Pass data via inputs (pure component) -->\r\n @if (!hideToolbar()) {\r\n <mt-formula-toolbar\r\n [functionCategories]=\"functionCategories()\"\r\n [visibleTabs]=\"resolvedToolbarTabs()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n >\r\n <ng-template #properties let-insertBlock=\"insertBlock\">\r\n @if (isContextLoading()) {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <p-skeleton\r\n width=\"18rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <p-skeleton\r\n width=\"7rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div class=\"flex items-center gap-4\">\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <!-- Scope Selection - Full width, centered -->\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <mt-radio-cards\r\n [options]=\"scopeOptions()\"\r\n [activeId]=\"propertyScope()\"\r\n (selectionChange)=\"onScopeChange($event)\"\r\n size=\"small\"\r\n />\r\n </div>\r\n\r\n <!-- Path + Field + Preview Row -->\r\n <div class=\"flex items-center gap-4\">\r\n <!-- Path Container - Flexible -->\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.path\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (isDirectAccess()) {\r\n <span\r\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\r\n >\r\n \u2713 {{ t(\"properties.direct-access\") }}\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\">{{\r\n t(\"properties.no-path-configured\")\r\n }}</span>\r\n } @else {\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\r\n >\r\n @for (\r\n segment of pathSegments();\r\n track $index;\r\n let segmentIndex = $index\r\n ) {\r\n @if (segmentIndex > 0) {\r\n <span\r\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\r\n >\u203A</span\r\n >\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"\n segment.value ||\n t('properties.select') +\n ' ' +\n getOperatorDisplayName(segment.operatorToken)\n \"\n icon=\"arrow.chevron-down\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [severity]=\"\r\n segment.value ? 'primary' : 'secondary'\r\n \"\r\n [iconPos]=\"'end'\"\r\n (onClick)=\"pathPopover.toggle($event)\"\r\n ></mt-button>\r\n\r\n <p-popover\r\n #pathPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.select\") }}\n {{ getOperatorDisplayName(segment.operatorToken) }}\n </div>\n <div class=\"flex flex-col gap-1\">\r\n @for (\r\n option of segmentOptions(segmentIndex);\r\n track option.key\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"option.name\"\r\n [icon]=\"\r\n segment.value === option.key\r\n ? 'general.check'\r\n : 'general.minus'\r\n \"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n [styleClass]=\"\r\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\r\n (segment.value === option.key\r\n ? 'bg-primary text-white'\r\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\r\n \"\r\n (onClick)=\"\r\n setPathSegmentValue(\r\n segmentIndex,\r\n option.key\r\n );\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n @if (segment.optional) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.clear')\"\r\n [outlined]=\"true\"\r\n icon=\"general.x-close\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\r\n (onClick)=\"\r\n setPathSegmentValue(segmentIndex, null);\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </p-popover>\r\n\r\n @if (\r\n segment.canRemove &&\r\n segmentIndex === pathSegments().length - 1\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.x-close\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\r\n (onClick)=\"removePathSegment(segmentIndex)\"\r\n ></mt-button>\r\n }\r\n }\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [disabled]=\"!canAddNextSegment()\"\r\n [class.hidden]=\"!canAddNextSegment()\"\r\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\r\n (onClick)=\"nextOperatorPopover.toggle($event)\"\r\n ></mt-button>\r\n </div>\r\n }\r\n <p-popover\r\n #nextOperatorPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.add-segment\") }}\r\n </div>\r\n <div class=\"flex flex-col gap-1\">\r\n @for (\r\n option of nextOperatorOptions();\r\n track option.token\r\n ) {\r\n <mt-button\n type=\"button\"\n [label]=\"getOperatorDisplayName(option.token)\"\n icon=\"general.plus\"\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\r\n (onClick)=\"\r\n onAddSegmentSelection(\r\n option.token,\r\n nextOperatorPopover\r\n )\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n </div>\r\n </div>\r\n\r\n <!-- Field Selection - Under Path -->\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.field\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isPropertyLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select')\"\r\n [(ngModel)]=\"propertyFieldKey\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n <div\r\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\r\n [mtTooltip]=\"\r\n '@' +\r\n propertyTablePath() +\r\n '::' +\r\n (selectedProperty()?.key ?? '...')\r\n \"\r\n tooltipPosition=\"top\"\r\n >\r\n @{{ propertyTablePath() }}::{{\r\n selectedProperty()?.key ?? \"...\"\r\n }}\r\n </div>\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert')\"\r\n icon=\"general.plus\"\r\n severity=\"primary\"\r\n [disabled]=\"!canInsertProperty()\"\r\n (onClick)=\"insertSelectedProperty(insertBlock)\"\r\n ></mt-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-formula-toolbar>\r\n }\r\n\r\n <!-- Editor Area -->\r\n <div class=\"p-3\">\r\n <div\r\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\r\n >\r\n @if (showModeToggle()) {\r\n <div\r\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\r\n >\r\n <mt-toggle-field\r\n [label]=\"t('codeMode')\"\r\n labelPosition=\"end\"\r\n size=\"small\"\r\n [ngModel]=\"isCodeMode()\"\r\n [readonly]=\"isCodeModeLocked()\"\r\n [pInputs]=\"{ disabled: isCodeModeLocked() }\"\r\n (ngModelChange)=\"onModeToggle($event)\"\r\n />\r\n </div>\r\n }\r\n <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialFormula]=\"expression()\"\r\n [borderless]=\"true\"\r\n [autocompleteProvider]=\"autocompleteProvider\"\r\n (formulaChange)=\"onCodeFormulaChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n } @else {\r\n <mt-formula-editor\r\n #formulaEditor\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialTokens]=\"tokens()\"\r\n [borderless]=\"true\"\r\n (formulaChange)=\"onFormulaChange($event)\"\r\n (tokensChange)=\"onTokensChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Status Bar - Pass data via inputs (pure component) -->\r\n @if (!hideStatusBar()) {\r\n <mt-formula-status-bar [validation]=\"validation()\" />\r\n }\r\n </div>\r\n</mt-card>\r\n" }]
1149
+ ], template: "<mt-card\r\n headless\r\n [class.ring-2]=\"hasFocus()\"\r\n [class.ring-primary]=\"hasFocus()\"\r\n [paddingless]=\"true\"\r\n>\r\n <div\r\n *transloco=\"let t; prefix: 'formulaBuilder'\"\r\n class=\"flex flex-col overflow-hidden\"\r\n >\r\n <!-- Toolbar - Pass data via inputs (pure component) -->\r\n @if (!hideToolbar()) {\r\n <mt-formula-toolbar\r\n [functionCategories]=\"functionCategories()\"\r\n [visibleTabs]=\"resolvedToolbarTabs()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n >\r\n <ng-template #properties let-insertBlock=\"insertBlock\">\r\n @if (isContextLoading()) {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <p-skeleton\r\n width=\"18rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <p-skeleton\r\n width=\"7rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div class=\"flex items-center gap-4\">\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <!-- Scope Selection - Full width, centered -->\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <mt-radio-cards\r\n [options]=\"scopeOptions()\"\r\n [activeId]=\"propertyScope()\"\r\n (selectionChange)=\"onScopeChange($event)\"\r\n size=\"small\"\r\n />\r\n </div>\r\n\r\n <!-- Path + Field + Preview Row -->\r\n <div class=\"flex items-center gap-4\">\r\n <!-- Path Container - Flexible -->\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.path\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (isDirectAccess()) {\r\n <span\r\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\r\n >\r\n \u2713 {{ t(\"properties.direct-access\") }}\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\">{{\r\n t(\"properties.no-path-configured\")\r\n }}</span>\r\n } @else {\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\r\n >\r\n @for (\r\n segment of pathSegments();\r\n track $index;\r\n let segmentIndex = $index\r\n ) {\r\n @if (segmentIndex > 0) {\r\n <span\r\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\r\n >\u203A</span\r\n >\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"\r\n segment.value ||\r\n t('properties.select') +\r\n ' ' +\r\n getOperatorDisplayName(segment.operatorToken)\r\n \"\r\n icon=\"arrow.chevron-down\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [severity]=\"\r\n segment.value ? 'primary' : 'secondary'\r\n \"\r\n [iconPos]=\"'end'\"\r\n (onClick)=\"pathPopover.toggle($event)\"\r\n ></mt-button>\r\n\r\n <p-popover\r\n #pathPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.select\") }}\r\n {{\r\n getOperatorDisplayName(\r\n segment.operatorToken\r\n )\r\n }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of segmentOptions(segmentIndex);\r\n track option.key\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"option.name\"\r\n [icon]=\"\r\n segment.value === option.key\r\n ? 'general.check'\r\n : 'general.minus'\r\n \"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n [styleClass]=\"\r\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\r\n (segment.value === option.key\r\n ? 'bg-primary text-white'\r\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\r\n \"\r\n (onClick)=\"\r\n setPathSegmentValue(\r\n segmentIndex,\r\n option.key\r\n );\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n @if (segment.optional) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.clear')\"\r\n [outlined]=\"true\"\r\n icon=\"general.x-close\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\r\n (onClick)=\"\r\n setPathSegmentValue(segmentIndex, null);\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </p-popover>\r\n\r\n @if (\r\n segment.canRemove &&\r\n segmentIndex === pathSegments().length - 1\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.x-close\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\r\n (onClick)=\"removePathSegment(segmentIndex)\"\r\n ></mt-button>\r\n }\r\n }\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [disabled]=\"!canAddNextSegment()\"\r\n [class.hidden]=\"!canAddNextSegment()\"\r\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\r\n (onClick)=\"nextOperatorPopover.toggle($event)\"\r\n ></mt-button>\r\n </div>\r\n }\r\n <p-popover\r\n #nextOperatorPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.add-segment\") }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of nextOperatorOptions();\r\n track option.token\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"getOperatorDisplayName(option.token)\"\r\n icon=\"general.plus\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\r\n (onClick)=\"\r\n onAddSegmentSelection(\r\n option.token,\r\n nextOperatorPopover\r\n )\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n </div>\r\n </div>\r\n\r\n <!-- Field Selection - Under Path -->\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.field\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isPropertyLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select')\"\r\n [(ngModel)]=\"propertyFieldKey\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n <div\r\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\r\n [mtTooltip]=\"\r\n '@' +\r\n propertyTablePath() +\r\n '::' +\r\n (selectedProperty()?.key ?? '...')\r\n \"\r\n tooltipPosition=\"top\"\r\n >\r\n @{{ propertyTablePath() }}::{{\r\n selectedProperty()?.key ?? \"...\"\r\n }}\r\n </div>\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert')\"\r\n icon=\"general.plus\"\r\n severity=\"primary\"\r\n [disabled]=\"!canInsertProperty()\"\r\n (onClick)=\"insertSelectedProperty(insertBlock)\"\r\n ></mt-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-formula-toolbar>\r\n }\r\n\r\n <!-- Editor Area -->\r\n <div class=\"p-3\">\r\n <div\r\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\r\n >\r\n @if (showModeToggle()) {\r\n <div\r\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\r\n >\r\n <mt-toggle-field\r\n [label]=\"t('codeMode')\"\r\n labelPosition=\"end\"\r\n size=\"small\"\r\n [ngModel]=\"isCodeMode()\"\r\n [readonly]=\"isCodeModeLocked()\"\r\n [pInputs]=\"{ disabled: isCodeModeLocked() }\"\r\n (ngModelChange)=\"onModeToggle($event)\"\r\n />\r\n </div>\r\n }\r\n <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialFormula]=\"expression()\"\r\n [borderless]=\"true\"\r\n [autocompleteProvider]=\"autocompleteProvider\"\r\n (formulaChange)=\"onCodeFormulaChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n } @else {\r\n <mt-formula-editor\r\n #formulaEditor\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialTokens]=\"tokens()\"\r\n [borderless]=\"true\"\r\n (formulaChange)=\"onFormulaChange($event)\"\r\n (tokensChange)=\"onTokensChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Status Bar - Pass data via inputs (pure component) -->\r\n @if (!hideStatusBar()) {\r\n <mt-formula-status-bar [validation]=\"validation()\" />\r\n }\r\n </div>\r\n</mt-card>\r\n" }]
1150
1150
  }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.ViewChild, args: ['formulaEditor', { isSignal: true }] }], codeEditor: [{ type: i0.ViewChild, args: ['formulaEditorCode', { isSignal: true }] }], propertiesByPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesByPath", required: false }] }], levelSchemaId: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelSchemaId", required: false }] }], moduleId: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleId", required: false }] }], contextEntityTypeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextEntityTypeKey", required: false }] }], templateId: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateId", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hideToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideToolbar", required: false }] }], hideStatusBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideStatusBar", required: false }] }], toolbarTabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarTabs", required: false }] }], codeOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "codeOnly", required: false }] }], isProcessBuilder: [{ type: i0.Input, args: [{ isSignal: true, alias: "isProcessBuilder", required: false }] }], validationChange: [{ type: i0.Output, args: ["validationChange"] }], tokensChange: [{ type: i0.Output, args: ["tokensChange"] }] } });
1151
1151
 
1152
1152
  /**