@masterteam/formula-builder 0.0.20 → 0.0.21
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.
package/assets/i18n/ar.json
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
{
|
|
2
|
-
"formulaBuilder": {
|
|
3
|
-
"placeholder": "أدخل الصيغة...",
|
|
4
|
-
"codeMode": "وضع الكود",
|
|
5
|
-
"errors": {
|
|
6
|
-
"validationFailed": "فشل التحقق"
|
|
7
|
-
},
|
|
8
|
-
"actions": {
|
|
9
|
-
"insert": "إدراج",
|
|
10
|
-
"clear": "مسح"
|
|
11
|
-
},
|
|
12
|
-
"properties": {
|
|
13
|
-
"path": "المسار",
|
|
14
|
-
"field": "الحقل",
|
|
15
|
-
"no-path-configured": "لا يوجد مسار محدد",
|
|
16
|
-
"direct-access": "وصول مباشر",
|
|
17
|
-
"add-segment": "إضافة جزء",
|
|
18
|
-
"select": "اختر"
|
|
19
|
-
},
|
|
20
|
-
"operatorNames": {
|
|
21
|
-
"level": "المستوى",
|
|
22
|
-
"current": "الحالي",
|
|
23
|
-
"host": "المضيف",
|
|
24
|
-
"parent": "الأصل",
|
|
25
|
-
"children": "الأبناء",
|
|
26
|
-
"descendants": "المتفرعات",
|
|
27
|
-
"modules": "الوحدات",
|
|
28
|
-
"schedule": "الجدول الزمني",
|
|
29
|
-
"phasegate": "بوابة المرحلة",
|
|
30
|
-
"taskbaseline": "خط الأساس للمهام"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"formulaBuilder": {
|
|
3
|
+
"placeholder": "أدخل الصيغة...",
|
|
4
|
+
"codeMode": "وضع الكود",
|
|
5
|
+
"errors": {
|
|
6
|
+
"validationFailed": "فشل التحقق"
|
|
7
|
+
},
|
|
8
|
+
"actions": {
|
|
9
|
+
"insert": "إدراج",
|
|
10
|
+
"clear": "مسح"
|
|
11
|
+
},
|
|
12
|
+
"properties": {
|
|
13
|
+
"path": "المسار",
|
|
14
|
+
"field": "الحقل",
|
|
15
|
+
"no-path-configured": "لا يوجد مسار محدد",
|
|
16
|
+
"direct-access": "وصول مباشر",
|
|
17
|
+
"add-segment": "إضافة جزء",
|
|
18
|
+
"select": "اختر"
|
|
19
|
+
},
|
|
20
|
+
"operatorNames": {
|
|
21
|
+
"level": "المستوى",
|
|
22
|
+
"current": "الحالي",
|
|
23
|
+
"host": "المضيف",
|
|
24
|
+
"parent": "الأصل",
|
|
25
|
+
"children": "الأبناء",
|
|
26
|
+
"descendants": "المتفرعات",
|
|
27
|
+
"modules": "الوحدات",
|
|
28
|
+
"schedule": "الجدول الزمني",
|
|
29
|
+
"phasegate": "بوابة المرحلة",
|
|
30
|
+
"taskbaseline": "خط الأساس للمهام"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/assets/i18n/en.json
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
{
|
|
2
|
-
"formulaBuilder": {
|
|
3
|
-
"placeholder": "Enter formula...",
|
|
4
|
-
"codeMode": "Code mode",
|
|
5
|
-
"errors": {
|
|
6
|
-
"validationFailed": "Validation failed"
|
|
7
|
-
},
|
|
8
|
-
"actions": {
|
|
9
|
-
"insert": "Insert",
|
|
10
|
-
"clear": "Clear"
|
|
11
|
-
},
|
|
12
|
-
"properties": {
|
|
13
|
-
"path": "Path",
|
|
14
|
-
"field": "Field",
|
|
15
|
-
"no-path-configured": "No path configured",
|
|
16
|
-
"direct-access": "Direct Access",
|
|
17
|
-
"add-segment": "Add Segment",
|
|
18
|
-
"select": "Select"
|
|
19
|
-
},
|
|
20
|
-
"operatorNames": {
|
|
21
|
-
"level": "Level",
|
|
22
|
-
"current": "Current",
|
|
23
|
-
"host": "Host",
|
|
24
|
-
"parent": "Parent",
|
|
25
|
-
"children": "Children",
|
|
26
|
-
"descendants": "Descendants",
|
|
27
|
-
"modules": "Modules",
|
|
28
|
-
"schedule": "Schedule",
|
|
29
|
-
"phasegate": "Phase Gate",
|
|
30
|
-
"taskbaseline": "Task Baseline"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"formulaBuilder": {
|
|
3
|
+
"placeholder": "Enter formula...",
|
|
4
|
+
"codeMode": "Code mode",
|
|
5
|
+
"errors": {
|
|
6
|
+
"validationFailed": "Validation failed"
|
|
7
|
+
},
|
|
8
|
+
"actions": {
|
|
9
|
+
"insert": "Insert",
|
|
10
|
+
"clear": "Clear"
|
|
11
|
+
},
|
|
12
|
+
"properties": {
|
|
13
|
+
"path": "Path",
|
|
14
|
+
"field": "Field",
|
|
15
|
+
"no-path-configured": "No path configured",
|
|
16
|
+
"direct-access": "Direct Access",
|
|
17
|
+
"add-segment": "Add Segment",
|
|
18
|
+
"select": "Select"
|
|
19
|
+
},
|
|
20
|
+
"operatorNames": {
|
|
21
|
+
"level": "Level",
|
|
22
|
+
"current": "Current",
|
|
23
|
+
"host": "Host",
|
|
24
|
+
"parent": "Parent",
|
|
25
|
+
"children": "Children",
|
|
26
|
+
"descendants": "Descendants",
|
|
27
|
+
"modules": "Modules",
|
|
28
|
+
"schedule": "Schedule",
|
|
29
|
+
"phasegate": "Phase Gate",
|
|
30
|
+
"taskbaseline": "Task Baseline"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -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 { serializeTokens, createPropertyBlock, FormulaToolbar, FormulaStatusBar, FormulaEditor, FormulaEditorCode } from '@masterteam/components/formula';
|
|
16
|
+
import { serializeTokens, tokenizeFormulaTemplate, 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';
|
|
@@ -532,20 +532,15 @@ class FormulaBuilder {
|
|
|
532
532
|
this.builderContext()?.contextEntityTypeKey,
|
|
533
533
|
}, this.isProcessBuilder() ? 'current-only' : 'default');
|
|
534
534
|
};
|
|
535
|
-
/** Track last synced builder JSON to avoid loops */
|
|
536
|
-
lastBuilderJson = '';
|
|
537
535
|
/** Editor mode */
|
|
538
536
|
editorMode = signal('builder', ...(ngDevMode ? [{ debugName: "editorMode" }] : /* istanbul ignore next */ []));
|
|
539
537
|
isCodeMode = computed(() => this.editorMode() === 'code', ...(ngDevMode ? [{ debugName: "isCodeMode" }] : /* istanbul ignore next */ []));
|
|
540
|
-
isCodeModeLocked = signal(false, ...(ngDevMode ? [{ debugName: "isCodeModeLocked" }] : /* istanbul ignore next */ []));
|
|
541
538
|
showModeToggle = computed(() => !this.codeOnly(), ...(ngDevMode ? [{ debugName: "showModeToggle" }] : /* istanbul ignore next */ []));
|
|
542
539
|
formulaApiMode = computed(() => this.isProcessBuilder() ? 'current-only' : 'default', ...(ngDevMode ? [{ debugName: "formulaApiMode" }] : /* istanbul ignore next */ []));
|
|
543
540
|
resolvedToolbarTabs = computed(() => {
|
|
544
541
|
const tabs = this.toolbarTabs();
|
|
545
542
|
return tabs.length > 0 ? tabs : DEFAULT_TOOLBAR_TABS;
|
|
546
543
|
}, ...(ngDevMode ? [{ debugName: "resolvedToolbarTabs" }] : /* istanbul ignore next */ []));
|
|
547
|
-
codeModeSnapshotTokens = [];
|
|
548
|
-
codeModeSnapshotExpression = '';
|
|
549
544
|
/** ControlValueAccessor callbacks */
|
|
550
545
|
onChange = () => { };
|
|
551
546
|
onTouched = () => { };
|
|
@@ -774,19 +769,16 @@ class FormulaBuilder {
|
|
|
774
769
|
this.validatorService.reset();
|
|
775
770
|
return;
|
|
776
771
|
}
|
|
777
|
-
const
|
|
778
|
-
const expression = this.
|
|
779
|
-
|
|
780
|
-
|
|
772
|
+
const inputBuilder = Array.isArray(value.builder) ? value.builder : [];
|
|
773
|
+
const expression = this.resolveExpressionValue(value.expression ?? '', inputBuilder);
|
|
774
|
+
const builder = inputBuilder.length > 0
|
|
775
|
+
? inputBuilder
|
|
776
|
+
: this.rebuildBuilderFromExpression(expression);
|
|
781
777
|
this.expressionValue.set(expression);
|
|
782
778
|
if (this.codeOnly()) {
|
|
783
779
|
this.applyFormulaValue(builder, expression, true);
|
|
784
780
|
return;
|
|
785
781
|
}
|
|
786
|
-
if (builder.length === 0) {
|
|
787
|
-
this.applyFormulaValue([], expression, expression.trim().length > 0, true);
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
782
|
this.applyFormulaValue(builder, expression, false);
|
|
791
783
|
}
|
|
792
784
|
registerOnChange(fn) {
|
|
@@ -806,19 +798,10 @@ class FormulaBuilder {
|
|
|
806
798
|
/** Handle formula change from code editor */
|
|
807
799
|
onCodeFormulaChange(newFormula) {
|
|
808
800
|
this.expressionValue.set(newFormula);
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
this.codeModeSnapshotExpression = '';
|
|
814
|
-
this.emitValueChange();
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
if (!this.isCodeModeLocked() &&
|
|
818
|
-
newFormula !== this.codeModeSnapshotExpression) {
|
|
819
|
-
this.isCodeModeLocked.set(true);
|
|
820
|
-
this.clearBuilderTokens();
|
|
821
|
-
}
|
|
801
|
+
this.syncBuilderFromExpression(newFormula, {
|
|
802
|
+
emitTokensChange: true,
|
|
803
|
+
writeVisualEditor: false,
|
|
804
|
+
});
|
|
822
805
|
this.emitValueChange();
|
|
823
806
|
}
|
|
824
807
|
/** Handle block insert from toolbar */
|
|
@@ -837,11 +820,10 @@ class FormulaBuilder {
|
|
|
837
820
|
}
|
|
838
821
|
/** Handle tokens change */
|
|
839
822
|
onTokensChange(newTokens) {
|
|
840
|
-
this.
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
this.tokensChange.emit(newTokens);
|
|
823
|
+
this.setBuilderTokens(newTokens, {
|
|
824
|
+
emitTokensChange: true,
|
|
825
|
+
writeVisualEditor: false,
|
|
826
|
+
});
|
|
845
827
|
this.emitValueChange();
|
|
846
828
|
}
|
|
847
829
|
onEditorFocus() {
|
|
@@ -874,54 +856,21 @@ class FormulaBuilder {
|
|
|
874
856
|
this.exitCodeMode();
|
|
875
857
|
}
|
|
876
858
|
enterCodeMode() {
|
|
877
|
-
this.codeModeSnapshotTokens = this.tokens().slice();
|
|
878
|
-
this.codeModeSnapshotExpression = this.expressionValue();
|
|
879
859
|
const editor = this.editor();
|
|
880
860
|
if (editor) {
|
|
881
861
|
const formula = editor.serialize();
|
|
882
|
-
this.codeModeSnapshotExpression = formula;
|
|
883
862
|
this.expressionValue.set(formula);
|
|
884
863
|
this.emitValueChange();
|
|
885
864
|
}
|
|
886
|
-
this.isCodeModeLocked.set(false);
|
|
887
865
|
this.editorMode.set('code');
|
|
888
866
|
}
|
|
889
867
|
exitCodeMode() {
|
|
890
868
|
this.editorMode.set('builder');
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
}
|
|
897
|
-
this.codeModeSnapshotTokens = [];
|
|
898
|
-
this.codeModeSnapshotExpression = '';
|
|
899
|
-
this.isCodeModeLocked.set(false);
|
|
900
|
-
return;
|
|
901
|
-
}
|
|
902
|
-
if (this.codeModeSnapshotTokens.length > 0) {
|
|
903
|
-
const restored = this.codeModeSnapshotTokens.slice();
|
|
904
|
-
this.tokens.set(restored);
|
|
905
|
-
this.builderValue.set(restored);
|
|
906
|
-
this.lastBuilderJson = JSON.stringify(restored);
|
|
907
|
-
const editor = this.editor();
|
|
908
|
-
if (editor) {
|
|
909
|
-
editor.writeValue(restored);
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if (this.codeModeSnapshotExpression) {
|
|
913
|
-
this.expressionValue.set(this.codeModeSnapshotExpression);
|
|
914
|
-
}
|
|
915
|
-
this.isCodeModeLocked.set(false);
|
|
916
|
-
}
|
|
917
|
-
clearBuilderTokens() {
|
|
918
|
-
if (this.tokens().length === 0 && this.builderValue().length === 0) {
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
this.tokens.set([]);
|
|
922
|
-
this.builderValue.set([]);
|
|
923
|
-
this.lastBuilderJson = '';
|
|
924
|
-
this.tokensChange.emit([]);
|
|
869
|
+
this.syncBuilderFromExpression(this.expressionValue(), {
|
|
870
|
+
emitTokensChange: true,
|
|
871
|
+
writeVisualEditor: true,
|
|
872
|
+
});
|
|
873
|
+
this.emitValueChange();
|
|
925
874
|
}
|
|
926
875
|
// ===== PUBLIC METHODS =====
|
|
927
876
|
/** Clear the formula */
|
|
@@ -937,30 +886,40 @@ class FormulaBuilder {
|
|
|
937
886
|
}
|
|
938
887
|
return builder.length > 0 ? serializeTokens(builder) : '';
|
|
939
888
|
}
|
|
940
|
-
applyFormulaValue(builder, expression, useCodeMode
|
|
941
|
-
|
|
942
|
-
this.builderValue.set(builder);
|
|
943
|
-
this.tokens.set(builder);
|
|
944
|
-
this.lastBuilderJson = builder.length > 0 ? serialized : '';
|
|
945
|
-
const editor = this.editor();
|
|
946
|
-
if (editor) {
|
|
947
|
-
editor.writeValue(builder);
|
|
948
|
-
}
|
|
889
|
+
applyFormulaValue(builder, expression, useCodeMode) {
|
|
890
|
+
this.setBuilderTokens(builder, { writeVisualEditor: true });
|
|
949
891
|
const codeEditor = this.codeEditor();
|
|
950
892
|
if (codeEditor) {
|
|
951
893
|
codeEditor.writeValue(expression);
|
|
952
894
|
}
|
|
953
895
|
if (useCodeMode) {
|
|
954
896
|
this.editorMode.set('code');
|
|
955
|
-
this.isCodeModeLocked.set(lockCodeMode);
|
|
956
|
-
this.codeModeSnapshotTokens = builder.slice();
|
|
957
|
-
this.codeModeSnapshotExpression = expression;
|
|
958
897
|
return;
|
|
959
898
|
}
|
|
960
899
|
this.editorMode.set('builder');
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
900
|
+
}
|
|
901
|
+
rebuildBuilderFromExpression(expression) {
|
|
902
|
+
const normalized = expression.trim();
|
|
903
|
+
return normalized ? tokenizeFormulaTemplate(normalized) : [];
|
|
904
|
+
}
|
|
905
|
+
syncBuilderFromExpression(expression, options) {
|
|
906
|
+
this.setBuilderTokens(this.rebuildBuilderFromExpression(expression), {
|
|
907
|
+
emitTokensChange: options?.emitTokensChange,
|
|
908
|
+
writeVisualEditor: options?.writeVisualEditor,
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
setBuilderTokens(builder, options) {
|
|
912
|
+
this.builderValue.set(builder);
|
|
913
|
+
this.tokens.set(builder);
|
|
914
|
+
if (options?.writeVisualEditor ?? true) {
|
|
915
|
+
const editor = this.editor();
|
|
916
|
+
if (editor) {
|
|
917
|
+
editor.writeValue(builder);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (options?.emitTokensChange) {
|
|
921
|
+
this.tokensChange.emit(builder);
|
|
922
|
+
}
|
|
964
923
|
}
|
|
965
924
|
// ===== PROPERTY COMPOSER =====
|
|
966
925
|
propertyScope = signal('', ...(ngDevMode ? [{ debugName: "propertyScope" }] : /* istanbul ignore next */ []));
|
|
@@ -1173,7 +1132,7 @@ class FormulaBuilder {
|
|
|
1173
1132
|
useExisting: forwardRef(() => FormulaBuilder),
|
|
1174
1133
|
multi: true,
|
|
1175
1134
|
},
|
|
1176
|
-
], 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\n headless\n [class.ring-2]=\"hasFocus()\"\n [class.ring-primary]=\"hasFocus()\"\n [paddingless]=\"true\"\n>\n <div\n *transloco=\"let t; prefix: 'formulaBuilder'\"\n class=\"flex flex-col overflow-hidden\"\n >\n <!-- Toolbar - Pass data via inputs (pure component) -->\n @if (!hideToolbar()) {\n <mt-formula-toolbar\n [functionCategories]=\"functionCategories()\"\n [visibleTabs]=\"resolvedToolbarTabs()\"\n (onBlockInsert)=\"onBlockInsert($event)\"\n >\n <ng-template #properties let-insertBlock=\"insertBlock\">\n @if (isContextLoading()) {\n <div class=\"flex flex-col gap-4 p-4\">\n <div class=\"flex items-center justify-between gap-4\">\n <p-skeleton\n width=\"18rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n <p-skeleton\n width=\"7rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div class=\"flex items-center gap-4\">\n <div\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\"\n >\n <div class=\"flex items-center gap-2\">\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\n </div>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-4 p-4\">\n <!-- Scope Selection - Full width, centered -->\n <div class=\"flex items-center justify-between gap-4\">\n <mt-radio-cards\n [options]=\"scopeOptions()\"\n [activeId]=\"propertyScope()\"\n (selectionChange)=\"onScopeChange($event)\"\n size=\"small\"\n />\n </div>\n\n <!-- Path + Field + Preview Row -->\n <div class=\"flex items-center gap-4\">\n <!-- Path Container - Flexible -->\n <div\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\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.path\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (isDirectAccess()) {\n <span\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\"\n >\n \u2713 {{ t(\"properties.direct-access\") }}\n </span>\n } @else if (pathSegments().length === 0) {\n <span class=\"text-xs italic text-slate-400\">{{\n t(\"properties.no-path-configured\")\n }}</span>\n } @else {\n <div\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\n >\n @for (\n segment of pathSegments();\n track $index;\n let segmentIndex = $index\n ) {\n @if (segmentIndex > 0) {\n <span\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\n >\u203A</span\n >\n }\n <mt-button\n type=\"button\"\n [label]=\"\n segment.value ||\n t('properties.select') +\n ' ' +\n getOperatorDisplayName(segment.operatorToken)\n \"\n icon=\"arrow.chevron-down\"\n [outlined]=\"true\"\n size=\"small\"\n [severity]=\"\n segment.value ? 'primary' : 'secondary'\n \"\n [iconPos]=\"'end'\"\n (onClick)=\"pathPopover.toggle($event)\"\n ></mt-button>\n\n <p-popover\n #pathPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.select\") }}\n {{\n getOperatorDisplayName(\n segment.operatorToken\n )\n }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of segmentOptions(segmentIndex);\n track option.key\n ) {\n <mt-button\n type=\"button\"\n [label]=\"option.name\"\n [icon]=\"\n segment.value === option.key\n ? 'general.check'\n : 'general.minus'\n \"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\n [styleClass]=\"\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\n (segment.value === option.key\n ? 'bg-primary text-white'\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\n \"\n (onClick)=\"\n setPathSegmentValue(\n segmentIndex,\n option.key\n );\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n @if (segment.optional) {\n <mt-button\n type=\"button\"\n [label]=\"t('actions.clear')\"\n [outlined]=\"true\"\n icon=\"general.x-close\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"danger\"\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\"\n (onClick)=\"\n setPathSegmentValue(segmentIndex, null);\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n </p-popover>\n\n @if (\n segment.canRemove &&\n segmentIndex === pathSegments().length - 1\n ) {\n <mt-button\n type=\"button\"\n icon=\"general.x-close\"\n size=\"small\"\n severity=\"danger\"\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\n (onClick)=\"removePathSegment(segmentIndex)\"\n ></mt-button>\n }\n }\n <mt-button\n type=\"button\"\n icon=\"general.plus\"\n size=\"small\"\n severity=\"primary\"\n [disabled]=\"!canAddNextSegment()\"\n [class.hidden]=\"!canAddNextSegment()\"\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\"\n (onClick)=\"nextOperatorPopover.toggle($event)\"\n ></mt-button>\n </div>\n }\n <p-popover\n #nextOperatorPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.add-segment\") }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of nextOperatorOptions();\n track option.token\n ) {\n <mt-button\n type=\"button\"\n [label]=\"getOperatorDisplayName(option.token)\"\n icon=\"general.plus\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\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\"\n (onClick)=\"\n onAddSegmentSelection(\n option.token,\n nextOperatorPopover\n )\n \"\n ></mt-button>\n }\n </div>\n </div>\n </p-popover>\n </div>\n </div>\n\n <!-- Field Selection - Under Path -->\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.field\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n @if (isPropertyLoading()) {\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n } @else {\n <mt-select-field\n class=\"flex-1\"\n [label]=\"''\"\n [filter]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"t('properties.select')\"\n [(ngModel)]=\"propertyFieldKey\"\n [options]=\"propertyOptions()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n [size]=\"'small'\"\n />\n }\n </div>\n <div\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\"\n [mtTooltip]=\"\n '@' +\n propertyTablePath() +\n '::' +\n (selectedProperty()?.key ?? '...')\n \"\n tooltipPosition=\"top\"\n >\n @{{ propertyTablePath() }}::{{\n selectedProperty()?.key ?? \"...\"\n }}\n </div>\n <div class=\"flex justify-end\">\n <mt-button\n type=\"button\"\n [label]=\"t('actions.insert')\"\n icon=\"general.plus\"\n severity=\"primary\"\n [disabled]=\"!canInsertProperty()\"\n (onClick)=\"insertSelectedProperty(insertBlock)\"\n ></mt-button>\n </div>\n </div>\n </div>\n </div>\n }\n </ng-template>\n </mt-formula-toolbar>\n }\n\n <!-- Editor Area -->\n <div class=\"p-3\">\n <div\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\n >\n @if (showModeToggle()) {\n <div\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\n >\n <mt-toggle-field\n [label]=\"t('codeMode')\"\n labelPosition=\"end\"\n size=\"small\"\n [ngModel]=\"isCodeMode()\"\n (ngModelChange)=\"onModeToggle($event)\"\n />\n </div>\n }\n <div class=\"p-0\">\n @if (isCodeMode()) {\n <mt-formula-editor-code\n #formulaEditorCode\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialFormula]=\"expression()\"\n [borderless]=\"true\"\n [autocompleteProvider]=\"autocompleteProvider\"\n (formulaChange)=\"onCodeFormulaChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n } @else {\n <mt-formula-editor\n #formulaEditor\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialTokens]=\"tokens()\"\n [borderless]=\"true\"\n (formulaChange)=\"onFormulaChange($event)\"\n (tokensChange)=\"onTokensChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n }\n </div>\n </div>\n </div>\n\n <!-- Status Bar - Pass data via inputs (pure component) -->\n @if (!hideStatusBar()) {\n <mt-formula-status-bar [validation]=\"validation()\" />\n }\n </div>\n</mt-card>\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", "hint", "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", "markCurrentUser"], 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"] }] });
|
|
1135
|
+
], 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 (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", "hint", "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", "markCurrentUser"], 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"] }] });
|
|
1177
1136
|
}
|
|
1178
1137
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaBuilder, decorators: [{
|
|
1179
1138
|
type: Component,
|
|
@@ -1201,7 +1160,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
1201
1160
|
useExisting: forwardRef(() => FormulaBuilder),
|
|
1202
1161
|
multi: true,
|
|
1203
1162
|
},
|
|
1204
|
-
], template: "<mt-card\n headless\n [class.ring-2]=\"hasFocus()\"\n [class.ring-primary]=\"hasFocus()\"\n [paddingless]=\"true\"\n>\n <div\n *transloco=\"let t; prefix: 'formulaBuilder'\"\n class=\"flex flex-col overflow-hidden\"\n >\n <!-- Toolbar - Pass data via inputs (pure component) -->\n @if (!hideToolbar()) {\n <mt-formula-toolbar\n [functionCategories]=\"functionCategories()\"\n [visibleTabs]=\"resolvedToolbarTabs()\"\n (onBlockInsert)=\"onBlockInsert($event)\"\n >\n <ng-template #properties let-insertBlock=\"insertBlock\">\n @if (isContextLoading()) {\n <div class=\"flex flex-col gap-4 p-4\">\n <div class=\"flex items-center justify-between gap-4\">\n <p-skeleton\n width=\"18rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n <p-skeleton\n width=\"7rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div class=\"flex items-center gap-4\">\n <div\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\"\n >\n <div class=\"flex items-center gap-2\">\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\n </div>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-4 p-4\">\n <!-- Scope Selection - Full width, centered -->\n <div class=\"flex items-center justify-between gap-4\">\n <mt-radio-cards\n [options]=\"scopeOptions()\"\n [activeId]=\"propertyScope()\"\n (selectionChange)=\"onScopeChange($event)\"\n size=\"small\"\n />\n </div>\n\n <!-- Path + Field + Preview Row -->\n <div class=\"flex items-center gap-4\">\n <!-- Path Container - Flexible -->\n <div\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\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.path\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (isDirectAccess()) {\n <span\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\"\n >\n \u2713 {{ t(\"properties.direct-access\") }}\n </span>\n } @else if (pathSegments().length === 0) {\n <span class=\"text-xs italic text-slate-400\">{{\n t(\"properties.no-path-configured\")\n }}</span>\n } @else {\n <div\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\n >\n @for (\n segment of pathSegments();\n track $index;\n let segmentIndex = $index\n ) {\n @if (segmentIndex > 0) {\n <span\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\n >\u203A</span\n >\n }\n <mt-button\n type=\"button\"\n [label]=\"\n segment.value ||\n t('properties.select') +\n ' ' +\n getOperatorDisplayName(segment.operatorToken)\n \"\n icon=\"arrow.chevron-down\"\n [outlined]=\"true\"\n size=\"small\"\n [severity]=\"\n segment.value ? 'primary' : 'secondary'\n \"\n [iconPos]=\"'end'\"\n (onClick)=\"pathPopover.toggle($event)\"\n ></mt-button>\n\n <p-popover\n #pathPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.select\") }}\n {{\n getOperatorDisplayName(\n segment.operatorToken\n )\n }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of segmentOptions(segmentIndex);\n track option.key\n ) {\n <mt-button\n type=\"button\"\n [label]=\"option.name\"\n [icon]=\"\n segment.value === option.key\n ? 'general.check'\n : 'general.minus'\n \"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\n [styleClass]=\"\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\n (segment.value === option.key\n ? 'bg-primary text-white'\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\n \"\n (onClick)=\"\n setPathSegmentValue(\n segmentIndex,\n option.key\n );\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n @if (segment.optional) {\n <mt-button\n type=\"button\"\n [label]=\"t('actions.clear')\"\n [outlined]=\"true\"\n icon=\"general.x-close\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"danger\"\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\"\n (onClick)=\"\n setPathSegmentValue(segmentIndex, null);\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n </p-popover>\n\n @if (\n segment.canRemove &&\n segmentIndex === pathSegments().length - 1\n ) {\n <mt-button\n type=\"button\"\n icon=\"general.x-close\"\n size=\"small\"\n severity=\"danger\"\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\n (onClick)=\"removePathSegment(segmentIndex)\"\n ></mt-button>\n }\n }\n <mt-button\n type=\"button\"\n icon=\"general.plus\"\n size=\"small\"\n severity=\"primary\"\n [disabled]=\"!canAddNextSegment()\"\n [class.hidden]=\"!canAddNextSegment()\"\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\"\n (onClick)=\"nextOperatorPopover.toggle($event)\"\n ></mt-button>\n </div>\n }\n <p-popover\n #nextOperatorPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.add-segment\") }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of nextOperatorOptions();\n track option.token\n ) {\n <mt-button\n type=\"button\"\n [label]=\"getOperatorDisplayName(option.token)\"\n icon=\"general.plus\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\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\"\n (onClick)=\"\n onAddSegmentSelection(\n option.token,\n nextOperatorPopover\n )\n \"\n ></mt-button>\n }\n </div>\n </div>\n </p-popover>\n </div>\n </div>\n\n <!-- Field Selection - Under Path -->\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.field\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n @if (isPropertyLoading()) {\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n } @else {\n <mt-select-field\n class=\"flex-1\"\n [label]=\"''\"\n [filter]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"t('properties.select')\"\n [(ngModel)]=\"propertyFieldKey\"\n [options]=\"propertyOptions()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n [size]=\"'small'\"\n />\n }\n </div>\n <div\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\"\n [mtTooltip]=\"\n '@' +\n propertyTablePath() +\n '::' +\n (selectedProperty()?.key ?? '...')\n \"\n tooltipPosition=\"top\"\n >\n @{{ propertyTablePath() }}::{{\n selectedProperty()?.key ?? \"...\"\n }}\n </div>\n <div class=\"flex justify-end\">\n <mt-button\n type=\"button\"\n [label]=\"t('actions.insert')\"\n icon=\"general.plus\"\n severity=\"primary\"\n [disabled]=\"!canInsertProperty()\"\n (onClick)=\"insertSelectedProperty(insertBlock)\"\n ></mt-button>\n </div>\n </div>\n </div>\n </div>\n }\n </ng-template>\n </mt-formula-toolbar>\n }\n\n <!-- Editor Area -->\n <div class=\"p-3\">\n <div\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\n >\n @if (showModeToggle()) {\n <div\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\n >\n <mt-toggle-field\n [label]=\"t('codeMode')\"\n labelPosition=\"end\"\n size=\"small\"\n [ngModel]=\"isCodeMode()\"\n (ngModelChange)=\"onModeToggle($event)\"\n />\n </div>\n }\n <div class=\"p-0\">\n @if (isCodeMode()) {\n <mt-formula-editor-code\n #formulaEditorCode\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialFormula]=\"expression()\"\n [borderless]=\"true\"\n [autocompleteProvider]=\"autocompleteProvider\"\n (formulaChange)=\"onCodeFormulaChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n } @else {\n <mt-formula-editor\n #formulaEditor\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialTokens]=\"tokens()\"\n [borderless]=\"true\"\n (formulaChange)=\"onFormulaChange($event)\"\n (tokensChange)=\"onTokensChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n }\n </div>\n </div>\n </div>\n\n <!-- Status Bar - Pass data via inputs (pure component) -->\n @if (!hideStatusBar()) {\n <mt-formula-status-bar [validation]=\"validation()\" />\n }\n </div>\n</mt-card>\n" }]
|
|
1163
|
+
], 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 (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" }]
|
|
1205
1164
|
}], 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"] }] } });
|
|
1206
1165
|
|
|
1207
1166
|
/**
|