@masterteam/formula-builder 0.0.2 → 0.0.4
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.
|
@@ -13,7 +13,7 @@ import { ToggleField } from '@masterteam/components/toggle-field';
|
|
|
13
13
|
import * as i2 from 'primeng/popover';
|
|
14
14
|
import { PopoverModule } from 'primeng/popover';
|
|
15
15
|
import { Skeleton } from 'primeng/skeleton';
|
|
16
|
-
import { createPropertyBlock, FormulaToolbar, FormulaStatusBar, FormulaEditor, FormulaEditorCode } from '@masterteam/components/formula';
|
|
16
|
+
import { serializeTokens, createPropertyBlock, FormulaToolbar, FormulaStatusBar, FormulaEditor, FormulaEditorCode } from '@masterteam/components/formula';
|
|
17
17
|
export { createFunctionBlock, createLiteralBlock, createOperatorBlock, createPropertyBlock } from '@masterteam/components/formula';
|
|
18
18
|
import { HttpClient } from '@angular/common/http';
|
|
19
19
|
import { Subject, debounceTime, distinctUntilChanged, tap, switchMap, of, map, catchError } from 'rxjs';
|
|
@@ -43,6 +43,11 @@ const ERROR_VALIDATION = {
|
|
|
43
43
|
class FormulaValidatorService {
|
|
44
44
|
http = inject(HttpClient);
|
|
45
45
|
apiUrl = '/formulas';
|
|
46
|
+
getBaseUrl(mode) {
|
|
47
|
+
return mode === 'current-only'
|
|
48
|
+
? `${this.apiUrl}/current-only`
|
|
49
|
+
: this.apiUrl;
|
|
50
|
+
}
|
|
46
51
|
/** Debounce time in ms */
|
|
47
52
|
DEBOUNCE_MS = 300;
|
|
48
53
|
/** Current validation result */
|
|
@@ -54,7 +59,9 @@ class FormulaValidatorService {
|
|
|
54
59
|
unwrapResponse(response) {
|
|
55
60
|
if (!response)
|
|
56
61
|
return null;
|
|
57
|
-
if (typeof response === 'object' &&
|
|
62
|
+
if (typeof response === 'object' &&
|
|
63
|
+
response !== null &&
|
|
64
|
+
'data' in response) {
|
|
58
65
|
return response.data ?? null;
|
|
59
66
|
}
|
|
60
67
|
return response;
|
|
@@ -69,6 +76,9 @@ class FormulaValidatorService {
|
|
|
69
76
|
setupValidationStream() {
|
|
70
77
|
this.validateSubject
|
|
71
78
|
.pipe(debounceTime(this.DEBOUNCE_MS), distinctUntilChanged((a, b) => a.formula === b.formula &&
|
|
79
|
+
a.levelSchemaId === b.levelSchemaId &&
|
|
80
|
+
a.templateId === b.templateId &&
|
|
81
|
+
a.apiMode === b.apiMode &&
|
|
72
82
|
JSON.stringify(a.knownProperties) ===
|
|
73
83
|
JSON.stringify(b.knownProperties)), tap(() => this._isValidating.set(true)), switchMap((request) => this.callValidateApi(request)))
|
|
74
84
|
.subscribe((result) => {
|
|
@@ -77,7 +87,7 @@ class FormulaValidatorService {
|
|
|
77
87
|
});
|
|
78
88
|
}
|
|
79
89
|
/** Validate formula (debounced) */
|
|
80
|
-
validate(formula, knownProperties, levelSchemaId, templateId) {
|
|
90
|
+
validate(formula, knownProperties, levelSchemaId, templateId, apiMode = 'default') {
|
|
81
91
|
// Handle empty formula
|
|
82
92
|
if (!formula || formula.trim() === '') {
|
|
83
93
|
this._validation.set(EMPTY_VALIDATION);
|
|
@@ -89,10 +99,11 @@ class FormulaValidatorService {
|
|
|
89
99
|
knownProperties,
|
|
90
100
|
levelSchemaId,
|
|
91
101
|
templateId,
|
|
102
|
+
apiMode,
|
|
92
103
|
});
|
|
93
104
|
}
|
|
94
105
|
/** Validate formula immediately (no debounce) */
|
|
95
|
-
validateImmediate(formula, knownProperties, levelSchemaId, templateId) {
|
|
106
|
+
validateImmediate(formula, knownProperties, levelSchemaId, templateId, apiMode = 'default') {
|
|
96
107
|
if (!formula || formula.trim() === '') {
|
|
97
108
|
return of(EMPTY_VALIDATION);
|
|
98
109
|
}
|
|
@@ -102,6 +113,7 @@ class FormulaValidatorService {
|
|
|
102
113
|
knownProperties,
|
|
103
114
|
levelSchemaId,
|
|
104
115
|
templateId,
|
|
116
|
+
apiMode,
|
|
105
117
|
}).pipe(tap((result) => {
|
|
106
118
|
this._validation.set(result);
|
|
107
119
|
this._isValidating.set(false);
|
|
@@ -109,8 +121,9 @@ class FormulaValidatorService {
|
|
|
109
121
|
}
|
|
110
122
|
/** Call validation API */
|
|
111
123
|
callValidateApi(request) {
|
|
124
|
+
const { apiMode, ...payload } = request;
|
|
112
125
|
return this.http
|
|
113
|
-
.post(`${this.
|
|
126
|
+
.post(`${this.getBaseUrl(apiMode)}/validate`, payload)
|
|
114
127
|
.pipe(map((response) => this.unwrapResponse(response) ?? ERROR_VALIDATION), catchError((error) => {
|
|
115
128
|
console.error('Validation API error:', error);
|
|
116
129
|
// Try to extract error message
|
|
@@ -164,10 +177,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
164
177
|
class FormulaContextService {
|
|
165
178
|
http = inject(HttpClient);
|
|
166
179
|
apiUrl = '/formulas';
|
|
180
|
+
getBaseUrl(mode) {
|
|
181
|
+
return mode === 'current-only'
|
|
182
|
+
? `${this.apiUrl}/current-only`
|
|
183
|
+
: this.apiUrl;
|
|
184
|
+
}
|
|
167
185
|
unwrapResponse(response) {
|
|
168
186
|
if (!response)
|
|
169
187
|
return null;
|
|
170
|
-
if (typeof response === 'object' &&
|
|
188
|
+
if (typeof response === 'object' &&
|
|
189
|
+
response !== null &&
|
|
190
|
+
'data' in response) {
|
|
171
191
|
return response.data ?? null;
|
|
172
192
|
}
|
|
173
193
|
return response;
|
|
@@ -175,19 +195,19 @@ class FormulaContextService {
|
|
|
175
195
|
contextCache = new Map();
|
|
176
196
|
propertiesCache = new Map();
|
|
177
197
|
nextTokensCache = new Map();
|
|
178
|
-
loadContext(schemaId, contextEntityTypeKey) {
|
|
198
|
+
loadContext(schemaId, contextEntityTypeKey, mode = 'default') {
|
|
179
199
|
if (!schemaId)
|
|
180
200
|
return of(null);
|
|
181
|
-
const cacheKey = `${schemaId}:${contextEntityTypeKey ?? ''}`;
|
|
201
|
+
const cacheKey = `${mode}:${schemaId}:${contextEntityTypeKey ?? ''}`;
|
|
182
202
|
const cached = this.contextCache.get(cacheKey);
|
|
183
203
|
if (cached) {
|
|
184
204
|
return of(cached);
|
|
185
205
|
}
|
|
186
|
-
const query = contextEntityTypeKey
|
|
206
|
+
const query = mode === 'default' && contextEntityTypeKey
|
|
187
207
|
? `?contextEntityTypeKey=${encodeURIComponent(contextEntityTypeKey)}`
|
|
188
208
|
: '';
|
|
189
209
|
return this.http
|
|
190
|
-
.get(`${this.
|
|
210
|
+
.get(`${this.getBaseUrl(mode)}/builder/context/${schemaId}${query}`)
|
|
191
211
|
.pipe(map((response) => this.unwrapResponse(response)), tap((context) => {
|
|
192
212
|
if (context) {
|
|
193
213
|
this.contextCache.set(cacheKey, context);
|
|
@@ -197,10 +217,12 @@ class FormulaContextService {
|
|
|
197
217
|
return of(null);
|
|
198
218
|
}));
|
|
199
219
|
}
|
|
200
|
-
getScopeProperties(schemaId, component, tablePath) {
|
|
220
|
+
getScopeProperties(schemaId, component, tablePath, mode = 'default') {
|
|
201
221
|
if (!schemaId || !component || !tablePath)
|
|
202
222
|
return of([]);
|
|
203
|
-
|
|
223
|
+
if (mode === 'current-only')
|
|
224
|
+
return of([]);
|
|
225
|
+
const cacheKey = `${mode}:${schemaId}:${component}:${tablePath}`;
|
|
204
226
|
const cached = this.propertiesCache.get(cacheKey);
|
|
205
227
|
if (cached) {
|
|
206
228
|
return of(cached);
|
|
@@ -211,7 +233,7 @@ class FormulaContextService {
|
|
|
211
233
|
tablePath,
|
|
212
234
|
});
|
|
213
235
|
return this.http
|
|
214
|
-
.get(`${this.
|
|
236
|
+
.get(`${this.getBaseUrl(mode)}/builder/properties?${params.toString()}`)
|
|
215
237
|
.pipe(map((response) => this.unwrapResponse(response) ?? []), tap((response) => {
|
|
216
238
|
this.propertiesCache.set(cacheKey, response);
|
|
217
239
|
}), catchError((error) => {
|
|
@@ -219,10 +241,12 @@ class FormulaContextService {
|
|
|
219
241
|
return of([]);
|
|
220
242
|
}));
|
|
221
243
|
}
|
|
222
|
-
getNextTokens(schemaId, component, tablePath) {
|
|
244
|
+
getNextTokens(schemaId, component, tablePath, mode = 'default') {
|
|
223
245
|
if (!schemaId || !component || !tablePath)
|
|
224
246
|
return of(null);
|
|
225
|
-
|
|
247
|
+
if (mode === 'current-only')
|
|
248
|
+
return of(null);
|
|
249
|
+
const cacheKey = `${mode}:${schemaId}:${component}:${tablePath}`;
|
|
226
250
|
const cached = this.nextTokensCache.get(cacheKey);
|
|
227
251
|
if (cached) {
|
|
228
252
|
return of(cached);
|
|
@@ -233,7 +257,7 @@ class FormulaContextService {
|
|
|
233
257
|
tablePath,
|
|
234
258
|
});
|
|
235
259
|
return this.http
|
|
236
|
-
.get(`${this.
|
|
260
|
+
.get(`${this.getBaseUrl(mode)}/builder/next-tokens?${params.toString()}`)
|
|
237
261
|
.pipe(map((response) => this.unwrapResponse(response)), tap((payload) => {
|
|
238
262
|
if (payload) {
|
|
239
263
|
this.nextTokensCache.set(cacheKey, payload);
|
|
@@ -254,15 +278,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
254
278
|
class FormulaAutocompleteService {
|
|
255
279
|
http = inject(HttpClient);
|
|
256
280
|
apiUrl = '/formulas';
|
|
281
|
+
getBaseUrl(mode) {
|
|
282
|
+
return mode === 'current-only'
|
|
283
|
+
? `${this.apiUrl}/current-only`
|
|
284
|
+
: this.apiUrl;
|
|
285
|
+
}
|
|
257
286
|
unwrapResponse(response) {
|
|
258
287
|
if (!response)
|
|
259
288
|
return null;
|
|
260
|
-
if (typeof response === 'object' &&
|
|
289
|
+
if (typeof response === 'object' &&
|
|
290
|
+
response !== null &&
|
|
291
|
+
'data' in response) {
|
|
261
292
|
return response.data ?? null;
|
|
262
293
|
}
|
|
263
294
|
return response;
|
|
264
295
|
}
|
|
265
|
-
getSuggestions(request) {
|
|
296
|
+
getSuggestions(request, apiMode = 'default') {
|
|
266
297
|
if (!request) {
|
|
267
298
|
return of(null);
|
|
268
299
|
}
|
|
@@ -271,7 +302,7 @@ class FormulaAutocompleteService {
|
|
|
271
302
|
formula: request.formula ?? '',
|
|
272
303
|
};
|
|
273
304
|
return this.http
|
|
274
|
-
.post(`${this.
|
|
305
|
+
.post(`${this.getBaseUrl(apiMode)}/autocomplete`, normalized)
|
|
275
306
|
.pipe(map((response) => this.unwrapResponse(response)), catchError((error) => {
|
|
276
307
|
console.warn('Autocomplete API error:', error);
|
|
277
308
|
return of(null);
|
|
@@ -374,6 +405,11 @@ function appendToPath(basePath, operatorToken, value, isBase) {
|
|
|
374
405
|
}
|
|
375
406
|
|
|
376
407
|
const DEFAULT_SCOPE_ICON = 'general.placeholder';
|
|
408
|
+
const DEFAULT_TOOLBAR_TABS = [
|
|
409
|
+
'functions',
|
|
410
|
+
'properties',
|
|
411
|
+
'operators',
|
|
412
|
+
];
|
|
377
413
|
const SCOPE_ICON_MAP = {
|
|
378
414
|
Current: 'map.marker-pin-01',
|
|
379
415
|
Level: 'map.marker-pin-01',
|
|
@@ -402,6 +438,12 @@ class FormulaBuilder {
|
|
|
402
438
|
hideToolbar = input(false, ...(ngDevMode ? [{ debugName: "hideToolbar" }] : []));
|
|
403
439
|
/** Hide the status bar */
|
|
404
440
|
hideStatusBar = input(false, ...(ngDevMode ? [{ debugName: "hideStatusBar" }] : []));
|
|
441
|
+
/** Visible toolbar tabs */
|
|
442
|
+
toolbarTabs = input(DEFAULT_TOOLBAR_TABS, ...(ngDevMode ? [{ debugName: "toolbarTabs" }] : []));
|
|
443
|
+
/** Force code editor mode and hide the mode toggle */
|
|
444
|
+
codeOnly = input(false, ...(ngDevMode ? [{ debugName: "codeOnly" }] : []));
|
|
445
|
+
/** Use Process Builder current-only Formula Engine endpoints */
|
|
446
|
+
isProcessBuilder = input(false, ...(ngDevMode ? [{ debugName: "isProcessBuilder" }] : []));
|
|
405
447
|
// ===== OUTPUTS =====
|
|
406
448
|
/** Emits validation result on change */
|
|
407
449
|
validationChange = output();
|
|
@@ -421,7 +463,7 @@ class FormulaBuilder {
|
|
|
421
463
|
...request,
|
|
422
464
|
levelSchemaId: this.levelSchemaId(),
|
|
423
465
|
contextEntityTypeKey: this.builderContext()?.contextEntityTypeKey,
|
|
424
|
-
});
|
|
466
|
+
}, this.isProcessBuilder() ? 'current-only' : 'default');
|
|
425
467
|
};
|
|
426
468
|
/** Track last synced builder JSON to avoid loops */
|
|
427
469
|
lastBuilderJson = '';
|
|
@@ -429,6 +471,12 @@ class FormulaBuilder {
|
|
|
429
471
|
editorMode = signal('builder', ...(ngDevMode ? [{ debugName: "editorMode" }] : []));
|
|
430
472
|
isCodeMode = computed(() => this.editorMode() === 'code', ...(ngDevMode ? [{ debugName: "isCodeMode" }] : []));
|
|
431
473
|
isCodeModeLocked = signal(false, ...(ngDevMode ? [{ debugName: "isCodeModeLocked" }] : []));
|
|
474
|
+
showModeToggle = computed(() => !this.codeOnly(), ...(ngDevMode ? [{ debugName: "showModeToggle" }] : []));
|
|
475
|
+
formulaApiMode = computed(() => this.isProcessBuilder() ? 'current-only' : 'default', ...(ngDevMode ? [{ debugName: "formulaApiMode" }] : []));
|
|
476
|
+
resolvedToolbarTabs = computed(() => {
|
|
477
|
+
const tabs = this.toolbarTabs();
|
|
478
|
+
return tabs.length > 0 ? tabs : DEFAULT_TOOLBAR_TABS;
|
|
479
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedToolbarTabs" }] : []));
|
|
432
480
|
codeModeSnapshotTokens = [];
|
|
433
481
|
codeModeSnapshotExpression = '';
|
|
434
482
|
/** ControlValueAccessor callbacks */
|
|
@@ -455,8 +503,9 @@ class FormulaBuilder {
|
|
|
455
503
|
// Validate when formula changes
|
|
456
504
|
effect(() => {
|
|
457
505
|
const formula = this.expressionValue();
|
|
506
|
+
const apiMode = this.formulaApiMode();
|
|
458
507
|
if (formula && formula.trim().length > 0) {
|
|
459
|
-
this.validatorService.validate(formula, undefined, this.levelSchemaId(), this.templateId());
|
|
508
|
+
this.validatorService.validate(formula, undefined, this.levelSchemaId(), this.templateId(), apiMode);
|
|
460
509
|
}
|
|
461
510
|
});
|
|
462
511
|
// Emit validation changes
|
|
@@ -467,6 +516,7 @@ class FormulaBuilder {
|
|
|
467
516
|
// Load builder context when schema changes
|
|
468
517
|
effect(() => {
|
|
469
518
|
const schemaId = this.levelSchemaId();
|
|
519
|
+
const apiMode = this.formulaApiMode();
|
|
470
520
|
if (!schemaId) {
|
|
471
521
|
this.builderContext.set(null);
|
|
472
522
|
this.propertiesByPathApi.set({});
|
|
@@ -476,8 +526,11 @@ class FormulaBuilder {
|
|
|
476
526
|
}
|
|
477
527
|
const requestId = ++this.contextRequestId;
|
|
478
528
|
this.isContextLoading.set(true);
|
|
529
|
+
this.propertiesByPathApi.set({});
|
|
479
530
|
this.nextTokenRulesByPath.set({});
|
|
480
|
-
this.contextService
|
|
531
|
+
this.contextService
|
|
532
|
+
.loadContext(schemaId, undefined, apiMode)
|
|
533
|
+
.subscribe((context) => {
|
|
481
534
|
if (requestId !== this.contextRequestId) {
|
|
482
535
|
return;
|
|
483
536
|
}
|
|
@@ -514,10 +567,15 @@ class FormulaBuilder {
|
|
|
514
567
|
// Fetch properties for the selected table path
|
|
515
568
|
effect(() => {
|
|
516
569
|
const schemaId = this.levelSchemaId();
|
|
570
|
+
const isProcessBuilder = this.isProcessBuilder();
|
|
517
571
|
const tablePath = this.resolvedTablePath();
|
|
518
572
|
const component = this.propertiesComponent();
|
|
519
573
|
const context = this.builderContext();
|
|
520
|
-
if (
|
|
574
|
+
if (isProcessBuilder ||
|
|
575
|
+
!schemaId ||
|
|
576
|
+
!tablePath ||
|
|
577
|
+
!component ||
|
|
578
|
+
!context) {
|
|
521
579
|
this.propertyLoadingPath.set(null);
|
|
522
580
|
return;
|
|
523
581
|
}
|
|
@@ -542,9 +600,10 @@ class FormulaBuilder {
|
|
|
542
600
|
// Fetch next-token rules for the current table path
|
|
543
601
|
effect(() => {
|
|
544
602
|
const schemaId = this.levelSchemaId();
|
|
603
|
+
const isProcessBuilder = this.isProcessBuilder();
|
|
545
604
|
const tablePath = this.resolvedTablePath();
|
|
546
605
|
const component = this.propertiesComponent();
|
|
547
|
-
if (!schemaId || !tablePath || !component)
|
|
606
|
+
if (isProcessBuilder || !schemaId || !tablePath || !component)
|
|
548
607
|
return;
|
|
549
608
|
if (this.nextTokenRulesByPath()[tablePath])
|
|
550
609
|
return;
|
|
@@ -615,46 +674,24 @@ class FormulaBuilder {
|
|
|
615
674
|
writeValue(value) {
|
|
616
675
|
if (!value) {
|
|
617
676
|
this.expressionValue.set('');
|
|
618
|
-
this.
|
|
619
|
-
this.tokens.set([]);
|
|
620
|
-
this.lastBuilderJson = '';
|
|
621
|
-
const editor = this.editor();
|
|
622
|
-
if (editor) {
|
|
623
|
-
editor.writeValue([]);
|
|
624
|
-
}
|
|
625
|
-
const codeEditor = this.codeEditor();
|
|
626
|
-
if (codeEditor) {
|
|
627
|
-
codeEditor.writeValue('');
|
|
628
|
-
}
|
|
677
|
+
this.applyFormulaValue([], '', this.codeOnly());
|
|
629
678
|
this.validatorService.reset();
|
|
630
679
|
return;
|
|
631
680
|
}
|
|
632
|
-
this.expressionValue.set(value.expression ?? '');
|
|
633
|
-
const codeEditor = this.codeEditor();
|
|
634
|
-
if (codeEditor) {
|
|
635
|
-
codeEditor.writeValue(this.expressionValue());
|
|
636
|
-
}
|
|
637
681
|
const builder = Array.isArray(value.builder) ? value.builder : [];
|
|
638
|
-
this.
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
editor.writeValue([]);
|
|
645
|
-
}
|
|
682
|
+
const expression = this.codeOnly()
|
|
683
|
+
? this.resolveExpressionValue(value.expression ?? '', builder)
|
|
684
|
+
: (value.expression ?? '');
|
|
685
|
+
this.expressionValue.set(expression);
|
|
686
|
+
if (this.codeOnly()) {
|
|
687
|
+
this.applyFormulaValue(builder, expression, true);
|
|
646
688
|
return;
|
|
647
689
|
}
|
|
648
|
-
|
|
649
|
-
|
|
690
|
+
if (builder.length === 0) {
|
|
691
|
+
this.applyFormulaValue([], expression, expression.trim().length > 0, true);
|
|
650
692
|
return;
|
|
651
693
|
}
|
|
652
|
-
this.
|
|
653
|
-
const editor = this.editor();
|
|
654
|
-
if (editor) {
|
|
655
|
-
editor.writeValue(builder);
|
|
656
|
-
}
|
|
657
|
-
this.lastBuilderJson = serialized;
|
|
694
|
+
this.applyFormulaValue(builder, expression, false);
|
|
658
695
|
}
|
|
659
696
|
registerOnChange(fn) {
|
|
660
697
|
this.onChange = fn;
|
|
@@ -673,6 +710,14 @@ class FormulaBuilder {
|
|
|
673
710
|
/** Handle formula change from code editor */
|
|
674
711
|
onCodeFormulaChange(newFormula) {
|
|
675
712
|
this.expressionValue.set(newFormula);
|
|
713
|
+
if (!newFormula.trim()) {
|
|
714
|
+
this.clearBuilderTokens();
|
|
715
|
+
this.isCodeModeLocked.set(false);
|
|
716
|
+
this.codeModeSnapshotTokens = [];
|
|
717
|
+
this.codeModeSnapshotExpression = '';
|
|
718
|
+
this.emitValueChange();
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
676
721
|
if (!this.isCodeModeLocked() &&
|
|
677
722
|
newFormula !== this.codeModeSnapshotExpression) {
|
|
678
723
|
this.isCodeModeLocked.set(true);
|
|
@@ -717,6 +762,9 @@ class FormulaBuilder {
|
|
|
717
762
|
});
|
|
718
763
|
}
|
|
719
764
|
onModeToggle(value) {
|
|
765
|
+
if (this.codeOnly()) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
720
768
|
const nextMode = value ? 'code' : 'builder';
|
|
721
769
|
this.setEditorMode(nextMode);
|
|
722
770
|
}
|
|
@@ -747,6 +795,17 @@ class FormulaBuilder {
|
|
|
747
795
|
}
|
|
748
796
|
exitCodeMode() {
|
|
749
797
|
this.editorMode.set('builder');
|
|
798
|
+
if (!this.expressionValue().trim()) {
|
|
799
|
+
this.clearBuilderTokens();
|
|
800
|
+
const editor = this.editor();
|
|
801
|
+
if (editor) {
|
|
802
|
+
editor.writeValue([]);
|
|
803
|
+
}
|
|
804
|
+
this.codeModeSnapshotTokens = [];
|
|
805
|
+
this.codeModeSnapshotExpression = '';
|
|
806
|
+
this.isCodeModeLocked.set(false);
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
750
809
|
if (this.codeModeSnapshotTokens.length > 0) {
|
|
751
810
|
const restored = this.codeModeSnapshotTokens.slice();
|
|
752
811
|
this.tokens.set(restored);
|
|
@@ -775,22 +834,40 @@ class FormulaBuilder {
|
|
|
775
834
|
/** Clear the formula */
|
|
776
835
|
clear() {
|
|
777
836
|
this.expressionValue.set('');
|
|
778
|
-
this.
|
|
779
|
-
this.
|
|
780
|
-
this.
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
837
|
+
this.applyFormulaValue([], '', this.codeOnly());
|
|
838
|
+
this.validatorService.reset();
|
|
839
|
+
this.emitValueChange();
|
|
840
|
+
}
|
|
841
|
+
resolveExpressionValue(expression, builder) {
|
|
842
|
+
if (expression.trim().length > 0) {
|
|
843
|
+
return expression;
|
|
844
|
+
}
|
|
845
|
+
return builder.length > 0 ? serializeTokens(builder) : '';
|
|
846
|
+
}
|
|
847
|
+
applyFormulaValue(builder, expression, useCodeMode, lockCodeMode = false) {
|
|
848
|
+
const serialized = JSON.stringify(builder);
|
|
849
|
+
this.builderValue.set(builder);
|
|
850
|
+
this.tokens.set(builder);
|
|
851
|
+
this.lastBuilderJson = builder.length > 0 ? serialized : '';
|
|
784
852
|
const editor = this.editor();
|
|
785
853
|
if (editor) {
|
|
786
|
-
editor.writeValue(
|
|
854
|
+
editor.writeValue(builder);
|
|
787
855
|
}
|
|
788
856
|
const codeEditor = this.codeEditor();
|
|
789
857
|
if (codeEditor) {
|
|
790
|
-
codeEditor.writeValue(
|
|
858
|
+
codeEditor.writeValue(expression);
|
|
791
859
|
}
|
|
792
|
-
|
|
793
|
-
|
|
860
|
+
if (useCodeMode) {
|
|
861
|
+
this.editorMode.set('code');
|
|
862
|
+
this.isCodeModeLocked.set(lockCodeMode);
|
|
863
|
+
this.codeModeSnapshotTokens = builder.slice();
|
|
864
|
+
this.codeModeSnapshotExpression = expression;
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
this.editorMode.set('builder');
|
|
868
|
+
this.isCodeModeLocked.set(false);
|
|
869
|
+
this.codeModeSnapshotTokens = [];
|
|
870
|
+
this.codeModeSnapshotExpression = '';
|
|
794
871
|
}
|
|
795
872
|
// ===== PROPERTY COMPOSER =====
|
|
796
873
|
propertyScope = signal('', ...(ngDevMode ? [{ debugName: "propertyScope" }] : []));
|
|
@@ -878,6 +955,9 @@ class FormulaBuilder {
|
|
|
878
955
|
return segments.every((segment) => !segment.requiresParameter || Boolean(segment.value));
|
|
879
956
|
}, ...(ngDevMode ? [{ debugName: "canAddNextSegment" }] : []));
|
|
880
957
|
propertiesComponent = computed(() => {
|
|
958
|
+
if (this.isProcessBuilder()) {
|
|
959
|
+
return undefined;
|
|
960
|
+
}
|
|
881
961
|
const contextKey = this.builderContext()?.contextEntityTypeKey;
|
|
882
962
|
return contextKey;
|
|
883
963
|
}, ...(ngDevMode ? [{ debugName: "propertiesComponent" }] : []));
|
|
@@ -971,13 +1051,13 @@ class FormulaBuilder {
|
|
|
971
1051
|
insertBlock(block);
|
|
972
1052
|
}
|
|
973
1053
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
974
|
-
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 }, 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 } }, outputs: { validationChange: "validationChange", tokensChange: "tokensChange" }, host: { classAttribute: "block" }, providers: [
|
|
1054
|
+
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 }, 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: [
|
|
975
1055
|
{
|
|
976
1056
|
provide: NG_VALUE_ACCESSOR,
|
|
977
1057
|
useExisting: forwardRef(() => FormulaBuilder),
|
|
978
1058
|
multi: true,
|
|
979
1059
|
},
|
|
980
|
-
], 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 (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 >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 Direct Access\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\"\r\n >No path configured</span\r\n >\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 'Select ' + 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 Select {{ segment.operatorToken }}\r\n </div>\r\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=\"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 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\r\n type=\"button\"\r\n [label]=\"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 >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=\"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=\"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 <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=\"Code mode\"\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 <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"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()\"\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"], 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", "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"] }] });
|
|
1060
|
+
], 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 >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 Direct Access\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\"\r\n >No path configured</span\r\n >\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 'Select ' + 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 Select {{ segment.operatorToken }}\r\n </div>\r\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=\"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 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\r\n type=\"button\"\r\n [label]=\"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 >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=\"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=\"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=\"Code mode\"\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()\"\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()\"\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"] }] });
|
|
981
1061
|
}
|
|
982
1062
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaBuilder, decorators: [{
|
|
983
1063
|
type: Component,
|
|
@@ -1005,8 +1085,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
1005
1085
|
useExisting: forwardRef(() => FormulaBuilder),
|
|
1006
1086
|
multi: true,
|
|
1007
1087
|
},
|
|
1008
|
-
], 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 (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 >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 Direct Access\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\"\r\n >No path configured</span\r\n >\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 'Select ' + 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 Select {{ segment.operatorToken }}\r\n </div>\r\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=\"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 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\r\n type=\"button\"\r\n [label]=\"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 >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=\"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=\"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 <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=\"Code mode\"\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 <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"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()\"\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" }]
|
|
1009
|
-
}], 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 }] }], 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 }] }], validationChange: [{ type: i0.Output, args: ["validationChange"] }], tokensChange: [{ type: i0.Output, args: ["tokensChange"] }] } });
|
|
1088
|
+
], 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 >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 Direct Access\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\"\r\n >No path configured</span\r\n >\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 'Select ' + 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 Select {{ segment.operatorToken }}\r\n </div>\r\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=\"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 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\r\n type=\"button\"\r\n [label]=\"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 >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=\"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=\"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=\"Code mode\"\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()\"\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()\"\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" }]
|
|
1089
|
+
}], 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 }] }], 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"] }] } });
|
|
1010
1090
|
|
|
1011
1091
|
/**
|
|
1012
1092
|
* Services barrel export
|