@masterteam/dashboard-builder 0.0.41 → 0.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, signal, Injectable, computed, Pipe, input, ViewEncapsulation, ChangeDetectionStrategy, Component, output, forwardRef, effect, ViewChild, untracked, ElementRef, NgZone, PLATFORM_ID, viewChild, ChangeDetectorRef, model, HostListener } from '@angular/core';
2
+ import { inject, signal, Injectable, computed, Pipe, input, ViewEncapsulation, ChangeDetectionStrategy, Component, effect, forwardRef, ViewChild, output, untracked, DestroyRef, ElementRef, NgZone, PLATFORM_ID, viewChild, ChangeDetectorRef, model, HostListener } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import { CommonModule, isPlatformBrowser, DatePipe, DecimalPipe } from '@angular/common';
5
5
  import * as i1 from '@angular/forms';
@@ -19,11 +19,13 @@ import { REQUEST_CONTEXT } from '@masterteam/components';
19
19
  import { TextField } from '@masterteam/components/text-field';
20
20
  import { CheckboxField } from '@masterteam/components/checkbox-field';
21
21
  import { ModalRef } from '@masterteam/components/dialog';
22
+ import { takeUntilDestroyed, rxResource } from '@angular/core/rxjs-interop';
22
23
  import { Icon } from '@masterteam/icons';
23
24
  import { SelectField } from '@masterteam/components/select-field';
24
25
  import { NumberField } from '@masterteam/components/number-field';
25
- import { TextareaField } from '@masterteam/components/textarea-field';
26
26
  import { MultiSelectField } from '@masterteam/components/multi-select-field';
27
+ import { ToggleField } from '@masterteam/components/toggle-field';
28
+ import { TextareaField } from '@masterteam/components/textarea-field';
27
29
  import { Card } from '@masterteam/components/card';
28
30
  import * as i2$1 from 'primeng/tooltip';
29
31
  import { Tooltip, TooltipModule } from 'primeng/tooltip';
@@ -43,7 +45,6 @@ import { DynamicDialogRef, DynamicDialogConfig } from 'primeng/dynamicdialog';
43
45
  import { DynamicDrawerConfig } from '@masterteam/components/dynamic-drawer';
44
46
  import { ColorPickerField } from '@masterteam/components/color-picker-field';
45
47
  import { SliderField } from '@masterteam/components/slider-field';
46
- import { ToggleField } from '@masterteam/components/toggle-field';
47
48
  import { IconField } from '@masterteam/components/icon-field';
48
49
  import { Router, ActivatedRoute } from '@angular/router';
49
50
  import { RadioCards } from '@masterteam/components/radio-cards';
@@ -55,7 +56,6 @@ import { Menu } from '@masterteam/components/menu';
55
56
  import { Chip } from '@masterteam/components/chip';
56
57
  import * as i2$3 from 'primeng/button';
57
58
  import { ButtonModule } from 'primeng/button';
58
- import { rxResource } from '@angular/core/rxjs-interop';
59
59
  import { Table } from '@masterteam/components/table';
60
60
 
61
61
  /**
@@ -903,6 +903,9 @@ function createDefaultFilterField() {
903
903
  selection: [
904
904
  {
905
905
  id: 1,
906
+ service: 'pplus',
907
+ selector: null,
908
+ selectorName: null,
906
909
  moduleType: undefined,
907
910
  moduleId: undefined,
908
911
  filters: [],
@@ -918,218 +921,6 @@ function createDefaultFilterField() {
918
921
  };
919
922
  }
920
923
 
921
- /**
922
- * Dynamic Filters Config Component
923
- *
924
- * Manages dynamic filter field configurations for dashboard pages.
925
- * Supports multiple filter types including dropdowns, lookups, status,
926
- * phase gates, dates, and more.
927
- */
928
- class DynamicFiltersConfig {
929
- /** Available lookups from parent context */
930
- lookups = input([], ...(ngDevMode ? [{ debugName: "lookups" }] : /* istanbul ignore next */ []));
931
- /** Available level schemas from parent context */
932
- levelsSchema = input([], ...(ngDevMode ? [{ debugName: "levelsSchema" }] : /* istanbul ignore next */ []));
933
- /** Available level logs from parent context */
934
- levelLogs = input([], ...(ngDevMode ? [{ debugName: "levelLogs" }] : /* istanbul ignore next */ []));
935
- /** Product type to filter available field types */
936
- productType = input('pplus', ...(ngDevMode ? [{ debugName: "productType" }] : /* istanbul ignore next */ []));
937
- /** Emit when level logs need to be loaded for a specific schema level */
938
- loadLevelLogs = output();
939
- /** Filter fields data */
940
- filterFields = signal([], ...(ngDevMode ? [{ debugName: "filterFields" }] : /* istanbul ignore next */ []));
941
- /** Paste configuration state */
942
- showPasteArea = signal(false, ...(ngDevMode ? [{ debugName: "showPasteArea" }] : /* istanbul ignore next */ []));
943
- pasteContent = signal('', ...(ngDevMode ? [{ debugName: "pasteContent" }] : /* istanbul ignore next */ []));
944
- pasteError = signal('', ...(ngDevMode ? [{ debugName: "pasteError" }] : /* istanbul ignore next */ []));
945
- /** Disabled state */
946
- disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
947
- /** Available field types filtered by product */
948
- availableFieldTypes = computed(() => {
949
- const product = this.productType();
950
- return FILTER_FIELD_TYPES.filter((type) => type.products.includes(product));
951
- }, ...(ngDevMode ? [{ debugName: "availableFieldTypes" }] : /* istanbul ignore next */ []));
952
- // ControlValueAccessor callbacks
953
- onChange = () => { };
954
- onTouched = () => { };
955
- // ============================================
956
- // ControlValueAccessor Implementation
957
- // ============================================
958
- writeValue(value) {
959
- if (value) {
960
- this.filterFields.set([...value]);
961
- }
962
- else {
963
- this.filterFields.set([]);
964
- }
965
- }
966
- registerOnChange(fn) {
967
- this.onChange = fn;
968
- }
969
- registerOnTouched(fn) {
970
- this.onTouched = fn;
971
- }
972
- setDisabledState(isDisabled) {
973
- this.disabled.set(isDisabled);
974
- }
975
- // ============================================
976
- // Filter Field Management
977
- // ============================================
978
- /** Add a new filter field */
979
- addFilterField() {
980
- const newField = createDefaultFilterField();
981
- this.filterFields.update((fields) => [...fields, newField]);
982
- this.notifyChange();
983
- }
984
- /** Remove a filter field by index */
985
- removeFilterField(index) {
986
- this.filterFields.update((fields) => {
987
- const newFields = [...fields];
988
- newFields.splice(index, 1);
989
- return newFields;
990
- });
991
- this.notifyChange();
992
- }
993
- /** Update a filter field property */
994
- updateField(index, key, value) {
995
- this.filterFields.update((fields) => {
996
- const newFields = [...fields];
997
- newFields[index] = { ...newFields[index], [key]: value };
998
- return newFields;
999
- });
1000
- this.notifyChange();
1001
- }
1002
- /** Update filter field name */
1003
- updateFieldName(index, lang, value) {
1004
- this.filterFields.update((fields) => {
1005
- const newFields = [...fields];
1006
- const field = newFields[index];
1007
- field.name = { ...field.name, [lang]: value };
1008
- return newFields;
1009
- });
1010
- this.notifyChange();
1011
- }
1012
- /** Update filter field configuration */
1013
- updateFieldConfig(index, key, value) {
1014
- this.filterFields.update((fields) => {
1015
- const newFields = [...fields];
1016
- const field = newFields[index];
1017
- field.configuration = { ...field.configuration, [key]: value };
1018
- return newFields;
1019
- });
1020
- this.notifyChange();
1021
- }
1022
- /** Handle field type change */
1023
- onFieldTypeChange(index, type) {
1024
- this.filterFields.update((fields) => {
1025
- const newFields = [...fields];
1026
- newFields[index] = { ...newFields[index], type };
1027
- // Reset configuration based on type
1028
- if (type === 'section' || type === 'separator') {
1029
- newFields[index].configuration = {};
1030
- }
1031
- return newFields;
1032
- });
1033
- this.notifyChange();
1034
- }
1035
- /** Handle schema level change for status/phaseGate */
1036
- onSchemaLevelChange(index, schemaLevelId) {
1037
- this.updateFieldConfig(index, 'schemaLevelId', schemaLevelId);
1038
- // Clear log ID and emit event to load level logs
1039
- this.updateFieldConfig(index, 'logId', null);
1040
- if (schemaLevelId) {
1041
- this.loadLevelLogs.emit(schemaLevelId);
1042
- }
1043
- }
1044
- // ============================================
1045
- // Copy/Paste Configuration
1046
- // ============================================
1047
- /** Copy current configuration to clipboard */
1048
- copyConfiguration() {
1049
- try {
1050
- const config = JSON.stringify(this.filterFields(), null, 2);
1051
- navigator.clipboard.writeText(config);
1052
- }
1053
- catch (error) {
1054
- console.error('Error copying configuration:', error);
1055
- }
1056
- }
1057
- /** Toggle paste area visibility */
1058
- togglePasteArea() {
1059
- this.showPasteArea.update((v) => !v);
1060
- this.pasteContent.set('');
1061
- this.pasteError.set('');
1062
- }
1063
- /** Apply pasted configuration */
1064
- applyPastedConfiguration() {
1065
- try {
1066
- const parsedConfig = JSON.parse(this.pasteContent());
1067
- if (!Array.isArray(parsedConfig)) {
1068
- throw new Error('Configuration must be an array');
1069
- }
1070
- // Validate each field
1071
- parsedConfig.forEach((field) => {
1072
- if (!field.type) {
1073
- throw new Error('Each field must have a type');
1074
- }
1075
- if (field.type !== 'separator' &&
1076
- (!field.name || !field.name.en || !field.name.ar)) {
1077
- throw new Error('Each field (except separator) must have name with en and ar properties');
1078
- }
1079
- });
1080
- this.filterFields.set(parsedConfig);
1081
- this.notifyChange();
1082
- this.showPasteArea.set(false);
1083
- this.pasteContent.set('');
1084
- this.pasteError.set('');
1085
- }
1086
- catch (error) {
1087
- this.pasteError.set(`Invalid configuration: ${error.message}`);
1088
- }
1089
- }
1090
- // ============================================
1091
- // Helpers
1092
- // ============================================
1093
- /** Track by function for ngFor */
1094
- trackByIndex(index) {
1095
- return index;
1096
- }
1097
- /** Notify parent of changes */
1098
- notifyChange() {
1099
- this.onChange(this.filterFields());
1100
- this.onTouched();
1101
- }
1102
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DynamicFiltersConfig, deps: [], target: i0.ɵɵFactoryTarget.Component });
1103
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DynamicFiltersConfig, isStandalone: true, selector: "mt-dynamic-filters-config", inputs: { lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, levelsSchema: { classPropertyName: "levelsSchema", publicName: "levelsSchema", isSignal: true, isRequired: false, transformFunction: null }, levelLogs: { classPropertyName: "levelLogs", publicName: "levelLogs", isSignal: true, isRequired: false, transformFunction: null }, productType: { classPropertyName: "productType", publicName: "productType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadLevelLogs: "loadLevelLogs" }, providers: [
1104
- {
1105
- provide: NG_VALUE_ACCESSOR,
1106
- useExisting: forwardRef(() => DynamicFiltersConfig),
1107
- multi: true,
1108
- },
1109
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <!-- Header Actions -->\n <div class=\"flex items-center justify-between\">\n <h3 class=\"text-lg font-semibold\">{{ t(\"filterFieldsConfiguration\") }}</h3>\n <div class=\"flex gap-2\">\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addField')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"addFilterField()\"\n [disabled]=\"disabled()\"\n />\n <mt-button\n icon=\"general.copy-06\"\n [pTooltip]=\"t('copyConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"copyConfiguration()\"\n />\n <mt-button\n icon=\"general.clipboard\"\n [pTooltip]=\"t('pasteConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"togglePasteArea()\"\n />\n </div>\n </div>\n\n <!-- Paste Area -->\n @if (showPasteArea()) {\n <div\n class=\"flex flex-col gap-2 p-3 bg-surface-100 rounded-lg border border-surface-300\"\n >\n <mt-textarea-field\n [label]=\"t('pasteConfigurationHere')\"\n [rows]=\"8\"\n [ngModel]=\"pasteContent()\"\n (ngModelChange)=\"pasteContent.set($event)\"\n [placeholder]=\"t('pasteJsonConfiguration')\"\n />\n @if (pasteError()) {\n <div class=\"text-red-500 text-sm\">{{ pasteError() }}</div>\n }\n <div class=\"flex justify-end gap-2\">\n <mt-button\n [label]=\"t('cancel')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"togglePasteArea()\"\n />\n <mt-button\n [label]=\"t('applyConfiguration')\"\n size=\"small\"\n (onClick)=\"applyPastedConfiguration()\"\n />\n </div>\n </div>\n }\n\n <!-- Filter Fields List -->\n <div class=\"flex flex-col gap-4\">\n @for (field of filterFields(); track trackByIndex($index); let i = $index) {\n <div\n class=\"relative p-4 bg-surface-50 border border-surface-200 rounded-lg\"\n >\n <!-- Remove Button -->\n <mt-button\n class=\"!absolute top-2 end-2\"\n icon=\"general.trash-01\"\n severity=\"danger\"\n size=\"small\"\n [rounded]=\"true\"\n [text]=\"true\"\n (onClick)=\"removeFilterField(i)\"\n [disabled]=\"disabled()\"\n />\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 pe-8\">\n <!-- Field Type -->\n <mt-select-field\n [label]=\"t('fieldType')\"\n [options]=\"availableFieldTypes()\"\n optionValue=\"value\"\n optionLabel=\"label\"\n [ngModel]=\"field.type\"\n (ngModelChange)=\"onFieldTypeChange(i, $event)\"\n />\n\n <!-- Key (not for section/separator) -->\n @if (field.type !== \"section\" && field.type !== \"separator\") {\n <mt-text-field\n [label]=\"t('fieldKey')\"\n [placeholder]=\"t('enterFieldKey')\"\n [ngModel]=\"field.key\"\n (ngModelChange)=\"updateField(i, 'key', $event)\"\n />\n }\n\n <!-- Name fields (not for separator) -->\n @if (field.type !== \"separator\") {\n <mt-text-field\n [label]=\"t('nameEnglish')\"\n [placeholder]=\"t('enterEnglishName')\"\n [ngModel]=\"field.name?.en\"\n (ngModelChange)=\"updateFieldName(i, 'en', $event)\"\n />\n <mt-text-field\n [label]=\"t('nameArabic')\"\n [placeholder]=\"t('enterArabicName')\"\n [ngModel]=\"field.name?.ar\"\n (ngModelChange)=\"updateFieldName(i, 'ar', $event)\"\n />\n }\n\n <!-- Configuration: Lookup -->\n @if (field.type === \"lookup\") {\n <mt-select-field\n [label]=\"t('lookupId')\"\n [options]=\"lookups()\"\n optionValue=\"id\"\n optionLabel=\"displayName\"\n [ngModel]=\"field.configuration?.lookupId\"\n (ngModelChange)=\"updateFieldConfig(i, 'lookupId', $event)\"\n />\n }\n\n <!-- Configuration: Status or Phase Gate -->\n @if (field.type === \"status\" || field.type === \"phaseGate\") {\n <mt-select-field\n [label]=\"t('schemaLevelId')\"\n [options]=\"levelsSchema()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [ngModel]=\"field.configuration?.schemaLevelId\"\n (ngModelChange)=\"onSchemaLevelChange(i, $event)\"\n />\n }\n\n <!-- Configuration: Status Log ID -->\n @if (field.type === \"status\" && field.configuration?.schemaLevelId) {\n <mt-select-field\n [label]=\"t('logId')\"\n [options]=\"levelLogs()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [ngModel]=\"field.configuration?.logId\"\n (ngModelChange)=\"updateFieldConfig(i, 'logId', $event)\"\n />\n }\n\n <!-- Configuration: Checkbox -->\n @if (field.type === \"checkbox\") {\n <mt-checkbox-field\n [label]=\"t('defaultChecked')\"\n [ngModel]=\"field.configuration?.checked\"\n (ngModelChange)=\"updateFieldConfig(i, 'checked', $event)\"\n />\n }\n\n <!-- Configuration: Year -->\n @if (field.type === \"year\") {\n <mt-number-field\n [label]=\"t('minYear')\"\n [placeholder]=\"t('minYear')\"\n [ngModel]=\"field.configuration?.minYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'minYear', $event)\"\n />\n <mt-number-field\n [label]=\"t('maxYear')\"\n [placeholder]=\"t('maxYear')\"\n [ngModel]=\"field.configuration?.maxYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'maxYear', $event)\"\n />\n }\n\n <!-- Is Required Checkbox -->\n <mt-checkbox-field\n [label]=\"t('isRequired')\"\n [ngModel]=\"field.configuration?.isRequird\"\n (ngModelChange)=\"updateFieldConfig(i, 'isRequird', $event)\"\n />\n\n <!-- Is Multiple Checkbox (not for section, separator, user, date, year) -->\n @if (\n field.type !== \"section\" &&\n field.type !== \"separator\" &&\n field.type !== \"user\" &&\n field.type !== \"date\" &&\n field.type !== \"year\"\n ) {\n <mt-checkbox-field\n [label]=\"t('isMultiple')\"\n [ngModel]=\"field.configuration?.isMultiple\"\n (ngModelChange)=\"updateFieldConfig(i, 'isMultiple', $event)\"\n />\n }\n </div>\n </div>\n } @empty {\n <div class=\"text-center py-8 text-muted-color\">\n <mt-icon icon=\"general.filter-lines\" class=\"text-4xl mb-2\" />\n <p>{{ t(\"noFilterFieldsConfigured\") }}</p>\n <p class=\"text-sm\">{{ t(\"clickAddFieldToStart\") }}</p>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Icon, selector: "mt-icon", inputs: ["icon"] }, { 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: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: CheckboxField, selector: "mt-checkbox-field", inputs: ["label", "labelPosition", "placeholder", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1110
- }
1111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DynamicFiltersConfig, decorators: [{
1112
- type: Component,
1113
- args: [{ selector: 'mt-dynamic-filters-config', standalone: true, imports: [
1114
- CommonModule,
1115
- FormsModule,
1116
- TranslocoDirective,
1117
- Button,
1118
- Icon,
1119
- SelectField,
1120
- TextField,
1121
- NumberField,
1122
- CheckboxField,
1123
- TextareaField,
1124
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
1125
- {
1126
- provide: NG_VALUE_ACCESSOR,
1127
- useExisting: forwardRef(() => DynamicFiltersConfig),
1128
- multi: true,
1129
- },
1130
- ], template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <!-- Header Actions -->\n <div class=\"flex items-center justify-between\">\n <h3 class=\"text-lg font-semibold\">{{ t(\"filterFieldsConfiguration\") }}</h3>\n <div class=\"flex gap-2\">\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addField')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"addFilterField()\"\n [disabled]=\"disabled()\"\n />\n <mt-button\n icon=\"general.copy-06\"\n [pTooltip]=\"t('copyConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"copyConfiguration()\"\n />\n <mt-button\n icon=\"general.clipboard\"\n [pTooltip]=\"t('pasteConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"togglePasteArea()\"\n />\n </div>\n </div>\n\n <!-- Paste Area -->\n @if (showPasteArea()) {\n <div\n class=\"flex flex-col gap-2 p-3 bg-surface-100 rounded-lg border border-surface-300\"\n >\n <mt-textarea-field\n [label]=\"t('pasteConfigurationHere')\"\n [rows]=\"8\"\n [ngModel]=\"pasteContent()\"\n (ngModelChange)=\"pasteContent.set($event)\"\n [placeholder]=\"t('pasteJsonConfiguration')\"\n />\n @if (pasteError()) {\n <div class=\"text-red-500 text-sm\">{{ pasteError() }}</div>\n }\n <div class=\"flex justify-end gap-2\">\n <mt-button\n [label]=\"t('cancel')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"togglePasteArea()\"\n />\n <mt-button\n [label]=\"t('applyConfiguration')\"\n size=\"small\"\n (onClick)=\"applyPastedConfiguration()\"\n />\n </div>\n </div>\n }\n\n <!-- Filter Fields List -->\n <div class=\"flex flex-col gap-4\">\n @for (field of filterFields(); track trackByIndex($index); let i = $index) {\n <div\n class=\"relative p-4 bg-surface-50 border border-surface-200 rounded-lg\"\n >\n <!-- Remove Button -->\n <mt-button\n class=\"!absolute top-2 end-2\"\n icon=\"general.trash-01\"\n severity=\"danger\"\n size=\"small\"\n [rounded]=\"true\"\n [text]=\"true\"\n (onClick)=\"removeFilterField(i)\"\n [disabled]=\"disabled()\"\n />\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 pe-8\">\n <!-- Field Type -->\n <mt-select-field\n [label]=\"t('fieldType')\"\n [options]=\"availableFieldTypes()\"\n optionValue=\"value\"\n optionLabel=\"label\"\n [ngModel]=\"field.type\"\n (ngModelChange)=\"onFieldTypeChange(i, $event)\"\n />\n\n <!-- Key (not for section/separator) -->\n @if (field.type !== \"section\" && field.type !== \"separator\") {\n <mt-text-field\n [label]=\"t('fieldKey')\"\n [placeholder]=\"t('enterFieldKey')\"\n [ngModel]=\"field.key\"\n (ngModelChange)=\"updateField(i, 'key', $event)\"\n />\n }\n\n <!-- Name fields (not for separator) -->\n @if (field.type !== \"separator\") {\n <mt-text-field\n [label]=\"t('nameEnglish')\"\n [placeholder]=\"t('enterEnglishName')\"\n [ngModel]=\"field.name?.en\"\n (ngModelChange)=\"updateFieldName(i, 'en', $event)\"\n />\n <mt-text-field\n [label]=\"t('nameArabic')\"\n [placeholder]=\"t('enterArabicName')\"\n [ngModel]=\"field.name?.ar\"\n (ngModelChange)=\"updateFieldName(i, 'ar', $event)\"\n />\n }\n\n <!-- Configuration: Lookup -->\n @if (field.type === \"lookup\") {\n <mt-select-field\n [label]=\"t('lookupId')\"\n [options]=\"lookups()\"\n optionValue=\"id\"\n optionLabel=\"displayName\"\n [ngModel]=\"field.configuration?.lookupId\"\n (ngModelChange)=\"updateFieldConfig(i, 'lookupId', $event)\"\n />\n }\n\n <!-- Configuration: Status or Phase Gate -->\n @if (field.type === \"status\" || field.type === \"phaseGate\") {\n <mt-select-field\n [label]=\"t('schemaLevelId')\"\n [options]=\"levelsSchema()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [ngModel]=\"field.configuration?.schemaLevelId\"\n (ngModelChange)=\"onSchemaLevelChange(i, $event)\"\n />\n }\n\n <!-- Configuration: Status Log ID -->\n @if (field.type === \"status\" && field.configuration?.schemaLevelId) {\n <mt-select-field\n [label]=\"t('logId')\"\n [options]=\"levelLogs()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [ngModel]=\"field.configuration?.logId\"\n (ngModelChange)=\"updateFieldConfig(i, 'logId', $event)\"\n />\n }\n\n <!-- Configuration: Checkbox -->\n @if (field.type === \"checkbox\") {\n <mt-checkbox-field\n [label]=\"t('defaultChecked')\"\n [ngModel]=\"field.configuration?.checked\"\n (ngModelChange)=\"updateFieldConfig(i, 'checked', $event)\"\n />\n }\n\n <!-- Configuration: Year -->\n @if (field.type === \"year\") {\n <mt-number-field\n [label]=\"t('minYear')\"\n [placeholder]=\"t('minYear')\"\n [ngModel]=\"field.configuration?.minYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'minYear', $event)\"\n />\n <mt-number-field\n [label]=\"t('maxYear')\"\n [placeholder]=\"t('maxYear')\"\n [ngModel]=\"field.configuration?.maxYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'maxYear', $event)\"\n />\n }\n\n <!-- Is Required Checkbox -->\n <mt-checkbox-field\n [label]=\"t('isRequired')\"\n [ngModel]=\"field.configuration?.isRequird\"\n (ngModelChange)=\"updateFieldConfig(i, 'isRequird', $event)\"\n />\n\n <!-- Is Multiple Checkbox (not for section, separator, user, date, year) -->\n @if (\n field.type !== \"section\" &&\n field.type !== \"separator\" &&\n field.type !== \"user\" &&\n field.type !== \"date\" &&\n field.type !== \"year\"\n ) {\n <mt-checkbox-field\n [label]=\"t('isMultiple')\"\n [ngModel]=\"field.configuration?.isMultiple\"\n (ngModelChange)=\"updateFieldConfig(i, 'isMultiple', $event)\"\n />\n }\n </div>\n </div>\n } @empty {\n <div class=\"text-center py-8 text-muted-color\">\n <mt-icon icon=\"general.filter-lines\" class=\"text-4xl mb-2\" />\n <p>{{ t(\"noFilterFieldsConfigured\") }}</p>\n <p class=\"text-sm\">{{ t(\"clickAddFieldToStart\") }}</p>\n </div>\n }\n </div>\n</div>\n" }]
1131
- }], propDecorators: { lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], levelsSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelsSchema", required: false }] }], levelLogs: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelLogs", required: false }] }], productType: [{ type: i0.Input, args: [{ isSignal: true, alias: "productType", required: false }] }], loadLevelLogs: [{ type: i0.Output, args: ["loadLevelLogs"] }] } });
1132
-
1133
924
  const TITLE_SHARED = ['titleAr', 'titleEn'];
1134
925
  const HEADER_BLOCK = ['centerHeader', 'advancedHeaderConfig', 'borderTop'];
1135
926
  const CHART_CAPABILITIES = [
@@ -3752,7 +3543,7 @@ class SelectionConfiguration {
3752
3543
  useExisting: forwardRef(() => SelectionConfiguration),
3753
3544
  multi: true,
3754
3545
  },
3755
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <mt-card [title]=\"t('selections')\">\r\n <ng-template #cardEnd>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n (onClick)=\"addSelection()\"\r\n [disabled]=\"disabled || loadingTree()\"\r\n [pTooltip]=\"t('addSelection')\"\r\n />\r\n }\r\n </ng-template>\r\n\r\n <!-- Loading Skeleton State - Show for entire component while tree is loading -->\r\n @if (loadingTree()) {\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton Selection Card -->\r\n <div class=\"p-4 rounded-lg border border-surface-200\">\r\n <!-- Skeleton Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton shape=\"circle\" width=\"24px\" height=\"24px\" />\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Module Selection -->\r\n <div class=\"grid grid-cols-1 gap-4 mb-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"60px\" height=\"14px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Filters Section -->\r\n <div class=\"border border-surface-200 rounded-lg p-4\">\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <p-skeleton width=\"50px\" height=\"14px\" />\r\n <div class=\"flex gap-1\">\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n </div>\r\n </div>\r\n <div class=\"text-center py-4\">\r\n <p-skeleton width=\"150px\" height=\"14px\" styleClass=\"mx-auto\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4\" [formGroup]=\"selectionsForm\">\r\n <div formArrayName=\"selections\">\r\n @for (\r\n selection of selectionsArray.controls;\r\n track trackBySelectionId($index, selection);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"p-4 rounded-lg border transition-all mb-4 last:mb-0\"\r\n [class.border-red-500]=\"selection.invalid\"\r\n [class.border-surface-200]=\"!selection.invalid\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Selection Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full text-sm font-semibold\"\r\n [class.bg-primary-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.text-primary-600]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-100]=\"isFixedSelection(selection.value.id)\"\r\n [class.text-amber-600]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n >\r\n @if (isFixedSelection(selection.value.id)) {\r\n <i class=\"mti mti-lock-01 text-xs\"></i>\r\n } @else {\r\n {{ selection.value.id }}\r\n }\r\n </span>\r\n <span class=\"text-sm font-medium text-muted-color\">\r\n @if (isFixedSelection(selection.value.id)) {\r\n {{ t(\"fixedSelection\") }}\r\n } @else {\r\n {{ t(\"selection\") }}\r\n }\r\n </span>\r\n </div>\r\n @if (\r\n selectionsArray.length > 1 &&\r\n !isSelectionStructureLocked(selection.value.id)\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeSelection(i)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Service & Module Selection -->\r\n <div\r\n class=\"grid grid-cols-1 gap-4 mb-4\"\r\n [class.md:grid-cols-2]=\"!hasSingleService()\"\r\n >\r\n <!-- Service (hidden when only one service) -->\r\n @if (!hasSingleService()) {\r\n <mt-select-field\r\n [label]=\"t('service')\"\r\n formControlName=\"service\"\r\n [options]=\"services()\"\r\n optionLabel=\"name\"\r\n optionValue=\"name\"\r\n [placeholder]=\"t('selectService')\"\r\n [loading]=\"loadingTree()\"\r\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module values (grouped by module type, multi-select within one type) -->\r\n <mt-multi-select-field\r\n [label]=\"t('module')\"\r\n [ngModel]=\"getSelectorValues(i)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [options]=\"getGroupedModulesForSelection(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"selector\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectModule')\"\r\n [filter]=\"true\"\r\n [showClear]=\"!isSelectionStructureLocked(selection.value.id)\"\r\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onModuleSelectionChange(i, $event)\"\r\n />\r\n </div>\r\n @if (\r\n selection.get(\"selector\")?.invalid &&\r\n selection.get(\"selector\")?.touched\r\n ) {\r\n <small class=\"text-red-500 mt-1 block mb-2\">{{\r\n t(\"moduleRequired\")\r\n }}</small>\r\n }\r\n\r\n <!-- Filters Section -->\r\n <div\r\n class=\"border border-surface-200 rounded-lg p-4\"\r\n [class.border-red-500]=\"getFilters(selection).invalid\"\r\n [class.border-amber-200]=\"isFixedSelection(selection.value.id)\"\r\n [class.bg-amber-50]=\"isFixedSelection(selection.value.id)\"\r\n >\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <span class=\"text-sm font-medium\">{{ t(\"filters\") }}</span>\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"general.copy-01\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"\r\n disabled || getFilters(selection).length === 0\r\n \"\r\n (onClick)=\"copyFilters(i)\"\r\n [pTooltip]=\"t('copyFilters')\"\r\n />\r\n <mt-button\r\n icon=\"file.clipboard\"\r\n severity=\"help\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"togglePaste(i)\"\r\n [pTooltip]=\"t('pasteFilters')\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addFilter(i)\"\r\n [pTooltip]=\"t('addFilter')\"\r\n />\r\n </div>\r\n } @else {\r\n <span class=\"text-xs text-amber-600 font-medium\">\r\n <i class=\"mti mti-lock-01 mr-1\"></i>\r\n {{ t(\"readOnly\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Paste JSON Area -->\r\n @if (selection.value.showPaste) {\r\n <div\r\n class=\"mb-4 p-3 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-textarea-field\r\n [label]=\"t('pasteFiltersJson')\"\r\n formControlName=\"filterJson\"\r\n [placeholder]=\"t('pasteFiltersJsonPlaceholder')\"\r\n [rows]=\"4\"\r\n />\r\n @if (selection.value.pasteError) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n selection.value.pasteError\r\n }}</small>\r\n }\r\n <div class=\"flex justify-end gap-2 mt-2\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"togglePaste(i)\"\r\n />\r\n <mt-button\r\n [label]=\"t('apply')\"\r\n size=\"small\"\r\n (onClick)=\"applyPastedFilters(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Filters List -->\r\n <div class=\"flex flex-col gap-3\" formArrayName=\"filters\">\r\n @for (\r\n filter of getFilters(selection).controls;\r\n track trackByFilterIndex(j);\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"flex flex-col gap-3 p-3 rounded-lg border\"\r\n [class.bg-surface-50]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.border-surface-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-25]=\"isFixedSelection(selection.value.id)\"\r\n [class.border-amber-100]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n [formGroupName]=\"j\"\r\n >\r\n <!-- Row 1: Property, Operation, Logical -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Property Key -->\r\n <div class=\"col-span-5\">\r\n <mt-select-field\r\n [label]=\"t('property')\"\r\n formControlName=\"propertyKey\"\r\n [options]=\"getPropertiesForSelection(i)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n (onChange)=\"onFilterPropertyChange(i, j, $event)\"\r\n />\r\n </div>\r\n\r\n <!-- Operation -->\r\n <div class=\"col-span-3\">\r\n <mt-select-field\r\n [label]=\"t('operation')\"\r\n formControlName=\"operation\"\r\n [options]=\"operations\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Logical Operator -->\r\n <div class=\"col-span-2\">\r\n <mt-select-field\r\n [label]=\"t('logical')\"\r\n formControlName=\"logical\"\r\n [options]=\"logicals\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Remove Filter (hidden for fixed selections) -->\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"col-span-2 flex items-end justify-end\">\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeFilter(i, j)\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"col-span-2\"></div>\r\n }\r\n </div>\r\n\r\n <!-- Row 2: Value, Level -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Value -->\r\n <div class=\"col-span-10\">\r\n @if (shouldShowPropertyItems(i, j)) {\r\n <mt-select-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [options]=\"getPropertyItemsForFilter(i, j)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n } @else {\r\n <mt-filter-value-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [placeholder]=\"t('enterValue')\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Operation Level -->\r\n <div class=\"col-span-2\">\r\n <mt-number-field\r\n [label]=\"t('level')\"\r\n formControlName=\"operationLevel\"\r\n [min]=\"1\"\r\n [max]=\"10\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (getFilters(selection).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noFiltersConfigured\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (selectionsArray.length === 0 && !loadingTree()) {\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-database text-3xl mb-2 block\"></i>\r\n <p class=\"mb-2\">{{ t(\"noSelectionsConfigured\") }}</p>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n [label]=\"t('addSelection')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addSelection()\"\r\n />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: FilterValueField, selector: "mt-filter-value-field", inputs: ["label", "placeholder", "extraProperties", "readonly"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3546
+ ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <mt-card [title]=\"t('selections')\">\r\n <ng-template #cardEnd>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n (onClick)=\"addSelection()\"\r\n [disabled]=\"disabled || loadingTree()\"\r\n [pTooltip]=\"t('addSelection')\"\r\n />\r\n }\r\n </ng-template>\r\n\r\n <!-- Loading Skeleton State - Show for entire component while tree is loading -->\r\n @if (loadingTree()) {\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton Selection Card -->\r\n <div class=\"p-4 rounded-lg border border-surface-200\">\r\n <!-- Skeleton Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton shape=\"circle\" width=\"24px\" height=\"24px\" />\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Module Selection -->\r\n <div class=\"grid grid-cols-1 gap-4 mb-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"60px\" height=\"14px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Filters Section -->\r\n <div class=\"border border-surface-200 rounded-lg p-4\">\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <p-skeleton width=\"50px\" height=\"14px\" />\r\n <div class=\"flex gap-1\">\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n </div>\r\n </div>\r\n <div class=\"text-center py-4\">\r\n <p-skeleton width=\"150px\" height=\"14px\" styleClass=\"mx-auto\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4\" [formGroup]=\"selectionsForm\">\r\n <div formArrayName=\"selections\">\r\n @for (\r\n selection of selectionsArray.controls;\r\n track trackBySelectionId($index, selection);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"p-4 rounded-lg border transition-all mb-4 last:mb-0\"\r\n [class.border-red-500]=\"selection.invalid\"\r\n [class.border-surface-200]=\"!selection.invalid\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Selection Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full text-sm font-semibold\"\r\n [class.bg-primary-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.text-primary-600]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-100]=\"isFixedSelection(selection.value.id)\"\r\n [class.text-amber-600]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n >\r\n @if (isFixedSelection(selection.value.id)) {\r\n <i class=\"mti mti-lock-01 text-xs\"></i>\r\n } @else {\r\n {{ selection.value.id }}\r\n }\r\n </span>\r\n <span class=\"text-sm font-medium text-muted-color\">\r\n @if (isFixedSelection(selection.value.id)) {\r\n {{ t(\"fixedSelection\") }}\r\n } @else {\r\n {{ t(\"selection\") }}\r\n }\r\n </span>\r\n </div>\r\n @if (\r\n selectionsArray.length > 1 &&\r\n !isSelectionStructureLocked(selection.value.id)\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeSelection(i)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Service & Module Selection -->\r\n <div\r\n class=\"grid grid-cols-1 gap-4 mb-4\"\r\n [class.md:grid-cols-2]=\"!hasSingleService()\"\r\n >\r\n <!-- Service (hidden when only one service) -->\r\n @if (!hasSingleService()) {\r\n <mt-select-field\r\n [label]=\"t('service')\"\r\n formControlName=\"service\"\r\n [options]=\"services()\"\r\n optionLabel=\"name\"\r\n optionValue=\"name\"\r\n [placeholder]=\"t('selectService')\"\r\n [loading]=\"loadingTree()\"\r\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module values (grouped by module type, multi-select within one type) -->\r\n <mt-multi-select-field\r\n [label]=\"t('module')\"\r\n [ngModel]=\"getSelectorValues(i)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [options]=\"getGroupedModulesForSelection(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"selector\"\r\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectModule')\"\n [filter]=\"true\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"38\"\n [showClear]=\"!isSelectionStructureLocked(selection.value.id)\"\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\n (ngModelChange)=\"onModuleSelectionChange(i, $event)\"\n />\n </div>\r\n @if (\r\n selection.get(\"selector\")?.invalid &&\r\n selection.get(\"selector\")?.touched\r\n ) {\r\n <small class=\"text-red-500 mt-1 block mb-2\">{{\r\n t(\"moduleRequired\")\r\n }}</small>\r\n }\r\n\r\n <!-- Filters Section -->\r\n <div\r\n class=\"border border-surface-200 rounded-lg p-4\"\r\n [class.border-red-500]=\"getFilters(selection).invalid\"\r\n [class.border-amber-200]=\"isFixedSelection(selection.value.id)\"\r\n [class.bg-amber-50]=\"isFixedSelection(selection.value.id)\"\r\n >\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <span class=\"text-sm font-medium\">{{ t(\"filters\") }}</span>\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"general.copy-01\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"\r\n disabled || getFilters(selection).length === 0\r\n \"\r\n (onClick)=\"copyFilters(i)\"\r\n [pTooltip]=\"t('copyFilters')\"\r\n />\r\n <mt-button\r\n icon=\"file.clipboard\"\r\n severity=\"help\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"togglePaste(i)\"\r\n [pTooltip]=\"t('pasteFilters')\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addFilter(i)\"\r\n [pTooltip]=\"t('addFilter')\"\r\n />\r\n </div>\r\n } @else {\r\n <span class=\"text-xs text-amber-600 font-medium\">\r\n <i class=\"mti mti-lock-01 mr-1\"></i>\r\n {{ t(\"readOnly\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Paste JSON Area -->\r\n @if (selection.value.showPaste) {\r\n <div\r\n class=\"mb-4 p-3 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-textarea-field\r\n [label]=\"t('pasteFiltersJson')\"\r\n formControlName=\"filterJson\"\r\n [placeholder]=\"t('pasteFiltersJsonPlaceholder')\"\r\n [rows]=\"4\"\r\n />\r\n @if (selection.value.pasteError) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n selection.value.pasteError\r\n }}</small>\r\n }\r\n <div class=\"flex justify-end gap-2 mt-2\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"togglePaste(i)\"\r\n />\r\n <mt-button\r\n [label]=\"t('apply')\"\r\n size=\"small\"\r\n (onClick)=\"applyPastedFilters(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Filters List -->\r\n <div class=\"flex flex-col gap-3\" formArrayName=\"filters\">\r\n @for (\r\n filter of getFilters(selection).controls;\r\n track trackByFilterIndex(j);\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"flex flex-col gap-3 p-3 rounded-lg border\"\r\n [class.bg-surface-50]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.border-surface-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-25]=\"isFixedSelection(selection.value.id)\"\r\n [class.border-amber-100]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n [formGroupName]=\"j\"\r\n >\r\n <!-- Row 1: Property, Operation, Logical -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Property Key -->\r\n <div class=\"col-span-5\">\r\n <mt-select-field\r\n [label]=\"t('property')\"\r\n formControlName=\"propertyKey\"\r\n [options]=\"getPropertiesForSelection(i)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n (onChange)=\"onFilterPropertyChange(i, j, $event)\"\r\n />\r\n </div>\r\n\r\n <!-- Operation -->\r\n <div class=\"col-span-3\">\r\n <mt-select-field\r\n [label]=\"t('operation')\"\r\n formControlName=\"operation\"\r\n [options]=\"operations\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Logical Operator -->\r\n <div class=\"col-span-2\">\r\n <mt-select-field\r\n [label]=\"t('logical')\"\r\n formControlName=\"logical\"\r\n [options]=\"logicals\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Remove Filter (hidden for fixed selections) -->\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"col-span-2 flex items-end justify-end\">\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeFilter(i, j)\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"col-span-2\"></div>\r\n }\r\n </div>\r\n\r\n <!-- Row 2: Value, Level -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Value -->\r\n <div class=\"col-span-10\">\r\n @if (shouldShowPropertyItems(i, j)) {\r\n <mt-select-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [options]=\"getPropertyItemsForFilter(i, j)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n } @else {\r\n <mt-filter-value-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [placeholder]=\"t('enterValue')\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Operation Level -->\r\n <div class=\"col-span-2\">\r\n <mt-number-field\r\n [label]=\"t('level')\"\r\n formControlName=\"operationLevel\"\r\n [min]=\"1\"\r\n [max]=\"10\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (getFilters(selection).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noFiltersConfigured\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (selectionsArray.length === 0 && !loadingTree()) {\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-database text-3xl mb-2 block\"></i>\r\n <p class=\"mb-2\">{{ t(\"noSelectionsConfigured\") }}</p>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n [label]=\"t('addSelection')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addSelection()\"\r\n />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: FilterValueField, selector: "mt-filter-value-field", inputs: ["label", "placeholder", "extraProperties", "readonly"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3756
3547
  }
3757
3548
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SelectionConfiguration, decorators: [{
3758
3549
  type: Component,
@@ -3781,75 +3572,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
3781
3572
  useExisting: forwardRef(() => SelectionConfiguration),
3782
3573
  multi: true,
3783
3574
  },
3784
- ], template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <mt-card [title]=\"t('selections')\">\r\n <ng-template #cardEnd>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n (onClick)=\"addSelection()\"\r\n [disabled]=\"disabled || loadingTree()\"\r\n [pTooltip]=\"t('addSelection')\"\r\n />\r\n }\r\n </ng-template>\r\n\r\n <!-- Loading Skeleton State - Show for entire component while tree is loading -->\r\n @if (loadingTree()) {\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton Selection Card -->\r\n <div class=\"p-4 rounded-lg border border-surface-200\">\r\n <!-- Skeleton Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton shape=\"circle\" width=\"24px\" height=\"24px\" />\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Module Selection -->\r\n <div class=\"grid grid-cols-1 gap-4 mb-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"60px\" height=\"14px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Filters Section -->\r\n <div class=\"border border-surface-200 rounded-lg p-4\">\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <p-skeleton width=\"50px\" height=\"14px\" />\r\n <div class=\"flex gap-1\">\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n </div>\r\n </div>\r\n <div class=\"text-center py-4\">\r\n <p-skeleton width=\"150px\" height=\"14px\" styleClass=\"mx-auto\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4\" [formGroup]=\"selectionsForm\">\r\n <div formArrayName=\"selections\">\r\n @for (\r\n selection of selectionsArray.controls;\r\n track trackBySelectionId($index, selection);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"p-4 rounded-lg border transition-all mb-4 last:mb-0\"\r\n [class.border-red-500]=\"selection.invalid\"\r\n [class.border-surface-200]=\"!selection.invalid\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Selection Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full text-sm font-semibold\"\r\n [class.bg-primary-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.text-primary-600]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-100]=\"isFixedSelection(selection.value.id)\"\r\n [class.text-amber-600]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n >\r\n @if (isFixedSelection(selection.value.id)) {\r\n <i class=\"mti mti-lock-01 text-xs\"></i>\r\n } @else {\r\n {{ selection.value.id }}\r\n }\r\n </span>\r\n <span class=\"text-sm font-medium text-muted-color\">\r\n @if (isFixedSelection(selection.value.id)) {\r\n {{ t(\"fixedSelection\") }}\r\n } @else {\r\n {{ t(\"selection\") }}\r\n }\r\n </span>\r\n </div>\r\n @if (\r\n selectionsArray.length > 1 &&\r\n !isSelectionStructureLocked(selection.value.id)\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeSelection(i)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Service & Module Selection -->\r\n <div\r\n class=\"grid grid-cols-1 gap-4 mb-4\"\r\n [class.md:grid-cols-2]=\"!hasSingleService()\"\r\n >\r\n <!-- Service (hidden when only one service) -->\r\n @if (!hasSingleService()) {\r\n <mt-select-field\r\n [label]=\"t('service')\"\r\n formControlName=\"service\"\r\n [options]=\"services()\"\r\n optionLabel=\"name\"\r\n optionValue=\"name\"\r\n [placeholder]=\"t('selectService')\"\r\n [loading]=\"loadingTree()\"\r\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module values (grouped by module type, multi-select within one type) -->\r\n <mt-multi-select-field\r\n [label]=\"t('module')\"\r\n [ngModel]=\"getSelectorValues(i)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [options]=\"getGroupedModulesForSelection(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"selector\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectModule')\"\r\n [filter]=\"true\"\r\n [showClear]=\"!isSelectionStructureLocked(selection.value.id)\"\r\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onModuleSelectionChange(i, $event)\"\r\n />\r\n </div>\r\n @if (\r\n selection.get(\"selector\")?.invalid &&\r\n selection.get(\"selector\")?.touched\r\n ) {\r\n <small class=\"text-red-500 mt-1 block mb-2\">{{\r\n t(\"moduleRequired\")\r\n }}</small>\r\n }\r\n\r\n <!-- Filters Section -->\r\n <div\r\n class=\"border border-surface-200 rounded-lg p-4\"\r\n [class.border-red-500]=\"getFilters(selection).invalid\"\r\n [class.border-amber-200]=\"isFixedSelection(selection.value.id)\"\r\n [class.bg-amber-50]=\"isFixedSelection(selection.value.id)\"\r\n >\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <span class=\"text-sm font-medium\">{{ t(\"filters\") }}</span>\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"general.copy-01\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"\r\n disabled || getFilters(selection).length === 0\r\n \"\r\n (onClick)=\"copyFilters(i)\"\r\n [pTooltip]=\"t('copyFilters')\"\r\n />\r\n <mt-button\r\n icon=\"file.clipboard\"\r\n severity=\"help\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"togglePaste(i)\"\r\n [pTooltip]=\"t('pasteFilters')\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addFilter(i)\"\r\n [pTooltip]=\"t('addFilter')\"\r\n />\r\n </div>\r\n } @else {\r\n <span class=\"text-xs text-amber-600 font-medium\">\r\n <i class=\"mti mti-lock-01 mr-1\"></i>\r\n {{ t(\"readOnly\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Paste JSON Area -->\r\n @if (selection.value.showPaste) {\r\n <div\r\n class=\"mb-4 p-3 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-textarea-field\r\n [label]=\"t('pasteFiltersJson')\"\r\n formControlName=\"filterJson\"\r\n [placeholder]=\"t('pasteFiltersJsonPlaceholder')\"\r\n [rows]=\"4\"\r\n />\r\n @if (selection.value.pasteError) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n selection.value.pasteError\r\n }}</small>\r\n }\r\n <div class=\"flex justify-end gap-2 mt-2\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"togglePaste(i)\"\r\n />\r\n <mt-button\r\n [label]=\"t('apply')\"\r\n size=\"small\"\r\n (onClick)=\"applyPastedFilters(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Filters List -->\r\n <div class=\"flex flex-col gap-3\" formArrayName=\"filters\">\r\n @for (\r\n filter of getFilters(selection).controls;\r\n track trackByFilterIndex(j);\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"flex flex-col gap-3 p-3 rounded-lg border\"\r\n [class.bg-surface-50]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.border-surface-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-25]=\"isFixedSelection(selection.value.id)\"\r\n [class.border-amber-100]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n [formGroupName]=\"j\"\r\n >\r\n <!-- Row 1: Property, Operation, Logical -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Property Key -->\r\n <div class=\"col-span-5\">\r\n <mt-select-field\r\n [label]=\"t('property')\"\r\n formControlName=\"propertyKey\"\r\n [options]=\"getPropertiesForSelection(i)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n (onChange)=\"onFilterPropertyChange(i, j, $event)\"\r\n />\r\n </div>\r\n\r\n <!-- Operation -->\r\n <div class=\"col-span-3\">\r\n <mt-select-field\r\n [label]=\"t('operation')\"\r\n formControlName=\"operation\"\r\n [options]=\"operations\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Logical Operator -->\r\n <div class=\"col-span-2\">\r\n <mt-select-field\r\n [label]=\"t('logical')\"\r\n formControlName=\"logical\"\r\n [options]=\"logicals\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Remove Filter (hidden for fixed selections) -->\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"col-span-2 flex items-end justify-end\">\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeFilter(i, j)\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"col-span-2\"></div>\r\n }\r\n </div>\r\n\r\n <!-- Row 2: Value, Level -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Value -->\r\n <div class=\"col-span-10\">\r\n @if (shouldShowPropertyItems(i, j)) {\r\n <mt-select-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [options]=\"getPropertyItemsForFilter(i, j)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n } @else {\r\n <mt-filter-value-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [placeholder]=\"t('enterValue')\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Operation Level -->\r\n <div class=\"col-span-2\">\r\n <mt-number-field\r\n [label]=\"t('level')\"\r\n formControlName=\"operationLevel\"\r\n [min]=\"1\"\r\n [max]=\"10\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (getFilters(selection).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noFiltersConfigured\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (selectionsArray.length === 0 && !loadingTree()) {\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-database text-3xl mb-2 block\"></i>\r\n <p class=\"mb-2\">{{ t(\"noSelectionsConfigured\") }}</p>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n [label]=\"t('addSelection')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addSelection()\"\r\n />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n</div>\r\n" }]
3575
+ ], template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <mt-card [title]=\"t('selections')\">\r\n <ng-template #cardEnd>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n (onClick)=\"addSelection()\"\r\n [disabled]=\"disabled || loadingTree()\"\r\n [pTooltip]=\"t('addSelection')\"\r\n />\r\n }\r\n </ng-template>\r\n\r\n <!-- Loading Skeleton State - Show for entire component while tree is loading -->\r\n @if (loadingTree()) {\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton Selection Card -->\r\n <div class=\"p-4 rounded-lg border border-surface-200\">\r\n <!-- Skeleton Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton shape=\"circle\" width=\"24px\" height=\"24px\" />\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Module Selection -->\r\n <div class=\"grid grid-cols-1 gap-4 mb-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"60px\" height=\"14px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <!-- Skeleton Filters Section -->\r\n <div class=\"border border-surface-200 rounded-lg p-4\">\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <p-skeleton width=\"50px\" height=\"14px\" />\r\n <div class=\"flex gap-1\">\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n <p-skeleton shape=\"circle\" width=\"28px\" height=\"28px\" />\r\n </div>\r\n </div>\r\n <div class=\"text-center py-4\">\r\n <p-skeleton width=\"150px\" height=\"14px\" styleClass=\"mx-auto\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4\" [formGroup]=\"selectionsForm\">\r\n <div formArrayName=\"selections\">\r\n @for (\r\n selection of selectionsArray.controls;\r\n track trackBySelectionId($index, selection);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"p-4 rounded-lg border transition-all mb-4 last:mb-0\"\r\n [class.border-red-500]=\"selection.invalid\"\r\n [class.border-surface-200]=\"!selection.invalid\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Selection Header -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full text-sm font-semibold\"\r\n [class.bg-primary-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.text-primary-600]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-100]=\"isFixedSelection(selection.value.id)\"\r\n [class.text-amber-600]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n >\r\n @if (isFixedSelection(selection.value.id)) {\r\n <i class=\"mti mti-lock-01 text-xs\"></i>\r\n } @else {\r\n {{ selection.value.id }}\r\n }\r\n </span>\r\n <span class=\"text-sm font-medium text-muted-color\">\r\n @if (isFixedSelection(selection.value.id)) {\r\n {{ t(\"fixedSelection\") }}\r\n } @else {\r\n {{ t(\"selection\") }}\r\n }\r\n </span>\r\n </div>\r\n @if (\r\n selectionsArray.length > 1 &&\r\n !isSelectionStructureLocked(selection.value.id)\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeSelection(i)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Service & Module Selection -->\r\n <div\r\n class=\"grid grid-cols-1 gap-4 mb-4\"\r\n [class.md:grid-cols-2]=\"!hasSingleService()\"\r\n >\r\n <!-- Service (hidden when only one service) -->\r\n @if (!hasSingleService()) {\r\n <mt-select-field\r\n [label]=\"t('service')\"\r\n formControlName=\"service\"\r\n [options]=\"services()\"\r\n optionLabel=\"name\"\r\n optionValue=\"name\"\r\n [placeholder]=\"t('selectService')\"\r\n [loading]=\"loadingTree()\"\r\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module values (grouped by module type, multi-select within one type) -->\r\n <mt-multi-select-field\r\n [label]=\"t('module')\"\r\n [ngModel]=\"getSelectorValues(i)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [options]=\"getGroupedModulesForSelection(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"selector\"\r\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectModule')\"\n [filter]=\"true\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"38\"\n [showClear]=\"!isSelectionStructureLocked(selection.value.id)\"\n [readonly]=\"isSelectionStructureLocked(selection.value.id)\"\n (ngModelChange)=\"onModuleSelectionChange(i, $event)\"\n />\n </div>\r\n @if (\r\n selection.get(\"selector\")?.invalid &&\r\n selection.get(\"selector\")?.touched\r\n ) {\r\n <small class=\"text-red-500 mt-1 block mb-2\">{{\r\n t(\"moduleRequired\")\r\n }}</small>\r\n }\r\n\r\n <!-- Filters Section -->\r\n <div\r\n class=\"border border-surface-200 rounded-lg p-4\"\r\n [class.border-red-500]=\"getFilters(selection).invalid\"\r\n [class.border-amber-200]=\"isFixedSelection(selection.value.id)\"\r\n [class.bg-amber-50]=\"isFixedSelection(selection.value.id)\"\r\n >\r\n <div class=\"flex items-center justify-between mb-3\">\r\n <span class=\"text-sm font-medium\">{{ t(\"filters\") }}</span>\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"general.copy-01\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"\r\n disabled || getFilters(selection).length === 0\r\n \"\r\n (onClick)=\"copyFilters(i)\"\r\n [pTooltip]=\"t('copyFilters')\"\r\n />\r\n <mt-button\r\n icon=\"file.clipboard\"\r\n severity=\"help\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"togglePaste(i)\"\r\n [pTooltip]=\"t('pasteFilters')\"\r\n />\r\n <mt-button\r\n icon=\"general.plus\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addFilter(i)\"\r\n [pTooltip]=\"t('addFilter')\"\r\n />\r\n </div>\r\n } @else {\r\n <span class=\"text-xs text-amber-600 font-medium\">\r\n <i class=\"mti mti-lock-01 mr-1\"></i>\r\n {{ t(\"readOnly\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Paste JSON Area -->\r\n @if (selection.value.showPaste) {\r\n <div\r\n class=\"mb-4 p-3 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-textarea-field\r\n [label]=\"t('pasteFiltersJson')\"\r\n formControlName=\"filterJson\"\r\n [placeholder]=\"t('pasteFiltersJsonPlaceholder')\"\r\n [rows]=\"4\"\r\n />\r\n @if (selection.value.pasteError) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n selection.value.pasteError\r\n }}</small>\r\n }\r\n <div class=\"flex justify-end gap-2 mt-2\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"togglePaste(i)\"\r\n />\r\n <mt-button\r\n [label]=\"t('apply')\"\r\n size=\"small\"\r\n (onClick)=\"applyPastedFilters(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Filters List -->\r\n <div class=\"flex flex-col gap-3\" formArrayName=\"filters\">\r\n @for (\r\n filter of getFilters(selection).controls;\r\n track trackByFilterIndex(j);\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"flex flex-col gap-3 p-3 rounded-lg border\"\r\n [class.bg-surface-50]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.border-surface-100]=\"\r\n !isFixedSelection(selection.value.id)\r\n \"\r\n [class.bg-amber-25]=\"isFixedSelection(selection.value.id)\"\r\n [class.border-amber-100]=\"\r\n isFixedSelection(selection.value.id)\r\n \"\r\n [formGroupName]=\"j\"\r\n >\r\n <!-- Row 1: Property, Operation, Logical -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Property Key -->\r\n <div class=\"col-span-5\">\r\n <mt-select-field\r\n [label]=\"t('property')\"\r\n formControlName=\"propertyKey\"\r\n [options]=\"getPropertiesForSelection(i)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n (onChange)=\"onFilterPropertyChange(i, j, $event)\"\r\n />\r\n </div>\r\n\r\n <!-- Operation -->\r\n <div class=\"col-span-3\">\r\n <mt-select-field\r\n [label]=\"t('operation')\"\r\n formControlName=\"operation\"\r\n [options]=\"operations\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Logical Operator -->\r\n <div class=\"col-span-2\">\r\n <mt-select-field\r\n [label]=\"t('logical')\"\r\n formControlName=\"logical\"\r\n [options]=\"logicals\"\r\n optionLabel=\"name\"\r\n optionValue=\"value\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n\r\n <!-- Remove Filter (hidden for fixed selections) -->\r\n @if (!isFixedSelection(selection.value.id)) {\r\n <div class=\"col-span-2 flex items-end justify-end\">\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeFilter(i, j)\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"col-span-2\"></div>\r\n }\r\n </div>\r\n\r\n <!-- Row 2: Value, Level -->\r\n <div class=\"grid grid-cols-12 gap-3\">\r\n <!-- Value -->\r\n <div class=\"col-span-10\">\r\n @if (shouldShowPropertyItems(i, j)) {\r\n <mt-select-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [options]=\"getPropertyItemsForFilter(i, j)\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n } @else {\r\n <mt-filter-value-field\r\n [label]=\"t('value')\"\r\n formControlName=\"propertyValue\"\r\n [placeholder]=\"t('enterValue')\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Operation Level -->\r\n <div class=\"col-span-2\">\r\n <mt-number-field\r\n [label]=\"t('level')\"\r\n formControlName=\"operationLevel\"\r\n [min]=\"1\"\r\n [max]=\"10\"\r\n [readonly]=\"isFixedSelection(selection.value.id)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (getFilters(selection).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noFiltersConfigured\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (selectionsArray.length === 0 && !loadingTree()) {\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-database text-3xl mb-2 block\"></i>\r\n <p class=\"mb-2\">{{ t(\"noSelectionsConfigured\") }}</p>\r\n @if (!structureLocked()) {\r\n <mt-button\r\n icon=\"general.plus\"\r\n [label]=\"t('addSelection')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addSelection()\"\r\n />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n</div>\r\n" }]
3785
3576
  }], ctorParameters: () => [], propDecorators: { structureLocked: [{ type: i0.Input, args: [{ isSignal: true, alias: "structureLocked", required: false }] }], workspaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "workspaceId", required: false }] }], modulesProperties: [{ type: i0.Input, args: [{ isSignal: true, alias: "modulesProperties", required: false }] }], propertiesFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesFlat", required: false }] }], moduleChange: [{ type: i0.Output, args: ["moduleChange"] }] } });
3786
3577
 
3787
3578
  /**
3788
- * Property Translations Component
3579
+ * Dynamic Filters Config Component
3789
3580
  *
3790
- * Manages property translations for Arabic and English.
3791
- * Implements ControlValueAccessor for form integration.
3581
+ * Manages dynamic filter field configurations for dashboard pages.
3582
+ * Supports multiple filter types including dropdowns, lookups, status,
3583
+ * phase gates, dates, and more.
3792
3584
  */
3793
- class PropertyTranslationsComponent {
3794
- /** Available properties for selection */
3795
- propertiesFlat = input([], ...(ngDevMode ? [{ debugName: "propertiesFlat" }] : /* istanbul ignore next */ []));
3796
- /** Selected properties to translate */
3797
- selectedProperties = input([], ...(ngDevMode ? [{ debugName: "selectedProperties" }] : /* istanbul ignore next */ []));
3798
- /** Translations map */
3799
- translations = signal({}, ...(ngDevMode ? [{ debugName: "translations" }] : /* istanbul ignore next */ []));
3800
- /** Selected property for adding */
3801
- selectedProperty = signal(null, ...(ngDevMode ? [{ debugName: "selectedProperty" }] : /* istanbul ignore next */ []));
3802
- /** Show paste area */
3585
+ class DynamicFiltersConfig {
3586
+ dashboardService = inject(DashboardBuilderService);
3587
+ destroyRef = inject(DestroyRef);
3588
+ emptySelections = [];
3589
+ emptyModulesProperties = [];
3590
+ emptyProperties = [];
3591
+ propertiesFlatCache = new Map();
3592
+ dropdownPropertiesSignatureByIndex = new Map();
3593
+ /** Available lookups from parent context */
3594
+ lookups = input([], ...(ngDevMode ? [{ debugName: "lookups" }] : /* istanbul ignore next */ []));
3595
+ /** Available level schemas from parent context */
3596
+ levelsSchema = input([], ...(ngDevMode ? [{ debugName: "levelsSchema" }] : /* istanbul ignore next */ []));
3597
+ /** Available level logs from parent context */
3598
+ levelLogs = input([], ...(ngDevMode ? [{ debugName: "levelLogs" }] : /* istanbul ignore next */ []));
3599
+ /** Product type to filter available field types */
3600
+ productType = input('pplus', ...(ngDevMode ? [{ debugName: "productType" }] : /* istanbul ignore next */ []));
3601
+ /** Emit when level logs need to be loaded for a specific schema level */
3602
+ loadLevelLogs = output();
3603
+ /** Filter fields data */
3604
+ filterFields = signal([], ...(ngDevMode ? [{ debugName: "filterFields" }] : /* istanbul ignore next */ []));
3605
+ /** Active dropdown selection editor. Heavy nested editors stay lazy. */
3606
+ activeDropdownConfigIndex = signal(null, ...(ngDevMode ? [{ debugName: "activeDropdownConfigIndex" }] : /* istanbul ignore next */ []));
3607
+ /** Properties loaded for dropdown-by-selection fields. */
3608
+ fieldModulesProperties = signal({}, ...(ngDevMode ? [{ debugName: "fieldModulesProperties" }] : /* istanbul ignore next */ []));
3609
+ /** Paste configuration state */
3803
3610
  showPasteArea = signal(false, ...(ngDevMode ? [{ debugName: "showPasteArea" }] : /* istanbul ignore next */ []));
3804
- /** Paste text */
3805
- pasteText = signal('', ...(ngDevMode ? [{ debugName: "pasteText" }] : /* istanbul ignore next */ []));
3806
- /** Paste error */
3611
+ pasteContent = signal('', ...(ngDevMode ? [{ debugName: "pasteContent" }] : /* istanbul ignore next */ []));
3807
3612
  pasteError = signal('', ...(ngDevMode ? [{ debugName: "pasteError" }] : /* istanbul ignore next */ []));
3808
3613
  /** Disabled state */
3809
- disabled = false;
3810
- /** Available properties (not yet translated) */
3811
- availableProperties = computed(() => {
3812
- const used = Object.keys(this.translations());
3813
- const selected = this.selectedProperties();
3814
- const props = this.propertiesFlat();
3815
- if (selected.length > 0) {
3816
- return selected
3817
- .filter((prop) => !used.includes(prop))
3818
- .map((prop) => {
3819
- const propInfo = props.find((p) => p.key === prop);
3820
- return {
3821
- value: prop,
3822
- label: propInfo?.name || prop,
3823
- };
3824
- });
3825
- }
3826
- return props
3827
- .filter((p) => !used.includes(p.key))
3828
- .map((p) => ({
3829
- value: p.key,
3830
- label: p.name,
3831
- }));
3832
- }, ...(ngDevMode ? [{ debugName: "availableProperties" }] : /* istanbul ignore next */ []));
3833
- /** Translation keys for iteration */
3834
- translationKeys = computed(() => Object.keys(this.translations()), ...(ngDevMode ? [{ debugName: "translationKeys" }] : /* istanbul ignore next */ []));
3835
- /** ControlValueAccessor callbacks */
3614
+ disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
3615
+ /** Available field types filtered by product */
3616
+ availableFieldTypes = computed(() => {
3617
+ const product = this.productType();
3618
+ return FILTER_FIELD_TYPES.filter((type) => type.products.includes(product));
3619
+ }, ...(ngDevMode ? [{ debugName: "availableFieldTypes" }] : /* istanbul ignore next */ []));
3620
+ // ControlValueAccessor callbacks
3836
3621
  onChange = () => { };
3837
3622
  onTouched = () => { };
3838
- // ==================== ControlValueAccessor ====================
3623
+ // ============================================
3624
+ // ControlValueAccessor Implementation
3625
+ // ============================================
3839
3626
  writeValue(value) {
3840
- if (value) {
3841
- if (Array.isArray(value)) {
3842
- // Convert array format to object format if needed
3843
- const obj = {};
3844
- value.forEach((item) => {
3845
- obj[item.key] = { ar: item.ar, en: item.en };
3846
- });
3847
- this.translations.set(obj);
3848
- }
3849
- else {
3850
- this.translations.set({ ...value });
3627
+ const fields = (value ?? []).map((field) => this.normalizeField(field));
3628
+ this.filterFields.set(fields);
3629
+ fields.forEach((field, index) => {
3630
+ if (field.type === 'status' && field.configuration?.schemaLevelId) {
3631
+ this.loadLevelLogs.emit(field.configuration.schemaLevelId);
3851
3632
  }
3852
- }
3633
+ });
3853
3634
  }
3854
3635
  registerOnChange(fn) {
3855
3636
  this.onChange = fn;
@@ -3858,99 +3639,497 @@ class PropertyTranslationsComponent {
3858
3639
  this.onTouched = fn;
3859
3640
  }
3860
3641
  setDisabledState(isDisabled) {
3861
- this.disabled = isDisabled;
3642
+ this.disabled.set(isDisabled);
3862
3643
  }
3863
- // ==================== Translation Methods ====================
3864
- addTranslation() {
3865
- const prop = this.selectedProperty();
3866
- if (prop && !this.translations()[prop]) {
3867
- this.translations.update((t) => ({
3868
- ...t,
3869
- [prop]: { ar: '', en: '' },
3870
- }));
3871
- this.selectedProperty.set(null);
3872
- this.onModelChange();
3644
+ // ============================================
3645
+ // Filter Field Management
3646
+ // ============================================
3647
+ /** Add a new filter field */
3648
+ addFilterField() {
3649
+ const newField = this.normalizeField(createDefaultFilterField());
3650
+ this.filterFields.update((fields) => [...fields, newField]);
3651
+ this.notifyChange();
3652
+ }
3653
+ /** Remove a filter field by index */
3654
+ removeFilterField(index) {
3655
+ this.filterFields.update((fields) => {
3656
+ const newFields = [...fields];
3657
+ newFields.splice(index, 1);
3658
+ return newFields;
3659
+ });
3660
+ this.removeCachedFieldState(index);
3661
+ this.notifyChange();
3662
+ }
3663
+ /** Update a filter field property */
3664
+ updateField(index, key, value) {
3665
+ this.filterFields.update((fields) => {
3666
+ const newFields = [...fields];
3667
+ newFields[index] = { ...newFields[index], [key]: value };
3668
+ return newFields;
3669
+ });
3670
+ this.notifyChange();
3671
+ }
3672
+ /** Update filter field name */
3673
+ updateFieldName(index, lang, value) {
3674
+ this.filterFields.update((fields) => {
3675
+ const newFields = [...fields];
3676
+ const field = newFields[index];
3677
+ field.name = {
3678
+ ...(field.name ?? { en: '', ar: '' }),
3679
+ [lang]: value,
3680
+ };
3681
+ return newFields;
3682
+ });
3683
+ this.notifyChange();
3684
+ }
3685
+ /** Update filter field configuration */
3686
+ updateFieldConfig(index, key, value) {
3687
+ this.filterFields.update((fields) => {
3688
+ const newFields = [...fields];
3689
+ const field = newFields[index];
3690
+ field.configuration = {
3691
+ ...this.createConfigurationForType(field.type, field.configuration),
3692
+ [key]: value,
3693
+ };
3694
+ return newFields;
3695
+ });
3696
+ this.notifyChange();
3697
+ }
3698
+ /** Handle field type change */
3699
+ onFieldTypeChange(index, type) {
3700
+ this.filterFields.update((fields) => {
3701
+ const newFields = [...fields];
3702
+ const current = newFields[index];
3703
+ newFields[index] = this.normalizeField({
3704
+ ...current,
3705
+ type,
3706
+ key: this.requiresKey(type) ? current.key : undefined,
3707
+ name: type === 'separator' ? undefined : current.name,
3708
+ configuration: this.createConfigurationForType(type, current.configuration),
3709
+ });
3710
+ return newFields;
3711
+ });
3712
+ const field = this.filterFields()[index];
3713
+ if (field?.type === 'dropdownTVService') {
3714
+ this.openDropdownConfig(index, field);
3715
+ }
3716
+ else {
3717
+ if (this.activeDropdownConfigIndex() === index) {
3718
+ this.activeDropdownConfigIndex.set(null);
3719
+ }
3720
+ this.setFieldModulesProperties(index, []);
3721
+ }
3722
+ this.notifyChange();
3723
+ }
3724
+ /** Handle schema level change for status/phaseGate */
3725
+ onSchemaLevelChange(index, schemaLevelId) {
3726
+ this.updateFieldConfig(index, 'schemaLevelId', schemaLevelId);
3727
+ // Clear log ID and emit event to load level logs
3728
+ this.updateFieldConfig(index, 'logId', null);
3729
+ if (schemaLevelId) {
3730
+ this.loadLevelLogs.emit(schemaLevelId);
3873
3731
  }
3874
3732
  }
3875
- removeTranslation(prop) {
3876
- this.translations.update((t) => {
3877
- const newT = { ...t };
3878
- delete newT[prop];
3879
- return newT;
3733
+ updateDropdownSelections(index, selections) {
3734
+ const normalizedSelections = this.normalizeSelections(selections ?? []);
3735
+ const currentField = this.filterFields()[index];
3736
+ if (currentField &&
3737
+ this.getSelectionSignature(this.getDropdownSelections(currentField)) ===
3738
+ this.getSelectionSignature(normalizedSelections)) {
3739
+ return;
3740
+ }
3741
+ this.filterFields.update((fields) => {
3742
+ const newFields = [...fields];
3743
+ const field = this.normalizeField(newFields[index]);
3744
+ const payload = this.ensurePayload(field.configuration?.payload);
3745
+ field.configuration = {
3746
+ ...field.configuration,
3747
+ payload: {
3748
+ ...payload,
3749
+ selection: normalizedSelections,
3750
+ },
3751
+ };
3752
+ newFields[index] = field;
3753
+ return newFields;
3880
3754
  });
3881
- this.onModelChange();
3755
+ this.loadDropdownProperties(index, normalizedSelections);
3756
+ this.notifyChange();
3882
3757
  }
3883
- updateTranslation(prop, lang, value) {
3884
- this.translations.update((t) => ({
3885
- ...t,
3886
- [prop]: { ...t[prop], [lang]: value },
3887
- }));
3888
- this.onModelChange();
3758
+ onDropdownModuleChange(index, _event) {
3759
+ const field = this.filterFields()[index];
3760
+ this.loadDropdownProperties(index, this.getDropdownSelections(field));
3889
3761
  }
3890
- // ==================== Copy/Paste Methods ====================
3891
- copyConfig() {
3892
- const configStr = JSON.stringify(this.translations(), null, 2);
3893
- navigator.clipboard.writeText(configStr).catch((err) => {
3894
- console.error('Failed to copy:', err);
3762
+ openDropdownConfig(index, field) {
3763
+ this.activeDropdownConfigIndex.set(index);
3764
+ this.loadDropdownProperties(index, this.getDropdownSelections(field));
3765
+ }
3766
+ closeDropdownConfig(index) {
3767
+ if (this.activeDropdownConfigIndex() === index) {
3768
+ this.activeDropdownConfigIndex.set(null);
3769
+ }
3770
+ }
3771
+ isDropdownConfigOpen(index) {
3772
+ return this.activeDropdownConfigIndex() === index;
3773
+ }
3774
+ updateSelectedProperties(index, properties) {
3775
+ this.filterFields.update((fields) => {
3776
+ const newFields = [...fields];
3777
+ const field = this.normalizeField(newFields[index]);
3778
+ const payload = this.ensurePayload(field.configuration?.payload);
3779
+ field.configuration = {
3780
+ ...field.configuration,
3781
+ payload: {
3782
+ ...payload,
3783
+ query: {
3784
+ ...payload.query,
3785
+ selectedProperties: properties ?? [],
3786
+ },
3787
+ },
3788
+ };
3789
+ newFields[index] = field;
3790
+ return newFields;
3895
3791
  });
3792
+ this.notifyChange();
3793
+ }
3794
+ // ============================================
3795
+ // Copy/Paste Configuration
3796
+ // ============================================
3797
+ /** Copy current configuration to clipboard */
3798
+ copyConfiguration() {
3799
+ try {
3800
+ const config = JSON.stringify(this.filterFields(), null, 2);
3801
+ navigator.clipboard.writeText(config);
3802
+ }
3803
+ catch (error) {
3804
+ console.error('Error copying configuration:', error);
3805
+ }
3896
3806
  }
3807
+ /** Toggle paste area visibility */
3897
3808
  togglePasteArea() {
3898
3809
  this.showPasteArea.update((v) => !v);
3899
- this.pasteText.set('');
3810
+ this.pasteContent.set('');
3900
3811
  this.pasteError.set('');
3901
3812
  }
3902
- applyPastedConfig() {
3813
+ /** Apply pasted configuration */
3814
+ applyPastedConfiguration() {
3903
3815
  try {
3904
- const parsed = JSON.parse(this.pasteText());
3905
- if (typeof parsed === 'object' && parsed !== null) {
3906
- this.translations.set(parsed);
3907
- this.showPasteArea.set(false);
3908
- this.pasteText.set('');
3909
- this.pasteError.set('');
3910
- this.onModelChange();
3911
- }
3912
- else {
3913
- this.pasteError.set('Invalid format');
3816
+ const parsedConfig = JSON.parse(this.pasteContent());
3817
+ if (!Array.isArray(parsedConfig)) {
3818
+ throw new Error('Configuration must be an array');
3914
3819
  }
3820
+ // Validate each field
3821
+ parsedConfig.forEach((field) => {
3822
+ if (!field.type) {
3823
+ throw new Error('Each field must have a type');
3824
+ }
3825
+ if (field.type !== 'separator' &&
3826
+ (!field.name || !field.name.en || !field.name.ar)) {
3827
+ throw new Error('Each field (except separator) must have name with en and ar properties');
3828
+ }
3829
+ });
3830
+ const normalizedConfig = parsedConfig.map((field) => this.normalizeField(field));
3831
+ this.filterFields.set(normalizedConfig);
3832
+ this.resetDropdownCaches();
3833
+ this.notifyChange();
3834
+ this.showPasteArea.set(false);
3835
+ this.pasteContent.set('');
3836
+ this.pasteError.set('');
3915
3837
  }
3916
- catch (_e) {
3917
- this.pasteError.set('Invalid JSON format');
3838
+ catch (error) {
3839
+ this.pasteError.set(`Invalid configuration: ${error.message}`);
3918
3840
  }
3919
3841
  }
3920
- // ==================== Helpers ====================
3921
- onModelChange() {
3922
- this.onChange(this.translations());
3842
+ // ============================================
3843
+ // Helpers
3844
+ // ============================================
3845
+ /** Track by function for ngFor */
3846
+ trackByIndex(index) {
3847
+ return index;
3848
+ }
3849
+ getFieldTitle(field, index) {
3850
+ const name = field.name?.en || field.name?.ar;
3851
+ return name || field.key || this.getFieldTypeLabel(field.type) || `#${index + 1}`;
3852
+ }
3853
+ getFieldTypeLabel(type) {
3854
+ return (this.availableFieldTypes().find((item) => item.value === type)?.label ??
3855
+ type);
3856
+ }
3857
+ requiresKey(type) {
3858
+ return type !== 'section' && type !== 'separator';
3859
+ }
3860
+ requiresName(type) {
3861
+ return type !== 'separator';
3862
+ }
3863
+ supportsRequired(field) {
3864
+ return field.type !== 'section' && field.type !== 'separator';
3865
+ }
3866
+ supportsMultiple(field) {
3867
+ return ![
3868
+ 'section',
3869
+ 'separator',
3870
+ 'checkbox',
3871
+ 'user',
3872
+ 'date',
3873
+ 'year',
3874
+ ].includes(field.type);
3875
+ }
3876
+ hasTypeConfiguration(field) {
3877
+ return [
3878
+ 'dropdownTVService',
3879
+ 'lookup',
3880
+ 'status',
3881
+ 'phaseGate',
3882
+ 'checkbox',
3883
+ 'year',
3884
+ ].includes(field.type);
3885
+ }
3886
+ getDropdownSelections(field) {
3887
+ const selection = field.configuration?.payload?.selection;
3888
+ if (!Array.isArray(selection))
3889
+ return this.emptySelections;
3890
+ return selection;
3891
+ }
3892
+ getSelectedProperties(field) {
3893
+ return field.configuration?.payload?.query?.selectedProperties ?? [];
3894
+ }
3895
+ getModulesPropertiesForField(index) {
3896
+ return this.fieldModulesProperties()[index] ?? this.emptyModulesProperties;
3897
+ }
3898
+ getPropertiesFlatForField(index) {
3899
+ const source = this.getModulesPropertiesForField(index);
3900
+ if (!source.length)
3901
+ return this.emptyProperties;
3902
+ const cached = this.propertiesFlatCache.get(index);
3903
+ if (cached?.source === source)
3904
+ return cached.value;
3905
+ const value = source.flatMap((module) => module.properties.map((property) => ({
3906
+ ...property,
3907
+ groupingBy: module.selectorName || module.moduleName,
3908
+ })));
3909
+ this.propertiesFlatCache.set(index, { source, value });
3910
+ return value;
3911
+ }
3912
+ getDropdownSummary(field) {
3913
+ const selections = this.getDropdownSelections(field);
3914
+ const selectionCount = selections.filter((selection) => {
3915
+ return !!selection.selector || !!selection.moduleType;
3916
+ }).length;
3917
+ const selectedProperties = this.getSelectedProperties(field).length;
3918
+ if (!selectionCount && !selectedProperties) {
3919
+ return 'No selection configured';
3920
+ }
3921
+ return `${selectionCount} selection${selectionCount === 1 ? '' : 's'}, ${selectedProperties} propert${selectedProperties === 1 ? 'y' : 'ies'}`;
3922
+ }
3923
+ /** Notify parent of changes */
3924
+ notifyChange() {
3925
+ this.onChange(this.filterFields());
3923
3926
  this.onTouched();
3924
3927
  }
3925
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertyTranslationsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3926
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PropertyTranslationsComponent, isStandalone: true, selector: "mt-property-translations", inputs: { propertiesFlat: { classPropertyName: "propertiesFlat", publicName: "propertiesFlat", isSignal: true, isRequired: false, transformFunction: null }, selectedProperties: { classPropertyName: "selectedProperties", publicName: "selectedProperties", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
3928
+ normalizeField(field) {
3929
+ const type = field.type ?? 'dropdownTVService';
3930
+ return {
3931
+ ...field,
3932
+ type,
3933
+ key: this.requiresKey(type) ? field.key : undefined,
3934
+ name: this.requiresName(type) ? (field.name ?? { en: '', ar: '' }) : undefined,
3935
+ configuration: this.createConfigurationForType(type, field.configuration),
3936
+ };
3937
+ }
3938
+ createConfigurationForType(type, current) {
3939
+ if (type === 'section' || type === 'separator') {
3940
+ return {};
3941
+ }
3942
+ const base = {
3943
+ isRequird: current?.isRequird ?? false,
3944
+ };
3945
+ if (this.supportsMultiple({ type })) {
3946
+ base.isMultiple = current?.isMultiple ?? false;
3947
+ }
3948
+ switch (type) {
3949
+ case 'dropdownTVService':
3950
+ return {
3951
+ ...base,
3952
+ payload: this.ensurePayload(current?.payload),
3953
+ };
3954
+ case 'lookup':
3955
+ return {
3956
+ ...base,
3957
+ lookupId: current?.lookupId,
3958
+ };
3959
+ case 'status':
3960
+ return {
3961
+ ...base,
3962
+ schemaLevelId: current?.schemaLevelId,
3963
+ logId: current?.logId ?? undefined,
3964
+ };
3965
+ case 'phaseGate':
3966
+ return {
3967
+ ...base,
3968
+ schemaLevelId: current?.schemaLevelId,
3969
+ };
3970
+ case 'checkbox':
3971
+ return {
3972
+ ...base,
3973
+ checked: current?.checked ?? false,
3974
+ };
3975
+ case 'year':
3976
+ return {
3977
+ ...base,
3978
+ minYear: current?.minYear,
3979
+ maxYear: current?.maxYear,
3980
+ };
3981
+ default:
3982
+ return base;
3983
+ }
3984
+ }
3985
+ ensurePayload(current) {
3986
+ return {
3987
+ dashboardId: current?.dashboardId ?? 0,
3988
+ chartType: current?.chartType ?? 'TableView',
3989
+ selection: current?.selection?.length
3990
+ ? this.normalizeSelections(current.selection)
3991
+ : [
3992
+ {
3993
+ id: 1,
3994
+ service: 'pplus',
3995
+ selector: null,
3996
+ selectorName: null,
3997
+ filters: [],
3998
+ },
3999
+ ],
4000
+ query: {
4001
+ selectedProperties: current?.query?.selectedProperties ?? [],
4002
+ },
4003
+ };
4004
+ }
4005
+ loadDropdownProperties(index, selections) {
4006
+ const items = (selections ?? [])
4007
+ .map((selection) => ({
4008
+ serviceName: selection.service || 'pplus',
4009
+ selector: selection.selector ??
4010
+ selectorFromLegacy(selection.moduleType, selection.moduleId),
4011
+ }))
4012
+ .filter((item) => {
4013
+ return !!item.serviceName && !!item.selector;
4014
+ });
4015
+ const signature = this.getSelectionSignature(selections);
4016
+ if (!items.length) {
4017
+ this.setFieldModulesProperties(index, []);
4018
+ this.dropdownPropertiesSignatureByIndex.set(index, '');
4019
+ return;
4020
+ }
4021
+ if (this.dropdownPropertiesSignatureByIndex.get(index) === signature) {
4022
+ return;
4023
+ }
4024
+ this.dropdownPropertiesSignatureByIndex.set(index, signature);
4025
+ this.dashboardService
4026
+ .getBulkProperties(items)
4027
+ .pipe(takeUntilDestroyed(this.destroyRef))
4028
+ .subscribe({
4029
+ next: (response) => {
4030
+ const enriched = this.dashboardService.enrichPropertiesWithSelectorName(response.data || []);
4031
+ this.setFieldModulesProperties(index, enriched.map((item) => ({
4032
+ moduleName: this.extractModuleTypeFromSelector(item.selector),
4033
+ selectorName: item.selectorName || null,
4034
+ selector: item.selector,
4035
+ properties: item.properties || [],
4036
+ })));
4037
+ },
4038
+ error: () => {
4039
+ this.dropdownPropertiesSignatureByIndex.delete(index);
4040
+ this.setFieldModulesProperties(index, []);
4041
+ },
4042
+ });
4043
+ }
4044
+ setFieldModulesProperties(index, modulesProperties) {
4045
+ this.propertiesFlatCache.delete(index);
4046
+ this.fieldModulesProperties.update((current) => ({
4047
+ ...current,
4048
+ [index]: modulesProperties,
4049
+ }));
4050
+ }
4051
+ extractModuleTypeFromSelector(selector) {
4052
+ if (!selector)
4053
+ return '';
4054
+ return selector.split(':')[0] ?? '';
4055
+ }
4056
+ normalizeSelections(selections) {
4057
+ return (selections ?? []).map((selection, index) => ({
4058
+ ...selection,
4059
+ id: selection.id ?? index + 1,
4060
+ service: selection.service ?? 'pplus',
4061
+ selector: selection.selector ??
4062
+ selectorFromLegacy(selection.moduleType, selection.moduleId),
4063
+ selectorName: selection.selectorName ?? null,
4064
+ filters: selection.filters ?? [],
4065
+ }));
4066
+ }
4067
+ getSelectionSignature(selections) {
4068
+ return JSON.stringify(this.normalizeSelections(selections).map((selection) => ({
4069
+ id: selection.id,
4070
+ service: selection.service ?? 'pplus',
4071
+ selector: selection.selector ??
4072
+ selectorFromLegacy(selection.moduleType, selection.moduleId),
4073
+ filters: selection.filters ?? [],
4074
+ })));
4075
+ }
4076
+ removeCachedFieldState(index) {
4077
+ this.resetDropdownCaches();
4078
+ this.fieldModulesProperties.update((current) => {
4079
+ const next = {};
4080
+ Object.entries(current).forEach(([key, value]) => {
4081
+ const numericKey = Number(key);
4082
+ if (numericKey < index)
4083
+ next[numericKey] = value;
4084
+ if (numericKey > index)
4085
+ next[numericKey - 1] = value;
4086
+ });
4087
+ return next;
4088
+ });
4089
+ const activeIndex = this.activeDropdownConfigIndex();
4090
+ if (activeIndex === index) {
4091
+ this.activeDropdownConfigIndex.set(null);
4092
+ }
4093
+ else if (activeIndex !== null && activeIndex > index) {
4094
+ this.activeDropdownConfigIndex.set(activeIndex - 1);
4095
+ }
4096
+ }
4097
+ resetDropdownCaches() {
4098
+ this.propertiesFlatCache.clear();
4099
+ this.dropdownPropertiesSignatureByIndex.clear();
4100
+ }
4101
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DynamicFiltersConfig, deps: [], target: i0.ɵɵFactoryTarget.Component });
4102
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DynamicFiltersConfig, isStandalone: true, selector: "mt-dynamic-filters-config", inputs: { lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, levelsSchema: { classPropertyName: "levelsSchema", publicName: "levelsSchema", isSignal: true, isRequired: false, transformFunction: null }, levelLogs: { classPropertyName: "levelLogs", publicName: "levelLogs", isSignal: true, isRequired: false, transformFunction: null }, productType: { classPropertyName: "productType", publicName: "productType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadLevelLogs: "loadLevelLogs" }, providers: [
3927
4103
  {
3928
4104
  provide: NG_VALUE_ACCESSOR,
3929
- useExisting: forwardRef(() => PropertyTranslationsComponent),
4105
+ useExisting: forwardRef(() => DynamicFiltersConfig),
3930
4106
  multi: true,
3931
4107
  },
3932
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <mt-card [title]=\"t('propertyTranslations')\">\n <ng-template #cardEnd>\n <div class=\"flex items-center gap-1\">\n <mt-button\n icon=\"general.copy-01\"\n severity=\"secondary\"\n [text]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"copyConfig()\"\n [pTooltip]=\"t('copyConfig')\"\n />\n <mt-button\n icon=\"general.clipboard\"\n severity=\"secondary\"\n [text]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"togglePasteArea()\"\n [pTooltip]=\"t('pasteConfig')\"\n />\n </div>\n </ng-template>\n\n <!-- Paste Area -->\n @if (showPasteArea()) {\n <div class=\"mb-4 p-4 bg-surface-50 rounded-lg border border-surface-200\">\n <mt-textarea-field\n [label]=\"t('pasteConfiguration')\"\n [ngModel]=\"pasteText()\"\n (ngModelChange)=\"pasteText.set($event)\"\n [placeholder]=\"t('pasteConfigurationPlaceholder')\"\n [rows]=\"4\"\n [disabled]=\"disabled\"\n />\n @if (pasteError()) {\n <small class=\"text-red-500 mt-1 block\">{{ pasteError() }}</small>\n }\n <div class=\"flex justify-end gap-2 mt-3\">\n <mt-button\n [label]=\"t('cancel')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"togglePasteArea()\"\n />\n <mt-button\n [label]=\"t('apply')\"\n size=\"small\"\n (onClick)=\"applyPastedConfig()\"\n />\n </div>\n </div>\n }\n\n <!-- Add Property Dropdown -->\n <div class=\"mb-4\">\n <div class=\"flex items-end gap-2\">\n <div class=\"flex-1\">\n <mt-select-field\n [label]=\"t('selectProperty')\"\n [ngModel]=\"selectedProperty()\"\n (ngModelChange)=\"selectedProperty.set($event)\"\n [options]=\"availableProperties()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectPropertyToTranslate')\"\n [filter]=\"true\"\n [disabled]=\"disabled\"\n />\n </div>\n <mt-button\n icon=\"general.plus\"\n [outlined]=\"true\"\n size=\"small\"\n [disabled]=\"disabled || !selectedProperty()\"\n (onClick)=\"addTranslation()\"\n [pTooltip]=\"t('addTranslation')\"\n />\n </div>\n </div>\n\n <!-- Translations List -->\n <div class=\"flex flex-col gap-4\">\n @for (prop of translationKeys(); track prop) {\n <div class=\"p-4 rounded-lg border border-surface-200 bg-surface-50\">\n <!-- Property Header -->\n <div class=\"flex items-center justify-between mb-3\">\n <span class=\"font-medium text-sm\">{{ prop }}</span>\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n [text]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"removeTranslation(prop)\"\n />\n </div>\n\n <!-- Translation Fields -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <mt-text-field\n [label]=\"t('arabicLabel')\"\n [ngModel]=\"translations()[prop].ar\"\n (ngModelChange)=\"updateTranslation(prop, 'ar', $event)\"\n [placeholder]=\"t('enterArabicTranslation')\"\n [disabled]=\"disabled\"\n />\n <mt-text-field\n [label]=\"t('englishLabel')\"\n [ngModel]=\"translations()[prop].en\"\n (ngModelChange)=\"updateTranslation(prop, 'en', $event)\"\n [placeholder]=\"t('enterEnglishTranslation')\"\n [disabled]=\"disabled\"\n />\n </div>\n </div>\n }\n\n @if (translationKeys().length === 0) {\n <div class=\"text-center py-8 text-muted-color\">\n <i class=\"mti mti-translate text-3xl mb-2 block\"></i>\n <p class=\"mb-2\">{{ t(\"noTranslationsConfigured\") }}</p>\n </div>\n }\n </div>\n </mt-card>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4108
+ ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-3\"\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\n>\n <div\n class=\"flex flex-wrap items-center justify-between gap-2 border-b border-surface-200 pb-3\"\n >\n <h3 class=\"text-base font-semibold text-surface-800\">\n {{ t(\"filterFieldsConfiguration\") }}\n </h3>\n <div class=\"flex items-center gap-1.5\">\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addField')\"\n severity=\"primary\"\n size=\"small\"\n (onClick)=\"addFilterField()\"\n [disabled]=\"disabled()\"\n />\n <mt-button\n icon=\"general.copy-06\"\n [pTooltip]=\"t('copyConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"copyConfiguration()\"\n />\n <mt-button\n icon=\"general.clipboard\"\n [pTooltip]=\"t('pasteConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"togglePasteArea()\"\n />\n </div>\n </div>\n\n @if (showPasteArea()) {\n <div\n class=\"flex flex-col gap-2 rounded-md border border-surface-200 bg-surface-50 p-3\"\n >\n <mt-textarea-field\n [label]=\"t('pasteConfigurationHere')\"\n [rows]=\"6\"\n [ngModel]=\"pasteContent()\"\n (ngModelChange)=\"pasteContent.set($event)\"\n [placeholder]=\"t('pasteJsonConfiguration')\"\n />\n @if (pasteError()) {\n <div class=\"text-sm text-red-500\">{{ pasteError() }}</div>\n }\n <div class=\"flex justify-end gap-2\">\n <mt-button\n [label]=\"t('cancel')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"togglePasteArea()\"\n />\n <mt-button\n [label]=\"t('applyConfiguration')\"\n size=\"small\"\n (onClick)=\"applyPastedConfiguration()\"\n />\n </div>\n </div>\n }\n\n <div class=\"flex flex-col gap-3\">\n @for (field of filterFields(); track trackByIndex($index); let i = $index) {\n <section\n class=\"overflow-hidden rounded-md border border-surface-200 bg-surface-0\"\n >\n <div\n class=\"flex items-center justify-between gap-3 border-b border-surface-200 bg-surface-100 px-3 py-2\"\n >\n <div class=\"min-w-0\">\n <div class=\"truncate text-sm font-semibold text-surface-800\">\n {{ getFieldTitle(field, i) }}\n </div>\n <div class=\"text-xs text-muted-color\">\n {{ getFieldTypeLabel(field.type) }}\n </div>\n </div>\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n size=\"small\"\n [rounded]=\"true\"\n [text]=\"true\"\n (onClick)=\"removeFilterField(i)\"\n [disabled]=\"disabled()\"\n />\n </div>\n\n <div class=\"flex flex-col gap-3 p-3\">\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('fieldType')\"\n [options]=\"availableFieldTypes()\"\n optionValue=\"value\"\n optionLabel=\"label\"\n [ngModel]=\"field.type\"\n (ngModelChange)=\"onFieldTypeChange(i, $event)\"\n />\n\n @if (requiresKey(field.type)) {\n <mt-text-field\n [label]=\"t('fieldKey')\"\n [placeholder]=\"t('enterFieldKey')\"\n [ngModel]=\"field.key\"\n (ngModelChange)=\"updateField(i, 'key', $event)\"\n />\n }\n\n @if (requiresName(field.type)) {\n <mt-text-field\n [label]=\"t('nameEnglish')\"\n [placeholder]=\"t('enterEnglishName')\"\n [ngModel]=\"field.name?.en\"\n (ngModelChange)=\"updateFieldName(i, 'en', $event)\"\n />\n <mt-text-field\n [label]=\"t('nameArabic')\"\n [placeholder]=\"t('enterArabicName')\"\n [ngModel]=\"field.name?.ar\"\n (ngModelChange)=\"updateFieldName(i, 'ar', $event)\"\n />\n }\n </div>\n\n @if (hasTypeConfiguration(field)) {\n <div\n class=\"flex w-full flex-col gap-3 rounded-md border border-surface-200 bg-surface-50 p-3\"\n >\n <div class=\"text-sm font-semibold text-surface-700\">\n {{ t(\"settings\") }}\n </div>\n\n @switch (field.type) {\n @case (\"dropdownTVService\") {\n @if (isDropdownConfigOpen(i)) {\n <div class=\"flex justify-end\">\n <mt-button\n [label]=\"t('close')\"\n icon=\"general.x-close\"\n severity=\"secondary\"\n size=\"small\"\n [text]=\"true\"\n (onClick)=\"closeDropdownConfig(i)\"\n />\n </div>\n\n <mt-selection-configuration\n class=\"block w-full\"\n [ngModel]=\"getDropdownSelections(field)\"\n (ngModelChange)=\"updateDropdownSelections(i, $event)\"\n (moduleChange)=\"onDropdownModuleChange(i, $event)\"\n [modulesProperties]=\"getModulesPropertiesForField(i)\"\n [propertiesFlat]=\"getPropertiesFlatForField(i)\"\n />\n\n <mt-multi-select-field\n class=\"block w-full\"\n [label]=\"t('selectedProperties')\"\n [options]=\"getPropertiesFlatForField(i)\"\n optionValue=\"key\"\n optionLabel=\"name\"\n [filter]=\"true\"\n [ngModel]=\"getSelectedProperties(field)\"\n (ngModelChange)=\"updateSelectedProperties(i, $event)\"\n />\n } @else {\n <div\n class=\"flex flex-wrap items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-0 px-3 py-2\"\n >\n <span class=\"text-sm text-muted-color\">\n {{ getDropdownSummary(field) }}\n </span>\n <mt-button\n [label]=\"t('selectionsConfiguration')\"\n icon=\"general.settings-01\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"openDropdownConfig(i, field)\"\n />\n </div>\n }\n }\n\n @case (\"lookup\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('lookupId')\"\n [options]=\"lookups()\"\n optionValue=\"id\"\n optionLabel=\"displayName\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.lookupId\"\n (ngModelChange)=\"updateFieldConfig(i, 'lookupId', $event)\"\n />\n </div>\n }\n\n @case (\"status\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('schemaLevelId')\"\n [options]=\"levelsSchema()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.schemaLevelId\"\n (ngModelChange)=\"onSchemaLevelChange(i, $event)\"\n />\n\n @if (field.configuration?.schemaLevelId) {\n <mt-select-field\n [label]=\"t('logId')\"\n [options]=\"levelLogs()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.logId\"\n (ngModelChange)=\"updateFieldConfig(i, 'logId', $event)\"\n />\n }\n </div>\n }\n\n @case (\"phaseGate\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('schemaLevelId')\"\n [options]=\"levelsSchema()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.schemaLevelId\"\n (ngModelChange)=\"onSchemaLevelChange(i, $event)\"\n />\n </div>\n }\n\n @case (\"checkbox\") {\n <mt-toggle-field\n [label]=\"t('defaultChecked')\"\n size=\"small\"\n [ngModel]=\"field.configuration?.checked ?? false\"\n (ngModelChange)=\"updateFieldConfig(i, 'checked', $event)\"\n />\n }\n\n @case (\"year\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-number-field\n [label]=\"t('minYear')\"\n [placeholder]=\"t('minYear')\"\n [ngModel]=\"field.configuration?.minYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'minYear', $event)\"\n />\n <mt-number-field\n [label]=\"t('maxYear')\"\n [placeholder]=\"t('maxYear')\"\n [ngModel]=\"field.configuration?.maxYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'maxYear', $event)\"\n />\n </div>\n }\n }\n </div>\n }\n\n <div class=\"flex flex-wrap items-center gap-4\">\n @if (supportsRequired(field)) {\n <mt-toggle-field\n [label]=\"t('isRequired')\"\n size=\"small\"\n [ngModel]=\"field.configuration?.isRequird ?? false\"\n (ngModelChange)=\"updateFieldConfig(i, 'isRequird', $event)\"\n />\n }\n\n @if (supportsMultiple(field)) {\n <mt-toggle-field\n [label]=\"t('isMultiple')\"\n size=\"small\"\n [ngModel]=\"field.configuration?.isMultiple ?? false\"\n (ngModelChange)=\"updateFieldConfig(i, 'isMultiple', $event)\"\n />\n }\n </div>\n </div>\n </section>\n } @empty {\n <div\n class=\"flex flex-col items-center justify-center gap-2 rounded-md border border-dashed border-surface-300 py-10 text-center text-muted-color\"\n >\n <mt-icon icon=\"general.filter-lines\" class=\"text-3xl\" />\n <p class=\"text-sm font-medium\">{{ t(\"noFilterFieldsConfigured\") }}</p>\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addField')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"addFilterField()\"\n [disabled]=\"disabled()\"\n />\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Icon, selector: "mt-icon", inputs: ["icon"] }, { 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: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: SelectionConfiguration, selector: "mt-selection-configuration", inputs: ["structureLocked", "workspaceId", "modulesProperties", "propertiesFlat"], outputs: ["moduleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3933
4109
  }
3934
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertyTranslationsComponent, decorators: [{
4110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DynamicFiltersConfig, decorators: [{
3935
4111
  type: Component,
3936
- args: [{ selector: 'mt-property-translations', standalone: true, imports: [
4112
+ args: [{ selector: 'mt-dynamic-filters-config', standalone: true, imports: [
3937
4113
  CommonModule,
3938
4114
  FormsModule,
3939
4115
  TranslocoDirective,
3940
4116
  Button,
4117
+ Icon,
3941
4118
  SelectField,
3942
4119
  TextField,
4120
+ NumberField,
4121
+ MultiSelectField,
4122
+ ToggleField,
3943
4123
  TextareaField,
3944
- Card,
3945
- Tooltip,
4124
+ SelectionConfiguration,
3946
4125
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
3947
4126
  {
3948
4127
  provide: NG_VALUE_ACCESSOR,
3949
- useExisting: forwardRef(() => PropertyTranslationsComponent),
4128
+ useExisting: forwardRef(() => DynamicFiltersConfig),
3950
4129
  multi: true,
3951
4130
  },
3952
- ], template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <mt-card [title]=\"t('propertyTranslations')\">\n <ng-template #cardEnd>\n <div class=\"flex items-center gap-1\">\n <mt-button\n icon=\"general.copy-01\"\n severity=\"secondary\"\n [text]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"copyConfig()\"\n [pTooltip]=\"t('copyConfig')\"\n />\n <mt-button\n icon=\"general.clipboard\"\n severity=\"secondary\"\n [text]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"togglePasteArea()\"\n [pTooltip]=\"t('pasteConfig')\"\n />\n </div>\n </ng-template>\n\n <!-- Paste Area -->\n @if (showPasteArea()) {\n <div class=\"mb-4 p-4 bg-surface-50 rounded-lg border border-surface-200\">\n <mt-textarea-field\n [label]=\"t('pasteConfiguration')\"\n [ngModel]=\"pasteText()\"\n (ngModelChange)=\"pasteText.set($event)\"\n [placeholder]=\"t('pasteConfigurationPlaceholder')\"\n [rows]=\"4\"\n [disabled]=\"disabled\"\n />\n @if (pasteError()) {\n <small class=\"text-red-500 mt-1 block\">{{ pasteError() }}</small>\n }\n <div class=\"flex justify-end gap-2 mt-3\">\n <mt-button\n [label]=\"t('cancel')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"togglePasteArea()\"\n />\n <mt-button\n [label]=\"t('apply')\"\n size=\"small\"\n (onClick)=\"applyPastedConfig()\"\n />\n </div>\n </div>\n }\n\n <!-- Add Property Dropdown -->\n <div class=\"mb-4\">\n <div class=\"flex items-end gap-2\">\n <div class=\"flex-1\">\n <mt-select-field\n [label]=\"t('selectProperty')\"\n [ngModel]=\"selectedProperty()\"\n (ngModelChange)=\"selectedProperty.set($event)\"\n [options]=\"availableProperties()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectPropertyToTranslate')\"\n [filter]=\"true\"\n [disabled]=\"disabled\"\n />\n </div>\n <mt-button\n icon=\"general.plus\"\n [outlined]=\"true\"\n size=\"small\"\n [disabled]=\"disabled || !selectedProperty()\"\n (onClick)=\"addTranslation()\"\n [pTooltip]=\"t('addTranslation')\"\n />\n </div>\n </div>\n\n <!-- Translations List -->\n <div class=\"flex flex-col gap-4\">\n @for (prop of translationKeys(); track prop) {\n <div class=\"p-4 rounded-lg border border-surface-200 bg-surface-50\">\n <!-- Property Header -->\n <div class=\"flex items-center justify-between mb-3\">\n <span class=\"font-medium text-sm\">{{ prop }}</span>\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n [text]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"removeTranslation(prop)\"\n />\n </div>\n\n <!-- Translation Fields -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <mt-text-field\n [label]=\"t('arabicLabel')\"\n [ngModel]=\"translations()[prop].ar\"\n (ngModelChange)=\"updateTranslation(prop, 'ar', $event)\"\n [placeholder]=\"t('enterArabicTranslation')\"\n [disabled]=\"disabled\"\n />\n <mt-text-field\n [label]=\"t('englishLabel')\"\n [ngModel]=\"translations()[prop].en\"\n (ngModelChange)=\"updateTranslation(prop, 'en', $event)\"\n [placeholder]=\"t('enterEnglishTranslation')\"\n [disabled]=\"disabled\"\n />\n </div>\n </div>\n }\n\n @if (translationKeys().length === 0) {\n <div class=\"text-center py-8 text-muted-color\">\n <i class=\"mti mti-translate text-3xl mb-2 block\"></i>\n <p class=\"mb-2\">{{ t(\"noTranslationsConfigured\") }}</p>\n </div>\n }\n </div>\n </mt-card>\n</div>\n" }]
3953
- }], propDecorators: { propertiesFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesFlat", required: false }] }], selectedProperties: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedProperties", required: false }] }] } });
4131
+ ], template: "<div\n class=\"flex flex-col gap-3\"\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\n>\n <div\n class=\"flex flex-wrap items-center justify-between gap-2 border-b border-surface-200 pb-3\"\n >\n <h3 class=\"text-base font-semibold text-surface-800\">\n {{ t(\"filterFieldsConfiguration\") }}\n </h3>\n <div class=\"flex items-center gap-1.5\">\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addField')\"\n severity=\"primary\"\n size=\"small\"\n (onClick)=\"addFilterField()\"\n [disabled]=\"disabled()\"\n />\n <mt-button\n icon=\"general.copy-06\"\n [pTooltip]=\"t('copyConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"copyConfiguration()\"\n />\n <mt-button\n icon=\"general.clipboard\"\n [pTooltip]=\"t('pasteConfiguration')\"\n tooltipPosition=\"top\"\n severity=\"secondary\"\n size=\"small\"\n [rounded]=\"true\"\n (onClick)=\"togglePasteArea()\"\n />\n </div>\n </div>\n\n @if (showPasteArea()) {\n <div\n class=\"flex flex-col gap-2 rounded-md border border-surface-200 bg-surface-50 p-3\"\n >\n <mt-textarea-field\n [label]=\"t('pasteConfigurationHere')\"\n [rows]=\"6\"\n [ngModel]=\"pasteContent()\"\n (ngModelChange)=\"pasteContent.set($event)\"\n [placeholder]=\"t('pasteJsonConfiguration')\"\n />\n @if (pasteError()) {\n <div class=\"text-sm text-red-500\">{{ pasteError() }}</div>\n }\n <div class=\"flex justify-end gap-2\">\n <mt-button\n [label]=\"t('cancel')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"togglePasteArea()\"\n />\n <mt-button\n [label]=\"t('applyConfiguration')\"\n size=\"small\"\n (onClick)=\"applyPastedConfiguration()\"\n />\n </div>\n </div>\n }\n\n <div class=\"flex flex-col gap-3\">\n @for (field of filterFields(); track trackByIndex($index); let i = $index) {\n <section\n class=\"overflow-hidden rounded-md border border-surface-200 bg-surface-0\"\n >\n <div\n class=\"flex items-center justify-between gap-3 border-b border-surface-200 bg-surface-100 px-3 py-2\"\n >\n <div class=\"min-w-0\">\n <div class=\"truncate text-sm font-semibold text-surface-800\">\n {{ getFieldTitle(field, i) }}\n </div>\n <div class=\"text-xs text-muted-color\">\n {{ getFieldTypeLabel(field.type) }}\n </div>\n </div>\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n size=\"small\"\n [rounded]=\"true\"\n [text]=\"true\"\n (onClick)=\"removeFilterField(i)\"\n [disabled]=\"disabled()\"\n />\n </div>\n\n <div class=\"flex flex-col gap-3 p-3\">\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('fieldType')\"\n [options]=\"availableFieldTypes()\"\n optionValue=\"value\"\n optionLabel=\"label\"\n [ngModel]=\"field.type\"\n (ngModelChange)=\"onFieldTypeChange(i, $event)\"\n />\n\n @if (requiresKey(field.type)) {\n <mt-text-field\n [label]=\"t('fieldKey')\"\n [placeholder]=\"t('enterFieldKey')\"\n [ngModel]=\"field.key\"\n (ngModelChange)=\"updateField(i, 'key', $event)\"\n />\n }\n\n @if (requiresName(field.type)) {\n <mt-text-field\n [label]=\"t('nameEnglish')\"\n [placeholder]=\"t('enterEnglishName')\"\n [ngModel]=\"field.name?.en\"\n (ngModelChange)=\"updateFieldName(i, 'en', $event)\"\n />\n <mt-text-field\n [label]=\"t('nameArabic')\"\n [placeholder]=\"t('enterArabicName')\"\n [ngModel]=\"field.name?.ar\"\n (ngModelChange)=\"updateFieldName(i, 'ar', $event)\"\n />\n }\n </div>\n\n @if (hasTypeConfiguration(field)) {\n <div\n class=\"flex w-full flex-col gap-3 rounded-md border border-surface-200 bg-surface-50 p-3\"\n >\n <div class=\"text-sm font-semibold text-surface-700\">\n {{ t(\"settings\") }}\n </div>\n\n @switch (field.type) {\n @case (\"dropdownTVService\") {\n @if (isDropdownConfigOpen(i)) {\n <div class=\"flex justify-end\">\n <mt-button\n [label]=\"t('close')\"\n icon=\"general.x-close\"\n severity=\"secondary\"\n size=\"small\"\n [text]=\"true\"\n (onClick)=\"closeDropdownConfig(i)\"\n />\n </div>\n\n <mt-selection-configuration\n class=\"block w-full\"\n [ngModel]=\"getDropdownSelections(field)\"\n (ngModelChange)=\"updateDropdownSelections(i, $event)\"\n (moduleChange)=\"onDropdownModuleChange(i, $event)\"\n [modulesProperties]=\"getModulesPropertiesForField(i)\"\n [propertiesFlat]=\"getPropertiesFlatForField(i)\"\n />\n\n <mt-multi-select-field\n class=\"block w-full\"\n [label]=\"t('selectedProperties')\"\n [options]=\"getPropertiesFlatForField(i)\"\n optionValue=\"key\"\n optionLabel=\"name\"\n [filter]=\"true\"\n [ngModel]=\"getSelectedProperties(field)\"\n (ngModelChange)=\"updateSelectedProperties(i, $event)\"\n />\n } @else {\n <div\n class=\"flex flex-wrap items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-0 px-3 py-2\"\n >\n <span class=\"text-sm text-muted-color\">\n {{ getDropdownSummary(field) }}\n </span>\n <mt-button\n [label]=\"t('selectionsConfiguration')\"\n icon=\"general.settings-01\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"openDropdownConfig(i, field)\"\n />\n </div>\n }\n }\n\n @case (\"lookup\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('lookupId')\"\n [options]=\"lookups()\"\n optionValue=\"id\"\n optionLabel=\"displayName\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.lookupId\"\n (ngModelChange)=\"updateFieldConfig(i, 'lookupId', $event)\"\n />\n </div>\n }\n\n @case (\"status\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('schemaLevelId')\"\n [options]=\"levelsSchema()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.schemaLevelId\"\n (ngModelChange)=\"onSchemaLevelChange(i, $event)\"\n />\n\n @if (field.configuration?.schemaLevelId) {\n <mt-select-field\n [label]=\"t('logId')\"\n [options]=\"levelLogs()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.logId\"\n (ngModelChange)=\"updateFieldConfig(i, 'logId', $event)\"\n />\n }\n </div>\n }\n\n @case (\"phaseGate\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-select-field\n [label]=\"t('schemaLevelId')\"\n [options]=\"levelsSchema()\"\n optionValue=\"id\"\n optionLabel=\"description\"\n [filter]=\"true\"\n [ngModel]=\"field.configuration?.schemaLevelId\"\n (ngModelChange)=\"onSchemaLevelChange(i, $event)\"\n />\n </div>\n }\n\n @case (\"checkbox\") {\n <mt-toggle-field\n [label]=\"t('defaultChecked')\"\n size=\"small\"\n [ngModel]=\"field.configuration?.checked ?? false\"\n (ngModelChange)=\"updateFieldConfig(i, 'checked', $event)\"\n />\n }\n\n @case (\"year\") {\n <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <mt-number-field\n [label]=\"t('minYear')\"\n [placeholder]=\"t('minYear')\"\n [ngModel]=\"field.configuration?.minYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'minYear', $event)\"\n />\n <mt-number-field\n [label]=\"t('maxYear')\"\n [placeholder]=\"t('maxYear')\"\n [ngModel]=\"field.configuration?.maxYear\"\n (ngModelChange)=\"updateFieldConfig(i, 'maxYear', $event)\"\n />\n </div>\n }\n }\n </div>\n }\n\n <div class=\"flex flex-wrap items-center gap-4\">\n @if (supportsRequired(field)) {\n <mt-toggle-field\n [label]=\"t('isRequired')\"\n size=\"small\"\n [ngModel]=\"field.configuration?.isRequird ?? false\"\n (ngModelChange)=\"updateFieldConfig(i, 'isRequird', $event)\"\n />\n }\n\n @if (supportsMultiple(field)) {\n <mt-toggle-field\n [label]=\"t('isMultiple')\"\n size=\"small\"\n [ngModel]=\"field.configuration?.isMultiple ?? false\"\n (ngModelChange)=\"updateFieldConfig(i, 'isMultiple', $event)\"\n />\n }\n </div>\n </div>\n </section>\n } @empty {\n <div\n class=\"flex flex-col items-center justify-center gap-2 rounded-md border border-dashed border-surface-300 py-10 text-center text-muted-color\"\n >\n <mt-icon icon=\"general.filter-lines\" class=\"text-3xl\" />\n <p class=\"text-sm font-medium\">{{ t(\"noFilterFieldsConfigured\") }}</p>\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addField')\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"addFilterField()\"\n [disabled]=\"disabled()\"\n />\n </div>\n }\n </div>\n</div>\n" }]
4132
+ }], propDecorators: { lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], levelsSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelsSchema", required: false }] }], levelLogs: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelLogs", required: false }] }], productType: [{ type: i0.Input, args: [{ isSignal: true, alias: "productType", required: false }] }], loadLevelLogs: [{ type: i0.Output, args: ["loadLevelLogs"] }] } });
3954
4133
 
3955
4134
  /**
3956
4135
  * Manage Filter On Page Component
@@ -3969,50 +4148,14 @@ class ManageFilterOnPage {
3969
4148
  ref = inject(ModalRef);
3970
4149
  /** Input: Initial filters data */
3971
4150
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
3972
- /** All charts and dialogs on the selected dashboard. */
3973
- chartItems = input([], ...(ngDevMode ? [{ debugName: "chartItems" }] : /* istanbul ignore next */ []));
3974
4151
  /** Input: Available lookups for dropdown */
3975
4152
  lookups = input([], ...(ngDevMode ? [{ debugName: "lookups" }] : /* istanbul ignore next */ []));
3976
4153
  /** Input: Available level schemas */
3977
4154
  levelsSchema = input([], ...(ngDevMode ? [{ debugName: "levelsSchema" }] : /* istanbul ignore next */ []));
3978
4155
  /** Filters configuration */
3979
4156
  filtersConfig = signal([], ...(ngDevMode ? [{ debugName: "filtersConfig" }] : /* istanbul ignore next */ []));
3980
- /** Bulk selection filters to apply/delete across matching charts. */
3981
- bulkSelection = signal([], ...(ngDevMode ? [{ debugName: "bulkSelection" }] : /* istanbul ignore next */ []));
3982
- /** Labels to apply to all table/dialog table charts. */
3983
- bulkLabels = signal({}, ...(ngDevMode ? [{ debugName: "bulkLabels" }] : /* istanbul ignore next */ []));
3984
4157
  /** Level logs for status filter */
3985
4158
  levelLogs = signal([], ...(ngDevMode ? [{ debugName: "levelLogs" }] : /* istanbul ignore next */ []));
3986
- bulkPropertyOptions = computed(() => {
3987
- const properties = new Map();
3988
- this.chartItems().forEach((item) => {
3989
- const query = item.config?.serviceConfig?.query;
3990
- [
3991
- query?.['properties'],
3992
- query?.['extraProperties'],
3993
- query?.['groupByProperties'],
3994
- ].forEach((value) => {
3995
- if (!Array.isArray(value))
3996
- return;
3997
- value.forEach((property) => {
3998
- const key = typeof property === 'string'
3999
- ? property
4000
- : (property?.key ?? property?.propertyKey ?? property?.value);
4001
- if (!key || properties.has(String(key)))
4002
- return;
4003
- const name = typeof property === 'string'
4004
- ? property
4005
- : (property?.name ?? property?.label ?? property?.displayName);
4006
- properties.set(String(key), {
4007
- key: String(key),
4008
- name: String(name || key),
4009
- });
4010
- });
4011
- });
4012
- });
4013
- return [...properties.values()];
4014
- }, ...(ngDevMode ? [{ debugName: "bulkPropertyOptions" }] : /* istanbul ignore next */ []));
4015
- bulkPropertyKeys = computed(() => this.bulkPropertyOptions().map((property) => property.key), ...(ngDevMode ? [{ debugName: "bulkPropertyKeys" }] : /* istanbul ignore next */ []));
4016
4159
  ngOnInit() {
4017
4160
  this.filtersConfig.set([...(this.data() || [])]);
4018
4161
  }
@@ -4020,12 +4163,6 @@ class ManageFilterOnPage {
4020
4163
  onFiltersChange(filters) {
4021
4164
  this.filtersConfig.set(filters);
4022
4165
  }
4023
- onBulkSelectionChange(selections) {
4024
- this.bulkSelection.set(selections ?? []);
4025
- }
4026
- onBulkLabelsChange(labels) {
4027
- this.bulkLabels.set(labels ?? {});
4028
- }
4029
4166
  /**
4030
4167
  * Hook for hosts that want to feed level-log values into the filter
4031
4168
  * dialog. The host listens to `(loadLevelLogs)` (when consumers wire it)
@@ -4038,26 +4175,8 @@ class ManageFilterOnPage {
4038
4175
  }
4039
4176
  /** Save and close the dialog */
4040
4177
  save() {
4041
- this.ref.close({ filters: this.filtersConfig() });
4042
- }
4043
- applyBulkFilters() {
4044
4178
  this.ref.close({
4045
4179
  filters: this.filtersConfig(),
4046
- bulkSelection: this.bulkSelection(),
4047
- bulkOperation: 'applyFilters',
4048
- });
4049
- }
4050
- deleteBulkFilters() {
4051
- this.ref.close({
4052
- filters: this.filtersConfig(),
4053
- bulkSelection: this.bulkSelection(),
4054
- bulkOperation: 'deleteFilters',
4055
- });
4056
- }
4057
- applyBulkLabels() {
4058
- this.ref.close({
4059
- filters: this.filtersConfig(),
4060
- labels: this.bulkLabels(),
4061
4180
  });
4062
4181
  }
4063
4182
  /** Cancel and close the dialog */
@@ -4065,7 +4184,7 @@ class ManageFilterOnPage {
4065
4184
  this.ref.close(null);
4066
4185
  }
4067
4186
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageFilterOnPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
4068
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: ManageFilterOnPage, isStandalone: true, selector: "mt-manage-filter-on-page", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, chartItems: { classPropertyName: "chartItems", publicName: "chartItems", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, levelsSchema: { classPropertyName: "levelsSchema", publicName: "levelsSchema", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\r\n class=\"flex h-full min-h-0 flex-col\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <!-- Content -->\r\n <div\r\n class=\"flex-1 min-h-0 overflow-y-auto p-4\"\r\n [class]=\"modal.contentClass\"\r\n >\r\n <div class=\"flex flex-col gap-5\">\r\n <section\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 p-4\"\r\n aria-labelledby=\"db-page-filters-title\"\r\n >\r\n <h3 id=\"db-page-filters-title\" class=\"mb-4 text-base font-semibold\">\r\n {{ t(\"pageFilters\") }}\r\n </h3>\r\n <mt-dynamic-filters-config\r\n [ngModel]=\"filtersConfig()\"\r\n (ngModelChange)=\"onFiltersChange($event)\"\r\n [lookups]=\"lookups()\"\r\n [levelsSchema]=\"levelsSchema()\"\r\n [levelLogs]=\"levelLogs()\"\r\n (loadLevelLogs)=\"onLoadLevelLogs($event)\"\r\n />\r\n </section>\r\n\r\n <section\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 p-4\"\r\n aria-labelledby=\"db-bulk-chart-filters-title\"\r\n >\r\n <h3\r\n id=\"db-bulk-chart-filters-title\"\r\n class=\"mb-2 text-base font-semibold\"\r\n >\r\n {{ t(\"bulkChartFilters\") }}\r\n </h3>\r\n <div class=\"mb-4 text-sm text-muted-color\">\r\n {{ t(\"bulkChartFiltersDescription\") }}\r\n </div>\r\n <mt-selection-configuration\r\n [ngModel]=\"bulkSelection()\"\r\n (ngModelChange)=\"onBulkSelectionChange($event)\"\r\n />\r\n <div class=\"mt-4 flex flex-wrap justify-end gap-2\">\r\n <mt-button\r\n [label]=\"t('applyFilter')\"\r\n icon=\"general.filter-lines\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n (onClick)=\"applyBulkFilters()\"\r\n />\r\n <mt-button\r\n [label]=\"t('deleteFilters')\"\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"deleteBulkFilters()\"\r\n />\r\n </div>\r\n </section>\r\n\r\n <mt-property-translations\r\n [ngModel]=\"bulkLabels()\"\r\n (ngModelChange)=\"onBulkLabelsChange($event)\"\r\n [propertiesFlat]=\"bulkPropertyOptions()\"\r\n [selectedProperties]=\"bulkPropertyKeys()\"\r\n />\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"t('applyLabels')\"\r\n icon=\"general.check\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"applyBulkLabels()\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div\r\n [class]=\"\r\n modal.footerClass +\r\n ' !h-auto !min-h-0 !justify-end !gap-2 !border-t !border-surface-200 !px-4 !py-3'\r\n \"\r\n >\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('save')\" icon=\"general.save-02\" (onClick)=\"save()\" />\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: DynamicFiltersConfig, selector: "mt-dynamic-filters-config", inputs: ["lookups", "levelsSchema", "levelLogs", "productType"], outputs: ["loadLevelLogs"] }, { kind: "component", type: SelectionConfiguration, selector: "mt-selection-configuration", inputs: ["structureLocked", "workspaceId", "modulesProperties", "propertiesFlat"], outputs: ["moduleChange"] }, { kind: "component", type: PropertyTranslationsComponent, selector: "mt-property-translations", inputs: ["propertiesFlat", "selectedProperties"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4187
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: ManageFilterOnPage, isStandalone: true, selector: "mt-manage-filter-on-page", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, levelsSchema: { classPropertyName: "levelsSchema", publicName: "levelsSchema", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\r\n class=\"flex h-full min-h-0 flex-col\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <div\n class=\"flex-1 min-h-0 overflow-y-auto px-4 py-3\"\n [class]=\"modal.contentClass\"\n >\n <mt-dynamic-filters-config\n class=\"block\"\n [ngModel]=\"filtersConfig()\"\n (ngModelChange)=\"onFiltersChange($event)\"\n [lookups]=\"lookups()\"\n [levelsSchema]=\"levelsSchema()\"\n [levelLogs]=\"levelLogs()\"\n (loadLevelLogs)=\"onLoadLevelLogs($event)\"\n />\n </div>\n\n <div\n [class]=\"\r\n modal.footerClass +\r\n ' !h-auto !min-h-0 !justify-end !gap-2 !border-t !border-surface-200 !px-4 !py-3'\r\n \"\r\n >\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('save')\" icon=\"general.save-02\" (onClick)=\"save()\" />\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: DynamicFiltersConfig, selector: "mt-dynamic-filters-config", inputs: ["lookups", "levelsSchema", "levelLogs", "productType"], outputs: ["loadLevelLogs"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4069
4188
  }
4070
4189
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageFilterOnPage, decorators: [{
4071
4190
  type: Component,
@@ -4075,10 +4194,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4075
4194
  TranslocoDirective,
4076
4195
  Button,
4077
4196
  DynamicFiltersConfig,
4078
- SelectionConfiguration,
4079
- PropertyTranslationsComponent,
4080
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\r\n class=\"flex h-full min-h-0 flex-col\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <!-- Content -->\r\n <div\r\n class=\"flex-1 min-h-0 overflow-y-auto p-4\"\r\n [class]=\"modal.contentClass\"\r\n >\r\n <div class=\"flex flex-col gap-5\">\r\n <section\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 p-4\"\r\n aria-labelledby=\"db-page-filters-title\"\r\n >\r\n <h3 id=\"db-page-filters-title\" class=\"mb-4 text-base font-semibold\">\r\n {{ t(\"pageFilters\") }}\r\n </h3>\r\n <mt-dynamic-filters-config\r\n [ngModel]=\"filtersConfig()\"\r\n (ngModelChange)=\"onFiltersChange($event)\"\r\n [lookups]=\"lookups()\"\r\n [levelsSchema]=\"levelsSchema()\"\r\n [levelLogs]=\"levelLogs()\"\r\n (loadLevelLogs)=\"onLoadLevelLogs($event)\"\r\n />\r\n </section>\r\n\r\n <section\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 p-4\"\r\n aria-labelledby=\"db-bulk-chart-filters-title\"\r\n >\r\n <h3\r\n id=\"db-bulk-chart-filters-title\"\r\n class=\"mb-2 text-base font-semibold\"\r\n >\r\n {{ t(\"bulkChartFilters\") }}\r\n </h3>\r\n <div class=\"mb-4 text-sm text-muted-color\">\r\n {{ t(\"bulkChartFiltersDescription\") }}\r\n </div>\r\n <mt-selection-configuration\r\n [ngModel]=\"bulkSelection()\"\r\n (ngModelChange)=\"onBulkSelectionChange($event)\"\r\n />\r\n <div class=\"mt-4 flex flex-wrap justify-end gap-2\">\r\n <mt-button\r\n [label]=\"t('applyFilter')\"\r\n icon=\"general.filter-lines\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n (onClick)=\"applyBulkFilters()\"\r\n />\r\n <mt-button\r\n [label]=\"t('deleteFilters')\"\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"deleteBulkFilters()\"\r\n />\r\n </div>\r\n </section>\r\n\r\n <mt-property-translations\r\n [ngModel]=\"bulkLabels()\"\r\n (ngModelChange)=\"onBulkLabelsChange($event)\"\r\n [propertiesFlat]=\"bulkPropertyOptions()\"\r\n [selectedProperties]=\"bulkPropertyKeys()\"\r\n />\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"t('applyLabels')\"\r\n icon=\"general.check\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"applyBulkLabels()\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div\r\n [class]=\"\r\n modal.footerClass +\r\n ' !h-auto !min-h-0 !justify-end !gap-2 !border-t !border-surface-200 !px-4 !py-3'\r\n \"\r\n >\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('save')\" icon=\"general.save-02\" (onClick)=\"save()\" />\r\n </div>\r\n</div>\r\n" }]
4081
- }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], chartItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "chartItems", required: false }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], levelsSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelsSchema", required: false }] }] } });
4197
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\r\n class=\"flex h-full min-h-0 flex-col\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <div\n class=\"flex-1 min-h-0 overflow-y-auto px-4 py-3\"\n [class]=\"modal.contentClass\"\n >\n <mt-dynamic-filters-config\n class=\"block\"\n [ngModel]=\"filtersConfig()\"\n (ngModelChange)=\"onFiltersChange($event)\"\n [lookups]=\"lookups()\"\n [levelsSchema]=\"levelsSchema()\"\n [levelLogs]=\"levelLogs()\"\n (loadLevelLogs)=\"onLoadLevelLogs($event)\"\n />\n </div>\n\n <div\n [class]=\"\r\n modal.footerClass +\r\n ' !h-auto !min-h-0 !justify-end !gap-2 !border-t !border-surface-200 !px-4 !py-3'\r\n \"\r\n >\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('save')\" icon=\"general.save-02\" (onClick)=\"save()\" />\r\n </div>\r\n</div>\r\n" }]
4198
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], levelsSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelsSchema", required: false }] }] } });
4082
4199
 
4083
4200
  /**
4084
4201
  * Map a manifest entry to the public ChartTypeConfig shape so that
@@ -9114,7 +9231,7 @@ class DisplaySettings {
9114
9231
  return '';
9115
9232
  }
9116
9233
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DisplaySettings, deps: [], target: i0.ɵɵFactoryTarget.Component });
9117
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DisplaySettings, isStandalone: true, selector: "mt-display-settings", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, chartType: { classPropertyName: "chartType", publicName: "chartType", isSignal: true, isRequired: false, transformFunction: null }, availableProperties: { classPropertyName: "availableProperties", publicName: "availableProperties", isSignal: true, isRequired: false, transformFunction: null }, selectedProperties: { classPropertyName: "selectedProperties", publicName: "selectedProperties", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clientConfigChange: "clientConfigChange" }, ngImport: i0, template: "<div class=\"flex flex-col gap-6\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Header Configuration -->\r\n @if (\r\n shouldShowField(\"centerHeader\") || shouldShowField(\"advancedHeaderConfig\")\r\n ) {\r\n <mt-card [title]=\"t('headerConfiguration')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-5\">\r\n @if (shouldShowField(\"centerHeader\")) {\r\n <mt-toggle-field\r\n [label]=\"t('centerHeader')\"\r\n [ngModel]=\"headerCardConfig().isHeaderCentered || false\"\r\n (ngModelChange)=\"updateHeaderCardConfig('isHeaderCentered', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"advancedHeaderConfig\")) {\r\n <mt-toggle-field\r\n [label]=\"t('hideHeader')\"\r\n [ngModel]=\"headerCardConfig().isHeaderHidden || false\"\r\n (ngModelChange)=\"updateHeaderCardConfig('isHeaderHidden', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('headerColor')\"\r\n [ngModel]=\"headerCardConfig().headerColor || ''\"\r\n (ngModelChange)=\"updateHeaderCardConfig('headerColor', $event)\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('headerFontSize')\"\r\n [ngModel]=\"headerCardConfig().headerFontSize || 14\"\r\n (ngModelChange)=\"updateHeaderCardConfig('headerFontSize', $event)\"\r\n [min]=\"10\"\r\n [max]=\"48\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Colors Section (for cards) -->\r\n @if (\r\n shouldShowField(\"bgColor\") ||\r\n shouldShowField(\"textColor\") ||\r\n shouldShowField(\"icon\")\r\n ) {\r\n <mt-card [title]=\"t('cardColors')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-5\">\r\n @if (shouldShowField(\"bgColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('backgroundColor')\"\r\n [ngModel]=\"styleConfig()['background-color'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('background-color', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"textColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('textColor')\"\r\n [ngModel]=\"styleConfig()['color'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('color', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"icon\")) {\r\n <mt-icon-field\r\n [label]=\"t('icon')\"\r\n [ngModel]=\"configAsType()['icon'] || ''\"\r\n (ngModelChange)=\"updateConfigAsType('icon', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"iconColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('iconColor')\"\r\n [ngModel]=\"styleConfig()['iconColor'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('iconColor', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"iconBgColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('iconBgColor')\"\r\n [ngModel]=\"styleConfig()['iconBgColor'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('iconBgColor', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"positionTitle\")) {\r\n <mt-select-field\r\n [label]=\"t('positionTitle')\"\r\n [ngModel]=\"styleConfig()['justify-content'] || 'start'\"\r\n (ngModelChange)=\"updateStyleConfig('justify-content', $event)\"\r\n [options]=\"positionOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Border Top Section -->\r\n @if (shouldShowField(\"borderTop\")) {\r\n <mt-card [title]=\"t('borderTop')\">\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-5\">\r\n <mt-toggle-field\r\n [label]=\"t('showBorderTop')\"\r\n [ngModel]=\"styleConfig()['border-top-show'] || false\"\r\n (ngModelChange)=\"updateBorderTopShow($event)\"\r\n />\r\n @if (styleConfig()[\"border-top-show\"]) {\r\n <mt-color-picker-field\r\n [label]=\"t('borderTopColor')\"\r\n [ngModel]=\"\r\n styleConfig()['border-top-color'] ||\r\n styleConfig()['border-color'] ||\r\n '#3b82f6'\r\n \"\r\n (ngModelChange)=\"updateBorderTopColor($event)\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Card Style Configuration -->\r\n @if (shouldShowField(\"cardStyleConfig\")) {\r\n <mt-card [title]=\"t('cardStyle')\">\r\n <div class=\"grid grid-cols-1 gap-5 mb-6\">\r\n <mt-slider-field\r\n [label]=\"t('borderRadius')\"\r\n [ngModel]=\"cardStyleConfig().borderRadius || 8\"\r\n (ngModelChange)=\"updateCardStyleConfig('borderRadius', $event)\"\r\n [min]=\"0\"\r\n [max]=\"24\"\r\n [step]=\"1\"\r\n unit=\"px\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('cardBackgroundColor')\"\r\n [ngModel]=\"cardStyleConfig().backgroundColor || ''\"\r\n (ngModelChange)=\"updateCardStyleConfig('backgroundColor', $event)\"\r\n />\r\n </div>\r\n\r\n <!-- Shadows -->\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-3\">\r\n <span class=\"font-medium\">{{ t(\"shadows\") }}</span>\r\n <mt-button\r\n [label]=\"t('addShadow')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addShadow()\"\r\n />\r\n </div>\r\n\r\n @for (\r\n shadow of cardStyleConfig().shadows || [];\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"mb-3 rounded-lg border border-surface-200 bg-surface-50 p-4\"\r\n >\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\r\n <span class=\"text-sm font-medium\"\r\n >{{ t(\"shadow\") }} {{ i + 1 }}</span\r\n >\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeShadow(i)\"\r\n />\r\n </div>\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <mt-number-field\r\n [label]=\"t('x')\"\r\n [ngModel]=\"shadow.x\"\r\n (ngModelChange)=\"updateShadow(i, 'x', $event)\"\r\n size=\"small\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('y')\"\r\n [ngModel]=\"shadow.y\"\r\n (ngModelChange)=\"updateShadow(i, 'y', $event)\"\r\n size=\"small\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('blur')\"\r\n [ngModel]=\"shadow.blur\"\r\n (ngModelChange)=\"updateShadow(i, 'blur', $event)\"\r\n size=\"small\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('spread')\"\r\n [ngModel]=\"shadow.spread\"\r\n (ngModelChange)=\"updateShadow(i, 'spread', $event)\"\r\n size=\"small\"\r\n />\r\n <div class=\"md:col-span-2\">\r\n <mt-color-picker-field\r\n [label]=\"t('color')\"\r\n [ngModel]=\"shadow.color\"\r\n (ngModelChange)=\"updateShadow(i, 'color', $event)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Legend Settings -->\r\n @if (shouldShowField(\"legend\")) {\r\n <mt-card [title]=\"t('legendSettings')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('showLegend')\"\r\n [ngModel]=\"legendConfig().show || false\"\r\n (ngModelChange)=\"updateLegend('show', $event)\"\r\n />\r\n @if (legendConfig().show) {\r\n <mt-select-field\r\n [label]=\"t('legendPosition')\"\r\n [ngModel]=\"legendConfig().position || 'bottom'\"\r\n (ngModelChange)=\"updateLegend('position', $event)\"\r\n [options]=\"legendPositionOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n @if (shouldShowField(\"legendIconType\")) {\r\n <mt-select-field\r\n [label]=\"t('legendIconType')\"\r\n [ngModel]=\"legendConfig().iconType || 'circle'\"\r\n (ngModelChange)=\"updateLegend('iconType', $event)\"\r\n [options]=\"legendIconOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n }\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Label Settings -->\r\n @if (shouldShowField(\"label\")) {\r\n <mt-card [title]=\"t('labelSettings')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('showLabels')\"\r\n [ngModel]=\"labelConfig().show || false\"\r\n (ngModelChange)=\"updateLabel('show', $event)\"\r\n />\r\n @if (labelConfig().show) {\r\n <mt-select-field\r\n [label]=\"t('labelPosition')\"\r\n [ngModel]=\"labelConfig().position || 'inside'\"\r\n (ngModelChange)=\"updateLabel('position', $event)\"\r\n [options]=\"labelPositionOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n @if (shouldShowField(\"showTotal\")) {\r\n <mt-toggle-field\r\n [label]=\"t('showTotalInTop')\"\r\n [ngModel]=\"labelConfig().showTotalInTop || false\"\r\n (ngModelChange)=\"updateLabel('showTotalInTop', $event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Label Center (for Pie/Donut charts) -->\r\n @if (shouldShowField(\"labelCenter\")) {\r\n <mt-card [title]=\"t('labelCenter')\">\r\n <div class=\"grid grid-cols-1 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('hideLabelCenter')\"\r\n [ngModel]=\"labelCenterConfig().hide || false\"\r\n (ngModelChange)=\"updateLabelCenterConfig('hide', $event)\"\r\n />\r\n @if (!labelCenterConfig().hide) {\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('labelCenterTextEn')\"\r\n [ngModel]=\"labelCenterConfig().text?.en || ''\"\r\n (ngModelChange)=\"updateLabelCenterText('en', $event)\"\r\n [placeholder]=\"t('enterLabelCenterText')\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('labelCenterTextAr')\"\r\n [ngModel]=\"labelCenterConfig().text?.ar || ''\"\r\n (ngModelChange)=\"updateLabelCenterText('ar', $event)\"\r\n [placeholder]=\"t('enterLabelCenterText')\"\r\n dir=\"rtl\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Override Labels -->\r\n @if (shouldShowField(\"overrideLabels\")) {\r\n <mt-card [title]=\"t('overrideLabels')\">\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-4\">\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"overrideLabelsDescription\")\r\n }}</span>\r\n <mt-button\r\n [label]=\"t('addLabel')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addOverrideLabel()\"\r\n />\r\n </div>\r\n\r\n @for (\r\n label of overrideLabels();\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"mb-3 rounded-lg border border-surface-200 bg-surface-50 p-4\"\r\n >\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\r\n <span class=\"text-sm font-medium\"\r\n >{{ t(\"label\") }} {{ i + 1 }}</span\r\n >\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeOverrideLabel(i)\"\r\n />\r\n </div>\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-3\">\r\n <mt-text-field\r\n [label]=\"t('labelEn')\"\r\n [ngModel]=\"label.en\"\r\n (ngModelChange)=\"updateOverrideLabel(i, 'en', $event)\"\r\n [placeholder]=\"t('enterLabelEn')\"\r\n size=\"small\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('labelAr')\"\r\n [ngModel]=\"label.ar\"\r\n (ngModelChange)=\"updateOverrideLabel(i, 'ar', $event)\"\r\n [placeholder]=\"t('enterLabelAr')\"\r\n dir=\"rtl\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (overrideLabels().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noOverrideLabels\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Sort Data Bars -->\r\n @if (shouldShowField(\"sortDataBars\")) {\r\n <mt-card [title]=\"t('sortDataBars')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('enableSorting')\"\r\n [ngModel]=\"sortDataBarsConfig().enable || false\"\r\n (ngModelChange)=\"updateSortDataBarsConfig('enable', $event)\"\r\n />\r\n @if (sortDataBarsConfig().enable) {\r\n <mt-text-field\r\n [label]=\"t('sortBy')\"\r\n [ngModel]=\"sortDataBarsConfig().sortBy || ''\"\r\n (ngModelChange)=\"updateSortDataBarsConfig('sortBy', $event)\"\r\n [placeholder]=\"t('propertyKey')\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('order')\"\r\n [ngModel]=\"sortDataBarsConfig().order || 'asc'\"\r\n (ngModelChange)=\"updateSortDataBarsConfig('order', $event)\"\r\n [options]=\"orderTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Default Colors (for charts) -->\r\n @if (shouldShowField(\"defaultColors\")) {\r\n <mt-card [title]=\"t('defaultColors')\">\r\n <div class=\"flex flex-wrap gap-2 mb-4\">\r\n @for (\r\n color of defaultColors();\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"flex items-center gap-1 p-2 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-color-picker-field\r\n [ngModel]=\"color\"\r\n (ngModelChange)=\"updateDefaultColor(i, $event)\"\r\n />\r\n <mt-button\r\n icon=\"general.x-close\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeDefaultColor(i)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"flex flex-wrap gap-2 items-center\">\r\n <span class=\"text-sm text-muted-color xl:mr-2\"\r\n >{{ t(\"quickAdd\") }}:</span\r\n >\r\n @for (color of defaultColorPalette; track color) {\r\n <button\r\n type=\"button\"\r\n class=\"w-6 h-6 rounded cursor-pointer border border-surface-300 hover:scale-110 transition-transform\"\r\n [style.background-color]=\"color\"\r\n (click)=\"addDefaultColor(color)\"\r\n [pTooltip]=\"color\"\r\n tooltipPosition=\"top\"\r\n ></button>\r\n }\r\n </div>\r\n\r\n @if (defaultColors().length === 0) {\r\n <div class=\"text-center py-2 text-muted-color text-sm mt-2\">\r\n {{ t(\"noColorsSelected\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Card Info -->\r\n @if (shouldShowField(\"cardInfo\")) {\r\n <mt-card [title]=\"t('cardInfo')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('showCardInfo')\"\r\n [ngModel]=\"cardInfo().show || false\"\r\n (ngModelChange)=\"updateCardInfoConfig('show', $event)\"\r\n />\r\n @if (cardInfo().show) {\r\n <mt-text-field\r\n [label]=\"t('cardInfoValue')\"\r\n [ngModel]=\"cardInfo().value || ''\"\r\n (ngModelChange)=\"updateCardInfoConfig('value', $event)\"\r\n [placeholder]=\"t('enterCardInfoValue')\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Table Settings -->\r\n @if (shouldShowField(\"hideIndex\")) {\r\n <mt-card [title]=\"t('tableSettings')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('hideIndex')\"\r\n [ngModel]=\"configAsType()['hideIndex'] || false\"\r\n (ngModelChange)=\"updateConfigAsType('hideIndex', $event)\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Map Settings -->\r\n @if (shouldShowField(\"mapChart\")) {\r\n <mt-card [title]=\"t('mapSettings')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('mapType')\"\r\n [ngModel]=\"config()?.clientConfig?.['map'] || 'SaudiArabia'\"\r\n (ngModelChange)=\"updateMapType($event)\"\r\n [options]=\"mapOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Format Configuration -->\r\n @if (shouldShowField(\"format\")) {\r\n <mt-card [title]=\"t('formatConfiguration')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('formatType')\"\r\n [ngModel]=\"formatConfig().type\"\r\n (ngModelChange)=\"updateFormatConfig('type', $event)\"\r\n [options]=\"formatTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectFormat')\"\r\n />\r\n\r\n @if (formatConfig().type === \"currency\") {\r\n <mt-toggle-field\r\n [label]=\"t('showCurrency')\"\r\n [ngModel]=\"formatConfig().showCurrency || false\"\r\n (ngModelChange)=\"updateFormatConfig('showCurrency', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('showCurrencyTooltip')\"\r\n [ngModel]=\"formatConfig().showCurrencyTooltip || false\"\r\n (ngModelChange)=\"updateFormatConfig('showCurrencyTooltip', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('handleLanguage')\"\r\n [ngModel]=\"formatConfig().handleLang || false\"\r\n (ngModelChange)=\"updateFormatConfig('handleLang', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('hideSuffixes')\"\r\n [ngModel]=\"formatConfig().hideSuffixes || false\"\r\n (ngModelChange)=\"updateFormatConfig('hideSuffixes', $event)\"\r\n />\r\n }\r\n\r\n @if (formatConfig().type === \"custom\") {\r\n <mt-text-field\r\n [label]=\"t('customText')\"\r\n [ngModel]=\"formatConfig().customText || ''\"\r\n (ngModelChange)=\"updateFormatConfig('customText', $event)\"\r\n [placeholder]=\"t('enterCustomText')\"\r\n />\r\n }\r\n\r\n @if (formatConfig().type === \"date\") {\r\n <mt-text-field\r\n [label]=\"t('dateFormat')\"\r\n [ngModel]=\"formatConfig().customDateFormat || ''\"\r\n (ngModelChange)=\"updateFormatConfig('customDateFormat', $event)\"\r\n [placeholder]=\"'YYYY-MM-DD'\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Table Format Configuration -->\r\n @if (shouldShowField(\"tableFormat\")) {\r\n <mt-card [title]=\"t('tableFormatConfiguration')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Colors -->\r\n <mt-color-picker-field\r\n [label]=\"t('headerTextColor')\"\r\n [ngModel]=\"tableFormatConfig().thTextColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('thTextColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('headerBackgroundColor')\"\r\n [ngModel]=\"tableFormatConfig().thBackgroundColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('thBackgroundColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('cellTextColor')\"\r\n [ngModel]=\"tableFormatConfig().tdTextColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('tdTextColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('groupBackgroundColor')\"\r\n [ngModel]=\"tableFormatConfig().groupBackgroundColor || ''\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('groupBackgroundColor', $event)\r\n \"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('groupTextColor')\"\r\n [ngModel]=\"tableFormatConfig().groupTextColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('groupTextColor', $event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Font Settings -->\r\n <mt-toggle-field\r\n [label]=\"t('boldHeaderFont')\"\r\n [ngModel]=\"tableFormatConfig().thFontBold || false\"\r\n (ngModelChange)=\"updateTableFormatConfig('thFontBold', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('boldCellFont')\"\r\n [ngModel]=\"tableFormatConfig().tdFontBold || false\"\r\n (ngModelChange)=\"updateTableFormatConfig('tdFontBold', $event)\"\r\n />\r\n <div>\r\n <label class=\"block text-sm font-medium mb-2\"\r\n >{{ t(\"headerFontSize\") }}:\r\n {{ tableFormatConfig().thFontSize || 14 }}px</label\r\n >\r\n <mt-slider-field\r\n [ngModel]=\"tableFormatConfig().thFontSize || 14\"\r\n (ngModelChange)=\"updateTableFormatConfig('thFontSize', $event)\"\r\n [min]=\"8\"\r\n [max]=\"32\"\r\n [step]=\"1\"\r\n />\r\n </div>\r\n <div>\r\n <label class=\"block text-sm font-medium mb-2\"\r\n >{{ t(\"cellFontSize\") }}:\r\n {{ tableFormatConfig().tdFontSize || 14 }}px</label\r\n >\r\n <mt-slider-field\r\n [ngModel]=\"tableFormatConfig().tdFontSize || 14\"\r\n (ngModelChange)=\"updateTableFormatConfig('tdFontSize', $event)\"\r\n [min]=\"8\"\r\n [max]=\"32\"\r\n [step]=\"1\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Options -->\r\n <mt-toggle-field\r\n [label]=\"t('hideTableSubheader')\"\r\n [ngModel]=\"tableFormatConfig().hideTableSubheader || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('hideTableSubheader', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('disableCurrencyFormat')\"\r\n [ngModel]=\"tableFormatConfig().disableCurrencyFormat || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('disableCurrencyFormat', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('showPercentageAsProgressBar')\"\r\n [ngModel]=\"tableFormatConfig().showPercentageAsProgressBar || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('showPercentageAsProgressBar', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('showPercentageStatus')\"\r\n [ngModel]=\"tableFormatConfig().showPercentageStatus || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('showPercentageStatus', $event)\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Sort & Hidden Columns -->\r\n <mt-select-field\r\n [label]=\"t('sortColumn')\"\r\n [ngModel]=\"tableFormatConfig().sortConfig?.column || ''\"\r\n (ngModelChange)=\"updateTableFormatSortConfig('column', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectColumn')\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('sortDirection')\"\r\n [ngModel]=\"tableFormatConfig().sortConfig?.direction || 'asc'\"\r\n (ngModelChange)=\"updateTableFormatSortConfig('direction', $event)\"\r\n [options]=\"orderTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n <mt-multi-select-field\r\n [label]=\"t('hiddenColumns')\"\r\n [ngModel]=\"tableFormatConfig().hiddenColumns || []\"\r\n (ngModelChange)=\"updateTableFormatConfig('hiddenColumns', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectColumns')\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <mt-button\r\n [label]=\"t('resetToDefault')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"resetTableFormat()\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Color By Condition -->\r\n @if (shouldShowField(\"colorByCondition\")) {\r\n <mt-card [title]=\"t('colorByCondition')\">\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-4\">\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"colorByConditionDescription\")\r\n }}</span>\r\n <mt-button\r\n [label]=\"t('add')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addColorConditionIndex()\"\r\n />\r\n </div>\r\n\r\n @for (barIndex of getColorConditionIndexes(); track barIndex) {\r\n <div class=\"mb-4 border border-surface-200 rounded-lg\">\r\n <div\r\n class=\"flex flex-wrap items-center justify-between gap-2 p-3 bg-surface-50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"text-sm text-muted-color\"\r\n (click)=\"toggleColorConditionExpanded(barIndex)\"\r\n >\r\n {{ isColorConditionExpanded(barIndex) ? \"-\" : \"+\" }}\r\n </button>\r\n <span class=\"font-medium text-sm\"\r\n >{{ t(\"bar\") }} {{ barIndex }}</span\r\n >\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n addColorCondition(barIndex); $event.stopPropagation()\r\n \"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n removeColorConditionIndex(barIndex); $event.stopPropagation()\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n @if (isColorConditionExpanded(barIndex)) {\r\n <div class=\"p-3\">\r\n <div\r\n class=\"flex flex-wrap items-center justify-between gap-2 mb-3\"\r\n >\r\n <span class=\"text-sm font-medium\">{{ t(\"conditions\") }}</span>\r\n <mt-button\r\n [label]=\"t('addCondition')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"addColorCondition(barIndex)\"\r\n />\r\n </div>\r\n\r\n @for (\r\n condition of colorByCondition()[barIndex] || [];\r\n track trackByIndex($index);\r\n let condIndex = $index\r\n ) {\r\n <div class=\"p-3 border border-surface-200 rounded-lg mb-3\">\r\n <div\r\n class=\"grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-3 items-end\"\r\n >\r\n <mt-color-picker-field\r\n [label]=\"t('color')\"\r\n [ngModel]=\"condition.color\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'color',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('condition')\"\r\n [ngModel]=\"condition.type\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'type',\r\n $event\r\n )\r\n \"\r\n [options]=\"colorConditionTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n <mt-number-field\r\n [label]=\"\r\n condition.type === 'between' ? t('from') : t('value')\r\n \"\r\n [ngModel]=\"condition.value1\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'value1',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n />\r\n @if (condition.type === \"between\") {\r\n <mt-number-field\r\n [label]=\"t('to')\"\r\n [ngModel]=\"condition.value2\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'value2',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n />\r\n }\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeColorCondition(barIndex, condIndex)\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-3 mt-3\">\r\n <mt-text-field\r\n [label]=\"t('labelEn')\"\r\n [ngModel]=\"condition.labelEn || ''\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'labelEn',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('labelAr')\"\r\n [ngModel]=\"condition.labelAr || ''\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'labelAr',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n dir=\"rtl\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if ((colorByCondition()[barIndex] || []).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noColorConditions\") }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getColorConditionIndexes().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noColorConditions\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Timeline Header Colors -->\r\n @if (shouldShowField(\"timelineHeaderColorsConfig\")) {\r\n <mt-card [title]=\"t('timelineHeaderColors')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-color-picker-field\r\n [label]=\"t('backgroundColor')\"\r\n [ngModel]=\"timelineHeaderColorsSingle().bgColor || ''\"\r\n (ngModelChange)=\"updateTimelineHeaderColorSingle('bgColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('textColor')\"\r\n [ngModel]=\"timelineHeaderColorsSingle().color || ''\"\r\n (ngModelChange)=\"updateTimelineHeaderColorSingle('color', $event)\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Ring Gauge Configuration -->\r\n @if (shouldShowField(\"ringGaugeConfig\")) {\r\n <mt-card [title]=\"t('ringGaugeConfiguration')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('centerProperty')\"\r\n [ngModel]=\"ringGaugeConfig().centerProperty || ''\"\r\n (ngModelChange)=\"updateRingGaugeConfig('centerProperty', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('statusProperty')\"\r\n [ngModel]=\"ringGaugeConfig().statusProperty || ''\"\r\n (ngModelChange)=\"updateRingGaugeConfig('statusProperty', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n <div class=\"mt-4\">\r\n <mt-multi-select-field\r\n [label]=\"t('hiddenProperties')\"\r\n [ngModel]=\"ringGaugeConfig().hiddenProperties || []\"\r\n (ngModelChange)=\"updateRingGaugeConfig('hiddenProperties', $event)\"\r\n [options]=\"ringGaugeHiddenOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperties')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Order Configuration -->\r\n @if (shouldShowField(\"orderConfig\")) {\r\n <mt-card [title]=\"t('orderConfiguration')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4 mb-4\">\r\n <mt-select-field\r\n [label]=\"t('operation')\"\r\n [ngModel]=\"orderConfig().operation || 'deleteNotEqual'\"\r\n (ngModelChange)=\"updateOrderConfig('operation', $event)\"\r\n [options]=\"orderOperationOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('orderBy')\"\r\n [ngModel]=\"orderConfig().orderBy || ''\"\r\n (ngModelChange)=\"updateOrderConfig('orderBy', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-4\">\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"orderConfigurationDescription\")\r\n }}</span>\r\n <mt-button\r\n [label]=\"t('addOrderItem')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addOrderItem()\"\r\n />\r\n </div>\r\n\r\n @for (\r\n item of orderConfig().order || [];\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"mb-3 flex flex-col gap-3 rounded-lg border border-surface-200 bg-surface-50 p-4 xl:flex-row xl:items-center\"\r\n >\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n <span class=\"text-sm font-medium w-auto xl:w-8\">{{ i + 1 }}.</span>\r\n <mt-select-field\r\n [ngModel]=\"item\"\r\n (ngModelChange)=\"updateOrderItem(i, $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n size=\"small\"\r\n class=\"min-w-0 flex-1\"\r\n />\r\n </div>\r\n <div class=\"flex items-center justify-end gap-1\">\r\n <mt-button\r\n icon=\"general.chevron-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"i === 0\"\r\n (onClick)=\"moveOrderItemUp(i)\"\r\n />\r\n <mt-button\r\n icon=\"general.chevron-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"i === (orderConfig().order || []).length - 1\"\r\n (onClick)=\"moveOrderItemDown(i)\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeOrderItem(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if ((orderConfig().order || []).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noOrderItems\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Card List Configuration -->\r\n @if (shouldShowField(\"cardListConfig\")) {\r\n <mt-card [title]=\"t('cardListConfiguration')\">\r\n <mt-multi-select-field\r\n [label]=\"t('hideProperties')\"\r\n [ngModel]=\"cardListConfig().hideProperties || []\"\r\n (ngModelChange)=\"updateCardListHideProperties($event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectPropertiesToHide')\"\r\n />\r\n </mt-card>\r\n }\r\n\r\n <!-- Props Config As Index -->\r\n @if (shouldShowPropertiesViewSettings()) {\r\n <mt-card [title]=\"t('entityPreviewSettings')\">\r\n @if (propertiesViewRows().length === 0) {\r\n <div class=\"py-4 text-sm text-muted-color\">\r\n {{ t(\"selectPropertiesFirst\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-4\">\r\n @for (property of propertiesViewRows(); track property.key) {\r\n <div class=\"rounded-xl border border-surface-200 bg-surface-50 p-5\">\r\n <div class=\"mb-4\">\r\n <div class=\"text-sm font-semibold text-surface-900\">\r\n {{ property.label }}\r\n </div>\r\n @if (property.label !== property.key) {\r\n <div class=\"mt-1 text-xs text-muted-color\">\r\n {{ property.key }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('width')\"\r\n [ngModel]=\"property.config.width || ''\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(property.index, 'width', $event)\r\n \"\r\n [placeholder]=\"'100%'\"\r\n size=\"small\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('colorProperty')\"\r\n [ngModel]=\"property.config.colorAsProperty || ''\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(\r\n property.index,\r\n 'colorAsProperty',\r\n $event\r\n )\r\n \"\r\n [options]=\"selectedPropertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectColorProperty')\"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n size=\"small\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('border')\"\r\n [ngModel]=\"!!property.config.border\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(property.index, 'border', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('hidden')\"\r\n [ngModel]=\"property.config.hidden || false\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(property.index, 'hidden', $event)\r\n \"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Toggle Association -->\r\n @if (shouldShowField(\"toggleAssociation\")) {\r\n <mt-card [title]=\"t('toggleAssociation')\">\r\n <mt-toggle-field\r\n [label]=\"t('enableToggleAssociation')\"\r\n [ngModel]=\"toggleAssociation()\"\r\n (ngModelChange)=\"updateToggleAssociation($event)\"\r\n />\r\n </mt-card>\r\n }\r\n\r\n <!-- Property Translations -->\r\n @if (\r\n shouldShowField(\"propertyTranslations\") &&\r\n resolvedSelectedProperties().length > 0\r\n ) {\r\n <mt-card [title]=\"t('propertyTranslations')\">\r\n <div class=\"space-y-4\">\r\n @for (property of propertyTranslationRows(); track property.key) {\r\n <div class=\"rounded-xl border border-surface-200 bg-surface-50 p-5\">\r\n <div class=\"mb-4\">\r\n <div class=\"text-sm font-semibold text-surface-900\">\r\n {{ property.label }}\r\n </div>\r\n @if (property.label !== property.key) {\r\n <div class=\"mt-1 text-xs text-muted-color\">\r\n {{ property.key }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('englishLabel')\"\r\n [ngModel]=\"property.translation.en\"\r\n (ngModelChange)=\"\r\n updatePropertyTranslation(property.key, 'en', $event)\r\n \"\r\n [placeholder]=\"t('enterEnglishLabel')\"\r\n size=\"small\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('arabicLabel')\"\r\n [ngModel]=\"property.translation.ar\"\r\n (ngModelChange)=\"\r\n updatePropertyTranslation(property.key, 'ar', $event)\r\n \"\r\n [placeholder]=\"t('enterArabicLabel')\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (propertyTranslationRows().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noPropertyTranslations\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Property Colors -->\r\n @if (\r\n shouldShowField(\"propertyColors\") && resolvedSelectedProperties().length > 0\r\n ) {\r\n <mt-card [title]=\"t('propertyColors')\">\r\n <ng-template #cardEnd>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"general.copy-01\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"copyPropertyColors()\"\r\n [pTooltip]=\"t('copyConfig')\"\r\n />\r\n <mt-button\r\n icon=\"general.clipboard\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"togglePropertyColorsPaste()\"\r\n [pTooltip]=\"t('pasteConfig')\"\r\n />\r\n </div>\r\n </ng-template>\r\n\r\n @if (showPropertyColorsPaste()) {\r\n <div\r\n class=\"mb-4 p-4 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-textarea-field\r\n [label]=\"t('pasteConfiguration')\"\r\n [ngModel]=\"propertyColorsPasteText()\"\r\n (ngModelChange)=\"propertyColorsPasteText.set($event)\"\r\n [placeholder]=\"t('pasteConfigurationPlaceholder')\"\r\n [rows]=\"4\"\r\n />\r\n @if (propertyColorsPasteError()) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n propertyColorsPasteError()\r\n }}</small>\r\n }\r\n <div class=\"flex justify-end gap-2 mt-3\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"togglePropertyColorsPaste()\"\r\n />\r\n <mt-button\r\n [label]=\"t('apply')\"\r\n size=\"small\"\r\n (onClick)=\"applyPropertyColorsPaste()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Property Selection -->\r\n <div class=\"mb-4\">\r\n <div class=\"flex flex-wrap items-end gap-2 xl:flex-nowrap\">\r\n <div class=\"flex-1\">\r\n <mt-select-field\r\n [label]=\"t('selectProperty')\"\r\n [ngModel]=\"selectedPropertyForColor()\"\r\n (ngModelChange)=\"selectedPropertyForColor.set($event)\"\r\n [options]=\"availableColorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"!selectedPropertyForColor()\"\r\n (onClick)=\"\r\n addPropertyColor(selectedPropertyForColor());\r\n selectedPropertyForColor.set('')\r\n \"\r\n [pTooltip]=\"t('addProperty')\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- Property Color List -->\r\n @for (propKey of getPropertyColorKeys(); track propKey) {\r\n <div\r\n class=\"mb-3 rounded-lg border border-surface-200 bg-surface-50 p-4\"\r\n >\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\r\n <span class=\"font-medium text-sm\">{{ propKey }}</span>\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removePropertyColor(propKey)\"\r\n />\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('selectColorProperty')\"\r\n [ngModel]=\"propertyColors()[propKey]?.selectedKey || ''\"\r\n (ngModelChange)=\"updatePropertyColor(propKey, $event)\"\r\n [options]=\"allPropertyKeyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n size=\"small\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (getPropertyColorKeys().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noPropertyColors\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Format X-Axis Configuration -->\r\n @if (shouldShowField(\"formatXAxis\")) {\r\n <mt-card [title]=\"t('formatXAxisConfiguration')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('formatType')\"\r\n [ngModel]=\"formatXAxisConfig().type\"\r\n (ngModelChange)=\"updateFormatXAxisConfig('type', $event)\"\r\n [options]=\"formatXAxisTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectFormat')\"\r\n />\r\n @if (\r\n formatXAxisConfig().type === \"dateToMonth\" ||\r\n formatXAxisConfig().type === \"month\"\r\n ) {\r\n <mt-toggle-field\r\n [label]=\"t('shortFormat')\"\r\n [ngModel]=\"formatXAxisConfig().shortFormate || false\"\r\n (ngModelChange)=\"updateFormatXAxisConfig('shortFormate', $event)\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Extra Column From Lookup -->\r\n @if (shouldShowField(\"extraColumnFromLookup\")) {\r\n <mt-card [title]=\"t('extraColumnFromLookup')\">\r\n <div class=\"grid grid-cols-1 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('enableExtraColumnFromLookup')\"\r\n [ngModel]=\"tableColumnsConfig().extraCoulmnFromLookup || false\"\r\n (ngModelChange)=\"\r\n updateTableColumnsConfig('extraCoulmnFromLookup', $event)\r\n \"\r\n />\r\n\r\n @if (tableColumnsConfig().extraCoulmnFromLookup) {\r\n <mt-select-field\r\n [label]=\"t('lookup')\"\r\n [ngModel]=\"tableColumnsConfig().lookupId\"\r\n (ngModelChange)=\"updateTableColumnsConfig('lookupId', $event)\"\r\n [options]=\"lookups()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"id\"\r\n [placeholder]=\"t('selectLookup')\"\r\n />\r\n\r\n <mt-select-field\r\n [label]=\"t('groupedBy')\"\r\n [ngModel]=\"tableColumnsConfig().groupedBy\"\r\n (ngModelChange)=\"updateTableColumnsConfig('groupedBy', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n />\r\n\r\n <mt-select-field\r\n [label]=\"t('propertyValue')\"\r\n [ngModel]=\"tableColumnsConfig().propKey\"\r\n (ngModelChange)=\"updateTableColumnsConfig('propKey', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: SliderField, selector: "mt-slider-field", inputs: ["field", "label", "class", "min", "max", "step", "hideNumber", "unit", "readonly", "required"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: IconField, selector: "mt-icon-field", inputs: ["label", "required"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
9234
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DisplaySettings, isStandalone: true, selector: "mt-display-settings", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, chartType: { classPropertyName: "chartType", publicName: "chartType", isSignal: true, isRequired: false, transformFunction: null }, availableProperties: { classPropertyName: "availableProperties", publicName: "availableProperties", isSignal: true, isRequired: false, transformFunction: null }, selectedProperties: { classPropertyName: "selectedProperties", publicName: "selectedProperties", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clientConfigChange: "clientConfigChange" }, ngImport: i0, template: "<div class=\"flex flex-col gap-6\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Header Configuration -->\r\n @if (\r\n shouldShowField(\"centerHeader\") || shouldShowField(\"advancedHeaderConfig\")\r\n ) {\r\n <mt-card [title]=\"t('headerConfiguration')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-5\">\r\n @if (shouldShowField(\"centerHeader\")) {\r\n <mt-toggle-field\r\n [label]=\"t('centerHeader')\"\r\n [ngModel]=\"headerCardConfig().isHeaderCentered || false\"\r\n (ngModelChange)=\"updateHeaderCardConfig('isHeaderCentered', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"advancedHeaderConfig\")) {\r\n <mt-toggle-field\r\n [label]=\"t('hideHeader')\"\r\n [ngModel]=\"headerCardConfig().isHeaderHidden || false\"\r\n (ngModelChange)=\"updateHeaderCardConfig('isHeaderHidden', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('headerColor')\"\r\n [ngModel]=\"headerCardConfig().headerColor || ''\"\r\n (ngModelChange)=\"updateHeaderCardConfig('headerColor', $event)\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('headerFontSize')\"\r\n [ngModel]=\"headerCardConfig().headerFontSize || 14\"\r\n (ngModelChange)=\"updateHeaderCardConfig('headerFontSize', $event)\"\r\n [min]=\"10\"\r\n [max]=\"48\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Colors Section (for cards) -->\r\n @if (\r\n shouldShowField(\"bgColor\") ||\r\n shouldShowField(\"textColor\") ||\r\n shouldShowField(\"icon\")\r\n ) {\r\n <mt-card [title]=\"t('cardColors')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-5\">\r\n @if (shouldShowField(\"bgColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('backgroundColor')\"\r\n [ngModel]=\"styleConfig()['background-color'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('background-color', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"textColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('textColor')\"\r\n [ngModel]=\"styleConfig()['color'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('color', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"icon\")) {\r\n <mt-icon-field\r\n [label]=\"t('icon')\"\r\n [ngModel]=\"configAsType()['icon'] || ''\"\r\n (ngModelChange)=\"updateConfigAsType('icon', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"iconColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('iconColor')\"\r\n [ngModel]=\"styleConfig()['iconColor'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('iconColor', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"iconBgColor\")) {\r\n <mt-color-picker-field\r\n [label]=\"t('iconBgColor')\"\r\n [ngModel]=\"styleConfig()['iconBgColor'] || ''\"\r\n (ngModelChange)=\"updateStyleConfig('iconBgColor', $event)\"\r\n />\r\n }\r\n @if (shouldShowField(\"positionTitle\")) {\r\n <mt-select-field\r\n [label]=\"t('positionTitle')\"\r\n [ngModel]=\"styleConfig()['justify-content'] || 'start'\"\r\n (ngModelChange)=\"updateStyleConfig('justify-content', $event)\"\r\n [options]=\"positionOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Border Top Section -->\r\n @if (shouldShowField(\"borderTop\")) {\r\n <mt-card [title]=\"t('borderTop')\">\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-5\">\r\n <mt-toggle-field\r\n [label]=\"t('showBorderTop')\"\r\n [ngModel]=\"styleConfig()['border-top-show'] || false\"\r\n (ngModelChange)=\"updateBorderTopShow($event)\"\r\n />\r\n @if (styleConfig()[\"border-top-show\"]) {\r\n <mt-color-picker-field\r\n [label]=\"t('borderTopColor')\"\r\n [ngModel]=\"\r\n styleConfig()['border-top-color'] ||\r\n styleConfig()['border-color'] ||\r\n '#3b82f6'\r\n \"\r\n (ngModelChange)=\"updateBorderTopColor($event)\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Card Style Configuration -->\r\n @if (shouldShowField(\"cardStyleConfig\")) {\r\n <mt-card [title]=\"t('cardStyle')\">\r\n <div class=\"grid grid-cols-1 gap-5 mb-6\">\r\n <mt-slider-field\r\n [label]=\"t('borderRadius')\"\r\n [ngModel]=\"cardStyleConfig().borderRadius || 8\"\r\n (ngModelChange)=\"updateCardStyleConfig('borderRadius', $event)\"\r\n [min]=\"0\"\r\n [max]=\"24\"\r\n [step]=\"1\"\r\n unit=\"px\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('cardBackgroundColor')\"\r\n [ngModel]=\"cardStyleConfig().backgroundColor || ''\"\r\n (ngModelChange)=\"updateCardStyleConfig('backgroundColor', $event)\"\r\n />\r\n </div>\r\n\r\n <!-- Shadows -->\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-3\">\r\n <span class=\"font-medium\">{{ t(\"shadows\") }}</span>\r\n <mt-button\r\n [label]=\"t('addShadow')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addShadow()\"\r\n />\r\n </div>\r\n\r\n @for (\r\n shadow of cardStyleConfig().shadows || [];\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"mb-3 rounded-lg border border-surface-200 bg-surface-50 p-4\"\r\n >\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\r\n <span class=\"text-sm font-medium\"\r\n >{{ t(\"shadow\") }} {{ i + 1 }}</span\r\n >\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeShadow(i)\"\r\n />\r\n </div>\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <mt-number-field\r\n [label]=\"t('x')\"\r\n [ngModel]=\"shadow.x\"\r\n (ngModelChange)=\"updateShadow(i, 'x', $event)\"\r\n size=\"small\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('y')\"\r\n [ngModel]=\"shadow.y\"\r\n (ngModelChange)=\"updateShadow(i, 'y', $event)\"\r\n size=\"small\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('blur')\"\r\n [ngModel]=\"shadow.blur\"\r\n (ngModelChange)=\"updateShadow(i, 'blur', $event)\"\r\n size=\"small\"\r\n />\r\n <mt-number-field\r\n [label]=\"t('spread')\"\r\n [ngModel]=\"shadow.spread\"\r\n (ngModelChange)=\"updateShadow(i, 'spread', $event)\"\r\n size=\"small\"\r\n />\r\n <div class=\"md:col-span-2\">\r\n <mt-color-picker-field\r\n [label]=\"t('color')\"\r\n [ngModel]=\"shadow.color\"\r\n (ngModelChange)=\"updateShadow(i, 'color', $event)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Legend Settings -->\r\n @if (shouldShowField(\"legend\")) {\r\n <mt-card [title]=\"t('legendSettings')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('showLegend')\"\r\n [ngModel]=\"legendConfig().show || false\"\r\n (ngModelChange)=\"updateLegend('show', $event)\"\r\n />\r\n @if (legendConfig().show) {\r\n <mt-select-field\r\n [label]=\"t('legendPosition')\"\r\n [ngModel]=\"legendConfig().position || 'bottom'\"\r\n (ngModelChange)=\"updateLegend('position', $event)\"\r\n [options]=\"legendPositionOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n @if (shouldShowField(\"legendIconType\")) {\r\n <mt-select-field\r\n [label]=\"t('legendIconType')\"\r\n [ngModel]=\"legendConfig().iconType || 'circle'\"\r\n (ngModelChange)=\"updateLegend('iconType', $event)\"\r\n [options]=\"legendIconOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n }\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Label Settings -->\r\n @if (shouldShowField(\"label\")) {\r\n <mt-card [title]=\"t('labelSettings')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('showLabels')\"\r\n [ngModel]=\"labelConfig().show || false\"\r\n (ngModelChange)=\"updateLabel('show', $event)\"\r\n />\r\n @if (labelConfig().show) {\r\n <mt-select-field\r\n [label]=\"t('labelPosition')\"\r\n [ngModel]=\"labelConfig().position || 'inside'\"\r\n (ngModelChange)=\"updateLabel('position', $event)\"\r\n [options]=\"labelPositionOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n @if (shouldShowField(\"showTotal\")) {\r\n <mt-toggle-field\r\n [label]=\"t('showTotalInTop')\"\r\n [ngModel]=\"labelConfig().showTotalInTop || false\"\r\n (ngModelChange)=\"updateLabel('showTotalInTop', $event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Label Center (for Pie/Donut charts) -->\r\n @if (shouldShowField(\"labelCenter\")) {\r\n <mt-card [title]=\"t('labelCenter')\">\r\n <div class=\"grid grid-cols-1 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('hideLabelCenter')\"\r\n [ngModel]=\"labelCenterConfig().hide || false\"\r\n (ngModelChange)=\"updateLabelCenterConfig('hide', $event)\"\r\n />\r\n @if (!labelCenterConfig().hide) {\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('labelCenterTextEn')\"\r\n [ngModel]=\"labelCenterConfig().text?.en || ''\"\r\n (ngModelChange)=\"updateLabelCenterText('en', $event)\"\r\n [placeholder]=\"t('enterLabelCenterText')\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('labelCenterTextAr')\"\r\n [ngModel]=\"labelCenterConfig().text?.ar || ''\"\r\n (ngModelChange)=\"updateLabelCenterText('ar', $event)\"\r\n [placeholder]=\"t('enterLabelCenterText')\"\r\n dir=\"rtl\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Override Labels -->\r\n @if (shouldShowField(\"overrideLabels\")) {\r\n <mt-card [title]=\"t('overrideLabels')\">\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-4\">\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"overrideLabelsDescription\")\r\n }}</span>\r\n <mt-button\r\n [label]=\"t('addLabel')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addOverrideLabel()\"\r\n />\r\n </div>\r\n\r\n @for (\r\n label of overrideLabels();\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"mb-3 rounded-lg border border-surface-200 bg-surface-50 p-4\"\r\n >\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\r\n <span class=\"text-sm font-medium\"\r\n >{{ t(\"label\") }} {{ i + 1 }}</span\r\n >\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeOverrideLabel(i)\"\r\n />\r\n </div>\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-3\">\r\n <mt-text-field\r\n [label]=\"t('labelEn')\"\r\n [ngModel]=\"label.en\"\r\n (ngModelChange)=\"updateOverrideLabel(i, 'en', $event)\"\r\n [placeholder]=\"t('enterLabelEn')\"\r\n size=\"small\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('labelAr')\"\r\n [ngModel]=\"label.ar\"\r\n (ngModelChange)=\"updateOverrideLabel(i, 'ar', $event)\"\r\n [placeholder]=\"t('enterLabelAr')\"\r\n dir=\"rtl\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (overrideLabels().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noOverrideLabels\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Sort Data Bars -->\r\n @if (shouldShowField(\"sortDataBars\")) {\r\n <mt-card [title]=\"t('sortDataBars')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('enableSorting')\"\r\n [ngModel]=\"sortDataBarsConfig().enable || false\"\r\n (ngModelChange)=\"updateSortDataBarsConfig('enable', $event)\"\r\n />\r\n @if (sortDataBarsConfig().enable) {\r\n <mt-text-field\r\n [label]=\"t('sortBy')\"\r\n [ngModel]=\"sortDataBarsConfig().sortBy || ''\"\r\n (ngModelChange)=\"updateSortDataBarsConfig('sortBy', $event)\"\r\n [placeholder]=\"t('propertyKey')\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('order')\"\r\n [ngModel]=\"sortDataBarsConfig().order || 'asc'\"\r\n (ngModelChange)=\"updateSortDataBarsConfig('order', $event)\"\r\n [options]=\"orderTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Default Colors (for charts) -->\r\n @if (shouldShowField(\"defaultColors\")) {\r\n <mt-card [title]=\"t('defaultColors')\">\r\n <div class=\"flex flex-wrap gap-2 mb-4\">\r\n @for (\r\n color of defaultColors();\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"flex items-center gap-1 p-2 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-color-picker-field\r\n [ngModel]=\"color\"\r\n (ngModelChange)=\"updateDefaultColor(i, $event)\"\r\n />\r\n <mt-button\r\n icon=\"general.x-close\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeDefaultColor(i)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"flex flex-wrap gap-2 items-center\">\r\n <span class=\"text-sm text-muted-color xl:mr-2\"\r\n >{{ t(\"quickAdd\") }}:</span\r\n >\r\n @for (color of defaultColorPalette; track color) {\r\n <button\r\n type=\"button\"\r\n class=\"w-6 h-6 rounded cursor-pointer border border-surface-300 hover:scale-110 transition-transform\"\r\n [style.background-color]=\"color\"\r\n (click)=\"addDefaultColor(color)\"\r\n [pTooltip]=\"color\"\r\n tooltipPosition=\"top\"\r\n ></button>\r\n }\r\n </div>\r\n\r\n @if (defaultColors().length === 0) {\r\n <div class=\"text-center py-2 text-muted-color text-sm mt-2\">\r\n {{ t(\"noColorsSelected\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Card Info -->\r\n @if (shouldShowField(\"cardInfo\")) {\r\n <mt-card [title]=\"t('cardInfo')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('showCardInfo')\"\r\n [ngModel]=\"cardInfo().show || false\"\r\n (ngModelChange)=\"updateCardInfoConfig('show', $event)\"\r\n />\r\n @if (cardInfo().show) {\r\n <mt-text-field\r\n [label]=\"t('cardInfoValue')\"\r\n [ngModel]=\"cardInfo().value || ''\"\r\n (ngModelChange)=\"updateCardInfoConfig('value', $event)\"\r\n [placeholder]=\"t('enterCardInfoValue')\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Table Settings -->\r\n @if (shouldShowField(\"hideIndex\")) {\r\n <mt-card [title]=\"t('tableSettings')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('hideIndex')\"\r\n [ngModel]=\"configAsType()['hideIndex'] || false\"\r\n (ngModelChange)=\"updateConfigAsType('hideIndex', $event)\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Map Settings -->\r\n @if (shouldShowField(\"mapChart\")) {\r\n <mt-card [title]=\"t('mapSettings')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('mapType')\"\r\n [ngModel]=\"config()?.clientConfig?.['map'] || 'SaudiArabia'\"\r\n (ngModelChange)=\"updateMapType($event)\"\r\n [options]=\"mapOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Format Configuration -->\r\n @if (shouldShowField(\"format\")) {\r\n <mt-card [title]=\"t('formatConfiguration')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('formatType')\"\r\n [ngModel]=\"formatConfig().type\"\r\n (ngModelChange)=\"updateFormatConfig('type', $event)\"\r\n [options]=\"formatTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectFormat')\"\r\n />\r\n\r\n @if (formatConfig().type === \"currency\") {\r\n <mt-toggle-field\r\n [label]=\"t('showCurrency')\"\r\n [ngModel]=\"formatConfig().showCurrency || false\"\r\n (ngModelChange)=\"updateFormatConfig('showCurrency', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('showCurrencyTooltip')\"\r\n [ngModel]=\"formatConfig().showCurrencyTooltip || false\"\r\n (ngModelChange)=\"updateFormatConfig('showCurrencyTooltip', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('handleLanguage')\"\r\n [ngModel]=\"formatConfig().handleLang || false\"\r\n (ngModelChange)=\"updateFormatConfig('handleLang', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('hideSuffixes')\"\r\n [ngModel]=\"formatConfig().hideSuffixes || false\"\r\n (ngModelChange)=\"updateFormatConfig('hideSuffixes', $event)\"\r\n />\r\n }\r\n\r\n @if (formatConfig().type === \"custom\") {\r\n <mt-text-field\r\n [label]=\"t('customText')\"\r\n [ngModel]=\"formatConfig().customText || ''\"\r\n (ngModelChange)=\"updateFormatConfig('customText', $event)\"\r\n [placeholder]=\"t('enterCustomText')\"\r\n />\r\n }\r\n\r\n @if (formatConfig().type === \"date\") {\r\n <mt-text-field\r\n [label]=\"t('dateFormat')\"\r\n [ngModel]=\"formatConfig().customDateFormat || ''\"\r\n (ngModelChange)=\"updateFormatConfig('customDateFormat', $event)\"\r\n [placeholder]=\"'YYYY-MM-DD'\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Table Format Configuration -->\r\n @if (shouldShowField(\"tableFormat\")) {\r\n <mt-card [title]=\"t('tableFormatConfiguration')\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Colors -->\r\n <mt-color-picker-field\r\n [label]=\"t('headerTextColor')\"\r\n [ngModel]=\"tableFormatConfig().thTextColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('thTextColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('headerBackgroundColor')\"\r\n [ngModel]=\"tableFormatConfig().thBackgroundColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('thBackgroundColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('cellTextColor')\"\r\n [ngModel]=\"tableFormatConfig().tdTextColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('tdTextColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('groupBackgroundColor')\"\r\n [ngModel]=\"tableFormatConfig().groupBackgroundColor || ''\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('groupBackgroundColor', $event)\r\n \"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('groupTextColor')\"\r\n [ngModel]=\"tableFormatConfig().groupTextColor || ''\"\r\n (ngModelChange)=\"updateTableFormatConfig('groupTextColor', $event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Font Settings -->\r\n <mt-toggle-field\r\n [label]=\"t('boldHeaderFont')\"\r\n [ngModel]=\"tableFormatConfig().thFontBold || false\"\r\n (ngModelChange)=\"updateTableFormatConfig('thFontBold', $event)\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('boldCellFont')\"\r\n [ngModel]=\"tableFormatConfig().tdFontBold || false\"\r\n (ngModelChange)=\"updateTableFormatConfig('tdFontBold', $event)\"\r\n />\r\n <div>\r\n <label class=\"block text-sm font-medium mb-2\"\r\n >{{ t(\"headerFontSize\") }}:\r\n {{ tableFormatConfig().thFontSize || 14 }}px</label\r\n >\r\n <mt-slider-field\r\n [ngModel]=\"tableFormatConfig().thFontSize || 14\"\r\n (ngModelChange)=\"updateTableFormatConfig('thFontSize', $event)\"\r\n [min]=\"8\"\r\n [max]=\"32\"\r\n [step]=\"1\"\r\n />\r\n </div>\r\n <div>\r\n <label class=\"block text-sm font-medium mb-2\"\r\n >{{ t(\"cellFontSize\") }}:\r\n {{ tableFormatConfig().tdFontSize || 14 }}px</label\r\n >\r\n <mt-slider-field\r\n [ngModel]=\"tableFormatConfig().tdFontSize || 14\"\r\n (ngModelChange)=\"updateTableFormatConfig('tdFontSize', $event)\"\r\n [min]=\"8\"\r\n [max]=\"32\"\r\n [step]=\"1\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Options -->\r\n <mt-toggle-field\r\n [label]=\"t('hideTableSubheader')\"\r\n [ngModel]=\"tableFormatConfig().hideTableSubheader || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('hideTableSubheader', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('disableCurrencyFormat')\"\r\n [ngModel]=\"tableFormatConfig().disableCurrencyFormat || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('disableCurrencyFormat', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('showPercentageAsProgressBar')\"\r\n [ngModel]=\"tableFormatConfig().showPercentageAsProgressBar || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('showPercentageAsProgressBar', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('showPercentageStatus')\"\r\n [ngModel]=\"tableFormatConfig().showPercentageStatus || false\"\r\n (ngModelChange)=\"\r\n updateTableFormatConfig('showPercentageStatus', $event)\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <!-- Sort & Hidden Columns -->\r\n <mt-select-field\r\n [label]=\"t('sortColumn')\"\r\n [ngModel]=\"tableFormatConfig().sortConfig?.column || ''\"\r\n (ngModelChange)=\"updateTableFormatSortConfig('column', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectColumn')\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('sortDirection')\"\r\n [ngModel]=\"tableFormatConfig().sortConfig?.direction || 'asc'\"\r\n (ngModelChange)=\"updateTableFormatSortConfig('direction', $event)\"\r\n [options]=\"orderTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n <mt-multi-select-field\r\n [label]=\"t('hiddenColumns')\"\r\n [ngModel]=\"tableFormatConfig().hiddenColumns || []\"\r\n (ngModelChange)=\"updateTableFormatConfig('hiddenColumns', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectColumns')\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"border-t border-surface-200 pt-4 mt-4\">\r\n <mt-button\r\n [label]=\"t('resetToDefault')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"resetTableFormat()\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Color By Condition -->\r\n @if (shouldShowField(\"colorByCondition\")) {\r\n <mt-card [title]=\"t('colorByCondition')\">\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-4\">\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"colorByConditionDescription\")\r\n }}</span>\r\n <mt-button\r\n [label]=\"t('add')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addColorConditionIndex()\"\r\n />\r\n </div>\r\n\r\n @for (barIndex of getColorConditionIndexes(); track barIndex) {\r\n <div class=\"mb-4 border border-surface-200 rounded-lg\">\r\n <div\r\n class=\"flex flex-wrap items-center justify-between gap-2 p-3 bg-surface-50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"text-sm text-muted-color\"\r\n (click)=\"toggleColorConditionExpanded(barIndex)\"\r\n >\r\n {{ isColorConditionExpanded(barIndex) ? \"-\" : \"+\" }}\r\n </button>\r\n <span class=\"font-medium text-sm\"\r\n >{{ t(\"bar\") }} {{ barIndex }}</span\r\n >\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n addColorCondition(barIndex); $event.stopPropagation()\r\n \"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n removeColorConditionIndex(barIndex); $event.stopPropagation()\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n @if (isColorConditionExpanded(barIndex)) {\r\n <div class=\"p-3\">\r\n <div\r\n class=\"flex flex-wrap items-center justify-between gap-2 mb-3\"\r\n >\r\n <span class=\"text-sm font-medium\">{{ t(\"conditions\") }}</span>\r\n <mt-button\r\n [label]=\"t('addCondition')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"addColorCondition(barIndex)\"\r\n />\r\n </div>\r\n\r\n @for (\r\n condition of colorByCondition()[barIndex] || [];\r\n track trackByIndex($index);\r\n let condIndex = $index\r\n ) {\r\n <div class=\"p-3 border border-surface-200 rounded-lg mb-3\">\r\n <div\r\n class=\"grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-3 items-end\"\r\n >\r\n <mt-color-picker-field\r\n [label]=\"t('color')\"\r\n [ngModel]=\"condition.color\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'color',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('condition')\"\r\n [ngModel]=\"condition.type\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'type',\r\n $event\r\n )\r\n \"\r\n [options]=\"colorConditionTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n <mt-number-field\r\n [label]=\"\r\n condition.type === 'between' ? t('from') : t('value')\r\n \"\r\n [ngModel]=\"condition.value1\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'value1',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n />\r\n @if (condition.type === \"between\") {\r\n <mt-number-field\r\n [label]=\"t('to')\"\r\n [ngModel]=\"condition.value2\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'value2',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n />\r\n }\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeColorCondition(barIndex, condIndex)\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-3 mt-3\">\r\n <mt-text-field\r\n [label]=\"t('labelEn')\"\r\n [ngModel]=\"condition.labelEn || ''\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'labelEn',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('labelAr')\"\r\n [ngModel]=\"condition.labelAr || ''\"\r\n (ngModelChange)=\"\r\n updateColorCondition(\r\n barIndex,\r\n condIndex,\r\n 'labelAr',\r\n $event\r\n )\r\n \"\r\n size=\"small\"\r\n dir=\"rtl\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if ((colorByCondition()[barIndex] || []).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noColorConditions\") }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getColorConditionIndexes().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noColorConditions\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Timeline Header Colors -->\r\n @if (shouldShowField(\"timelineHeaderColorsConfig\")) {\r\n <mt-card [title]=\"t('timelineHeaderColors')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-color-picker-field\r\n [label]=\"t('backgroundColor')\"\r\n [ngModel]=\"timelineHeaderColorsSingle().bgColor || ''\"\r\n (ngModelChange)=\"updateTimelineHeaderColorSingle('bgColor', $event)\"\r\n />\r\n <mt-color-picker-field\r\n [label]=\"t('textColor')\"\r\n [ngModel]=\"timelineHeaderColorsSingle().color || ''\"\r\n (ngModelChange)=\"updateTimelineHeaderColorSingle('color', $event)\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Ring Gauge Configuration -->\r\n @if (shouldShowField(\"ringGaugeConfig\")) {\r\n <mt-card [title]=\"t('ringGaugeConfiguration')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('centerProperty')\"\r\n [ngModel]=\"ringGaugeConfig().centerProperty || ''\"\r\n (ngModelChange)=\"updateRingGaugeConfig('centerProperty', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('statusProperty')\"\r\n [ngModel]=\"ringGaugeConfig().statusProperty || ''\"\r\n (ngModelChange)=\"updateRingGaugeConfig('statusProperty', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n <div class=\"mt-4\">\r\n <mt-multi-select-field\r\n [label]=\"t('hiddenProperties')\"\r\n [ngModel]=\"ringGaugeConfig().hiddenProperties || []\"\r\n (ngModelChange)=\"updateRingGaugeConfig('hiddenProperties', $event)\"\r\n [options]=\"ringGaugeHiddenOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperties')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Order Configuration -->\r\n @if (shouldShowField(\"orderConfig\")) {\r\n <mt-card [title]=\"t('orderConfiguration')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4 mb-4\">\r\n <mt-select-field\r\n [label]=\"t('operation')\"\r\n [ngModel]=\"orderConfig().operation || 'deleteNotEqual'\"\r\n (ngModelChange)=\"updateOrderConfig('operation', $event)\"\r\n [options]=\"orderOperationOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('orderBy')\"\r\n [ngModel]=\"orderConfig().orderBy || ''\"\r\n (ngModelChange)=\"updateOrderConfig('orderBy', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-4\">\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"orderConfigurationDescription\")\r\n }}</span>\r\n <mt-button\r\n [label]=\"t('addOrderItem')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n (onClick)=\"addOrderItem()\"\r\n />\r\n </div>\r\n\r\n @for (\r\n item of orderConfig().order || [];\r\n track trackByIndex($index);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"mb-3 flex flex-col gap-3 rounded-lg border border-surface-200 bg-surface-50 p-4 xl:flex-row xl:items-center\"\r\n >\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n <span class=\"text-sm font-medium w-auto xl:w-8\">{{ i + 1 }}.</span>\r\n <mt-select-field\r\n [ngModel]=\"item\"\r\n (ngModelChange)=\"updateOrderItem(i, $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n size=\"small\"\r\n class=\"min-w-0 flex-1\"\r\n />\r\n </div>\r\n <div class=\"flex items-center justify-end gap-1\">\r\n <mt-button\r\n icon=\"general.chevron-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"i === 0\"\r\n (onClick)=\"moveOrderItemUp(i)\"\r\n />\r\n <mt-button\r\n icon=\"general.chevron-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"i === (orderConfig().order || []).length - 1\"\r\n (onClick)=\"moveOrderItemDown(i)\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removeOrderItem(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if ((orderConfig().order || []).length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noOrderItems\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Card List Configuration -->\r\n @if (shouldShowField(\"cardListConfig\")) {\r\n <mt-card [title]=\"t('cardListConfiguration')\">\r\n <mt-multi-select-field\r\n [label]=\"t('hideProperties')\"\r\n [ngModel]=\"cardListConfig().hideProperties || []\"\r\n (ngModelChange)=\"updateCardListHideProperties($event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectPropertiesToHide')\"\r\n />\r\n </mt-card>\r\n }\r\n\r\n <!-- Props Config As Index -->\r\n @if (shouldShowPropertiesViewSettings()) {\r\n <mt-card [title]=\"t('entityPreviewSettings')\">\r\n @if (propertiesViewRows().length === 0) {\r\n <div class=\"py-4 text-sm text-muted-color\">\r\n {{ t(\"selectPropertiesFirst\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-4\">\r\n @for (property of propertiesViewRows(); track property.key) {\r\n <div class=\"rounded-xl border border-surface-200 bg-surface-50 p-5\">\r\n <div class=\"mb-4\">\r\n <div class=\"text-sm font-semibold text-surface-900\">\r\n {{ property.label }}\r\n </div>\r\n @if (property.label !== property.key) {\r\n <div class=\"mt-1 text-xs text-muted-color\">\r\n {{ property.key }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('width')\"\r\n [ngModel]=\"property.config.width || ''\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(property.index, 'width', $event)\r\n \"\r\n [placeholder]=\"'100%'\"\r\n size=\"small\"\r\n />\r\n <mt-select-field\r\n [label]=\"t('colorProperty')\"\r\n [ngModel]=\"property.config.colorAsProperty || ''\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(\r\n property.index,\r\n 'colorAsProperty',\r\n $event\r\n )\r\n \"\r\n [options]=\"selectedPropertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectColorProperty')\"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n size=\"small\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('border')\"\r\n [ngModel]=\"!!property.config.border\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(property.index, 'border', $event)\r\n \"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('hidden')\"\r\n [ngModel]=\"property.config.hidden || false\"\r\n (ngModelChange)=\"\r\n updatePropsConfigItem(property.index, 'hidden', $event)\r\n \"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Toggle Association -->\r\n @if (shouldShowField(\"toggleAssociation\")) {\r\n <mt-card [title]=\"t('toggleAssociation')\">\r\n <mt-toggle-field\r\n [label]=\"t('enableToggleAssociation')\"\r\n [ngModel]=\"toggleAssociation()\"\r\n (ngModelChange)=\"updateToggleAssociation($event)\"\r\n />\r\n </mt-card>\r\n }\r\n\r\n <!-- Property Translations -->\r\n @if (\r\n shouldShowField(\"propertyTranslations\") &&\r\n resolvedSelectedProperties().length > 0\r\n ) {\r\n <mt-card [title]=\"t('propertyTranslations')\">\r\n <div class=\"space-y-4\">\r\n @for (property of propertyTranslationRows(); track property.key) {\r\n <div class=\"rounded-xl border border-surface-200 bg-surface-50 p-5\">\r\n <div class=\"mb-4\">\r\n <div class=\"text-sm font-semibold text-surface-900\">\r\n {{ property.label }}\r\n </div>\r\n @if (property.label !== property.key) {\r\n <div class=\"mt-1 text-xs text-muted-color\">\r\n {{ property.key }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('englishLabel')\"\r\n [ngModel]=\"property.translation.en\"\r\n (ngModelChange)=\"\r\n updatePropertyTranslation(property.key, 'en', $event)\r\n \"\r\n [placeholder]=\"t('enterEnglishLabel')\"\r\n size=\"small\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('arabicLabel')\"\r\n [ngModel]=\"property.translation.ar\"\r\n (ngModelChange)=\"\r\n updatePropertyTranslation(property.key, 'ar', $event)\r\n \"\r\n [placeholder]=\"t('enterArabicLabel')\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (propertyTranslationRows().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noPropertyTranslations\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Property Colors -->\r\n @if (\r\n shouldShowField(\"propertyColors\") && resolvedSelectedProperties().length > 0\r\n ) {\r\n <mt-card [title]=\"t('propertyColors')\">\r\n <ng-template #cardEnd>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"general.copy-01\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"copyPropertyColors()\"\r\n [pTooltip]=\"t('copyConfig')\"\r\n />\r\n <mt-button\r\n icon=\"general.clipboard\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"togglePropertyColorsPaste()\"\r\n [pTooltip]=\"t('pasteConfig')\"\r\n />\r\n </div>\r\n </ng-template>\r\n\r\n @if (showPropertyColorsPaste()) {\r\n <div\r\n class=\"mb-4 p-4 bg-surface-50 rounded-lg border border-surface-200\"\r\n >\r\n <mt-textarea-field\r\n [label]=\"t('pasteConfiguration')\"\r\n [ngModel]=\"propertyColorsPasteText()\"\r\n (ngModelChange)=\"propertyColorsPasteText.set($event)\"\r\n [placeholder]=\"t('pasteConfigurationPlaceholder')\"\r\n [rows]=\"4\"\r\n />\r\n @if (propertyColorsPasteError()) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n propertyColorsPasteError()\r\n }}</small>\r\n }\r\n <div class=\"flex justify-end gap-2 mt-3\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"togglePropertyColorsPaste()\"\r\n />\r\n <mt-button\r\n [label]=\"t('apply')\"\r\n size=\"small\"\r\n (onClick)=\"applyPropertyColorsPaste()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Property Selection -->\r\n <div class=\"mb-4\">\r\n <div class=\"flex flex-wrap items-end gap-2 xl:flex-nowrap\">\r\n <div class=\"flex-1\">\r\n <mt-select-field\r\n [label]=\"t('selectProperty')\"\r\n [ngModel]=\"selectedPropertyForColor()\"\r\n (ngModelChange)=\"selectedPropertyForColor.set($event)\"\r\n [options]=\"availableColorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"!selectedPropertyForColor()\"\r\n (onClick)=\"\r\n addPropertyColor(selectedPropertyForColor());\r\n selectedPropertyForColor.set('')\r\n \"\r\n [pTooltip]=\"t('addProperty')\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- Property Color List -->\r\n @for (propKey of getPropertyColorKeys(); track propKey) {\r\n <div\r\n class=\"mb-3 rounded-lg border border-surface-200 bg-surface-50 p-4\"\r\n >\r\n <div class=\"flex flex-wrap items-center justify-between gap-2 mb-2\">\r\n <span class=\"font-medium text-sm\">{{ propKey }}</span>\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"removePropertyColor(propKey)\"\r\n />\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('selectColorProperty')\"\r\n [ngModel]=\"propertyColors()[propKey]?.selectedKey || ''\"\r\n (ngModelChange)=\"updatePropertyColor(propKey, $event)\"\r\n [options]=\"allPropertyKeyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n size=\"small\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (getPropertyColorKeys().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color\">\r\n {{ t(\"noPropertyColors\") }}\r\n </div>\r\n }\r\n </mt-card>\r\n }\r\n\r\n <!-- Format X-Axis Configuration -->\r\n @if (shouldShowField(\"formatXAxis\")) {\r\n <mt-card [title]=\"t('formatXAxisConfiguration')\">\r\n <div class=\"grid grid-cols-1 xl:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('formatType')\"\r\n [ngModel]=\"formatXAxisConfig().type\"\r\n (ngModelChange)=\"updateFormatXAxisConfig('type', $event)\"\r\n [options]=\"formatXAxisTypeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectFormat')\"\r\n />\r\n @if (\r\n formatXAxisConfig().type === \"dateToMonth\" ||\r\n formatXAxisConfig().type === \"month\"\r\n ) {\r\n <mt-toggle-field\r\n [label]=\"t('shortFormat')\"\r\n [ngModel]=\"formatXAxisConfig().shortFormate || false\"\r\n (ngModelChange)=\"updateFormatXAxisConfig('shortFormate', $event)\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n <!-- Extra Column From Lookup -->\r\n @if (shouldShowField(\"extraColumnFromLookup\")) {\r\n <mt-card [title]=\"t('extraColumnFromLookup')\">\r\n <div class=\"grid grid-cols-1 gap-4\">\r\n <mt-toggle-field\r\n [label]=\"t('enableExtraColumnFromLookup')\"\r\n [ngModel]=\"tableColumnsConfig().extraCoulmnFromLookup || false\"\r\n (ngModelChange)=\"\r\n updateTableColumnsConfig('extraCoulmnFromLookup', $event)\r\n \"\r\n />\r\n\r\n @if (tableColumnsConfig().extraCoulmnFromLookup) {\r\n <mt-select-field\r\n [label]=\"t('lookup')\"\r\n [ngModel]=\"tableColumnsConfig().lookupId\"\r\n (ngModelChange)=\"updateTableColumnsConfig('lookupId', $event)\"\r\n [options]=\"lookups()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"id\"\r\n [placeholder]=\"t('selectLookup')\"\r\n />\r\n\r\n <mt-select-field\r\n [label]=\"t('groupedBy')\"\r\n [ngModel]=\"tableColumnsConfig().groupedBy\"\r\n (ngModelChange)=\"updateTableColumnsConfig('groupedBy', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n />\r\n\r\n <mt-select-field\r\n [label]=\"t('propertyValue')\"\r\n [ngModel]=\"tableColumnsConfig().propKey\"\r\n (ngModelChange)=\"updateTableColumnsConfig('propKey', $event)\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [placeholder]=\"t('selectProperty')\"\r\n />\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: SliderField, selector: "mt-slider-field", inputs: ["field", "label", "class", "min", "max", "step", "hideNumber", "unit", "readonly", "required"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: IconField, selector: "mt-icon-field", inputs: ["label", "required"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
9118
9235
  }
9119
9236
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DisplaySettings, decorators: [{
9120
9237
  type: Component,
@@ -9337,7 +9454,7 @@ class PieControlUi {
9337
9454
  useExisting: forwardRef(() => PieControlUi),
9338
9455
  multi: true,
9339
9456
  },
9340
- ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.pie'\"\n>\n <!-- Basic Chart Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"pieSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('radius')\"\n [ngModel]=\"config().radius\"\n (ngModelChange)=\"updateConfig({ radius: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('thickness')\"\n [ngModel]=\"config().thickness\"\n (ngModelChange)=\"updateConfig({ thickness: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('padAngle')\"\n [ngModel]=\"config().padAngle\"\n (ngModelChange)=\"updateConfig({ padAngle: $event })\"\n [min]=\"0\"\n [max]=\"20\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"50\"\n />\n\n <mt-number-field\n [label]=\"t('centerX')\"\n [ngModel]=\"config().centerX\"\n (ngModelChange)=\"updateConfig({ centerX: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('centerY')\"\n [ngModel]=\"config().centerY\"\n (ngModelChange)=\"updateConfig({ centerY: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('startAngle')\"\n [ngModel]=\"config().startAngle\"\n (ngModelChange)=\"updateConfig({ startAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-number-field\n [label]=\"t('endAngle')\"\n [ngModel]=\"config().endAngle\"\n (ngModelChange)=\"updateConfig({ endAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-select-field\n [label]=\"t('roseType')\"\n [ngModel]=\"config().roseType\"\n (ngModelChange)=\"updateConfig({ roseType: $event })\"\n [options]=\"roseTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('useEnhancedLegend')\"\n [ngModel]=\"config().useEnhancedLegend\"\n (ngModelChange)=\"updateConfig({ useEnhancedLegend: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('legendPosition')\"\n [ngModel]=\"config().legendPosition\"\n (ngModelChange)=\"updateConfig({ legendPosition: $event })\"\n [options]=\"legendPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendVerticalAlign')\"\n [ngModel]=\"config().legendVerticalAlign\"\n (ngModelChange)=\"updateConfig({ legendVerticalAlign: $event })\"\n [options]=\"legendVerticalAlignOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendOrientation')\"\n [ngModel]=\"config().legendOrientation\"\n (ngModelChange)=\"updateConfig({ legendOrientation: $event })\"\n [options]=\"legendOrientationOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendType')\"\n [ngModel]=\"config().legendType\"\n (ngModelChange)=\"updateConfig({ legendType: $event })\"\n [options]=\"legendTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('legendIcon')\"\n [ngModel]=\"config().legendIcon\"\n (ngModelChange)=\"updateConfig({ legendIcon: $event })\"\n [options]=\"legendIconOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('totalValueFontSize')\"\n [ngModel]=\"config().totalValueFontSize\"\n (ngModelChange)=\"updateConfig({ totalValueFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('showLabelLine')\"\n [ngModel]=\"config().showLabelLine\"\n (ngModelChange)=\"updateConfig({ showLabelLine: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n\n <!-- Animation Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"animationSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('animation')\"\n [ngModel]=\"config().animation\"\n (ngModelChange)=\"updateConfig({ animation: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('animationDuration')\"\n [ngModel]=\"config().animationDuration\"\n (ngModelChange)=\"updateConfig({ animationDuration: $event })\"\n [min]=\"0\"\n [max]=\"5000\"\n />\n\n <mt-toggle-field\n [label]=\"t('explode')\"\n [ngModel]=\"config().explode\"\n (ngModelChange)=\"updateConfig({ explode: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }] });
9457
+ ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.pie'\"\n>\n <!-- Basic Chart Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"pieSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('radius')\"\n [ngModel]=\"config().radius\"\n (ngModelChange)=\"updateConfig({ radius: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('thickness')\"\n [ngModel]=\"config().thickness\"\n (ngModelChange)=\"updateConfig({ thickness: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('padAngle')\"\n [ngModel]=\"config().padAngle\"\n (ngModelChange)=\"updateConfig({ padAngle: $event })\"\n [min]=\"0\"\n [max]=\"20\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"50\"\n />\n\n <mt-number-field\n [label]=\"t('centerX')\"\n [ngModel]=\"config().centerX\"\n (ngModelChange)=\"updateConfig({ centerX: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('centerY')\"\n [ngModel]=\"config().centerY\"\n (ngModelChange)=\"updateConfig({ centerY: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('startAngle')\"\n [ngModel]=\"config().startAngle\"\n (ngModelChange)=\"updateConfig({ startAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-number-field\n [label]=\"t('endAngle')\"\n [ngModel]=\"config().endAngle\"\n (ngModelChange)=\"updateConfig({ endAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-select-field\n [label]=\"t('roseType')\"\n [ngModel]=\"config().roseType\"\n (ngModelChange)=\"updateConfig({ roseType: $event })\"\n [options]=\"roseTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('useEnhancedLegend')\"\n [ngModel]=\"config().useEnhancedLegend\"\n (ngModelChange)=\"updateConfig({ useEnhancedLegend: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('legendPosition')\"\n [ngModel]=\"config().legendPosition\"\n (ngModelChange)=\"updateConfig({ legendPosition: $event })\"\n [options]=\"legendPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendVerticalAlign')\"\n [ngModel]=\"config().legendVerticalAlign\"\n (ngModelChange)=\"updateConfig({ legendVerticalAlign: $event })\"\n [options]=\"legendVerticalAlignOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendOrientation')\"\n [ngModel]=\"config().legendOrientation\"\n (ngModelChange)=\"updateConfig({ legendOrientation: $event })\"\n [options]=\"legendOrientationOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendType')\"\n [ngModel]=\"config().legendType\"\n (ngModelChange)=\"updateConfig({ legendType: $event })\"\n [options]=\"legendTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('legendIcon')\"\n [ngModel]=\"config().legendIcon\"\n (ngModelChange)=\"updateConfig({ legendIcon: $event })\"\n [options]=\"legendIconOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('totalValueFontSize')\"\n [ngModel]=\"config().totalValueFontSize\"\n (ngModelChange)=\"updateConfig({ totalValueFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('showLabelLine')\"\n [ngModel]=\"config().showLabelLine\"\n (ngModelChange)=\"updateConfig({ showLabelLine: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n\n <!-- Animation Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"animationSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('animation')\"\n [ngModel]=\"config().animation\"\n (ngModelChange)=\"updateConfig({ animation: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('animationDuration')\"\n [ngModel]=\"config().animationDuration\"\n (ngModelChange)=\"updateConfig({ animationDuration: $event })\"\n [min]=\"0\"\n [max]=\"5000\"\n />\n\n <mt-toggle-field\n [label]=\"t('explode')\"\n [ngModel]=\"config().explode\"\n (ngModelChange)=\"updateConfig({ explode: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }] });
9341
9458
  }
9342
9459
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PieControlUi, decorators: [{
9343
9460
  type: Component,
@@ -9355,7 +9472,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
9355
9472
  useExisting: forwardRef(() => PieControlUi),
9356
9473
  multi: true,
9357
9474
  },
9358
- ], template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.pie'\"\n>\n <!-- Basic Chart Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"pieSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('radius')\"\n [ngModel]=\"config().radius\"\n (ngModelChange)=\"updateConfig({ radius: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('thickness')\"\n [ngModel]=\"config().thickness\"\n (ngModelChange)=\"updateConfig({ thickness: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('padAngle')\"\n [ngModel]=\"config().padAngle\"\n (ngModelChange)=\"updateConfig({ padAngle: $event })\"\n [min]=\"0\"\n [max]=\"20\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"50\"\n />\n\n <mt-number-field\n [label]=\"t('centerX')\"\n [ngModel]=\"config().centerX\"\n (ngModelChange)=\"updateConfig({ centerX: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('centerY')\"\n [ngModel]=\"config().centerY\"\n (ngModelChange)=\"updateConfig({ centerY: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('startAngle')\"\n [ngModel]=\"config().startAngle\"\n (ngModelChange)=\"updateConfig({ startAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-number-field\n [label]=\"t('endAngle')\"\n [ngModel]=\"config().endAngle\"\n (ngModelChange)=\"updateConfig({ endAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-select-field\n [label]=\"t('roseType')\"\n [ngModel]=\"config().roseType\"\n (ngModelChange)=\"updateConfig({ roseType: $event })\"\n [options]=\"roseTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('useEnhancedLegend')\"\n [ngModel]=\"config().useEnhancedLegend\"\n (ngModelChange)=\"updateConfig({ useEnhancedLegend: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('legendPosition')\"\n [ngModel]=\"config().legendPosition\"\n (ngModelChange)=\"updateConfig({ legendPosition: $event })\"\n [options]=\"legendPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendVerticalAlign')\"\n [ngModel]=\"config().legendVerticalAlign\"\n (ngModelChange)=\"updateConfig({ legendVerticalAlign: $event })\"\n [options]=\"legendVerticalAlignOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendOrientation')\"\n [ngModel]=\"config().legendOrientation\"\n (ngModelChange)=\"updateConfig({ legendOrientation: $event })\"\n [options]=\"legendOrientationOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendType')\"\n [ngModel]=\"config().legendType\"\n (ngModelChange)=\"updateConfig({ legendType: $event })\"\n [options]=\"legendTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('legendIcon')\"\n [ngModel]=\"config().legendIcon\"\n (ngModelChange)=\"updateConfig({ legendIcon: $event })\"\n [options]=\"legendIconOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('totalValueFontSize')\"\n [ngModel]=\"config().totalValueFontSize\"\n (ngModelChange)=\"updateConfig({ totalValueFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('showLabelLine')\"\n [ngModel]=\"config().showLabelLine\"\n (ngModelChange)=\"updateConfig({ showLabelLine: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n\n <!-- Animation Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"animationSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('animation')\"\n [ngModel]=\"config().animation\"\n (ngModelChange)=\"updateConfig({ animation: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('animationDuration')\"\n [ngModel]=\"config().animationDuration\"\n (ngModelChange)=\"updateConfig({ animationDuration: $event })\"\n [min]=\"0\"\n [max]=\"5000\"\n />\n\n <mt-toggle-field\n [label]=\"t('explode')\"\n [ngModel]=\"config().explode\"\n (ngModelChange)=\"updateConfig({ explode: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n</div>\n" }]
9475
+ ], template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.pie'\"\n>\n <!-- Basic Chart Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"pieSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('radius')\"\n [ngModel]=\"config().radius\"\n (ngModelChange)=\"updateConfig({ radius: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('thickness')\"\n [ngModel]=\"config().thickness\"\n (ngModelChange)=\"updateConfig({ thickness: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('padAngle')\"\n [ngModel]=\"config().padAngle\"\n (ngModelChange)=\"updateConfig({ padAngle: $event })\"\n [min]=\"0\"\n [max]=\"20\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"50\"\n />\n\n <mt-number-field\n [label]=\"t('centerX')\"\n [ngModel]=\"config().centerX\"\n (ngModelChange)=\"updateConfig({ centerX: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('centerY')\"\n [ngModel]=\"config().centerY\"\n (ngModelChange)=\"updateConfig({ centerY: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('startAngle')\"\n [ngModel]=\"config().startAngle\"\n (ngModelChange)=\"updateConfig({ startAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-number-field\n [label]=\"t('endAngle')\"\n [ngModel]=\"config().endAngle\"\n (ngModelChange)=\"updateConfig({ endAngle: $event })\"\n [min]=\"0\"\n [max]=\"360\"\n />\n\n <mt-select-field\n [label]=\"t('roseType')\"\n [ngModel]=\"config().roseType\"\n (ngModelChange)=\"updateConfig({ roseType: $event })\"\n [options]=\"roseTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('useEnhancedLegend')\"\n [ngModel]=\"config().useEnhancedLegend\"\n (ngModelChange)=\"updateConfig({ useEnhancedLegend: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('legendPosition')\"\n [ngModel]=\"config().legendPosition\"\n (ngModelChange)=\"updateConfig({ legendPosition: $event })\"\n [options]=\"legendPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendVerticalAlign')\"\n [ngModel]=\"config().legendVerticalAlign\"\n (ngModelChange)=\"updateConfig({ legendVerticalAlign: $event })\"\n [options]=\"legendVerticalAlignOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendOrientation')\"\n [ngModel]=\"config().legendOrientation\"\n (ngModelChange)=\"updateConfig({ legendOrientation: $event })\"\n [options]=\"legendOrientationOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendType')\"\n [ngModel]=\"config().legendType\"\n (ngModelChange)=\"updateConfig({ legendType: $event })\"\n [options]=\"legendTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('legendIcon')\"\n [ngModel]=\"config().legendIcon\"\n (ngModelChange)=\"updateConfig({ legendIcon: $event })\"\n [options]=\"legendIconOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('totalValueFontSize')\"\n [ngModel]=\"config().totalValueFontSize\"\n (ngModelChange)=\"updateConfig({ totalValueFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('showLabelLine')\"\n [ngModel]=\"config().showLabelLine\"\n (ngModelChange)=\"updateConfig({ showLabelLine: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n\n <!-- Animation Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"animationSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('animation')\"\n [ngModel]=\"config().animation\"\n (ngModelChange)=\"updateConfig({ animation: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('animationDuration')\"\n [ngModel]=\"config().animationDuration\"\n (ngModelChange)=\"updateConfig({ animationDuration: $event })\"\n [min]=\"0\"\n [max]=\"5000\"\n />\n\n <mt-toggle-field\n [label]=\"t('explode')\"\n [ngModel]=\"config().explode\"\n (ngModelChange)=\"updateConfig({ explode: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n</div>\n" }]
9359
9476
  }] });
9360
9477
 
9361
9478
  class BarControlUi {
@@ -9465,7 +9582,7 @@ class BarControlUi {
9465
9582
  useExisting: forwardRef(() => BarControlUi),
9466
9583
  multi: true,
9467
9584
  },
9468
- ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.bar'\"\n>\n <!-- Bar Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-toggle-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('isGrouped')\"\n [ngModel]=\"config().isGrouped\"\n (ngModelChange)=\"updateConfig({ isGrouped: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- X-Axis Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"xAxisSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('xAxisShow')\"\n [ngModel]=\"config().xAxisShow\"\n (ngModelChange)=\"updateConfig({ xAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisFontColor')\"\n [ngModel]=\"config().xAxisFontColor\"\n (ngModelChange)=\"updateConfig({ xAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisLineColor')\"\n [ngModel]=\"config().xAxisLineColor\"\n (ngModelChange)=\"updateConfig({ xAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Y-Axis Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"yAxisSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n @if (config().yAxisShow) {\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n @if (config().yAxisFormat === \"currency\") {\n <mt-toggle-field\n [label]=\"t('showCurrency')\"\n [ngModel]=\"config().showCurrency\"\n (ngModelChange)=\"updateConfig({ showCurrency: $event })\"\n labelPosition=\"start\"\n />\n }\n }\n\n <mt-select-field\n [label]=\"t('yAxisFontSize')\"\n [ngModel]=\"config().yAxisFontSize\"\n (ngModelChange)=\"updateConfig({ yAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisFontColor')\"\n [ngModel]=\"config().yAxisFontColor\"\n (ngModelChange)=\"updateConfig({ yAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisLineColor')\"\n [ngModel]=\"config().yAxisLineColor\"\n (ngModelChange)=\"updateConfig({ yAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('labelShow')\"\n [ngModel]=\"config().labelShow\"\n (ngModelChange)=\"updateConfig({ labelShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('tooltipShow')\"\n [ngModel]=\"config().tooltipShow\"\n (ngModelChange)=\"updateConfig({ tooltipShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('showValueOnlyInTooltip')\"\n [ngModel]=\"config().showValueOnlyInTooltip\"\n (ngModelChange)=\"updateConfig({ showValueOnlyInTooltip: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('maxCharsPerLine')\"\n [ngModel]=\"config().maxCharsPerLine\"\n (ngModelChange)=\"updateConfig({ maxCharsPerLine: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }] });
9585
+ ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.bar'\"\n>\n <!-- Bar Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-toggle-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('isGrouped')\"\n [ngModel]=\"config().isGrouped\"\n (ngModelChange)=\"updateConfig({ isGrouped: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- X-Axis Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"xAxisSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('xAxisShow')\"\n [ngModel]=\"config().xAxisShow\"\n (ngModelChange)=\"updateConfig({ xAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisFontColor')\"\n [ngModel]=\"config().xAxisFontColor\"\n (ngModelChange)=\"updateConfig({ xAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisLineColor')\"\n [ngModel]=\"config().xAxisLineColor\"\n (ngModelChange)=\"updateConfig({ xAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Y-Axis Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"yAxisSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n @if (config().yAxisShow) {\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n @if (config().yAxisFormat === \"currency\") {\n <mt-toggle-field\n [label]=\"t('showCurrency')\"\n [ngModel]=\"config().showCurrency\"\n (ngModelChange)=\"updateConfig({ showCurrency: $event })\"\n labelPosition=\"start\"\n />\n }\n }\n\n <mt-select-field\n [label]=\"t('yAxisFontSize')\"\n [ngModel]=\"config().yAxisFontSize\"\n (ngModelChange)=\"updateConfig({ yAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisFontColor')\"\n [ngModel]=\"config().yAxisFontColor\"\n (ngModelChange)=\"updateConfig({ yAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisLineColor')\"\n [ngModel]=\"config().yAxisLineColor\"\n (ngModelChange)=\"updateConfig({ yAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('labelShow')\"\n [ngModel]=\"config().labelShow\"\n (ngModelChange)=\"updateConfig({ labelShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('tooltipShow')\"\n [ngModel]=\"config().tooltipShow\"\n (ngModelChange)=\"updateConfig({ tooltipShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('showValueOnlyInTooltip')\"\n [ngModel]=\"config().showValueOnlyInTooltip\"\n (ngModelChange)=\"updateConfig({ showValueOnlyInTooltip: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('maxCharsPerLine')\"\n [ngModel]=\"config().maxCharsPerLine\"\n (ngModelChange)=\"updateConfig({ maxCharsPerLine: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }] });
9469
9586
  }
9470
9587
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BarControlUi, decorators: [{
9471
9588
  type: Component,
@@ -9483,7 +9600,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
9483
9600
  useExisting: forwardRef(() => BarControlUi),
9484
9601
  multi: true,
9485
9602
  },
9486
- ], template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.bar'\"\n>\n <!-- Bar Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-toggle-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('isGrouped')\"\n [ngModel]=\"config().isGrouped\"\n (ngModelChange)=\"updateConfig({ isGrouped: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- X-Axis Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"xAxisSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('xAxisShow')\"\n [ngModel]=\"config().xAxisShow\"\n (ngModelChange)=\"updateConfig({ xAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisFontColor')\"\n [ngModel]=\"config().xAxisFontColor\"\n (ngModelChange)=\"updateConfig({ xAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisLineColor')\"\n [ngModel]=\"config().xAxisLineColor\"\n (ngModelChange)=\"updateConfig({ xAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Y-Axis Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"yAxisSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n @if (config().yAxisShow) {\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n @if (config().yAxisFormat === \"currency\") {\n <mt-toggle-field\n [label]=\"t('showCurrency')\"\n [ngModel]=\"config().showCurrency\"\n (ngModelChange)=\"updateConfig({ showCurrency: $event })\"\n labelPosition=\"start\"\n />\n }\n }\n\n <mt-select-field\n [label]=\"t('yAxisFontSize')\"\n [ngModel]=\"config().yAxisFontSize\"\n (ngModelChange)=\"updateConfig({ yAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisFontColor')\"\n [ngModel]=\"config().yAxisFontColor\"\n (ngModelChange)=\"updateConfig({ yAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisLineColor')\"\n [ngModel]=\"config().yAxisLineColor\"\n (ngModelChange)=\"updateConfig({ yAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('labelShow')\"\n [ngModel]=\"config().labelShow\"\n (ngModelChange)=\"updateConfig({ labelShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('tooltipShow')\"\n [ngModel]=\"config().tooltipShow\"\n (ngModelChange)=\"updateConfig({ tooltipShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('showValueOnlyInTooltip')\"\n [ngModel]=\"config().showValueOnlyInTooltip\"\n (ngModelChange)=\"updateConfig({ showValueOnlyInTooltip: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('maxCharsPerLine')\"\n [ngModel]=\"config().maxCharsPerLine\"\n (ngModelChange)=\"updateConfig({ maxCharsPerLine: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n" }]
9603
+ ], template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.bar'\"\n>\n <!-- Bar Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-toggle-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-toggle-field\n [label]=\"t('isGrouped')\"\n [ngModel]=\"config().isGrouped\"\n (ngModelChange)=\"updateConfig({ isGrouped: $event })\"\n labelPosition=\"start\"\n />\n </div>\n </div>\n\n <!-- X-Axis Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"xAxisSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('xAxisShow')\"\n [ngModel]=\"config().xAxisShow\"\n (ngModelChange)=\"updateConfig({ xAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisFontColor')\"\n [ngModel]=\"config().xAxisFontColor\"\n (ngModelChange)=\"updateConfig({ xAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('xAxisLineColor')\"\n [ngModel]=\"config().xAxisLineColor\"\n (ngModelChange)=\"updateConfig({ xAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Y-Axis Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"yAxisSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n @if (config().yAxisShow) {\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n @if (config().yAxisFormat === \"currency\") {\n <mt-toggle-field\n [label]=\"t('showCurrency')\"\n [ngModel]=\"config().showCurrency\"\n (ngModelChange)=\"updateConfig({ showCurrency: $event })\"\n labelPosition=\"start\"\n />\n }\n }\n\n <mt-select-field\n [label]=\"t('yAxisFontSize')\"\n [ngModel]=\"config().yAxisFontSize\"\n (ngModelChange)=\"updateConfig({ yAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisFontColor')\"\n [ngModel]=\"config().yAxisFontColor\"\n (ngModelChange)=\"updateConfig({ yAxisFontColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('yAxisLineColor')\"\n [ngModel]=\"config().yAxisLineColor\"\n (ngModelChange)=\"updateConfig({ yAxisLineColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('labelShow')\"\n [ngModel]=\"config().labelShow\"\n (ngModelChange)=\"updateConfig({ labelShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelPosition')\"\n [ngModel]=\"config().labelPosition\"\n (ngModelChange)=\"updateConfig({ labelPosition: $event })\"\n [options]=\"labelPositionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n\n <mt-select-field\n [label]=\"t('labelFormatter')\"\n [ngModel]=\"config().labelFormatter\"\n (ngModelChange)=\"updateConfig({ labelFormatter: $event })\"\n [options]=\"labelFormatterOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('tooltipShow')\"\n [ngModel]=\"config().tooltipShow\"\n (ngModelChange)=\"updateConfig({ tooltipShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('showValueOnlyInTooltip')\"\n [ngModel]=\"config().showValueOnlyInTooltip\"\n (ngModelChange)=\"updateConfig({ showValueOnlyInTooltip: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-number-field\n [label]=\"t('maxCharsPerLine')\"\n [ngModel]=\"config().maxCharsPerLine\"\n (ngModelChange)=\"updateConfig({ maxCharsPerLine: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-select-field\n [label]=\"t('tooltipTrigger')\"\n [ngModel]=\"config().tooltipTrigger\"\n (ngModelChange)=\"updateConfig({ tooltipTrigger: $event })\"\n [options]=\"tooltipTriggerOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n" }]
9487
9604
  }] });
9488
9605
 
9489
9606
  class StackBarControlUi {
@@ -9576,7 +9693,7 @@ class StackBarControlUi {
9576
9693
  useExisting: forwardRef(() => StackBarControlUi),
9577
9694
  multi: true,
9578
9695
  },
9579
- ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.stackBar'\"\n>\n <!-- Bar Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('isStacked')\"\n [ngModel]=\"config().isStacked\"\n (ngModelChange)=\"updateConfig({ isStacked: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('hasLines')\"\n [ngModel]=\"config().hasLines\"\n (ngModelChange)=\"updateConfig({ hasLines: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Axis Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"axisSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat?.type\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('xAxisLabelRotate')\"\n [ngModel]=\"config().xAxisLabelRotate\"\n (ngModelChange)=\"updateConfig({ xAxisLabelRotate: $event })\"\n [min]=\"-90\"\n [max]=\"90\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('legendPositionY')\"\n [ngModel]=\"config().legendPositionY\"\n (ngModelChange)=\"updateConfig({ legendPositionY: $event })\"\n [options]=\"legendPositionYOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendPositionX')\"\n [ngModel]=\"config().legendPositionX\"\n (ngModelChange)=\"updateConfig({ legendPositionX: $event })\"\n [options]=\"legendPositionXOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('showLabel')\"\n [ngModel]=\"config().showLabel\"\n (ngModelChange)=\"updateConfig({ showLabel: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }] });
9696
+ ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.stackBar'\"\n>\n <!-- Bar Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('isStacked')\"\n [ngModel]=\"config().isStacked\"\n (ngModelChange)=\"updateConfig({ isStacked: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('hasLines')\"\n [ngModel]=\"config().hasLines\"\n (ngModelChange)=\"updateConfig({ hasLines: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Axis Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"axisSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat?.type\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('xAxisLabelRotate')\"\n [ngModel]=\"config().xAxisLabelRotate\"\n (ngModelChange)=\"updateConfig({ xAxisLabelRotate: $event })\"\n [min]=\"-90\"\n [max]=\"90\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('legendPositionY')\"\n [ngModel]=\"config().legendPositionY\"\n (ngModelChange)=\"updateConfig({ legendPositionY: $event })\"\n [options]=\"legendPositionYOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendPositionX')\"\n [ngModel]=\"config().legendPositionX\"\n (ngModelChange)=\"updateConfig({ legendPositionX: $event })\"\n [options]=\"legendPositionXOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('showLabel')\"\n [ngModel]=\"config().showLabel\"\n (ngModelChange)=\"updateConfig({ showLabel: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }] });
9580
9697
  }
9581
9698
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StackBarControlUi, decorators: [{
9582
9699
  type: Component,
@@ -9594,7 +9711,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
9594
9711
  useExisting: forwardRef(() => StackBarControlUi),
9595
9712
  multi: true,
9596
9713
  },
9597
- ], template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.stackBar'\"\n>\n <!-- Bar Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('isStacked')\"\n [ngModel]=\"config().isStacked\"\n (ngModelChange)=\"updateConfig({ isStacked: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('hasLines')\"\n [ngModel]=\"config().hasLines\"\n (ngModelChange)=\"updateConfig({ hasLines: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Axis Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"axisSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat?.type\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('xAxisLabelRotate')\"\n [ngModel]=\"config().xAxisLabelRotate\"\n (ngModelChange)=\"updateConfig({ xAxisLabelRotate: $event })\"\n [min]=\"-90\"\n [max]=\"90\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('legendPositionY')\"\n [ngModel]=\"config().legendPositionY\"\n (ngModelChange)=\"updateConfig({ legendPositionY: $event })\"\n [options]=\"legendPositionYOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendPositionX')\"\n [ngModel]=\"config().legendPositionX\"\n (ngModelChange)=\"updateConfig({ legendPositionX: $event })\"\n [options]=\"legendPositionXOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('showLabel')\"\n [ngModel]=\"config().showLabel\"\n (ngModelChange)=\"updateConfig({ showLabel: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"rounded-xl border border-surface-200 bg-surface-0 p-4\">\n <h4 class=\"mb-4 text-sm font-semibold text-color\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"flex flex-col gap-4\">\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n" }]
9714
+ ], template: "<div\n class=\"flex flex-col gap-5\"\n *transloco=\"let t; prefix: 'dashboardBuilder.chartControls.stackBar'\"\n>\n <!-- Bar Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"barSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('isStacked')\"\n [ngModel]=\"config().isStacked\"\n (ngModelChange)=\"updateConfig({ isStacked: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-toggle-field\n [label]=\"t('hasLines')\"\n [ngModel]=\"config().hasLines\"\n (ngModelChange)=\"updateConfig({ hasLines: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('barType')\"\n [ngModel]=\"config().barType\"\n (ngModelChange)=\"updateConfig({ barType: $event })\"\n [options]=\"barTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('barWidth')\"\n [ngModel]=\"config().barWidth\"\n (ngModelChange)=\"updateConfig({ barWidth: $event })\"\n [min]=\"10\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('borderRadius')\"\n [ngModel]=\"config().borderRadius\"\n (ngModelChange)=\"updateConfig({ borderRadius: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Grid Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"gridSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-number-field\n [label]=\"t('gridLeft')\"\n [ngModel]=\"config().gridLeft\"\n (ngModelChange)=\"updateConfig({ gridLeft: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridRight')\"\n [ngModel]=\"config().gridRight\"\n (ngModelChange)=\"updateConfig({ gridRight: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridTop')\"\n [ngModel]=\"config().gridTop\"\n (ngModelChange)=\"updateConfig({ gridTop: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n\n <mt-number-field\n [label]=\"t('gridBottom')\"\n [ngModel]=\"config().gridBottom\"\n (ngModelChange)=\"updateConfig({ gridBottom: $event })\"\n [min]=\"0\"\n [max]=\"100\"\n />\n </div>\n </div>\n\n <!-- Axis Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"axisSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('yAxisShow')\"\n [ngModel]=\"config().yAxisShow\"\n (ngModelChange)=\"updateConfig({ yAxisShow: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('yAxisFormat')\"\n [ngModel]=\"config().yAxisFormat?.type\"\n (ngModelChange)=\"onYAxisFormatChange($event)\"\n [options]=\"yAxisFormatOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-number-field\n [label]=\"t('xAxisLabelRotate')\"\n [ngModel]=\"config().xAxisLabelRotate\"\n (ngModelChange)=\"updateConfig({ xAxisLabelRotate: $event })\"\n [min]=\"-90\"\n [max]=\"90\"\n />\n\n <mt-select-field\n [label]=\"t('xAxisFontSize')\"\n [ngModel]=\"config().xAxisFontSize\"\n (ngModelChange)=\"updateConfig({ xAxisFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n </div>\n\n <!-- Legend Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"legendSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-select-field\n [label]=\"t('legendPositionY')\"\n [ngModel]=\"config().legendPositionY\"\n (ngModelChange)=\"updateConfig({ legendPositionY: $event })\"\n [options]=\"legendPositionYOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendPositionX')\"\n [ngModel]=\"config().legendPositionX\"\n (ngModelChange)=\"updateConfig({ legendPositionX: $event })\"\n [options]=\"legendPositionXOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-select-field\n [label]=\"t('legendFontSize')\"\n [ngModel]=\"config().legendFontSize\"\n (ngModelChange)=\"updateConfig({ legendFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('legendFontColor')\"\n [ngModel]=\"config().legendFontColor\"\n (ngModelChange)=\"updateConfig({ legendFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Label Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"labelSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-toggle-field\n [label]=\"t('showLabel')\"\n [ngModel]=\"config().showLabel\"\n (ngModelChange)=\"updateConfig({ showLabel: $event })\"\n labelPosition=\"start\"\n />\n\n <mt-select-field\n [label]=\"t('labelFontSize')\"\n [ngModel]=\"config().labelFontSize\"\n (ngModelChange)=\"updateConfig({ labelFontSize: $event })\"\n [options]=\"fontSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n\n <mt-color-picker-field\n [label]=\"t('labelFontColor')\"\n [ngModel]=\"config().labelFontColor\"\n (ngModelChange)=\"updateConfig({ labelFontColor: $event })\"\n />\n </div>\n </div>\n\n <!-- Tooltip Settings -->\n <div class=\"db-control-section\">\n <h4 class=\"db-control-section__header\">\n {{ t(\"tooltipSettings\") }}\n </h4>\n\n <div class=\"db-control-section__body flex flex-col gap-4\">\n <mt-color-picker-field\n [label]=\"t('tooltipBackgroundColor')\"\n [ngModel]=\"config().tooltipBackgroundColor\"\n (ngModelChange)=\"updateConfig({ tooltipBackgroundColor: $event })\"\n />\n\n <mt-color-picker-field\n [label]=\"t('tooltipBorderColor')\"\n [ngModel]=\"config().tooltipBorderColor\"\n (ngModelChange)=\"updateConfig({ tooltipBorderColor: $event })\"\n />\n\n <mt-number-field\n [label]=\"t('tooltipBorderWidth')\"\n [ngModel]=\"config().tooltipBorderWidth\"\n (ngModelChange)=\"updateConfig({ tooltipBorderWidth: $event })\"\n [min]=\"0\"\n [max]=\"10\"\n />\n </div>\n </div>\n</div>\n" }]
9598
9715
  }] });
9599
9716
 
9600
9717
  /**
@@ -11281,7 +11398,7 @@ class SchemaControlRendererComponent {
11281
11398
  </section>
11282
11399
  }
11283
11400
  </div>
11284
- `, isInline: true, styles: [".db-schema-controls{display:flex;flex-direction:column;gap:1rem}.db-schema-section{display:flex;flex-direction:column;gap:.5rem;padding:.75rem;background:var(--p-surface-50, #f9fafb);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.5rem}.db-schema-section__header{display:flex;align-items:center;gap:.5rem}.db-schema-section__header i{color:var(--p-primary-500, #3b82f6)}.db-schema-section__title{margin:0;font-size:.85rem;font-weight:600;color:var(--p-text-color, #1f2937)}.db-schema-section__hint{margin:0;font-size:.75rem;color:var(--p-text-muted-color, #6b7280)}.db-schema-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:.5rem 1rem}.db-schema-field{display:flex;flex-direction:column;gap:.25rem;font-size:.75rem}.db-schema-field__label{font-weight:500;color:var(--p-text-color, #1f2937);display:inline-flex;gap:.25rem}.db-schema-field__required{color:var(--p-red-500, #ef4444)}.db-schema-field__input,.db-schema-field__select,.db-schema-field__textarea,.db-schema-field__json{font-size:.8rem;padding:.35rem .5rem;border-radius:.375rem;border:1px solid var(--p-surface-300, #d1d5db);background:var(--p-surface-0, #fff)}.db-schema-field__color{width:3rem;height:1.75rem;padding:0;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.375rem;background:transparent}.db-schema-field__json{font-family:ui-monospace,SFMono-Regular,monospace}.db-schema-field__multiselect{display:flex;flex-wrap:wrap;gap:.5rem}.db-schema-field__multiselect-option{display:inline-flex;align-items:center;gap:.25rem}.db-schema-field[data-type=boolean]{flex-direction:row;align-items:center;gap:.5rem}.db-schema-field[data-type=boolean] .db-schema-field__label{order:2}.db-schema-field__hint{color:var(--p-text-muted-color, #6b7280)}.db-schema-field__error{color:var(--p-red-600, #dc2626)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11401
+ `, isInline: true, styles: [".db-schema-controls{display:flex;flex-direction:column;gap:1rem}.db-schema-section{display:flex;flex-direction:column;gap:0;overflow:hidden;background:var(--p-surface-0, #fff);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.375rem}.db-schema-section__header{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb)}.db-schema-section__header i{color:var(--p-primary-500, #3b82f6)}.db-schema-section__title{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #1f2937)}.db-schema-section__hint{margin:0;padding:.75rem 1rem 0;font-size:.75rem;color:var(--p-text-muted-color, #6b7280)}.db-schema-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));padding:1rem;gap:.5rem 1rem}.db-schema-field{display:flex;flex-direction:column;gap:.25rem;font-size:.75rem}.db-schema-field__label{font-weight:500;color:var(--p-text-color, #1f2937);display:inline-flex;gap:.25rem}.db-schema-field__required{color:var(--p-red-500, #ef4444)}.db-schema-field__input,.db-schema-field__select,.db-schema-field__textarea,.db-schema-field__json{font-size:.8rem;padding:.35rem .5rem;border-radius:.375rem;border:1px solid var(--p-surface-300, #d1d5db);background:var(--p-surface-0, #fff)}.db-schema-field__color{width:3rem;height:1.75rem;padding:0;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.375rem;background:transparent}.db-schema-field__json{font-family:ui-monospace,SFMono-Regular,monospace}.db-schema-field__multiselect{display:flex;flex-wrap:wrap;gap:.5rem}.db-schema-field__multiselect-option{display:inline-flex;align-items:center;gap:.25rem}.db-schema-field[data-type=boolean]{flex-direction:row;align-items:center;gap:.5rem}.db-schema-field[data-type=boolean] .db-schema-field__label{order:2}.db-schema-field__hint{color:var(--p-text-muted-color, #6b7280)}.db-schema-field__error{color:var(--p-red-600, #dc2626)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11285
11402
  }
11286
11403
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SchemaControlRendererComponent, decorators: [{
11287
11404
  type: Component,
@@ -11437,7 +11554,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
11437
11554
  </section>
11438
11555
  }
11439
11556
  </div>
11440
- `, styles: [".db-schema-controls{display:flex;flex-direction:column;gap:1rem}.db-schema-section{display:flex;flex-direction:column;gap:.5rem;padding:.75rem;background:var(--p-surface-50, #f9fafb);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.5rem}.db-schema-section__header{display:flex;align-items:center;gap:.5rem}.db-schema-section__header i{color:var(--p-primary-500, #3b82f6)}.db-schema-section__title{margin:0;font-size:.85rem;font-weight:600;color:var(--p-text-color, #1f2937)}.db-schema-section__hint{margin:0;font-size:.75rem;color:var(--p-text-muted-color, #6b7280)}.db-schema-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:.5rem 1rem}.db-schema-field{display:flex;flex-direction:column;gap:.25rem;font-size:.75rem}.db-schema-field__label{font-weight:500;color:var(--p-text-color, #1f2937);display:inline-flex;gap:.25rem}.db-schema-field__required{color:var(--p-red-500, #ef4444)}.db-schema-field__input,.db-schema-field__select,.db-schema-field__textarea,.db-schema-field__json{font-size:.8rem;padding:.35rem .5rem;border-radius:.375rem;border:1px solid var(--p-surface-300, #d1d5db);background:var(--p-surface-0, #fff)}.db-schema-field__color{width:3rem;height:1.75rem;padding:0;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.375rem;background:transparent}.db-schema-field__json{font-family:ui-monospace,SFMono-Regular,monospace}.db-schema-field__multiselect{display:flex;flex-wrap:wrap;gap:.5rem}.db-schema-field__multiselect-option{display:inline-flex;align-items:center;gap:.25rem}.db-schema-field[data-type=boolean]{flex-direction:row;align-items:center;gap:.5rem}.db-schema-field[data-type=boolean] .db-schema-field__label{order:2}.db-schema-field__hint{color:var(--p-text-muted-color, #6b7280)}.db-schema-field__error{color:var(--p-red-600, #dc2626)}\n"] }]
11557
+ `, styles: [".db-schema-controls{display:flex;flex-direction:column;gap:1rem}.db-schema-section{display:flex;flex-direction:column;gap:0;overflow:hidden;background:var(--p-surface-0, #fff);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.375rem}.db-schema-section__header{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb)}.db-schema-section__header i{color:var(--p-primary-500, #3b82f6)}.db-schema-section__title{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #1f2937)}.db-schema-section__hint{margin:0;padding:.75rem 1rem 0;font-size:.75rem;color:var(--p-text-muted-color, #6b7280)}.db-schema-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));padding:1rem;gap:.5rem 1rem}.db-schema-field{display:flex;flex-direction:column;gap:.25rem;font-size:.75rem}.db-schema-field__label{font-weight:500;color:var(--p-text-color, #1f2937);display:inline-flex;gap:.25rem}.db-schema-field__required{color:var(--p-red-500, #ef4444)}.db-schema-field__input,.db-schema-field__select,.db-schema-field__textarea,.db-schema-field__json{font-size:.8rem;padding:.35rem .5rem;border-radius:.375rem;border:1px solid var(--p-surface-300, #d1d5db);background:var(--p-surface-0, #fff)}.db-schema-field__color{width:3rem;height:1.75rem;padding:0;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.375rem;background:transparent}.db-schema-field__json{font-family:ui-monospace,SFMono-Regular,monospace}.db-schema-field__multiselect{display:flex;flex-wrap:wrap;gap:.5rem}.db-schema-field__multiselect-option{display:inline-flex;align-items:center;gap:.25rem}.db-schema-field[data-type=boolean]{flex-direction:row;align-items:center;gap:.5rem}.db-schema-field[data-type=boolean] .db-schema-field__label{order:2}.db-schema-field__hint{color:var(--p-text-muted-color, #6b7280)}.db-schema-field__error{color:var(--p-red-600, #dc2626)}\n"] }]
11441
11558
  }], propDecorators: { schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: true }] }], persisted: [{ type: i0.Input, args: [{ isSignal: true, alias: "persisted", required: true }] }], capability: [{ type: i0.Input, args: [{ isSignal: true, alias: "capability", required: false }] }], scope: [{ type: i0.Input, args: [{ isSignal: true, alias: "scope", required: false }] }], patch: [{ type: i0.Output, args: ["patch"] }] } });
11442
11559
 
11443
11560
  /**
@@ -11516,8 +11633,11 @@ class EChartComponent {
11516
11633
  /** Show custom legend */
11517
11634
  showCustomLegend = computed(() => {
11518
11635
  const item = this.configurationItem();
11519
- return Boolean(item?.clientConfig?.configAsType?.['legend']?.show &&
11520
- item?.clientConfig?.pieConfigOverried?.useEnhancedLegend);
11636
+ const legendVisible = item?.clientConfig?.configAsType?.['legend']?.show;
11637
+ if (!legendVisible)
11638
+ return false;
11639
+ return Boolean(item?.clientConfig?.pieConfigOverried?.useEnhancedLegend ||
11640
+ this.hasPieSeries(this.chartOptions()));
11521
11641
  }, ...(ngDevMode ? [{ debugName: "showCustomLegend" }] : /* istanbul ignore next */ []));
11522
11642
  customLegendIconIsRect = computed(() => {
11523
11643
  const iconType = this.configurationItem()?.clientConfig?.configAsType?.['legend']?.['iconType'];
@@ -11582,6 +11702,14 @@ class EChartComponent {
11582
11702
  }
11583
11703
  this.legendItems.set(legends);
11584
11704
  }
11705
+ hasPieSeries(option) {
11706
+ const series = Array.isArray(option?.series)
11707
+ ? option.series
11708
+ : option?.series
11709
+ ? [option.series]
11710
+ : [];
11711
+ return series.some((item) => item?.type === 'pie');
11712
+ }
11585
11713
  /**
11586
11714
  * Toggle legend item visibility
11587
11715
  */
@@ -11801,26 +11929,7 @@ class EChartComponent {
11801
11929
  const mapped = seriesList.map((series) => {
11802
11930
  const type = series?.type;
11803
11931
  if (type === 'pie') {
11804
- return {
11805
- ...series,
11806
- radius: this.getResponsivePieRadius(series.radius, compact, veryCompact),
11807
- center: series.center,
11808
- avoidLabelOverlap: series.avoidLabelOverlap ?? true,
11809
- labelLayout: {
11810
- ...(series.labelLayout || {}),
11811
- hideOverlap: true,
11812
- },
11813
- label: {
11814
- ...(series.label || {}),
11815
- show: veryCompact ? false : series.label?.show,
11816
- fontFamily: series.label?.fontFamily ?? fontFamily,
11817
- fontSize: series.label?.fontSize ?? fontSizes.label,
11818
- },
11819
- labelLine: {
11820
- ...(series.labelLine || {}),
11821
- show: veryCompact ? false : series.labelLine?.show,
11822
- },
11823
- };
11932
+ return series;
11824
11933
  }
11825
11934
  if (type === 'bar' || type === 'line') {
11826
11935
  return {
@@ -12170,14 +12279,6 @@ class EChartComponent {
12170
12279
  }
12171
12280
  return next;
12172
12281
  }
12173
- getResponsivePieRadius(radius, compact, veryCompact) {
12174
- if (!compact)
12175
- return radius;
12176
- if (Array.isArray(radius)) {
12177
- return veryCompact ? ['40%', '62%'] : ['36%', '66%'];
12178
- }
12179
- return veryCompact ? '58%' : '64%';
12180
- }
12181
12282
  estimateCategoryCount(option) {
12182
12283
  const xAxis = Array.isArray(option?.xAxis)
12183
12284
  ? option.xAxis[0]
@@ -12234,7 +12335,7 @@ class EChartComponent {
12234
12335
  }
12235
12336
  </div>
12236
12337
  }
12237
- `, isInline: true, styles: [":host{display:block;width:100%;height:100%;min-height:0;position:relative}.chart-wrapper{width:100%;height:100%;display:flex;justify-content:center;align-items:center;position:relative;min-height:0}.chart-wrapper.in-group-with-header{height:100%}.scroll-wrapper{width:100%;height:100%;overflow-x:auto;overflow-y:hidden;position:relative;min-height:0}.scroll-wrapper.in-group-with-header{height:100%}.chart-wrapper.with-custom-legend,.scroll-wrapper.with-custom-legend{height:calc(100% - 34px)}.chart{width:100%;height:100%;min-height:0}.chart-scroll{width:100%;height:100%;min-height:0;overflow-y:hidden}.custom-legend{position:absolute;bottom:10px;left:0;right:0;z-index:1000;background:transparent;padding:4px 8px;display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:4px;width:100%;max-width:100%}.custom-legend.has-scroll{bottom:25px}.legend-item{display:flex;align-items:center;gap:3px;padding:2px 4px;border-radius:3px;cursor:pointer;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:11px;white-space:nowrap;background:transparent;line-height:1.2;flex-direction:row}.legend-item:hover{background-color:#0000000d}.legend-item.disabled{opacity:.5}.legend-item.disabled .legend-text{text-decoration:line-through}.legend-icon{width:10px;height:10px;border-radius:50%;flex-shrink:0}.legend-text{font-family:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
12338
+ `, isInline: true, styles: [":host{display:block;width:100%;height:100%;min-height:0;position:relative}.chart-wrapper{width:100%;height:96%;display:flex;justify-content:center;align-items:center;position:relative;min-height:0}.chart-wrapper.in-group-with-header{height:86%}.scroll-wrapper{width:100%;height:96%;overflow-x:auto;overflow-y:hidden;position:relative;min-height:0}.scroll-wrapper.in-group-with-header{height:86%}.chart{width:100%;height:100%;min-height:0}.chart-scroll{width:100%;height:100%;min-height:0;overflow-y:hidden}.custom-legend{position:absolute;bottom:10px;left:0;right:0;z-index:1000;background:transparent;padding:4px 8px;display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:4px;width:100%;max-width:100%}.custom-legend.has-scroll{bottom:25px}.legend-item{display:flex;align-items:center;gap:3px;padding:2px 4px;border-radius:3px;cursor:pointer;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:11px;white-space:nowrap;background:transparent;line-height:1.2;flex-direction:row}.legend-item:hover{background-color:#0000000d}.legend-item.disabled{opacity:.5}.legend-item.disabled .legend-text{text-decoration:line-through}.legend-icon{width:10px;height:10px;border-radius:50%;flex-shrink:0}.legend-text{font-family:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
12238
12339
  }
12239
12340
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EChartComponent, decorators: [{
12240
12341
  type: Component,
@@ -12282,7 +12383,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
12282
12383
  }
12283
12384
  </div>
12284
12385
  }
12285
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%;height:100%;min-height:0;position:relative}.chart-wrapper{width:100%;height:100%;display:flex;justify-content:center;align-items:center;position:relative;min-height:0}.chart-wrapper.in-group-with-header{height:100%}.scroll-wrapper{width:100%;height:100%;overflow-x:auto;overflow-y:hidden;position:relative;min-height:0}.scroll-wrapper.in-group-with-header{height:100%}.chart-wrapper.with-custom-legend,.scroll-wrapper.with-custom-legend{height:calc(100% - 34px)}.chart{width:100%;height:100%;min-height:0}.chart-scroll{width:100%;height:100%;min-height:0;overflow-y:hidden}.custom-legend{position:absolute;bottom:10px;left:0;right:0;z-index:1000;background:transparent;padding:4px 8px;display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:4px;width:100%;max-width:100%}.custom-legend.has-scroll{bottom:25px}.legend-item{display:flex;align-items:center;gap:3px;padding:2px 4px;border-radius:3px;cursor:pointer;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:11px;white-space:nowrap;background:transparent;line-height:1.2;flex-direction:row}.legend-item:hover{background-color:#0000000d}.legend-item.disabled{opacity:.5}.legend-item.disabled .legend-text{text-decoration:line-through}.legend-icon{width:10px;height:10px;border-radius:50%;flex-shrink:0}.legend-text{font-family:inherit}\n"] }]
12386
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%;height:100%;min-height:0;position:relative}.chart-wrapper{width:100%;height:96%;display:flex;justify-content:center;align-items:center;position:relative;min-height:0}.chart-wrapper.in-group-with-header{height:86%}.scroll-wrapper{width:100%;height:96%;overflow-x:auto;overflow-y:hidden;position:relative;min-height:0}.scroll-wrapper.in-group-with-header{height:86%}.chart{width:100%;height:100%;min-height:0}.chart-scroll{width:100%;height:100%;min-height:0;overflow-y:hidden}.custom-legend{position:absolute;bottom:10px;left:0;right:0;z-index:1000;background:transparent;padding:4px 8px;display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:4px;width:100%;max-width:100%}.custom-legend.has-scroll{bottom:25px}.legend-item{display:flex;align-items:center;gap:3px;padding:2px 4px;border-radius:3px;cursor:pointer;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:11px;white-space:nowrap;background:transparent;line-height:1.2;flex-direction:row}.legend-item:hover{background-color:#0000000d}.legend-item.disabled{opacity:.5}.legend-item.disabled .legend-text{text-decoration:line-through}.legend-icon{width:10px;height:10px;border-radius:50%;flex-shrink:0}.legend-text{font-family:inherit}\n"] }]
12286
12387
  }], ctorParameters: () => [], propDecorators: { dashboardId: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardId", required: false }] }], chartConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "chartConfig", required: false }] }], configurationItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "configurationItem", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], inGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "inGroup", required: false }] }], headerHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerHidden", required: false }] }], chartClick: [{ type: i0.Output, args: ["chartClick"] }] } });
12287
12388
 
12288
12389
  /**
@@ -15060,6 +15161,8 @@ class PieChartHandler {
15060
15161
  pieOverride?.outerRadiusPercent ??
15061
15162
  undefined;
15062
15163
  const labelPosition = this.normalizePieLabelPosition(pieOverride?.labelPosition);
15164
+ const hasCanvasLegend = showLegend && !pieOverride?.useEnhancedLegend;
15165
+ const suppressCanvasSliceLabels = hasCanvasLegend;
15063
15166
  // Chart settings
15064
15167
  const chartSettings = {
15065
15168
  radius: [
@@ -15071,14 +15174,16 @@ class PieChartHandler {
15071
15174
  totalValueFontSize: labelInCenter
15072
15175
  ? pieOverride?.totalValueFontSize || 22
15073
15176
  : pieOverride?.totalValueFontSize || 30,
15074
- labelFormatter: this.resolvePieLabelFormatter(Boolean(displayPercentage), Boolean(isPercentage), pieOverride?.labelFormatter, labelPosition, clientConfig?.['format'], languageCode),
15177
+ labelFormatter: this.resolvePieLabelFormatter(Boolean(displayPercentage), Boolean(isPercentage), pieOverride?.labelFormatter, labelPosition, clientConfig?.['format'], languageCode, hasCanvasLegend),
15075
15178
  };
15076
15179
  // Build legends
15077
15180
  const allLegend = [
15078
15181
  {
15079
- show: showLegend && !pieOverride?.useEnhancedLegend, // will use custom legend instead
15182
+ show: hasCanvasLegend, // will use custom legend instead
15080
15183
  align: languageCode === 'en' ? 'left' : 'right',
15081
- bottom: 8,
15184
+ left: 'center',
15185
+ bottom: '3%',
15186
+ orient: 'horizontal',
15082
15187
  type: pieOverride?.legendType ||
15083
15188
  (seriesData.length > 8 ? 'scroll' : 'plain'),
15084
15189
  icon: configAsType?.['legend']?.['iconType'] || 'circle',
@@ -15121,7 +15226,9 @@ class PieChartHandler {
15121
15226
  legends = legendChunks.map((chunk, index) => ({
15122
15227
  show: true,
15123
15228
  align: 'right',
15229
+ left: 'center',
15124
15230
  bottom: (legendChunks?.length - index) * 18,
15231
+ orient: 'horizontal',
15125
15232
  type: seriesData.length > 8 ? 'scroll' : 'plain',
15126
15233
  icon: 'circle',
15127
15234
  data: chunk,
@@ -15164,6 +15271,7 @@ class PieChartHandler {
15164
15271
  radius: chartSettings.radius,
15165
15272
  center: ['50%', '45%'], // default; might be overridden below
15166
15273
  padAngle: pieOverride?.padAngle || 0,
15274
+ minShowLabelAngle: hasCanvasLegend ? 8 : 0,
15167
15275
  avoidLabelOverlap: true,
15168
15276
  itemStyle: {
15169
15277
  borderRadius: pieOverride?.borderRadius ?? 8,
@@ -15172,7 +15280,9 @@ class PieChartHandler {
15172
15280
  hideOverlap: true,
15173
15281
  },
15174
15282
  label: {
15175
- show: configAsType?.['label']?.show ?? true,
15283
+ show: suppressCanvasSliceLabels
15284
+ ? false
15285
+ : (configAsType?.['label']?.show ?? true),
15176
15286
  position: labelPosition,
15177
15287
  formatter: chartSettings.labelFormatter,
15178
15288
  fontFamily: generalConfiguration?.fontConfig?.fontFamily,
@@ -15180,7 +15290,7 @@ class PieChartHandler {
15180
15290
  },
15181
15291
  emphasis: {
15182
15292
  label: {
15183
- show: true,
15293
+ show: !suppressCanvasSliceLabels,
15184
15294
  fontSize: '16',
15185
15295
  fontWeight: 'bold',
15186
15296
  },
@@ -15192,9 +15302,11 @@ class PieChartHandler {
15192
15302
  noData: seriesData.length === 0 ||
15193
15303
  seriesData.every((d) => d.value === 0 || d.isStaticProperty),
15194
15304
  };
15305
+ if (suppressCanvasSliceLabels) {
15306
+ baseConfig.series[0].labelLine = { show: false };
15307
+ }
15195
15308
  const genericLegendPosition = this.normalizeLegendPosition(configAsType?.['legend']?.position);
15196
15309
  if (genericLegendPosition &&
15197
- genericLegendPosition !== 'bottom' &&
15198
15310
  !pieOverride?.legendPosition) {
15199
15311
  this.applyPieLegendPosition(baseConfig.legend, genericLegendPosition);
15200
15312
  }
@@ -15246,7 +15358,7 @@ class PieChartHandler {
15246
15358
  legend.left = legend.left ?? 'center';
15247
15359
  break;
15248
15360
  case 'bottom':
15249
- legend.bottom = '2%';
15361
+ legend.bottom = '3%';
15250
15362
  legend.left = legend.left ?? 'center';
15251
15363
  break;
15252
15364
  }
@@ -15273,9 +15385,7 @@ class PieChartHandler {
15273
15385
  if (pieOverride.legendVerticalAlign) {
15274
15386
  applyLegendOverride((legend) => {
15275
15387
  const appliedPosition = pieOverride?.legendPosition;
15276
- if (!appliedPosition ||
15277
- appliedPosition === 'left' ||
15278
- appliedPosition === 'right') {
15388
+ if (appliedPosition === 'left' || appliedPosition === 'right') {
15279
15389
  legend.top = pieOverride.legendVerticalAlign;
15280
15390
  delete legend.bottom;
15281
15391
  }
@@ -15321,11 +15431,14 @@ class PieChartHandler {
15321
15431
  series.avoidLabelOverlap = pieOverride.avoidLabelOverlap;
15322
15432
  if (pieOverride.labelPosition) {
15323
15433
  series.label.position = labelPosition;
15324
- series.label.show = true;
15434
+ series.label.show = !suppressCanvasSliceLabels;
15325
15435
  }
15326
15436
  if (pieOverride.labelFontColor)
15327
15437
  series.label.color = pieOverride.labelFontColor;
15328
- if (pieOverride.showLabelLine !== undefined) {
15438
+ if (suppressCanvasSliceLabels) {
15439
+ series.labelLine = { show: false };
15440
+ }
15441
+ else if (pieOverride.showLabelLine !== undefined) {
15329
15442
  series.labelLine = { show: pieOverride.showLabelLine };
15330
15443
  }
15331
15444
  if (pieOverride.selectedMode !== undefined)
@@ -15362,7 +15475,6 @@ class PieChartHandler {
15362
15475
  }
15363
15476
  }
15364
15477
  const finalLegendPosition = this.normalizeLegendPosition(pieOverride?.legendPosition ?? genericLegendPosition);
15365
- const hasCanvasLegend = showLegend && !pieOverride?.useEnhancedLegend;
15366
15478
  if (finalLegendPosition &&
15367
15479
  !this.hasExplicitPieCenter(pieOverride) &&
15368
15480
  (finalLegendPosition !== 'bottom' || hasCanvasLegend)) {
@@ -15426,7 +15538,7 @@ class PieChartHandler {
15426
15538
  }
15427
15539
  return baseConfig;
15428
15540
  }
15429
- resolvePieLabelFormatter(displayPercentage, isPercentage, configuredFormatter, labelPosition, clientFormat, languageCode) {
15541
+ resolvePieLabelFormatter(displayPercentage, isPercentage, configuredFormatter, labelPosition, clientFormat, languageCode, hasCanvasLegend) {
15430
15542
  const valueFormatter = (params) => {
15431
15543
  if (params.data?.isStaticProperty === true && isPercentage) {
15432
15544
  return '';
@@ -15441,6 +15553,9 @@ class PieChartHandler {
15441
15553
  return ` ${params.percent}%`;
15442
15554
  };
15443
15555
  }
15556
+ if (hasCanvasLegend && labelPosition === 'inside') {
15557
+ return valueFormatter;
15558
+ }
15444
15559
  if (typeof configuredFormatter === 'string' &&
15445
15560
  this.pieLabelFormatterUsesName(configuredFormatter)) {
15446
15561
  return valueFormatter;
@@ -15451,7 +15566,7 @@ class PieChartHandler {
15451
15566
  return position === 'outside' ? 'outside' : 'inside';
15452
15567
  }
15453
15568
  pieLabelFormatterUsesName(formatter) {
15454
- return /\{b(?:\d*)?\}/.test(formatter);
15569
+ return /\{(?:b|name)(?:\d*)?\}/i.test(formatter);
15455
15570
  }
15456
15571
  normalizeLegendPosition(position) {
15457
15572
  return position === 'top' ||
@@ -15488,7 +15603,7 @@ class PieChartHandler {
15488
15603
  legend.orient = legend.orient ?? 'horizontal';
15489
15604
  break;
15490
15605
  case 'bottom':
15491
- legend.bottom = '2%';
15606
+ legend.bottom = '3%';
15492
15607
  legend.left = legend.left ?? 'center';
15493
15608
  legend.orient = legend.orient ?? 'horizontal';
15494
15609
  break;
@@ -22081,7 +22196,7 @@ class ChartSettingsDrawer {
22081
22196
  this.item.set(item);
22082
22197
  }
22083
22198
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ChartSettingsDrawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
22084
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ChartSettingsDrawer, isStandalone: true, selector: "mt-chart-settings-drawer", ngImport: i0, template: "<div\r\n [class]=\"modal.contentClass + ' flex h-full min-h-0 flex-col p-0'\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <div\r\n class=\"sticky top-0 z-10 border-b border-surface-200 bg-surface-0 px-4 pb-3 pt-4\"\r\n >\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3\">\r\n @if (showDisplayTab()) {\r\n <!-- Display Tab -->\r\n <div [hidden]=\"activeTab() !== 'display'\" class=\"flex flex-col gap-3\">\r\n <mt-display-settings\r\n [config]=\"itemConfig()\"\r\n [chartType]=\"resolvedChartType()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Chart Controls Tab -->\r\n <div [hidden]=\"activeTab() !== 'chartControls'\" class=\"flex flex-col gap-3\">\r\n @switch (manageType()) {\r\n @case (\"default\") {\r\n <mt-default-control-ui\r\n [ngModel]=\"defaultControlConfig()\"\r\n [showIconSettings]=\"isLayoutItem()\"\r\n [layoutComponent]=\"layoutComponentName()\"\r\n (ngModelChange)=\"onDefaultConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"pie\") {\r\n <mt-pie-control-ui\r\n [ngModel]=\"pieConfig()\"\r\n (ngModelChange)=\"onPieConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"bar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"barConfig()\"\r\n (ngModelChange)=\"onBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"stackBar\") {\r\n <mt-stack-bar-control-ui\r\n [ngModel]=\"stackBarConfig()\"\r\n (ngModelChange)=\"onStackBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"snapshotBar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"snapshotBarConfig()\"\r\n (ngModelChange)=\"onSnapshotBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @default {\r\n <!-- Pass-4: schema-driven controls fill the gap for chart/item types\r\n that don't have a bespoke quick-control component. Every supported\r\n chart in the manifest has a control schema in the registry, so\r\n this branch always renders real controls instead of\r\n noSettingsAvailable. -->\r\n <mt-schema-control-renderer\r\n [schema]=\"schemaForItem()\"\r\n [persisted]=\"itemConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Isolated Preview Tab -->\r\n <div [hidden]=\"activeTab() !== 'preview'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"preview\") {\r\n @if (canRenderChartPreview()) {\r\n <div\r\n class=\"h-[28rem] min-h-[28rem] rounded-lg border border-surface-200 bg-surface-50 p-3\"\r\n >\r\n <mt-card-content\r\n class=\"block h-full w-full\"\r\n [headerConfig]=\"previewHeaderConfig()\"\r\n [styleConfig]=\"previewStyleConfig()\"\r\n [cardStyleConfig]=\"previewCardStyleConfig()\"\r\n [density]=\"previewDensity()\"\r\n [title]=\"previewTitle()\"\r\n [isNoTopEnd]=\"true\"\r\n [isChart]=\"true\"\r\n >\r\n <ng-container body>\r\n <mt-echart\r\n class=\"block h-full w-full\"\r\n [dashboardId]=\"previewDashboardId\"\r\n [chartConfig]=\"previewChartData()\"\r\n [configurationItem]=\"itemConfig()\"\r\n height=\"100%\"\r\n />\r\n </ng-container>\r\n </mt-card-content>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[16rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-4 text-center\"\r\n >\r\n <div class=\"max-w-sm\">\r\n <p class=\"text-sm font-medium text-color\">\r\n {{ t(\"noPreviewAvailable\") }}\r\n </p>\r\n <p class=\"mt-1 text-xs text-muted-color\">\r\n {{ t(\"configureChartToPreview\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Advanced Override (JSON) - Pass-2 -->\r\n <div [hidden]=\"activeTab() !== 'advanced'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"advanced\") {\r\n <ng-container>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ t(\"pass4.advanced.hint\") }}\r\n </p>\r\n <textarea\r\n class=\"font-mono text-xs w-full p-2 rounded border border-surface-300 bg-surface-50\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"text-xs text-red-600\">{{ advancedJsonError() }}</p>\r\n }\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"t('pass4.advanced.apply')\"\r\n icon=\"general.check\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n [class]=\"\r\n modal.footerClass + ' border-t border-surface-200 bg-surface-0 px-4 py-3'\r\n \"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('apply')\" icon=\"general.check\" (onClick)=\"apply()\" />\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: DisplaySettings, selector: "mt-display-settings", inputs: ["config", "chartType", "availableProperties", "selectedProperties", "lookups"], outputs: ["clientConfigChange"] }, { kind: "component", type: DefaultControlUi, selector: "mt-default-control-ui", inputs: ["showIconSettings", "layoutComponent"] }, { kind: "component", type: PieControlUi, selector: "mt-pie-control-ui" }, { kind: "component", type: BarControlUi, selector: "mt-bar-control-ui" }, { kind: "component", type: StackBarControlUi, selector: "mt-stack-bar-control-ui" }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }, { kind: "component", type: EChartComponent, selector: "mt-echart", inputs: ["dashboardId", "chartConfig", "configurationItem", "height", "inGroup", "headerHidden"], outputs: ["chartClick"] }, { kind: "component", type: CardContentComponent, selector: "mt-card-content", inputs: ["title", "inGroup", "headerConfig", "styleConfig", "cardStyleConfig", "density", "showHeader", "headerClickable", "isNoTopEnd", "isChart", "titleEditable"], outputs: ["headerClick", "titleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
22199
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ChartSettingsDrawer, isStandalone: true, selector: "mt-chart-settings-drawer", ngImport: i0, template: "<div\n [class]=\"\n modal.contentClass + ' db-sectioned-drawer flex h-full min-h-0 flex-col p-0'\n \"\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\n>\n <div\r\n class=\"sticky top-0 z-10 border-b border-surface-200 bg-surface-0 px-4 pb-3 pt-4\"\r\n >\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3\">\r\n @if (showDisplayTab()) {\r\n <!-- Display Tab -->\r\n <div [hidden]=\"activeTab() !== 'display'\" class=\"flex flex-col gap-3\">\r\n <mt-display-settings\r\n [config]=\"itemConfig()\"\r\n [chartType]=\"resolvedChartType()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Chart Controls Tab -->\r\n <div [hidden]=\"activeTab() !== 'chartControls'\" class=\"flex flex-col gap-3\">\r\n @switch (manageType()) {\r\n @case (\"default\") {\r\n <mt-default-control-ui\r\n [ngModel]=\"defaultControlConfig()\"\r\n [showIconSettings]=\"isLayoutItem()\"\r\n [layoutComponent]=\"layoutComponentName()\"\r\n (ngModelChange)=\"onDefaultConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"pie\") {\r\n <mt-pie-control-ui\r\n [ngModel]=\"pieConfig()\"\r\n (ngModelChange)=\"onPieConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"bar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"barConfig()\"\r\n (ngModelChange)=\"onBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"stackBar\") {\r\n <mt-stack-bar-control-ui\r\n [ngModel]=\"stackBarConfig()\"\r\n (ngModelChange)=\"onStackBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"snapshotBar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"snapshotBarConfig()\"\r\n (ngModelChange)=\"onSnapshotBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @default {\r\n <!-- Pass-4: schema-driven controls fill the gap for chart/item types\r\n that don't have a bespoke quick-control component. Every supported\r\n chart in the manifest has a control schema in the registry, so\r\n this branch always renders real controls instead of\r\n noSettingsAvailable. -->\r\n <mt-schema-control-renderer\r\n [schema]=\"schemaForItem()\"\r\n [persisted]=\"itemConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Isolated Preview Tab -->\r\n <div [hidden]=\"activeTab() !== 'preview'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"preview\") {\r\n @if (canRenderChartPreview()) {\r\n <div\r\n class=\"h-[28rem] min-h-[28rem] rounded-lg border border-surface-200 bg-surface-50 p-3\"\r\n >\r\n <mt-card-content\r\n class=\"block h-full w-full\"\r\n [headerConfig]=\"previewHeaderConfig()\"\r\n [styleConfig]=\"previewStyleConfig()\"\r\n [cardStyleConfig]=\"previewCardStyleConfig()\"\r\n [density]=\"previewDensity()\"\r\n [title]=\"previewTitle()\"\r\n [isNoTopEnd]=\"true\"\r\n [isChart]=\"true\"\r\n >\r\n <ng-container body>\r\n <mt-echart\r\n class=\"block h-full w-full\"\r\n [dashboardId]=\"previewDashboardId\"\r\n [chartConfig]=\"previewChartData()\"\r\n [configurationItem]=\"itemConfig()\"\r\n height=\"100%\"\r\n />\r\n </ng-container>\r\n </mt-card-content>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[16rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-4 text-center\"\r\n >\r\n <div class=\"max-w-sm\">\r\n <p class=\"text-sm font-medium text-color\">\r\n {{ t(\"noPreviewAvailable\") }}\r\n </p>\r\n <p class=\"mt-1 text-xs text-muted-color\">\r\n {{ t(\"configureChartToPreview\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Advanced Override (JSON) - Pass-2 -->\r\n <div [hidden]=\"activeTab() !== 'advanced'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"advanced\") {\r\n <ng-container>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ t(\"pass4.advanced.hint\") }}\r\n </p>\r\n <textarea\r\n class=\"font-mono text-xs w-full p-2 rounded border border-surface-300 bg-surface-50\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"text-xs text-red-600\">{{ advancedJsonError() }}</p>\r\n }\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"t('pass4.advanced.apply')\"\r\n icon=\"general.check\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n [class]=\"\r\n modal.footerClass + ' border-t border-surface-200 bg-surface-0 px-4 py-3'\r\n \"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('apply')\" icon=\"general.check\" (onClick)=\"apply()\" />\r\n</div>\r\n", styles: [".db-sectioned-drawer mt-card{overflow:hidden;border-color:var(--p-surface-200, #e5e7eb);background:var(--p-surface-0, #fff);border-radius:.375rem}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1){padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb)}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1) h3{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #111827)}.db-control-section{display:flex;flex-direction:column;gap:0;overflow:hidden;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.375rem;background:var(--p-surface-0, #fff)}.db-control-section__header{margin:0;padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb);font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #111827)}.db-control-section__body{padding:1rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: DisplaySettings, selector: "mt-display-settings", inputs: ["config", "chartType", "availableProperties", "selectedProperties", "lookups"], outputs: ["clientConfigChange"] }, { kind: "component", type: DefaultControlUi, selector: "mt-default-control-ui", inputs: ["showIconSettings", "layoutComponent"] }, { kind: "component", type: PieControlUi, selector: "mt-pie-control-ui" }, { kind: "component", type: BarControlUi, selector: "mt-bar-control-ui" }, { kind: "component", type: StackBarControlUi, selector: "mt-stack-bar-control-ui" }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }, { kind: "component", type: EChartComponent, selector: "mt-echart", inputs: ["dashboardId", "chartConfig", "configurationItem", "height", "inGroup", "headerHidden"], outputs: ["chartClick"] }, { kind: "component", type: CardContentComponent, selector: "mt-card-content", inputs: ["title", "inGroup", "headerConfig", "styleConfig", "cardStyleConfig", "density", "showHeader", "headerClickable", "isNoTopEnd", "isChart", "titleEditable"], outputs: ["headerClick", "titleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
22085
22200
  }
22086
22201
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ChartSettingsDrawer, decorators: [{
22087
22202
  type: Component,
@@ -22099,7 +22214,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
22099
22214
  SchemaControlRendererComponent,
22100
22215
  EChartComponent,
22101
22216
  CardContentComponent,
22102
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\r\n [class]=\"modal.contentClass + ' flex h-full min-h-0 flex-col p-0'\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <div\r\n class=\"sticky top-0 z-10 border-b border-surface-200 bg-surface-0 px-4 pb-3 pt-4\"\r\n >\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3\">\r\n @if (showDisplayTab()) {\r\n <!-- Display Tab -->\r\n <div [hidden]=\"activeTab() !== 'display'\" class=\"flex flex-col gap-3\">\r\n <mt-display-settings\r\n [config]=\"itemConfig()\"\r\n [chartType]=\"resolvedChartType()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Chart Controls Tab -->\r\n <div [hidden]=\"activeTab() !== 'chartControls'\" class=\"flex flex-col gap-3\">\r\n @switch (manageType()) {\r\n @case (\"default\") {\r\n <mt-default-control-ui\r\n [ngModel]=\"defaultControlConfig()\"\r\n [showIconSettings]=\"isLayoutItem()\"\r\n [layoutComponent]=\"layoutComponentName()\"\r\n (ngModelChange)=\"onDefaultConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"pie\") {\r\n <mt-pie-control-ui\r\n [ngModel]=\"pieConfig()\"\r\n (ngModelChange)=\"onPieConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"bar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"barConfig()\"\r\n (ngModelChange)=\"onBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"stackBar\") {\r\n <mt-stack-bar-control-ui\r\n [ngModel]=\"stackBarConfig()\"\r\n (ngModelChange)=\"onStackBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"snapshotBar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"snapshotBarConfig()\"\r\n (ngModelChange)=\"onSnapshotBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @default {\r\n <!-- Pass-4: schema-driven controls fill the gap for chart/item types\r\n that don't have a bespoke quick-control component. Every supported\r\n chart in the manifest has a control schema in the registry, so\r\n this branch always renders real controls instead of\r\n noSettingsAvailable. -->\r\n <mt-schema-control-renderer\r\n [schema]=\"schemaForItem()\"\r\n [persisted]=\"itemConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Isolated Preview Tab -->\r\n <div [hidden]=\"activeTab() !== 'preview'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"preview\") {\r\n @if (canRenderChartPreview()) {\r\n <div\r\n class=\"h-[28rem] min-h-[28rem] rounded-lg border border-surface-200 bg-surface-50 p-3\"\r\n >\r\n <mt-card-content\r\n class=\"block h-full w-full\"\r\n [headerConfig]=\"previewHeaderConfig()\"\r\n [styleConfig]=\"previewStyleConfig()\"\r\n [cardStyleConfig]=\"previewCardStyleConfig()\"\r\n [density]=\"previewDensity()\"\r\n [title]=\"previewTitle()\"\r\n [isNoTopEnd]=\"true\"\r\n [isChart]=\"true\"\r\n >\r\n <ng-container body>\r\n <mt-echart\r\n class=\"block h-full w-full\"\r\n [dashboardId]=\"previewDashboardId\"\r\n [chartConfig]=\"previewChartData()\"\r\n [configurationItem]=\"itemConfig()\"\r\n height=\"100%\"\r\n />\r\n </ng-container>\r\n </mt-card-content>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[16rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-4 text-center\"\r\n >\r\n <div class=\"max-w-sm\">\r\n <p class=\"text-sm font-medium text-color\">\r\n {{ t(\"noPreviewAvailable\") }}\r\n </p>\r\n <p class=\"mt-1 text-xs text-muted-color\">\r\n {{ t(\"configureChartToPreview\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Advanced Override (JSON) - Pass-2 -->\r\n <div [hidden]=\"activeTab() !== 'advanced'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"advanced\") {\r\n <ng-container>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ t(\"pass4.advanced.hint\") }}\r\n </p>\r\n <textarea\r\n class=\"font-mono text-xs w-full p-2 rounded border border-surface-300 bg-surface-50\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"text-xs text-red-600\">{{ advancedJsonError() }}</p>\r\n }\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"t('pass4.advanced.apply')\"\r\n icon=\"general.check\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n [class]=\"\r\n modal.footerClass + ' border-t border-surface-200 bg-surface-0 px-4 py-3'\r\n \"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('apply')\" icon=\"general.check\" (onClick)=\"apply()\" />\r\n</div>\r\n" }]
22217
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n [class]=\"\n modal.contentClass + ' db-sectioned-drawer flex h-full min-h-0 flex-col p-0'\n \"\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\n>\n <div\r\n class=\"sticky top-0 z-10 border-b border-surface-200 bg-surface-0 px-4 pb-3 pt-4\"\r\n >\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3\">\r\n @if (showDisplayTab()) {\r\n <!-- Display Tab -->\r\n <div [hidden]=\"activeTab() !== 'display'\" class=\"flex flex-col gap-3\">\r\n <mt-display-settings\r\n [config]=\"itemConfig()\"\r\n [chartType]=\"resolvedChartType()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Chart Controls Tab -->\r\n <div [hidden]=\"activeTab() !== 'chartControls'\" class=\"flex flex-col gap-3\">\r\n @switch (manageType()) {\r\n @case (\"default\") {\r\n <mt-default-control-ui\r\n [ngModel]=\"defaultControlConfig()\"\r\n [showIconSettings]=\"isLayoutItem()\"\r\n [layoutComponent]=\"layoutComponentName()\"\r\n (ngModelChange)=\"onDefaultConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"pie\") {\r\n <mt-pie-control-ui\r\n [ngModel]=\"pieConfig()\"\r\n (ngModelChange)=\"onPieConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"bar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"barConfig()\"\r\n (ngModelChange)=\"onBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"stackBar\") {\r\n <mt-stack-bar-control-ui\r\n [ngModel]=\"stackBarConfig()\"\r\n (ngModelChange)=\"onStackBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"snapshotBar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"snapshotBarConfig()\"\r\n (ngModelChange)=\"onSnapshotBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @default {\r\n <!-- Pass-4: schema-driven controls fill the gap for chart/item types\r\n that don't have a bespoke quick-control component. Every supported\r\n chart in the manifest has a control schema in the registry, so\r\n this branch always renders real controls instead of\r\n noSettingsAvailable. -->\r\n <mt-schema-control-renderer\r\n [schema]=\"schemaForItem()\"\r\n [persisted]=\"itemConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Isolated Preview Tab -->\r\n <div [hidden]=\"activeTab() !== 'preview'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"preview\") {\r\n @if (canRenderChartPreview()) {\r\n <div\r\n class=\"h-[28rem] min-h-[28rem] rounded-lg border border-surface-200 bg-surface-50 p-3\"\r\n >\r\n <mt-card-content\r\n class=\"block h-full w-full\"\r\n [headerConfig]=\"previewHeaderConfig()\"\r\n [styleConfig]=\"previewStyleConfig()\"\r\n [cardStyleConfig]=\"previewCardStyleConfig()\"\r\n [density]=\"previewDensity()\"\r\n [title]=\"previewTitle()\"\r\n [isNoTopEnd]=\"true\"\r\n [isChart]=\"true\"\r\n >\r\n <ng-container body>\r\n <mt-echart\r\n class=\"block h-full w-full\"\r\n [dashboardId]=\"previewDashboardId\"\r\n [chartConfig]=\"previewChartData()\"\r\n [configurationItem]=\"itemConfig()\"\r\n height=\"100%\"\r\n />\r\n </ng-container>\r\n </mt-card-content>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[16rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-4 text-center\"\r\n >\r\n <div class=\"max-w-sm\">\r\n <p class=\"text-sm font-medium text-color\">\r\n {{ t(\"noPreviewAvailable\") }}\r\n </p>\r\n <p class=\"mt-1 text-xs text-muted-color\">\r\n {{ t(\"configureChartToPreview\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Advanced Override (JSON) - Pass-2 -->\r\n <div [hidden]=\"activeTab() !== 'advanced'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"advanced\") {\r\n <ng-container>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ t(\"pass4.advanced.hint\") }}\r\n </p>\r\n <textarea\r\n class=\"font-mono text-xs w-full p-2 rounded border border-surface-300 bg-surface-50\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"text-xs text-red-600\">{{ advancedJsonError() }}</p>\r\n }\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"t('pass4.advanced.apply')\"\r\n icon=\"general.check\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n [class]=\"\r\n modal.footerClass + ' border-t border-surface-200 bg-surface-0 px-4 py-3'\r\n \"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('apply')\" icon=\"general.check\" (onClick)=\"apply()\" />\r\n</div>\r\n", styles: [".db-sectioned-drawer mt-card{overflow:hidden;border-color:var(--p-surface-200, #e5e7eb);background:var(--p-surface-0, #fff);border-radius:.375rem}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1){padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb)}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1) h3{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #111827)}.db-control-section{display:flex;flex-direction:column;gap:0;overflow:hidden;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.375rem;background:var(--p-surface-0, #fff)}.db-control-section__header{margin:0;padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb);font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #111827)}.db-control-section__body{padding:1rem}\n"] }]
22103
22218
  }], ctorParameters: () => [] });
22104
22219
  /**
22105
22220
  * Deep-merge two plain object trees. Arrays and primitives in the source
@@ -23033,7 +23148,7 @@ class GeneralQuery {
23033
23148
  useExisting: forwardRef(() => GeneralQuery),
23034
23149
  multi: true,
23035
23150
  },
23036
- ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-4\"\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\n [formGroup]=\"queryForm\"\n>\n <!-- Category Property (shown for certain chart types) -->\n @if (shouldShowField(\"categoryProperty\")) {\n <div class=\"mb-2\">\n <mt-select-field\n [label]=\"t('categoryProperty')\"\n formControlName=\"categoryProperty\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectCategoryProperty')\"\n [filter]=\"true\"\n />\n </div>\n }\n\n <!-- Add Series Button -->\n @if (chartType() !== \"overview\" || seriesArray.length === 0) {\n <div class=\"flex justify-end\">\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addSeries')\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"addSeries()\"\n />\n </div>\n }\n\n <!-- Series List -->\n <div formArrayName=\"series\" class=\"flex flex-col gap-4\">\n @for (\n series of seriesArray.controls;\n track trackByIndex(i);\n let i = $index\n ) {\n <div\n class=\"p-4 rounded-lg border transition-all\"\n [class.border-red-500]=\"series.invalid\"\n [class.border-surface-200]=\"!series.invalid\"\n [formGroupName]=\"i\"\n >\n <!-- Series Header -->\n <div class=\"flex items-center justify-between mb-4\">\n <div class=\"flex items-center gap-2\">\n <span\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full bg-primary-100 text-primary-600 text-sm font-semibold\"\n >\n {{ i + 1 }}\n </span>\n <span class=\"text-sm font-medium text-muted-color\">{{\n t(\"series\")\n }}</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <mt-button\n icon=\"general.settings-02\"\n severity=\"secondary\"\n [rounded]=\"true\"\n size=\"small\"\n (onClick)=\"toggleAdvanced(i)\"\n [pTooltip]=\"t('advancedSettings')\"\n />\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"deleteSeries(i)\"\n />\n </div>\n </div>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n <!-- Auto Stack Toggle -->\n @if (shouldShowField(\"autoStack\")) {\n <div class=\"md:col-span-2 lg:col-span-3\">\n <mt-toggle-field\n [label]=\"t('autoStack')\"\n formControlName=\"autoStack\"\n />\n </div>\n }\n\n <!-- Value Property -->\n @if (shouldShowField(\"valueProperty\") || series.value.autoStack) {\n <mt-select-field\n [label]=\"t('valueProperty')\"\n formControlName=\"valueProperty\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectValueProperty')\"\n [filter]=\"true\"\n />\n }\n\n <!-- Aggregate Function -->\n @if (shouldShowField(\"aggregateFunction\")) {\n <mt-select-field\n [label]=\"t('aggregateFunction')\"\n formControlName=\"aggregateFunction\"\n [options]=\"aggregateFunctions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n }\n\n <!-- Color Picker -->\n @if (shouldShowField(\"color\")) {\n <mt-color-picker-field\n [label]=\"t('seriesColor')\"\n formControlName=\"color\"\n />\n }\n\n <!-- Bar Type (for stacked bar charts) -->\n @if (shouldShowField(\"barType\")) {\n <mt-select-field\n [label]=\"t('barType')\"\n formControlName=\"barType\"\n [options]=\"barTypes\"\n optionLabel=\"name\"\n optionValue=\"key\"\n />\n }\n\n <!-- Auto Stack By Property -->\n @if (\n shouldShowField(\"autoStackByProperty\") && series.value.autoStack\n ) {\n <mt-select-field\n [label]=\"t('autoStackByProperty')\"\n formControlName=\"autoStackByProperty\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperty')\"\n [filter]=\"true\"\n />\n }\n\n <!-- Group By Properties -->\n @if (shouldShowField(\"groupByProperties\")) {\n <div class=\"col-span-full\">\n <mt-multi-select-field\n [label]=\"t('groupByProperties')\"\n formControlName=\"groupByProperties\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperties')\"\n [filter]=\"true\"\n />\n </div>\n }\n\n <!-- Stack Properties (for stacked charts) -->\n @if (shouldShowField(\"stackProperties\") && !series.value.autoStack) {\n <div class=\"col-span-full\">\n <mt-multi-select-field\n [label]=\"t('stackProperties')\"\n formControlName=\"stackProperties\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperties')\"\n [filter]=\"true\"\n />\n </div>\n }\n\n <!-- Extra Properties -->\n @if (shouldShowField(\"extraProperties\")) {\n <div class=\"col-span-full\">\n <mt-multi-select-field\n [label]=\"t('extraProperties')\"\n formControlName=\"extraProperties\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperties')\"\n [filter]=\"true\"\n />\n </div>\n }\n </div>\n\n <!-- Advanced Settings (Formula) -->\n @if (series.value.showAdvancedSettings && shouldShowField(\"formula\")) {\n <div\n class=\"mt-4 p-3 bg-surface-50 rounded-lg border border-surface-200\"\n >\n <div class=\"text-sm font-medium mb-2\">\n {{ t(\"advancedSettings\") }}\n </div>\n <mt-text-field\n [label]=\"t('formula')\"\n formControlName=\"formula\"\n [placeholder]=\"t('enterFormula')\"\n />\n </div>\n }\n\n <!-- Filters Section -->\n @if (shouldShowField(\"filters\")) {\n <div class=\"mt-4 border border-surface-200 rounded-lg p-4\">\n <div class=\"flex items-center justify-between mb-3\">\n <span class=\"text-sm font-medium\">{{ t(\"seriesFilters\") }}</span>\n <mt-button\n icon=\"general.plus\"\n severity=\"secondary\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"addFilter(i)\"\n [pTooltip]=\"t('addFilter')\"\n />\n </div>\n\n <div class=\"flex flex-col gap-3\" formArrayName=\"filters\">\n @for (\n filter of getFilters(series).controls;\n track trackByIndex(j);\n let j = $index\n ) {\n <div\n class=\"grid grid-cols-12 gap-2 p-3 bg-surface-50 rounded-lg border border-surface-100\"\n [formGroupName]=\"j\"\n >\n <!-- Property Key -->\n <div class=\"col-span-4\">\n <mt-select-field\n [label]=\"j === 0 ? t('property') : ''\"\n formControlName=\"propertyKey\"\n [options]=\"\n useGroupedSelect()\n ? propertiesGrouped()\n : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperty')\"\n [filter]=\"true\"\n />\n </div>\n\n <!-- Operator -->\n <div class=\"col-span-2\">\n <mt-select-field\n [label]=\"j === 0 ? t('operator') : ''\"\n formControlName=\"operator\"\n [options]=\"operators\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n\n <!-- Value -->\n <div class=\"col-span-4\">\n <mt-text-field\n [label]=\"j === 0 ? t('value') : ''\"\n formControlName=\"value\"\n [placeholder]=\"t('enterValue')\"\n />\n </div>\n\n <!-- Remove Filter -->\n <div class=\"col-span-2 flex items-end justify-end pb-1\">\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"removeFilter(i, j)\"\n />\n </div>\n </div>\n }\n\n @if (getFilters(series).length === 0) {\n <div class=\"text-center py-3 text-muted-color text-sm\">\n {{ t(\"noFiltersConfigured\") }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n\n @if (seriesArray.length === 0) {\n <div\n class=\"text-center py-8 text-muted-color border border-dashed border-surface-300 rounded-lg\"\n >\n <i class=\"mti mti-chart-bar text-3xl mb-2 block\"></i>\n <p class=\"mb-2\">{{ t(\"noSeriesConfigured\") }}</p>\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addSeries')\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"addSeries()\"\n />\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23151
+ ], ngImport: i0, template: "<div\n class=\"flex flex-col gap-4\"\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\n [formGroup]=\"queryForm\"\n>\n <!-- Category Property (shown for certain chart types) -->\n @if (shouldShowField(\"categoryProperty\")) {\n <div class=\"mb-2\">\n <mt-select-field\n [label]=\"t('categoryProperty')\"\n formControlName=\"categoryProperty\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectCategoryProperty')\"\n [filter]=\"true\"\n />\n </div>\n }\n\n <!-- Add Series Button -->\n @if (chartType() !== \"overview\" || seriesArray.length === 0) {\n <div class=\"flex justify-end\">\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addSeries')\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"addSeries()\"\n />\n </div>\n }\n\n <!-- Series List -->\n <div formArrayName=\"series\" class=\"flex flex-col gap-4\">\n @for (\n series of seriesArray.controls;\n track trackByIndex(i);\n let i = $index\n ) {\n <div\n class=\"p-4 rounded-lg border transition-all\"\n [class.border-red-500]=\"series.invalid\"\n [class.border-surface-200]=\"!series.invalid\"\n [formGroupName]=\"i\"\n >\n <!-- Series Header -->\n <div class=\"flex items-center justify-between mb-4\">\n <div class=\"flex items-center gap-2\">\n <span\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full bg-primary-100 text-primary-600 text-sm font-semibold\"\n >\n {{ i + 1 }}\n </span>\n <span class=\"text-sm font-medium text-muted-color\">{{\n t(\"series\")\n }}</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <mt-button\n icon=\"general.settings-02\"\n severity=\"secondary\"\n [rounded]=\"true\"\n size=\"small\"\n (onClick)=\"toggleAdvanced(i)\"\n [pTooltip]=\"t('advancedSettings')\"\n />\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"deleteSeries(i)\"\n />\n </div>\n </div>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n <!-- Auto Stack Toggle -->\n @if (shouldShowField(\"autoStack\")) {\n <div class=\"md:col-span-2 lg:col-span-3\">\n <mt-toggle-field\n [label]=\"t('autoStack')\"\n formControlName=\"autoStack\"\n />\n </div>\n }\n\n <!-- Value Property -->\n @if (shouldShowField(\"valueProperty\") || series.value.autoStack) {\n <mt-select-field\n [label]=\"t('valueProperty')\"\n formControlName=\"valueProperty\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectValueProperty')\"\n [filter]=\"true\"\n />\n }\n\n <!-- Aggregate Function -->\n @if (shouldShowField(\"aggregateFunction\")) {\n <mt-select-field\n [label]=\"t('aggregateFunction')\"\n formControlName=\"aggregateFunction\"\n [options]=\"aggregateFunctions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n }\n\n <!-- Color Picker -->\n @if (shouldShowField(\"color\")) {\n <mt-color-picker-field\n [label]=\"t('seriesColor')\"\n formControlName=\"color\"\n />\n }\n\n <!-- Bar Type (for stacked bar charts) -->\n @if (shouldShowField(\"barType\")) {\n <mt-select-field\n [label]=\"t('barType')\"\n formControlName=\"barType\"\n [options]=\"barTypes\"\n optionLabel=\"name\"\n optionValue=\"key\"\n />\n }\n\n <!-- Auto Stack By Property -->\n @if (\n shouldShowField(\"autoStackByProperty\") && series.value.autoStack\n ) {\n <mt-select-field\n [label]=\"t('autoStackByProperty')\"\n formControlName=\"autoStackByProperty\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperty')\"\n [filter]=\"true\"\n />\n }\n\n <!-- Group By Properties -->\n @if (shouldShowField(\"groupByProperties\")) {\n <div class=\"col-span-full\">\n <mt-multi-select-field\n [label]=\"t('groupByProperties')\"\n formControlName=\"groupByProperties\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperties')\"\n [filter]=\"true\"\n />\n </div>\n }\n\n <!-- Stack Properties (for stacked charts) -->\n @if (shouldShowField(\"stackProperties\") && !series.value.autoStack) {\n <div class=\"col-span-full\">\n <mt-multi-select-field\n [label]=\"t('stackProperties')\"\n formControlName=\"stackProperties\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperties')\"\n [filter]=\"true\"\n />\n </div>\n }\n\n <!-- Extra Properties -->\n @if (shouldShowField(\"extraProperties\")) {\n <div class=\"col-span-full\">\n <mt-multi-select-field\n [label]=\"t('extraProperties')\"\n formControlName=\"extraProperties\"\n [options]=\"\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperties')\"\n [filter]=\"true\"\n />\n </div>\n }\n </div>\n\n <!-- Advanced Settings (Formula) -->\n @if (series.value.showAdvancedSettings && shouldShowField(\"formula\")) {\n <div\n class=\"mt-4 p-3 bg-surface-50 rounded-lg border border-surface-200\"\n >\n <div class=\"text-sm font-medium mb-2\">\n {{ t(\"advancedSettings\") }}\n </div>\n <mt-text-field\n [label]=\"t('formula')\"\n formControlName=\"formula\"\n [placeholder]=\"t('enterFormula')\"\n />\n </div>\n }\n\n <!-- Filters Section -->\n @if (shouldShowField(\"filters\")) {\n <div class=\"mt-4 border border-surface-200 rounded-lg p-4\">\n <div class=\"flex items-center justify-between mb-3\">\n <span class=\"text-sm font-medium\">{{ t(\"seriesFilters\") }}</span>\n <mt-button\n icon=\"general.plus\"\n severity=\"secondary\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"addFilter(i)\"\n [pTooltip]=\"t('addFilter')\"\n />\n </div>\n\n <div class=\"flex flex-col gap-3\" formArrayName=\"filters\">\n @for (\n filter of getFilters(series).controls;\n track trackByIndex(j);\n let j = $index\n ) {\n <div\n class=\"grid grid-cols-12 gap-2 p-3 bg-surface-50 rounded-lg border border-surface-100\"\n [formGroupName]=\"j\"\n >\n <!-- Property Key -->\n <div class=\"col-span-4\">\n <mt-select-field\n [label]=\"j === 0 ? t('property') : ''\"\n formControlName=\"propertyKey\"\n [options]=\"\n useGroupedSelect()\n ? propertiesGrouped()\n : propertiesFlat()\n \"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [placeholder]=\"t('selectProperty')\"\n [filter]=\"true\"\n />\n </div>\n\n <!-- Operator -->\n <div class=\"col-span-2\">\n <mt-select-field\n [label]=\"j === 0 ? t('operator') : ''\"\n formControlName=\"operator\"\n [options]=\"operators\"\n optionLabel=\"label\"\n optionValue=\"value\"\n />\n </div>\n\n <!-- Value -->\n <div class=\"col-span-4\">\n <mt-text-field\n [label]=\"j === 0 ? t('value') : ''\"\n formControlName=\"value\"\n [placeholder]=\"t('enterValue')\"\n />\n </div>\n\n <!-- Remove Filter -->\n <div class=\"col-span-2 flex items-end justify-end pb-1\">\n <mt-button\n icon=\"general.trash-01\"\n severity=\"danger\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"removeFilter(i, j)\"\n />\n </div>\n </div>\n }\n\n @if (getFilters(series).length === 0) {\n <div class=\"text-center py-3 text-muted-color text-sm\">\n {{ t(\"noFiltersConfigured\") }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n\n @if (seriesArray.length === 0) {\n <div\n class=\"text-center py-8 text-muted-color border border-dashed border-surface-300 rounded-lg\"\n >\n <i class=\"mti mti-chart-bar text-3xl mb-2 block\"></i>\n <p class=\"mb-2\">{{ t(\"noSeriesConfigured\") }}</p>\n <mt-button\n icon=\"general.plus\"\n [label]=\"t('addSeries')\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"disabled\"\n (onClick)=\"addSeries()\"\n />\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: ColorPickerField, selector: "mt-color-picker-field", inputs: ["label", "appendTo", "placeholder", "class", "variant", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23037
23152
  }
23038
23153
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GeneralQuery, decorators: [{
23039
23154
  type: Component,
@@ -23232,7 +23347,7 @@ class TableQuery {
23232
23347
  useExisting: forwardRef(() => TableQuery),
23233
23348
  multi: true,
23234
23349
  },
23235
- ], ngImport: i0, template: "<div\r\n class=\"flex flex-col gap-4\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n [formGroup]=\"queryForm\"\r\n>\r\n <!-- Lookup Property -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('lookupProperty')\"\r\n formControlName=\"lookupProperty\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectLookupProperty')\"\r\n [filter]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- Selected Properties -->\r\n <div class=\"w-full\">\r\n <mt-multi-select-field\r\n [label]=\"t('properties')\"\r\n formControlName=\"selectedProperties\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperties')\"\r\n [filter]=\"true\"\r\n />\r\n @if (\r\n queryForm.get(\"selectedProperties\")?.invalid &&\r\n queryForm.get(\"selectedProperties\")?.touched\r\n ) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n t(\"atLeastOnePropertyRequired\")\r\n }}</small>\r\n }\r\n @if (selectedProperties().length > 1) {\r\n <div class=\"mt-3 flex flex-col gap-2\">\r\n <span class=\"text-xs font-medium text-muted-color\">\r\n {{ t(\"propertyOrder\") }}\r\n </span>\r\n @for (propertyKey of selectedProperties(); track propertyKey + $index) {\r\n <div\r\n class=\"flex items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <span class=\"min-w-0 truncate text-sm\">\r\n {{ getPropertyLabel(propertyKey) }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"arrow.arrow-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === 0\"\r\n [pTooltip]=\"t('moveUp')\"\r\n (onClick)=\"moveSelectedProperty($index, -1)\"\r\n />\r\n <mt-button\r\n icon=\"arrow.arrow-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"\r\n disabled || $index === selectedProperties().length - 1\r\n \"\r\n [pTooltip]=\"t('moveDown')\"\r\n (onClick)=\"moveSelectedProperty($index, 1)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Pivot Properties -->\r\n <div class=\"w-full\">\r\n <mt-multi-select-field\r\n [label]=\"t('pivotProperties')\"\r\n formControlName=\"PivotProperties\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectPivotProperties')\"\r\n [filter]=\"true\"\r\n />\r\n @if (pivotProperties().length > 1) {\r\n <div class=\"mt-3 flex flex-col gap-2\">\r\n <span class=\"text-xs font-medium text-muted-color\">\r\n {{ t(\"pivotPropertyOrder\") }}\r\n </span>\r\n @for (propertyKey of pivotProperties(); track propertyKey + $index) {\r\n <div\r\n class=\"flex items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <span class=\"min-w-0 truncate text-sm\">\r\n {{ getPropertyLabel(propertyKey) }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"arrow.arrow-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === 0\"\r\n [pTooltip]=\"t('moveUp')\"\r\n (onClick)=\"movePivotProperty($index, -1)\"\r\n />\r\n <mt-button\r\n icon=\"arrow.arrow-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === pivotProperties().length - 1\"\r\n [pTooltip]=\"t('moveDown')\"\r\n (onClick)=\"movePivotProperty($index, 1)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Aggregation Properties -->\r\n <mt-card [title]=\"t('aggregationProperties')\">\r\n <ng-template #cardEnd>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"addAggregation()\"\r\n [disabled]=\"disabled\"\r\n [pTooltip]=\"t('addAggregation')\"\r\n />\r\n </ng-template>\r\n\r\n <div class=\"flex flex-col gap-3\" formArrayName=\"AggregationProperties\">\r\n @for (\r\n agg of aggregationArray.controls;\r\n track trackByIndex(i);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"grid grid-cols-12 gap-3 p-3 bg-surface-50 rounded-lg border border-surface-100\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Property Key -->\r\n <div class=\"col-span-5\">\r\n <mt-select-field\r\n [label]=\"i === 0 ? t('property') : ''\"\r\n formControlName=\"propertyKey\"\r\n [options]=\"\r\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\r\n \"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- Aggregate Function -->\r\n <div class=\"col-span-4\">\r\n <mt-select-field\r\n [label]=\"i === 0 ? t('aggregateFunction') : ''\"\r\n formControlName=\"aggregateFunction\"\r\n [options]=\"aggregateFunctions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n </div>\r\n\r\n <!-- Remove -->\r\n <div class=\"col-span-3 flex items-end justify-end pb-1\">\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeAggregation(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (aggregationArray.length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noAggregationsConfigured\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23350
+ ], ngImport: i0, template: "<div\r\n class=\"flex flex-col gap-4\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n [formGroup]=\"queryForm\"\r\n>\r\n <!-- Lookup Property -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <mt-select-field\r\n [label]=\"t('lookupProperty')\"\r\n formControlName=\"lookupProperty\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectLookupProperty')\"\r\n [filter]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- Selected Properties -->\r\n <div class=\"w-full\">\r\n <mt-multi-select-field\r\n [label]=\"t('properties')\"\r\n formControlName=\"selectedProperties\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperties')\"\r\n [filter]=\"true\"\r\n />\r\n @if (\r\n queryForm.get(\"selectedProperties\")?.invalid &&\r\n queryForm.get(\"selectedProperties\")?.touched\r\n ) {\r\n <small class=\"text-red-500 mt-1 block\">{{\r\n t(\"atLeastOnePropertyRequired\")\r\n }}</small>\r\n }\r\n @if (selectedProperties().length > 1) {\r\n <div class=\"mt-3 flex flex-col gap-2\">\r\n <span class=\"text-xs font-medium text-muted-color\">\r\n {{ t(\"propertyOrder\") }}\r\n </span>\r\n @for (propertyKey of selectedProperties(); track propertyKey + $index) {\r\n <div\r\n class=\"flex items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <span class=\"min-w-0 truncate text-sm\">\r\n {{ getPropertyLabel(propertyKey) }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"arrow.arrow-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === 0\"\r\n [pTooltip]=\"t('moveUp')\"\r\n (onClick)=\"moveSelectedProperty($index, -1)\"\r\n />\r\n <mt-button\r\n icon=\"arrow.arrow-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"\r\n disabled || $index === selectedProperties().length - 1\r\n \"\r\n [pTooltip]=\"t('moveDown')\"\r\n (onClick)=\"moveSelectedProperty($index, 1)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Pivot Properties -->\r\n <div class=\"w-full\">\r\n <mt-multi-select-field\r\n [label]=\"t('pivotProperties')\"\r\n formControlName=\"PivotProperties\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectPivotProperties')\"\r\n [filter]=\"true\"\r\n />\r\n @if (pivotProperties().length > 1) {\r\n <div class=\"mt-3 flex flex-col gap-2\">\r\n <span class=\"text-xs font-medium text-muted-color\">\r\n {{ t(\"pivotPropertyOrder\") }}\r\n </span>\r\n @for (propertyKey of pivotProperties(); track propertyKey + $index) {\r\n <div\r\n class=\"flex items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <span class=\"min-w-0 truncate text-sm\">\r\n {{ getPropertyLabel(propertyKey) }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"arrow.arrow-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === 0\"\r\n [pTooltip]=\"t('moveUp')\"\r\n (onClick)=\"movePivotProperty($index, -1)\"\r\n />\r\n <mt-button\r\n icon=\"arrow.arrow-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === pivotProperties().length - 1\"\r\n [pTooltip]=\"t('moveDown')\"\r\n (onClick)=\"movePivotProperty($index, 1)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Aggregation Properties -->\r\n <mt-card [title]=\"t('aggregationProperties')\">\r\n <ng-template #cardEnd>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"addAggregation()\"\r\n [disabled]=\"disabled\"\r\n [pTooltip]=\"t('addAggregation')\"\r\n />\r\n </ng-template>\r\n\r\n <div class=\"flex flex-col gap-3\" formArrayName=\"AggregationProperties\">\r\n @for (\r\n agg of aggregationArray.controls;\r\n track trackByIndex(i);\r\n let i = $index\r\n ) {\r\n <div\r\n class=\"grid grid-cols-12 gap-3 p-3 bg-surface-50 rounded-lg border border-surface-100\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Property Key -->\r\n <div class=\"col-span-5\">\r\n <mt-select-field\r\n [label]=\"i === 0 ? t('property') : ''\"\r\n formControlName=\"propertyKey\"\r\n [options]=\"\r\n useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\r\n \"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- Aggregate Function -->\r\n <div class=\"col-span-4\">\r\n <mt-select-field\r\n [label]=\"i === 0 ? t('aggregateFunction') : ''\"\r\n formControlName=\"aggregateFunction\"\r\n [options]=\"aggregateFunctions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n </div>\r\n\r\n <!-- Remove -->\r\n <div class=\"col-span-3 flex items-end justify-end pb-1\">\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [rounded]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeAggregation(i)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (aggregationArray.length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noAggregationsConfigured\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23236
23351
  }
23237
23352
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableQuery, decorators: [{
23238
23353
  type: Component,
@@ -23323,7 +23438,7 @@ class TimelineQuery {
23323
23438
  useExisting: forwardRef(() => TimelineQuery),
23324
23439
  multi: true,
23325
23440
  },
23326
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Pivot Property -->\n <mt-select-field\n [label]=\"t('pivotProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().pivotProperty\"\n (ngModelChange)=\"updateField('pivotProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Lookup Property -->\n <mt-select-field\n [label]=\"t('lookupProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().lookupProperty\"\n (ngModelChange)=\"updateField('lookupProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Time Frame -->\n <mt-select-field\n [label]=\"t('timeFrame')\"\n [options]=\"timeFrameOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectTimeFrame')\"\n [ngModel]=\"query().timeFrame\"\n (ngModelChange)=\"updateField('timeFrame', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Start Point Time Property -->\n <mt-select-field\n [label]=\"t('startPointTimeProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().startPoint_timeProperty\"\n (ngModelChange)=\"updateField('startPoint_timeProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- End Point Time Property -->\n <mt-select-field\n [label]=\"t('endPointTimeProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().endPoint_timeProperty\"\n (ngModelChange)=\"updateField('endPoint_timeProperty', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n\n <!-- Extra Properties -->\n <div class=\"w-full\">\n <mt-multi-select-field\n [label]=\"t('extraProperties')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperties')\"\n [ngModel]=\"query().extraProperties\"\n (ngModelChange)=\"updateField('extraProperties', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23441
+ ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Pivot Property -->\n <mt-select-field\n [label]=\"t('pivotProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().pivotProperty\"\n (ngModelChange)=\"updateField('pivotProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Lookup Property -->\n <mt-select-field\n [label]=\"t('lookupProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().lookupProperty\"\n (ngModelChange)=\"updateField('lookupProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Time Frame -->\n <mt-select-field\n [label]=\"t('timeFrame')\"\n [options]=\"timeFrameOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectTimeFrame')\"\n [ngModel]=\"query().timeFrame\"\n (ngModelChange)=\"updateField('timeFrame', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Start Point Time Property -->\n <mt-select-field\n [label]=\"t('startPointTimeProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().startPoint_timeProperty\"\n (ngModelChange)=\"updateField('startPoint_timeProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- End Point Time Property -->\n <mt-select-field\n [label]=\"t('endPointTimeProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().endPoint_timeProperty\"\n (ngModelChange)=\"updateField('endPoint_timeProperty', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n\n <!-- Extra Properties -->\n <div class=\"w-full\">\n <mt-multi-select-field\n [label]=\"t('extraProperties')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperties')\"\n [ngModel]=\"query().extraProperties\"\n (ngModelChange)=\"updateField('extraProperties', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23327
23442
  }
23328
23443
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TimelineQuery, decorators: [{
23329
23444
  type: Component,
@@ -23419,7 +23534,7 @@ class PropertiesQuery {
23419
23534
  useExisting: forwardRef(() => PropertiesQuery),
23420
23535
  multi: true,
23421
23536
  },
23422
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <div class=\"w-full\">\r\n <mt-multi-select-field\r\n [label]=\"t('selectProperties')\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [filter]=\"true\"\r\n [placeholder]=\"t('selectProperties')\"\r\n [ngModel]=\"query().selectedProperties\"\r\n (ngModelChange)=\"updateSelectedProperties($event)\"\r\n [disabled]=\"disabled\"\r\n />\r\n @if ((query().selectedProperties?.length || 0) > 1) {\r\n <div class=\"mt-3 flex flex-col gap-2\">\r\n <span class=\"text-xs font-medium text-muted-color\">\r\n {{ t(\"propertyOrder\") }}\r\n </span>\r\n @for (\r\n propertyKey of query().selectedProperties;\r\n track propertyKey + $index\r\n ) {\r\n <div\r\n class=\"flex items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <span class=\"min-w-0 truncate text-sm\">\r\n {{ getPropertyLabel(propertyKey) }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"arrow.arrow-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === 0\"\r\n [pTooltip]=\"t('moveUp')\"\r\n (onClick)=\"moveSelectedProperty($index, -1)\"\r\n />\r\n <mt-button\r\n icon=\"arrow.arrow-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"\r\n disabled ||\r\n $index === (query().selectedProperties?.length || 0) - 1\r\n \"\r\n [pTooltip]=\"t('moveDown')\"\r\n (onClick)=\"moveSelectedProperty($index, 1)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (query().selectedProperties?.length) {\r\n <div class=\"text-sm text-muted-color\">\r\n {{ t(\"selectedCount\") }}: {{ query().selectedProperties?.length }}\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { 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: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23537
+ ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <div class=\"w-full\">\r\n <mt-multi-select-field\r\n [label]=\"t('selectProperties')\"\r\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\r\n [group]=\"useGroupedSelect()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [filter]=\"true\"\r\n [placeholder]=\"t('selectProperties')\"\r\n [ngModel]=\"query().selectedProperties\"\r\n (ngModelChange)=\"updateSelectedProperties($event)\"\r\n [disabled]=\"disabled\"\r\n />\r\n @if ((query().selectedProperties?.length || 0) > 1) {\r\n <div class=\"mt-3 flex flex-col gap-2\">\r\n <span class=\"text-xs font-medium text-muted-color\">\r\n {{ t(\"propertyOrder\") }}\r\n </span>\r\n @for (\r\n propertyKey of query().selectedProperties;\r\n track propertyKey + $index\r\n ) {\r\n <div\r\n class=\"flex items-center justify-between gap-2 rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <span class=\"min-w-0 truncate text-sm\">\r\n {{ getPropertyLabel(propertyKey) }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <mt-button\r\n icon=\"arrow.arrow-up\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled || $index === 0\"\r\n [pTooltip]=\"t('moveUp')\"\r\n (onClick)=\"moveSelectedProperty($index, -1)\"\r\n />\r\n <mt-button\r\n icon=\"arrow.arrow-down\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"\r\n disabled ||\r\n $index === (query().selectedProperties?.length || 0) - 1\r\n \"\r\n [pTooltip]=\"t('moveDown')\"\r\n (onClick)=\"moveSelectedProperty($index, 1)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (query().selectedProperties?.length) {\r\n <div class=\"text-sm text-muted-color\">\r\n {{ t(\"selectedCount\") }}: {{ query().selectedProperties?.length }}\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { 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: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23423
23538
  }
23424
23539
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertiesQuery, decorators: [{
23425
23540
  type: Component,
@@ -23514,7 +23629,7 @@ class SnapshotQuery {
23514
23629
  useExisting: forwardRef(() => SnapshotQuery),
23515
23630
  multi: true,
23516
23631
  },
23517
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Level ID -->\n <mt-text-field\n [label]=\"t('levelId')\"\n [placeholder]=\"t('enterLevelId')\"\n [ngModel]=\"query().levelId\"\n (ngModelChange)=\"updateField('levelId', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Time Frame -->\n <mt-select-field\n [label]=\"t('timeFrame')\"\n [options]=\"timeFrameOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectTimeFrame')\"\n [ngModel]=\"query().timeFrame\"\n (ngModelChange)=\"updateField('timeFrame', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Year -->\n <mt-select-field\n [label]=\"t('year')\"\n [options]=\"yearOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectYear')\"\n [ngModel]=\"query().year\"\n (ngModelChange)=\"updateField('year', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Get Average Per Period -->\n <div class=\"flex items-end pb-2\">\n <mt-toggle-field\n [label]=\"t('getAveragePerPeriod')\"\n [ngModel]=\"query().getAveragePerPeriod\"\n (ngModelChange)=\"updateField('getAveragePerPeriod', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n </div>\n\n <!-- Selected Properties -->\n <div class=\"w-full\">\n <mt-multi-select-field\n [label]=\"t('selectedProperties')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperties')\"\n [ngModel]=\"query().selectedProperties\"\n (ngModelChange)=\"updateField('selectedProperties', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23632
+ ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Level ID -->\n <mt-text-field\n [label]=\"t('levelId')\"\n [placeholder]=\"t('enterLevelId')\"\n [ngModel]=\"query().levelId\"\n (ngModelChange)=\"updateField('levelId', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Time Frame -->\n <mt-select-field\n [label]=\"t('timeFrame')\"\n [options]=\"timeFrameOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectTimeFrame')\"\n [ngModel]=\"query().timeFrame\"\n (ngModelChange)=\"updateField('timeFrame', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Year -->\n <mt-select-field\n [label]=\"t('year')\"\n [options]=\"yearOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"t('selectYear')\"\n [ngModel]=\"query().year\"\n (ngModelChange)=\"updateField('year', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Get Average Per Period -->\n <div class=\"flex items-end pb-2\">\n <mt-toggle-field\n [label]=\"t('getAveragePerPeriod')\"\n [ngModel]=\"query().getAveragePerPeriod\"\n (ngModelChange)=\"updateField('getAveragePerPeriod', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n </div>\n\n <!-- Selected Properties -->\n <div class=\"w-full\">\n <mt-multi-select-field\n [label]=\"t('selectedProperties')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperties')\"\n [ngModel]=\"query().selectedProperties\"\n (ngModelChange)=\"updateField('selectedProperties', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23518
23633
  }
23519
23634
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SnapshotQuery, decorators: [{
23520
23635
  type: Component,
@@ -23599,7 +23714,7 @@ class MapQuery {
23599
23714
  useExisting: forwardRef(() => MapQuery),
23600
23715
  multi: true,
23601
23716
  },
23602
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Location Property -->\n <mt-select-field\n [label]=\"t('locationProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().locationProperty\"\n (ngModelChange)=\"updateField('locationProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Grouping Property -->\n <mt-select-field\n [label]=\"t('groupingProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().groupingProperty\"\n (ngModelChange)=\"updateField('groupingProperty', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n\n <!-- Extra Properties -->\n <div class=\"w-full\">\n <mt-multi-select-field\n [label]=\"t('extraProperties')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperties')\"\n [ngModel]=\"query().extraProperties\"\n (ngModelChange)=\"updateField('extraProperties', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23717
+ ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Location Property -->\n <mt-select-field\n [label]=\"t('locationProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().locationProperty\"\n (ngModelChange)=\"updateField('locationProperty', $event)\"\n [disabled]=\"disabled\"\n />\n\n <!-- Grouping Property -->\n <mt-select-field\n [label]=\"t('groupingProperty')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperty')\"\n [ngModel]=\"query().groupingProperty\"\n (ngModelChange)=\"updateField('groupingProperty', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n\n <!-- Extra Properties -->\n <div class=\"w-full\">\n <mt-multi-select-field\n [label]=\"t('extraProperties')\"\n [options]=\"useGroupedSelect() ? propertiesGrouped() : propertiesFlat()\"\n [group]=\"useGroupedSelect()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n optionGroupLabel=\"label\"\n optionGroupChildren=\"items\"\n [filter]=\"true\"\n [placeholder]=\"t('selectProperties')\"\n [ngModel]=\"query().extraProperties\"\n (ngModelChange)=\"updateField('extraProperties', $event)\"\n [disabled]=\"disabled\"\n />\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23603
23718
  }
23604
23719
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: MapQuery, decorators: [{
23605
23720
  type: Component,
@@ -28974,11 +29089,11 @@ class PropertiesCardComponent {
28974
29089
  return '';
28975
29090
  }
28976
29091
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertiesCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28977
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PropertiesCardComponent, isStandalone: true, selector: "mt-properties-card, mt-entities-preview-card", inputs: { dashboardId: { classPropertyName: "dashboardId", publicName: "dashboardId", isSignal: true, isRequired: true, transformFunction: null }, inGroup: { classPropertyName: "inGroup", publicName: "inGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n @if (showTabs()) {\r\n <div class=\"mb-3\">\r\n <mt-tabs [(active)]=\"tabSelected\" [options]=\"tabOptions()\" size=\"small\" />\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"overflow-y-auto overflow-x-hidden\"\r\n [style.max-height]=\"inGroup() ? '500px' : '90%'\"\r\n >\r\n @if (currentTabCards().length === 0) {\r\n <div class=\"py-6 text-center text-sm text-gray-400\">\r\n {{ t(\"noData\") }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap\">\r\n @for (cardView of currentTabCards(); track cardView.trackId) {\r\n <div\r\n class=\"mb-2 cursor-pointer p-2\"\r\n [class.card-col]=\"!galleryMode()\"\r\n [class.gallery-card-col]=\"galleryMode()\"\r\n [class.w-full]=\"!galleryMode()\"\r\n [class.md:w-1/2]=\"!galleryMode()\"\r\n [class.lg:w-1/3]=\"!galleryMode()\"\r\n (click)=\"onCardClick(cardView.card)\"\r\n >\r\n @defer (on viewport) {\r\n <ng-container>\r\n @if (cardView.entities.length > 0) {\r\n <mt-entities-preview [entities]=\"cardView.entities\" />\r\n } @else {\r\n <div class=\"py-6 text-center text-sm text-gray-400\">\r\n {{ t(\"noData\") }}\r\n </div>\r\n }\r\n </ng-container>\r\n } @placeholder {\r\n <div class=\"min-h-24 p-2\">\r\n <div class=\"flex animate-pulse flex-col gap-3\">\r\n <div class=\"h-4 w-2/3 rounded bg-surface-200\"></div>\r\n <div class=\"h-4 w-full rounded bg-surface-100\"></div>\r\n <div class=\"h-4 w-5/6 rounded bg-surface-100\"></div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}.card-col{flex:0 0 100%}@media(min-width:768px){.card-col{flex:0 0 50%}}@media(min-width:1024px){.card-col{flex:0 0 33.333%}}.gallery-card-col{flex:0 0 100%}@media(min-width:640px){.gallery-card-col{flex:0 0 50%}}@media(min-width:1024px){.gallery-card-col{flex:0 0 25%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [EntitiesPreview]] });
29092
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PropertiesCardComponent, isStandalone: true, selector: "mt-properties-card, mt-entities-preview-card", inputs: { dashboardId: { classPropertyName: "dashboardId", publicName: "dashboardId", isSignal: true, isRequired: true, transformFunction: null }, inGroup: { classPropertyName: "inGroup", publicName: "inGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n @if (showTabs()) {\r\n <div class=\"mb-3\">\r\n <mt-tabs [(active)]=\"tabSelected\" [options]=\"tabOptions()\" size=\"small\" />\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"overflow-y-auto overflow-x-hidden\"\r\n [style.max-height]=\"inGroup() ? '500px' : '90%'\"\r\n >\r\n @if (currentTabCards().length === 0) {\r\n <div class=\"py-6 text-center text-sm text-gray-400\">\r\n {{ t(\"noData\") }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap\">\r\n @for (cardView of currentTabCards(); track cardView.trackId) {\r\n <div\r\n class=\"mb-2 cursor-pointer p-2\"\r\n [class.card-col]=\"!galleryMode()\"\r\n [class.gallery-card-col]=\"galleryMode()\"\r\n [class.w-full]=\"!galleryMode()\"\r\n [class.md:w-1/2]=\"!galleryMode()\"\r\n [class.lg:w-1/3]=\"!galleryMode()\"\n (click)=\"onCardClick(cardView.card)\"\n >\n <div class=\"rounded-lg bg-white p-3 shadow-sm\">\n @defer (on viewport) {\n <ng-container>\n @if (cardView.entities.length > 0) {\n <mt-entities-preview [entities]=\"cardView.entities\" />\n } @else {\n <div class=\"py-6 text-center text-sm text-gray-400\">\n {{ t(\"noData\") }}\n </div>\n }\n </ng-container>\n } @placeholder {\n <div class=\"min-h-24 p-2\">\n <div class=\"flex animate-pulse flex-col gap-3\">\n <div class=\"h-4 w-2/3 rounded bg-surface-200\"></div>\n <div class=\"h-4 w-full rounded bg-surface-100\"></div>\n <div class=\"h-4 w-5/6 rounded bg-surface-100\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}.card-col{flex:0 0 100%}@media(min-width:768px){.card-col{flex:0 0 50%}}@media(min-width:1024px){.card-col{flex:0 0 33.333%}}.gallery-card-col{flex:0 0 100%}@media(min-width:640px){.gallery-card-col{flex:0 0 50%}}@media(min-width:1024px){.gallery-card-col{flex:0 0 25%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [EntitiesPreview]] });
28978
29093
  }
28979
29094
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertiesCardComponent, decorators: [{
28980
29095
  type: Component,
28981
- args: [{ selector: 'mt-properties-card, mt-entities-preview-card', standalone: true, imports: [CommonModule, TranslocoDirective, Tabs, EntitiesPreview], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n @if (showTabs()) {\r\n <div class=\"mb-3\">\r\n <mt-tabs [(active)]=\"tabSelected\" [options]=\"tabOptions()\" size=\"small\" />\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"overflow-y-auto overflow-x-hidden\"\r\n [style.max-height]=\"inGroup() ? '500px' : '90%'\"\r\n >\r\n @if (currentTabCards().length === 0) {\r\n <div class=\"py-6 text-center text-sm text-gray-400\">\r\n {{ t(\"noData\") }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap\">\r\n @for (cardView of currentTabCards(); track cardView.trackId) {\r\n <div\r\n class=\"mb-2 cursor-pointer p-2\"\r\n [class.card-col]=\"!galleryMode()\"\r\n [class.gallery-card-col]=\"galleryMode()\"\r\n [class.w-full]=\"!galleryMode()\"\r\n [class.md:w-1/2]=\"!galleryMode()\"\r\n [class.lg:w-1/3]=\"!galleryMode()\"\r\n (click)=\"onCardClick(cardView.card)\"\r\n >\r\n @defer (on viewport) {\r\n <ng-container>\r\n @if (cardView.entities.length > 0) {\r\n <mt-entities-preview [entities]=\"cardView.entities\" />\r\n } @else {\r\n <div class=\"py-6 text-center text-sm text-gray-400\">\r\n {{ t(\"noData\") }}\r\n </div>\r\n }\r\n </ng-container>\r\n } @placeholder {\r\n <div class=\"min-h-24 p-2\">\r\n <div class=\"flex animate-pulse flex-col gap-3\">\r\n <div class=\"h-4 w-2/3 rounded bg-surface-200\"></div>\r\n <div class=\"h-4 w-full rounded bg-surface-100\"></div>\r\n <div class=\"h-4 w-5/6 rounded bg-surface-100\"></div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}.card-col{flex:0 0 100%}@media(min-width:768px){.card-col{flex:0 0 50%}}@media(min-width:1024px){.card-col{flex:0 0 33.333%}}.gallery-card-col{flex:0 0 100%}@media(min-width:640px){.gallery-card-col{flex:0 0 50%}}@media(min-width:1024px){.gallery-card-col{flex:0 0 25%}}\n"] }]
29096
+ args: [{ selector: 'mt-properties-card, mt-entities-preview-card', standalone: true, imports: [CommonModule, TranslocoDirective, Tabs, EntitiesPreview], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n @if (showTabs()) {\r\n <div class=\"mb-3\">\r\n <mt-tabs [(active)]=\"tabSelected\" [options]=\"tabOptions()\" size=\"small\" />\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"overflow-y-auto overflow-x-hidden\"\r\n [style.max-height]=\"inGroup() ? '500px' : '90%'\"\r\n >\r\n @if (currentTabCards().length === 0) {\r\n <div class=\"py-6 text-center text-sm text-gray-400\">\r\n {{ t(\"noData\") }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap\">\r\n @for (cardView of currentTabCards(); track cardView.trackId) {\r\n <div\r\n class=\"mb-2 cursor-pointer p-2\"\r\n [class.card-col]=\"!galleryMode()\"\r\n [class.gallery-card-col]=\"galleryMode()\"\r\n [class.w-full]=\"!galleryMode()\"\r\n [class.md:w-1/2]=\"!galleryMode()\"\r\n [class.lg:w-1/3]=\"!galleryMode()\"\n (click)=\"onCardClick(cardView.card)\"\n >\n <div class=\"rounded-lg bg-white p-3 shadow-sm\">\n @defer (on viewport) {\n <ng-container>\n @if (cardView.entities.length > 0) {\n <mt-entities-preview [entities]=\"cardView.entities\" />\n } @else {\n <div class=\"py-6 text-center text-sm text-gray-400\">\n {{ t(\"noData\") }}\n </div>\n }\n </ng-container>\n } @placeholder {\n <div class=\"min-h-24 p-2\">\n <div class=\"flex animate-pulse flex-col gap-3\">\n <div class=\"h-4 w-2/3 rounded bg-surface-200\"></div>\n <div class=\"h-4 w-full rounded bg-surface-100\"></div>\n <div class=\"h-4 w-5/6 rounded bg-surface-100\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}.card-col{flex:0 0 100%}@media(min-width:768px){.card-col{flex:0 0 50%}}@media(min-width:1024px){.card-col{flex:0 0 33.333%}}.gallery-card-col{flex:0 0 100%}@media(min-width:640px){.gallery-card-col{flex:0 0 50%}}@media(min-width:1024px){.gallery-card-col{flex:0 0 25%}}\n"] }]
28982
29097
  }], ctorParameters: () => [], propDecorators: { dashboardId: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardId", required: true }] }], inGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "inGroup", required: false }] }], onAction: [{ type: i0.Output, args: ["onAction"] }] } });
28983
29098
 
28984
29099
  const VIEW_TYPE_MAP = {
@@ -30107,7 +30222,7 @@ class ManageItem {
30107
30222
  this._manageItemService.updateClientConfig(partialConfig);
30108
30223
  }
30109
30224
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
30110
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ManageItem, isStandalone: true, selector: "mt-manage-item", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, providers: [ManageItemService], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\n <!-- Main Layout: 60% Config | 40% Preview -->\n <div class=\"flex flex-1\">\n <!-- Left Side: Configuration (60%) -->\n <div class=\"w-[60%] flex flex-col border-r border-surface-200\">\n <!-- Content -->\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\n <!-- Chart Type Badge -->\n @if (selectedChartType()) {\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\n <span\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\n >\n <mt-icon\n [icon]=\"selectedChartType()?.icon\"\n class=\"text-xl\"\n ></mt-icon>\n </span>\n <div class=\"flex-1\">\n <h3 class=\"text-sm font-semibold text-surface-700\">\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\n </h3>\n <p class=\"text-xs text-muted-color\">\n {{ selectedChartType()?.name }}\n </p>\n </div>\n </div>\n }\n\n <!-- Tabs -->\n <mt-tabs\n [options]=\"tabOptions()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(active)]=\"activeTab\"\n />\n\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\n <div [hidden]=\"activeTab() !== 'general'\">\n <mt-general-settings\n [config]=\"config()\"\n [isDialog]=\"isDialog()\"\n [hasPreselectedType]=\"hasPreselectedType()\"\n (configChange)=\"onConfigUpdate($event)\"\n (chartTypeChange)=\"onChartTypeChange($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'dataSource'\">\n <mt-data-source-settings\n [config]=\"config()\"\n [chartType]=\"selectedChartType()\"\n [informativeContext]=\"informativeContext()\"\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'actions'\">\n <mt-actions-settings\n [config]=\"config()\"\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\n />\n </div>\n </div>\n </div>\n\n <!-- Right Side: Chart Preview (40%) -->\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\n </div>\n </div>\n </div>\n <!-- Footer -->\n <div [class]=\"modal.footerClass\">\n <!-- Validation Status -->\n <div class=\"flex items-center gap-2 text-sm flex-1\">\n @if (isValid()) {\n <span class=\"flex items-center gap-1 text-green-600\">\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\n {{ t(\"ready\") }}\n </span>\n } @else {\n <span class=\"flex items-center gap-1 text-amber-600\">\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\n {{ t(\"incomplete\") }}\n </span>\n }\n </div>\n\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"cancel()\" />\n <mt-button\n [label]=\"t('save')\"\n icon=\"general.save-02\"\n [loading]=\"saving()\"\n [disabled]=\"!isValid()\"\n (onClick)=\"save()\"\n />\n </div>\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: GeneralSettings, selector: "mt-general-settings", inputs: ["config", "isDialog", "hasPreselectedType"], outputs: ["configChange", "chartTypeChange"] }, { kind: "component", type: DataSourceSettings, selector: "mt-data-source-settings", inputs: ["config", "chartType", "informativeContext"], outputs: ["serviceConfigChange"] }, { kind: "component", type: ActionsSettings, selector: "mt-actions-settings", inputs: ["config"], outputs: ["clientConfigChange"] }, { kind: "component", type: ChartViewer, selector: "mt-chart-viewer", inputs: ["config", "chartTypeId"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
30225
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ManageItem, isStandalone: true, selector: "mt-manage-item", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, providers: [ManageItemService], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\n <!-- Main Layout: 60% Config | 40% Preview -->\n <div class=\"flex flex-1\">\n <!-- Left Side: Configuration (60%) -->\n <div\n class=\"db-sectioned-drawer w-[60%] flex flex-col border-r border-surface-200\"\n >\n <!-- Content -->\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\n <!-- Chart Type Badge -->\n @if (selectedChartType()) {\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\n <span\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\n >\n <mt-icon\n [icon]=\"selectedChartType()?.icon\"\n class=\"text-xl\"\n ></mt-icon>\n </span>\n <div class=\"flex-1\">\n <h3 class=\"text-sm font-semibold text-surface-700\">\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\n </h3>\n <p class=\"text-xs text-muted-color\">\n {{ selectedChartType()?.name }}\n </p>\n </div>\n </div>\n }\n\n <!-- Tabs -->\n <mt-tabs\n [options]=\"tabOptions()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(active)]=\"activeTab\"\n />\n\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\n <div [hidden]=\"activeTab() !== 'general'\">\n <mt-general-settings\n [config]=\"config()\"\n [isDialog]=\"isDialog()\"\n [hasPreselectedType]=\"hasPreselectedType()\"\n (configChange)=\"onConfigUpdate($event)\"\n (chartTypeChange)=\"onChartTypeChange($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'dataSource'\">\n <mt-data-source-settings\n [config]=\"config()\"\n [chartType]=\"selectedChartType()\"\n [informativeContext]=\"informativeContext()\"\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'actions'\">\n <mt-actions-settings\n [config]=\"config()\"\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\n />\n </div>\n </div>\n </div>\n\n <!-- Right Side: Chart Preview (40%) -->\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\n </div>\n </div>\n </div>\n <!-- Footer -->\n <div [class]=\"modal.footerClass\">\n <!-- Validation Status -->\n <div class=\"flex items-center gap-2 text-sm flex-1\">\n @if (isValid()) {\n <span class=\"flex items-center gap-1 text-green-600\">\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\n {{ t(\"ready\") }}\n </span>\n } @else {\n <span class=\"flex items-center gap-1 text-amber-600\">\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\n {{ t(\"incomplete\") }}\n </span>\n }\n </div>\n\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"cancel()\" />\n <mt-button\n [label]=\"t('save')\"\n icon=\"general.save-02\"\n [loading]=\"saving()\"\n [disabled]=\"!isValid()\"\n (onClick)=\"save()\"\n />\n </div>\n</ng-container>\n", styles: [".db-sectioned-drawer mt-card{overflow:hidden;border-color:var(--p-surface-200, #e5e7eb);background:var(--p-surface-0, #fff);border-radius:.375rem}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1){padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb)}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1) h3{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #111827)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: GeneralSettings, selector: "mt-general-settings", inputs: ["config", "isDialog", "hasPreselectedType"], outputs: ["configChange", "chartTypeChange"] }, { kind: "component", type: DataSourceSettings, selector: "mt-data-source-settings", inputs: ["config", "chartType", "informativeContext"], outputs: ["serviceConfigChange"] }, { kind: "component", type: ActionsSettings, selector: "mt-actions-settings", inputs: ["config"], outputs: ["clientConfigChange"] }, { kind: "component", type: ChartViewer, selector: "mt-chart-viewer", inputs: ["config", "chartTypeId"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
30111
30226
  }
30112
30227
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageItem, decorators: [{
30113
30228
  type: Component,
@@ -30122,7 +30237,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
30122
30237
  ActionsSettings,
30123
30238
  ChartViewer,
30124
30239
  Icon,
30125
- ], providers: [ManageItemService], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\n <!-- Main Layout: 60% Config | 40% Preview -->\n <div class=\"flex flex-1\">\n <!-- Left Side: Configuration (60%) -->\n <div class=\"w-[60%] flex flex-col border-r border-surface-200\">\n <!-- Content -->\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\n <!-- Chart Type Badge -->\n @if (selectedChartType()) {\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\n <span\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\n >\n <mt-icon\n [icon]=\"selectedChartType()?.icon\"\n class=\"text-xl\"\n ></mt-icon>\n </span>\n <div class=\"flex-1\">\n <h3 class=\"text-sm font-semibold text-surface-700\">\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\n </h3>\n <p class=\"text-xs text-muted-color\">\n {{ selectedChartType()?.name }}\n </p>\n </div>\n </div>\n }\n\n <!-- Tabs -->\n <mt-tabs\n [options]=\"tabOptions()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(active)]=\"activeTab\"\n />\n\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\n <div [hidden]=\"activeTab() !== 'general'\">\n <mt-general-settings\n [config]=\"config()\"\n [isDialog]=\"isDialog()\"\n [hasPreselectedType]=\"hasPreselectedType()\"\n (configChange)=\"onConfigUpdate($event)\"\n (chartTypeChange)=\"onChartTypeChange($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'dataSource'\">\n <mt-data-source-settings\n [config]=\"config()\"\n [chartType]=\"selectedChartType()\"\n [informativeContext]=\"informativeContext()\"\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'actions'\">\n <mt-actions-settings\n [config]=\"config()\"\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\n />\n </div>\n </div>\n </div>\n\n <!-- Right Side: Chart Preview (40%) -->\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\n </div>\n </div>\n </div>\n <!-- Footer -->\n <div [class]=\"modal.footerClass\">\n <!-- Validation Status -->\n <div class=\"flex items-center gap-2 text-sm flex-1\">\n @if (isValid()) {\n <span class=\"flex items-center gap-1 text-green-600\">\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\n {{ t(\"ready\") }}\n </span>\n } @else {\n <span class=\"flex items-center gap-1 text-amber-600\">\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\n {{ t(\"incomplete\") }}\n </span>\n }\n </div>\n\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"cancel()\" />\n <mt-button\n [label]=\"t('save')\"\n icon=\"general.save-02\"\n [loading]=\"saving()\"\n [disabled]=\"!isValid()\"\n (onClick)=\"save()\"\n />\n </div>\n</ng-container>\n" }]
30240
+ ], providers: [ManageItemService], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\n <!-- Main Layout: 60% Config | 40% Preview -->\n <div class=\"flex flex-1\">\n <!-- Left Side: Configuration (60%) -->\n <div\n class=\"db-sectioned-drawer w-[60%] flex flex-col border-r border-surface-200\"\n >\n <!-- Content -->\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\n <!-- Chart Type Badge -->\n @if (selectedChartType()) {\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\n <span\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\n >\n <mt-icon\n [icon]=\"selectedChartType()?.icon\"\n class=\"text-xl\"\n ></mt-icon>\n </span>\n <div class=\"flex-1\">\n <h3 class=\"text-sm font-semibold text-surface-700\">\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\n </h3>\n <p class=\"text-xs text-muted-color\">\n {{ selectedChartType()?.name }}\n </p>\n </div>\n </div>\n }\n\n <!-- Tabs -->\n <mt-tabs\n [options]=\"tabOptions()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(active)]=\"activeTab\"\n />\n\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\n <div [hidden]=\"activeTab() !== 'general'\">\n <mt-general-settings\n [config]=\"config()\"\n [isDialog]=\"isDialog()\"\n [hasPreselectedType]=\"hasPreselectedType()\"\n (configChange)=\"onConfigUpdate($event)\"\n (chartTypeChange)=\"onChartTypeChange($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'dataSource'\">\n <mt-data-source-settings\n [config]=\"config()\"\n [chartType]=\"selectedChartType()\"\n [informativeContext]=\"informativeContext()\"\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\n />\n </div>\n\n <div [hidden]=\"activeTab() !== 'actions'\">\n <mt-actions-settings\n [config]=\"config()\"\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\n />\n </div>\n </div>\n </div>\n\n <!-- Right Side: Chart Preview (40%) -->\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\n </div>\n </div>\n </div>\n <!-- Footer -->\n <div [class]=\"modal.footerClass\">\n <!-- Validation Status -->\n <div class=\"flex items-center gap-2 text-sm flex-1\">\n @if (isValid()) {\n <span class=\"flex items-center gap-1 text-green-600\">\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\n {{ t(\"ready\") }}\n </span>\n } @else {\n <span class=\"flex items-center gap-1 text-amber-600\">\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\n {{ t(\"incomplete\") }}\n </span>\n }\n </div>\n\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"cancel()\" />\n <mt-button\n [label]=\"t('save')\"\n icon=\"general.save-02\"\n [loading]=\"saving()\"\n [disabled]=\"!isValid()\"\n (onClick)=\"save()\"\n />\n </div>\n</ng-container>\n", styles: [".db-sectioned-drawer mt-card{overflow:hidden;border-color:var(--p-surface-200, #e5e7eb);background:var(--p-surface-0, #fff);border-radius:.375rem}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1){padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-50, #f9fafb)}.db-sectioned-drawer mt-card>div>div:first-child:not(.flex-1) h3{margin:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;color:var(--p-text-color, #111827)}\n"] }]
30126
30241
  }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
30127
30242
 
30128
30243
  class TitleEditor {
@@ -30201,11 +30316,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
30201
30316
  * Primary entries (always present for chart cards):
30202
30317
  * - Configure datasource → opens ManageItem advanced editor
30203
30318
  * - Style → opens ChartSettingsDrawer
30204
- * - Filters → opens ChartFilterDrawer
30205
30319
  * - Edit title → focuses inline title input
30206
30320
  * - Duplicate → host duplicates the chart
30207
30321
  * - Delete → host deletes the chart (severity: danger)
30208
30322
  *
30323
+ * The Filters action still routes to ChartFilterDrawer when emitted, but its
30324
+ * menu entry is currently hidden from the chart-card action menu.
30325
+ *
30209
30326
  * Optional dialog entries (only when the chart has a linked dialog):
30210
30327
  * - Open dialog
30211
30328
  * - Edit dialog
@@ -30213,6 +30330,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
30213
30330
  */
30214
30331
  class ItemCardMenuComponent {
30215
30332
  transloco = inject(TranslocoService);
30333
+ filtersActionVisible = false;
30216
30334
  /** Whether to allow duplicate (excluded for layout/group widgets). */
30217
30335
  allowDuplicate = input(true, ...(ngDevMode ? [{ debugName: "allowDuplicate" }] : /* istanbul ignore next */ []));
30218
30336
  /** Whether the chart has a linked dialog already. */
@@ -30239,17 +30357,19 @@ class ItemCardMenuComponent {
30239
30357
  label: t('style'),
30240
30358
  icon: 'editor.palette',
30241
30359
  },
30242
- {
30243
- id: 'filters',
30244
- label: t('filters'),
30245
- icon: 'general.filter-funnel-01',
30246
- },
30247
30360
  {
30248
30361
  id: 'edit-title',
30249
30362
  label: t('editTitle'),
30250
30363
  icon: 'general.edit-05',
30251
30364
  },
30252
30365
  ];
30366
+ if (this.filtersActionVisible) {
30367
+ items.splice(2, 0, {
30368
+ id: 'filters',
30369
+ label: t('filters'),
30370
+ icon: 'general.filter-funnel-01',
30371
+ });
30372
+ }
30253
30373
  if (this.allowDuplicate()) {
30254
30374
  items.push({
30255
30375
  id: 'duplicate',
@@ -34480,6 +34600,10 @@ class DashboardBuilder {
34480
34600
  }
34481
34601
  return true;
34482
34602
  }
34603
+ isPropertiesListChart(chart) {
34604
+ const componentName = chart.config?.clientConfig?.componentName;
34605
+ return componentName === 'listOfLevelCards' || componentName === 'entitiesPreview';
34606
+ }
34483
34607
  editItem(chart, parentItem, defaultTab) {
34484
34608
  this.dashboardService.chartForSelectedDialog.set(parentItem);
34485
34609
  this.prefetchModulesTree(this.resolveWorkspaceId(chart.config));
@@ -34890,12 +35014,11 @@ class DashboardBuilder {
34890
35014
  openManageFilter() {
34891
35015
  const ref = this.modalService.openModal(ManageFilterOnPage, 'drawer', {
34892
35016
  header: this.transloco.translate('dashboardBuilder.manageFilter'),
34893
- styleClass: '!w-2/5 !absolute',
35017
+ styleClass: '!w-[56rem] max-w-[96vw] !absolute',
34894
35018
  appendTo: '#page-content',
34895
35019
  position: 'end',
34896
35020
  inputValues: {
34897
35021
  data: this.filtersConfig() || [],
34898
- chartItems: [...this.charts(), ...this.dialogs()],
34899
35022
  },
34900
35023
  });
34901
35024
  ref.onClose.subscribe((result) => {
@@ -35528,7 +35651,7 @@ class DashboardBuilder {
35528
35651
  return current;
35529
35652
  }
35530
35653
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DashboardBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
35531
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DashboardBuilder, isStandalone: true, selector: "mt-dashboard-builder", inputs: { isPage: { classPropertyName: "isPage", publicName: "isPage", isSignal: true, isRequired: false, transformFunction: null }, pageTitle: { classPropertyName: "pageTitle", publicName: "pageTitle", isSignal: true, isRequired: false, transformFunction: null }, backButton: { classPropertyName: "backButton", publicName: "backButton", isSignal: true, isRequired: false, transformFunction: null }, pageId: { classPropertyName: "pageId", publicName: "pageId", isSignal: true, isRequired: false, transformFunction: null }, standalone: { classPropertyName: "standalone", publicName: "standalone", isSignal: true, isRequired: false, transformFunction: null }, services: { classPropertyName: "services", publicName: "services", isSignal: true, isRequired: false, transformFunction: null }, dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, informativeContext: { classPropertyName: "informativeContext", publicName: "informativeContext", isSignal: true, isRequired: false, transformFunction: null }, extraFilters: { classPropertyName: "extraFilters", publicName: "extraFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dashboardData: "dashboardDataChange", pageChange: "pageChange", chartsChange: "chartsChange", onSave: "onSave", onBack: "onBack", onAddChart: "onAddChart", onEditChart: "onEditChart" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true, isSignal: true }, { propertyName: "gridsterContainer", first: true, predicate: ["gridsterContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Shared Actions Template -->\r\n <ng-template #actionsTemplate let-inPage=\"inPage\">\r\n <mt-button\r\n [label]=\"t('addWidget')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"toggleWidgetPalette()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"saving()\"\r\n (onClick)=\"saveDash()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <span [class]=\"'w-px h-5 bg-surface-300'\"></span>\r\n\r\n <mt-button\r\n [icon]=\"stopActionsOnCards() ? 'media.play' : 'media.stop'\"\r\n [tooltip]=\"stopActionsOnCards() ? t('activateActions') : t('stopActions')\"\r\n (onClick)=\"stopAndActiveActions()\"\r\n [severity]=\"'warn'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('pageSettings')\"\r\n (onClick)=\"addOrEditPage(pageConfig()!)\"\r\n [severity]=\"'help'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.filter-lines\"\r\n [tooltip]=\"t('manageFilter')\"\r\n (onClick)=\"openManageFilter()\"\r\n [severity]=\"'info'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n </ng-template>\r\n\r\n <!-- Page mode -->\r\n @if (isPage()) {\r\n <mt-page\r\n [title]=\"\r\n pageTitle() ||\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n t('builder')\r\n \"\r\n [backButton]=\"backButton()\"\r\n (backButtonClick)=\"onBack.emit()\"\r\n >\r\n <!-- Header actions -->\r\n <ng-template #headerEnd>\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: true }\"\r\n />\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Content -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <!-- Non-page mode -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n }\r\n\r\n <!-- Reusable builder content template -->\r\n <ng-template #builderContent>\r\n <div class=\"relative h-full min-h-[600px]\">\r\n <!-- Loading State -->\r\n @if (loading()) {\r\n <div class=\"flex items-center justify-center h-64\">\r\n <i class=\"mti mti-spinner-third mti-spin text-4xl text-primary\"></i>\r\n </div>\r\n }\r\n\r\n <!-- Main Content -->\r\n @if (!loading() && pageConfig()) {\r\n <!-- Fixed Actions Bar (only when NOT page mode) -->\r\n @if (!isPage()) {\r\n <div\r\n class=\"fixed bottom-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-2 bg-surface-0 rounded-full shadow-lg px-4 py-2 border border-surface-200\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: false }\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Gridster Container -->\r\n <gridster\r\n #gridsterContainer\r\n [options]=\"options\"\r\n class=\"h-full min-h-[500px] bg-surface-50!\"\r\n [class.is-page]=\"isPage()\"\r\n [class.pointer-events-none]=\"readonly()\"\r\n (dragover)=\"onGridDragOver($event)\"\r\n (drop)=\"onGridDrop($event)\"\r\n >\r\n @for (chart of charts() | filterByGroup: undefined; track $index) {\r\n <gridster-item\r\n [item]=\"chart\"\r\n class=\"db-gridster-item bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden hover:shadow-md hover:border-surface-300\"\r\n [class.ring-2]=\"isSelected(chart)\"\r\n [class.ring-primary]=\"isSelected(chart)\"\r\n [class.ring-offset-2]=\"isSelected(chart)\"\r\n [attr.data-chart-id]=\"chart.config?.serviceConfig?.dashboardId\"\r\n (click)=\"onSelect(chart, $event)\"\r\n >\r\n <!-- Chart Content -->\r\n <div class=\"h-full w-full relative group\">\r\n <!-- Drag Handle -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"drag-handler absolute top-0 left-0 right-0 h-6 cursor-move bg-gradient-to-b from-black/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center z-10\"\r\n >\r\n <i\r\n class=\"mti mti-grip-horizontal text-white/70 text-sm\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!--\r\n Pass 7 \u2014 Single top-end Manage menu per chart card.\r\n Layout widgets (header/topbar/group) keep their dedicated\r\n affordances; chart cards have **only** the kebab.\r\n -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"db-card-actions absolute top-1 end-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Single kebab for chart cards (Pass 7 sole owner). -->\r\n @if (showContextToolbar(chart)) {\r\n <mt-item-card-menu\r\n [allowDuplicate]=\"true\"\r\n [hasLinkedDialog]=\"hasLinkedDialog(chart)\"\r\n [canLinkDialog]=\"canLinkDialog(chart)\"\r\n (action)=\"onItemCardMenuAction(chart, $event)\"\r\n />\r\n }\r\n\r\n <!-- Topbar: breadcrumb editor (layout-specific). -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.slash-divider\"\r\n [tooltip]=\"t('manageBreadcrumb')\"\r\n (onClick)=\"openBreadcrumb(chart)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!--\r\n Header / topbar \u2014 quick style + delete.\r\n These widgets don't have a datasource so they don't\r\n use the chart kebab; the affordances stay minimal.\r\n -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"header\" ||\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('actions.editTitle')\"\r\n (onClick)=\"requestLayoutTitleEdit(chart, $event)\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('actions.style')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('actions.delete')\"\r\n (onClick)=\"deleteItem(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('removeGroup')\"\r\n (onClick)=\"removeGroup(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chart Rendering -->\r\n @if (!chart.loading) {\r\n <mt-dashboard-item\r\n [config]=\"chart.config\"\r\n [chartTypeId]=\"chart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"configureChart(chart)\"\r\n (titleEdited)=\"onChartTitleEdited(chart, $event)\"\r\n />\r\n } @else {\r\n <div class=\"flex items-center justify-center h-full\">\r\n <i\r\n class=\"mti mti-spinner-third mti-spin text-2xl text-primary\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!-- Group Children -->\r\n @if (chart.config?.clientConfig?.componentName === \"Group\") {\r\n <div class=\"h-full flex flex-col p-2\">\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n @if (idx === chart.selectedGroupIndex) {\r\n <div class=\"flex-1 min-h-0\">\r\n <mt-dashboard-item\r\n [config]=\"childChart.config\"\r\n [chartTypeId]=\"childChart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"\r\n editItem(childChart, chart, 'dataSource')\r\n \"\r\n (titleEdited)=\"\r\n onChartTitleEdited(childChart, $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Group Tabs -->\r\n <div\r\n class=\"absolute bottom-0 left-0 right-0 flex gap-1 p-1 bg-surface-100 rounded-b-lg overflow-x-auto\"\r\n >\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n <mt-button\r\n [label]=\"\r\n childChart.config?.clientConfig?.title?.[\r\n languageCode()\r\n ] ||\r\n childChart.config?.clientConfig?.title?.['en'] ||\r\n 'Chart ' + (idx + 1)\r\n \"\r\n [severity]=\"\r\n idx === chart.selectedGroupIndex\r\n ? 'primary'\r\n : 'secondary'\r\n \"\r\n [text]=\"idx !== chart.selectedGroupIndex\"\r\n size=\"small\"\r\n (onClick)=\"chart.selectedGroupIndex = idx\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </gridster-item>\r\n }\r\n </gridster>\r\n\r\n <!-- Context Menu -->\r\n <p-contextMenu #contextMenu [model]=\"menuItems()\" appendTo=\"body\" />\r\n }\r\n\r\n <!-- Empty State -->\r\n @if (!loading() && !pageConfig()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center h-64 text-muted-color\"\r\n >\r\n <i class=\"mti mti-layout text-6xl mb-4\"></i>\r\n <p class=\"text-lg\">{{ t(\"noPageSelected\") }}</p>\r\n <p class=\"text-sm\">{{ t(\"selectPageToStart\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}gridster{min-height:calc(100vh - 120px);height:100%}gridster .gridster-column{border-left:1px solid var(--p-primary-100)!important;border-right:1px solid var(--p-primary-100)!important}gridster .gridster-row{border-top:1px solid var(--p-primary-100)!important;border-bottom:1px solid var(--p-primary-100)!important}gridster.is-page{min-height:calc(100vh - 200px)}gridster-item.db-gridster-item{transition:none!important}.mti-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gridster-drop-indicator{position:absolute;background:var(--p-primary-100);border:2px dashed var(--p-primary-400);border-radius:8px;pointer-events:none;z-index:100}.db-card-actions{pointer-events:auto;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.25rem;max-width:calc(100% - 2.5rem)}@media(max-width:640px){.db-card-actions{top:.25rem;right:.25rem}}.db-card-title-edit{background:transparent;border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.375rem;padding:.25rem .5rem;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);text-align:center;width:min(100%,22rem);outline:none}.db-card-title-edit:focus{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff)}.mt-item-config-popover-host .p-dialog-content{padding:0!important;height:clamp(420px,70vh,720px);max-height:80vh}.mt-item-config-popover-host .p-dialog-header{display:none}@media(max-width:768px){.mt-item-config-popover-host{width:100%!important;max-width:100%!important;margin:0!important;inset:auto 0 0!important;border-radius:1rem 1rem 0 0!important;transform:none!important}.mt-item-config-popover-host .p-dialog-content{height:80vh;border-radius:1rem 1rem 0 0}}.db-context-popover{--p-popover-content-padding: .4rem;min-width:200px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: GridsterModule }, { kind: "component", type: i2$2.GridsterComponent, selector: "gridster", inputs: ["options"] }, { kind: "component", type: i2$2.GridsterItemComponent, selector: "gridster-item", inputs: ["item"], outputs: ["itemInit", "itemChange", "itemResize"] }, { 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: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i3$1.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: DashboardItem, selector: "mt-dashboard-item", inputs: ["config", "chartTypeId", "readonly", "pageName", "inGroup", "isDialog", "queryParams", "extraFilters", "ignoreQueryFilter", "builderMode"], outputs: ["actionTriggered", "configureRequested", "titleEdited"] }, { kind: "component", type: ItemCardMenuComponent, selector: "mt-item-card-menu", inputs: ["allowDuplicate", "hasLinkedDialog", "canLinkDialog"], outputs: ["action"] }, { kind: "pipe", type: FilterByGroupPipe, name: "filterByGroup" }], encapsulation: i0.ViewEncapsulation.None });
35654
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DashboardBuilder, isStandalone: true, selector: "mt-dashboard-builder", inputs: { isPage: { classPropertyName: "isPage", publicName: "isPage", isSignal: true, isRequired: false, transformFunction: null }, pageTitle: { classPropertyName: "pageTitle", publicName: "pageTitle", isSignal: true, isRequired: false, transformFunction: null }, backButton: { classPropertyName: "backButton", publicName: "backButton", isSignal: true, isRequired: false, transformFunction: null }, pageId: { classPropertyName: "pageId", publicName: "pageId", isSignal: true, isRequired: false, transformFunction: null }, standalone: { classPropertyName: "standalone", publicName: "standalone", isSignal: true, isRequired: false, transformFunction: null }, services: { classPropertyName: "services", publicName: "services", isSignal: true, isRequired: false, transformFunction: null }, dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, informativeContext: { classPropertyName: "informativeContext", publicName: "informativeContext", isSignal: true, isRequired: false, transformFunction: null }, extraFilters: { classPropertyName: "extraFilters", publicName: "extraFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dashboardData: "dashboardDataChange", pageChange: "pageChange", chartsChange: "chartsChange", onSave: "onSave", onBack: "onBack", onAddChart: "onAddChart", onEditChart: "onEditChart" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true, isSignal: true }, { propertyName: "gridsterContainer", first: true, predicate: ["gridsterContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Shared Actions Template -->\r\n <ng-template #actionsTemplate let-inPage=\"inPage\">\r\n <mt-button\r\n [label]=\"t('addWidget')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"toggleWidgetPalette()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"saving()\"\r\n (onClick)=\"saveDash()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <span [class]=\"'w-px h-5 bg-surface-300'\"></span>\r\n\r\n <mt-button\r\n [icon]=\"stopActionsOnCards() ? 'media.play' : 'media.stop'\"\r\n [tooltip]=\"stopActionsOnCards() ? t('activateActions') : t('stopActions')\"\r\n (onClick)=\"stopAndActiveActions()\"\r\n [severity]=\"'warn'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('pageSettings')\"\r\n (onClick)=\"addOrEditPage(pageConfig()!)\"\r\n [severity]=\"'help'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.filter-lines\"\r\n [tooltip]=\"t('manageFilter')\"\r\n (onClick)=\"openManageFilter()\"\r\n [severity]=\"'info'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n </ng-template>\r\n\r\n <!-- Page mode -->\r\n @if (isPage()) {\r\n <mt-page\r\n [title]=\"\r\n pageTitle() ||\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n t('builder')\r\n \"\r\n [backButton]=\"backButton()\"\r\n (backButtonClick)=\"onBack.emit()\"\r\n >\r\n <!-- Header actions -->\r\n <ng-template #headerEnd>\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: true }\"\r\n />\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Content -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <!-- Non-page mode -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n }\r\n\r\n <!-- Reusable builder content template -->\r\n <ng-template #builderContent>\r\n <div class=\"relative h-full min-h-[600px]\">\r\n <!-- Loading State -->\r\n @if (loading()) {\r\n <div class=\"flex items-center justify-center h-64\">\r\n <i class=\"mti mti-spinner-third mti-spin text-4xl text-primary\"></i>\r\n </div>\r\n }\r\n\r\n <!-- Main Content -->\r\n @if (!loading() && pageConfig()) {\r\n <!-- Fixed Actions Bar (only when NOT page mode) -->\r\n @if (!isPage()) {\r\n <div\r\n class=\"fixed bottom-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-2 bg-surface-0 rounded-full shadow-lg px-4 py-2 border border-surface-200\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: false }\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Gridster Container -->\r\n <gridster\r\n #gridsterContainer\r\n [options]=\"options\"\r\n class=\"h-full min-h-[500px] bg-surface-50!\"\r\n [class.is-page]=\"isPage()\"\r\n [class.pointer-events-none]=\"readonly()\"\r\n (dragover)=\"onGridDragOver($event)\"\r\n (drop)=\"onGridDrop($event)\"\r\n >\r\n @for (chart of charts() | filterByGroup: undefined; track $index) {\r\n <gridster-item\n [item]=\"chart\"\n class=\"db-gridster-item bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden hover:shadow-md hover:border-surface-300\"\n [class.db-gridster-item--properties-list]=\"\n isPropertiesListChart(chart)\n \"\n [class.ring-2]=\"isSelected(chart)\"\n [class.ring-primary]=\"isSelected(chart)\"\n [class.ring-offset-2]=\"isSelected(chart)\"\n [attr.data-chart-id]=\"chart.config?.serviceConfig?.dashboardId\"\r\n (click)=\"onSelect(chart, $event)\"\r\n >\r\n <!-- Chart Content -->\r\n <div class=\"h-full w-full relative group\">\r\n <!-- Drag Handle -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"drag-handler absolute top-0 left-0 right-0 h-6 cursor-move bg-gradient-to-b from-black/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center z-10\"\r\n >\r\n <i\r\n class=\"mti mti-grip-horizontal text-white/70 text-sm\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!--\r\n Pass 7 \u2014 Single top-end Manage menu per chart card.\r\n Layout widgets (header/topbar/group) keep their dedicated\r\n affordances; chart cards have **only** the kebab.\r\n -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"db-card-actions absolute top-1 end-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Single kebab for chart cards (Pass 7 sole owner). -->\r\n @if (showContextToolbar(chart)) {\r\n <mt-item-card-menu\r\n [allowDuplicate]=\"true\"\r\n [hasLinkedDialog]=\"hasLinkedDialog(chart)\"\r\n [canLinkDialog]=\"canLinkDialog(chart)\"\r\n (action)=\"onItemCardMenuAction(chart, $event)\"\r\n />\r\n }\r\n\r\n <!-- Topbar: breadcrumb editor (layout-specific). -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.slash-divider\"\r\n [tooltip]=\"t('manageBreadcrumb')\"\r\n (onClick)=\"openBreadcrumb(chart)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!--\r\n Header / topbar \u2014 quick style + delete.\r\n These widgets don't have a datasource so they don't\r\n use the chart kebab; the affordances stay minimal.\r\n -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"header\" ||\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('actions.editTitle')\"\r\n (onClick)=\"requestLayoutTitleEdit(chart, $event)\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('actions.style')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('actions.delete')\"\r\n (onClick)=\"deleteItem(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('removeGroup')\"\r\n (onClick)=\"removeGroup(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chart Rendering -->\r\n @if (!chart.loading) {\r\n <mt-dashboard-item\r\n [config]=\"chart.config\"\r\n [chartTypeId]=\"chart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"configureChart(chart)\"\r\n (titleEdited)=\"onChartTitleEdited(chart, $event)\"\r\n />\r\n } @else {\r\n <div class=\"flex items-center justify-center h-full\">\r\n <i\r\n class=\"mti mti-spinner-third mti-spin text-2xl text-primary\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!-- Group Children -->\r\n @if (chart.config?.clientConfig?.componentName === \"Group\") {\r\n <div class=\"h-full flex flex-col p-2\">\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n @if (idx === chart.selectedGroupIndex) {\r\n <div class=\"flex-1 min-h-0\">\r\n <mt-dashboard-item\r\n [config]=\"childChart.config\"\r\n [chartTypeId]=\"childChart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"\r\n editItem(childChart, chart, 'dataSource')\r\n \"\r\n (titleEdited)=\"\r\n onChartTitleEdited(childChart, $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Group Tabs -->\r\n <div\r\n class=\"absolute bottom-0 left-0 right-0 flex gap-1 p-1 bg-surface-100 rounded-b-lg overflow-x-auto\"\r\n >\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n <mt-button\r\n [label]=\"\r\n childChart.config?.clientConfig?.title?.[\r\n languageCode()\r\n ] ||\r\n childChart.config?.clientConfig?.title?.['en'] ||\r\n 'Chart ' + (idx + 1)\r\n \"\r\n [severity]=\"\r\n idx === chart.selectedGroupIndex\r\n ? 'primary'\r\n : 'secondary'\r\n \"\r\n [text]=\"idx !== chart.selectedGroupIndex\"\r\n size=\"small\"\r\n (onClick)=\"chart.selectedGroupIndex = idx\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </gridster-item>\r\n }\r\n </gridster>\r\n\r\n <!-- Context Menu -->\r\n <p-contextMenu #contextMenu [model]=\"menuItems()\" appendTo=\"body\" />\r\n }\r\n\r\n <!-- Empty State -->\r\n @if (!loading() && !pageConfig()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center h-64 text-muted-color\"\r\n >\r\n <i class=\"mti mti-layout text-6xl mb-4\"></i>\r\n <p class=\"text-lg\">{{ t(\"noPageSelected\") }}</p>\r\n <p class=\"text-sm\">{{ t(\"selectPageToStart\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}gridster{min-height:calc(100vh - 120px);height:100%}gridster .gridster-column{border-left:1px solid var(--p-primary-100)!important;border-right:1px solid var(--p-primary-100)!important}gridster .gridster-row{border-top:1px solid var(--p-primary-100)!important;border-bottom:1px solid var(--p-primary-100)!important}gridster.is-page{min-height:calc(100vh - 200px)}gridster-item.db-gridster-item{transition:none!important}gridster-item.db-gridster-item.db-gridster-item--properties-list{background:transparent!important;border-color:transparent!important;border-radius:0!important;box-shadow:none!important;overflow:visible!important}gridster-item.db-gridster-item.db-gridster-item--properties-list:hover{border-color:transparent!important;box-shadow:none!important}.mti-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gridster-drop-indicator{position:absolute;background:var(--p-primary-100);border:2px dashed var(--p-primary-400);border-radius:8px;pointer-events:none;z-index:100}.db-card-actions{pointer-events:auto;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.25rem;max-width:calc(100% - 2.5rem)}@media(max-width:640px){.db-card-actions{top:.25rem;right:.25rem}}.db-card-title-edit{background:transparent;border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.375rem;padding:.25rem .5rem;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);text-align:center;width:min(100%,22rem);outline:none}.db-card-title-edit:focus{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff)}.mt-item-config-popover-host .p-dialog-content{padding:0!important;height:clamp(420px,70vh,720px);max-height:80vh}.mt-item-config-popover-host .p-dialog-header{display:none}@media(max-width:768px){.mt-item-config-popover-host{width:100%!important;max-width:100%!important;margin:0!important;inset:auto 0 0!important;border-radius:1rem 1rem 0 0!important;transform:none!important}.mt-item-config-popover-host .p-dialog-content{height:80vh;border-radius:1rem 1rem 0 0}}.db-context-popover{--p-popover-content-padding: .4rem;min-width:200px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: GridsterModule }, { kind: "component", type: i2$2.GridsterComponent, selector: "gridster", inputs: ["options"] }, { kind: "component", type: i2$2.GridsterItemComponent, selector: "gridster-item", inputs: ["item"], outputs: ["itemInit", "itemChange", "itemResize"] }, { 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: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i3$1.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: DashboardItem, selector: "mt-dashboard-item", inputs: ["config", "chartTypeId", "readonly", "pageName", "inGroup", "isDialog", "queryParams", "extraFilters", "ignoreQueryFilter", "builderMode"], outputs: ["actionTriggered", "configureRequested", "titleEdited"] }, { kind: "component", type: ItemCardMenuComponent, selector: "mt-item-card-menu", inputs: ["allowDuplicate", "hasLinkedDialog", "canLinkDialog"], outputs: ["action"] }, { kind: "pipe", type: FilterByGroupPipe, name: "filterByGroup" }], encapsulation: i0.ViewEncapsulation.None });
35532
35655
  }
35533
35656
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DashboardBuilder, decorators: [{
35534
35657
  type: Component,
@@ -35543,7 +35666,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
35543
35666
  FilterByGroupPipe,
35544
35667
  DashboardItem,
35545
35668
  ItemCardMenuComponent,
35546
- ], encapsulation: ViewEncapsulation.None, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Shared Actions Template -->\r\n <ng-template #actionsTemplate let-inPage=\"inPage\">\r\n <mt-button\r\n [label]=\"t('addWidget')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"toggleWidgetPalette()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"saving()\"\r\n (onClick)=\"saveDash()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <span [class]=\"'w-px h-5 bg-surface-300'\"></span>\r\n\r\n <mt-button\r\n [icon]=\"stopActionsOnCards() ? 'media.play' : 'media.stop'\"\r\n [tooltip]=\"stopActionsOnCards() ? t('activateActions') : t('stopActions')\"\r\n (onClick)=\"stopAndActiveActions()\"\r\n [severity]=\"'warn'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('pageSettings')\"\r\n (onClick)=\"addOrEditPage(pageConfig()!)\"\r\n [severity]=\"'help'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.filter-lines\"\r\n [tooltip]=\"t('manageFilter')\"\r\n (onClick)=\"openManageFilter()\"\r\n [severity]=\"'info'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n </ng-template>\r\n\r\n <!-- Page mode -->\r\n @if (isPage()) {\r\n <mt-page\r\n [title]=\"\r\n pageTitle() ||\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n t('builder')\r\n \"\r\n [backButton]=\"backButton()\"\r\n (backButtonClick)=\"onBack.emit()\"\r\n >\r\n <!-- Header actions -->\r\n <ng-template #headerEnd>\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: true }\"\r\n />\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Content -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <!-- Non-page mode -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n }\r\n\r\n <!-- Reusable builder content template -->\r\n <ng-template #builderContent>\r\n <div class=\"relative h-full min-h-[600px]\">\r\n <!-- Loading State -->\r\n @if (loading()) {\r\n <div class=\"flex items-center justify-center h-64\">\r\n <i class=\"mti mti-spinner-third mti-spin text-4xl text-primary\"></i>\r\n </div>\r\n }\r\n\r\n <!-- Main Content -->\r\n @if (!loading() && pageConfig()) {\r\n <!-- Fixed Actions Bar (only when NOT page mode) -->\r\n @if (!isPage()) {\r\n <div\r\n class=\"fixed bottom-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-2 bg-surface-0 rounded-full shadow-lg px-4 py-2 border border-surface-200\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: false }\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Gridster Container -->\r\n <gridster\r\n #gridsterContainer\r\n [options]=\"options\"\r\n class=\"h-full min-h-[500px] bg-surface-50!\"\r\n [class.is-page]=\"isPage()\"\r\n [class.pointer-events-none]=\"readonly()\"\r\n (dragover)=\"onGridDragOver($event)\"\r\n (drop)=\"onGridDrop($event)\"\r\n >\r\n @for (chart of charts() | filterByGroup: undefined; track $index) {\r\n <gridster-item\r\n [item]=\"chart\"\r\n class=\"db-gridster-item bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden hover:shadow-md hover:border-surface-300\"\r\n [class.ring-2]=\"isSelected(chart)\"\r\n [class.ring-primary]=\"isSelected(chart)\"\r\n [class.ring-offset-2]=\"isSelected(chart)\"\r\n [attr.data-chart-id]=\"chart.config?.serviceConfig?.dashboardId\"\r\n (click)=\"onSelect(chart, $event)\"\r\n >\r\n <!-- Chart Content -->\r\n <div class=\"h-full w-full relative group\">\r\n <!-- Drag Handle -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"drag-handler absolute top-0 left-0 right-0 h-6 cursor-move bg-gradient-to-b from-black/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center z-10\"\r\n >\r\n <i\r\n class=\"mti mti-grip-horizontal text-white/70 text-sm\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!--\r\n Pass 7 \u2014 Single top-end Manage menu per chart card.\r\n Layout widgets (header/topbar/group) keep their dedicated\r\n affordances; chart cards have **only** the kebab.\r\n -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"db-card-actions absolute top-1 end-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Single kebab for chart cards (Pass 7 sole owner). -->\r\n @if (showContextToolbar(chart)) {\r\n <mt-item-card-menu\r\n [allowDuplicate]=\"true\"\r\n [hasLinkedDialog]=\"hasLinkedDialog(chart)\"\r\n [canLinkDialog]=\"canLinkDialog(chart)\"\r\n (action)=\"onItemCardMenuAction(chart, $event)\"\r\n />\r\n }\r\n\r\n <!-- Topbar: breadcrumb editor (layout-specific). -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.slash-divider\"\r\n [tooltip]=\"t('manageBreadcrumb')\"\r\n (onClick)=\"openBreadcrumb(chart)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!--\r\n Header / topbar \u2014 quick style + delete.\r\n These widgets don't have a datasource so they don't\r\n use the chart kebab; the affordances stay minimal.\r\n -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"header\" ||\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('actions.editTitle')\"\r\n (onClick)=\"requestLayoutTitleEdit(chart, $event)\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('actions.style')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('actions.delete')\"\r\n (onClick)=\"deleteItem(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('removeGroup')\"\r\n (onClick)=\"removeGroup(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chart Rendering -->\r\n @if (!chart.loading) {\r\n <mt-dashboard-item\r\n [config]=\"chart.config\"\r\n [chartTypeId]=\"chart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"configureChart(chart)\"\r\n (titleEdited)=\"onChartTitleEdited(chart, $event)\"\r\n />\r\n } @else {\r\n <div class=\"flex items-center justify-center h-full\">\r\n <i\r\n class=\"mti mti-spinner-third mti-spin text-2xl text-primary\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!-- Group Children -->\r\n @if (chart.config?.clientConfig?.componentName === \"Group\") {\r\n <div class=\"h-full flex flex-col p-2\">\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n @if (idx === chart.selectedGroupIndex) {\r\n <div class=\"flex-1 min-h-0\">\r\n <mt-dashboard-item\r\n [config]=\"childChart.config\"\r\n [chartTypeId]=\"childChart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"\r\n editItem(childChart, chart, 'dataSource')\r\n \"\r\n (titleEdited)=\"\r\n onChartTitleEdited(childChart, $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Group Tabs -->\r\n <div\r\n class=\"absolute bottom-0 left-0 right-0 flex gap-1 p-1 bg-surface-100 rounded-b-lg overflow-x-auto\"\r\n >\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n <mt-button\r\n [label]=\"\r\n childChart.config?.clientConfig?.title?.[\r\n languageCode()\r\n ] ||\r\n childChart.config?.clientConfig?.title?.['en'] ||\r\n 'Chart ' + (idx + 1)\r\n \"\r\n [severity]=\"\r\n idx === chart.selectedGroupIndex\r\n ? 'primary'\r\n : 'secondary'\r\n \"\r\n [text]=\"idx !== chart.selectedGroupIndex\"\r\n size=\"small\"\r\n (onClick)=\"chart.selectedGroupIndex = idx\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </gridster-item>\r\n }\r\n </gridster>\r\n\r\n <!-- Context Menu -->\r\n <p-contextMenu #contextMenu [model]=\"menuItems()\" appendTo=\"body\" />\r\n }\r\n\r\n <!-- Empty State -->\r\n @if (!loading() && !pageConfig()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center h-64 text-muted-color\"\r\n >\r\n <i class=\"mti mti-layout text-6xl mb-4\"></i>\r\n <p class=\"text-lg\">{{ t(\"noPageSelected\") }}</p>\r\n <p class=\"text-sm\">{{ t(\"selectPageToStart\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}gridster{min-height:calc(100vh - 120px);height:100%}gridster .gridster-column{border-left:1px solid var(--p-primary-100)!important;border-right:1px solid var(--p-primary-100)!important}gridster .gridster-row{border-top:1px solid var(--p-primary-100)!important;border-bottom:1px solid var(--p-primary-100)!important}gridster.is-page{min-height:calc(100vh - 200px)}gridster-item.db-gridster-item{transition:none!important}.mti-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gridster-drop-indicator{position:absolute;background:var(--p-primary-100);border:2px dashed var(--p-primary-400);border-radius:8px;pointer-events:none;z-index:100}.db-card-actions{pointer-events:auto;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.25rem;max-width:calc(100% - 2.5rem)}@media(max-width:640px){.db-card-actions{top:.25rem;right:.25rem}}.db-card-title-edit{background:transparent;border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.375rem;padding:.25rem .5rem;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);text-align:center;width:min(100%,22rem);outline:none}.db-card-title-edit:focus{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff)}.mt-item-config-popover-host .p-dialog-content{padding:0!important;height:clamp(420px,70vh,720px);max-height:80vh}.mt-item-config-popover-host .p-dialog-header{display:none}@media(max-width:768px){.mt-item-config-popover-host{width:100%!important;max-width:100%!important;margin:0!important;inset:auto 0 0!important;border-radius:1rem 1rem 0 0!important;transform:none!important}.mt-item-config-popover-host .p-dialog-content{height:80vh;border-radius:1rem 1rem 0 0}}.db-context-popover{--p-popover-content-padding: .4rem;min-width:200px}\n"] }]
35669
+ ], encapsulation: ViewEncapsulation.None, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Shared Actions Template -->\r\n <ng-template #actionsTemplate let-inPage=\"inPage\">\r\n <mt-button\r\n [label]=\"t('addWidget')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"toggleWidgetPalette()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"saving()\"\r\n (onClick)=\"saveDash()\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <span [class]=\"'w-px h-5 bg-surface-300'\"></span>\r\n\r\n <mt-button\r\n [icon]=\"stopActionsOnCards() ? 'media.play' : 'media.stop'\"\r\n [tooltip]=\"stopActionsOnCards() ? t('activateActions') : t('stopActions')\"\r\n (onClick)=\"stopAndActiveActions()\"\r\n [severity]=\"'warn'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('pageSettings')\"\r\n (onClick)=\"addOrEditPage(pageConfig()!)\"\r\n [severity]=\"'help'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.filter-lines\"\r\n [tooltip]=\"t('manageFilter')\"\r\n (onClick)=\"openManageFilter()\"\r\n [severity]=\"'info'\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [rounded]=\"!inPage\"\r\n />\r\n </ng-template>\r\n\r\n <!-- Page mode -->\r\n @if (isPage()) {\r\n <mt-page\r\n [title]=\"\r\n pageTitle() ||\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n t('builder')\r\n \"\r\n [backButton]=\"backButton()\"\r\n (backButtonClick)=\"onBack.emit()\"\r\n >\r\n <!-- Header actions -->\r\n <ng-template #headerEnd>\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: true }\"\r\n />\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Content -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <!-- Non-page mode -->\r\n <ng-container *ngTemplateOutlet=\"builderContent\" />\r\n }\r\n\r\n <!-- Reusable builder content template -->\r\n <ng-template #builderContent>\r\n <div class=\"relative h-full min-h-[600px]\">\r\n <!-- Loading State -->\r\n @if (loading()) {\r\n <div class=\"flex items-center justify-center h-64\">\r\n <i class=\"mti mti-spinner-third mti-spin text-4xl text-primary\"></i>\r\n </div>\r\n }\r\n\r\n <!-- Main Content -->\r\n @if (!loading() && pageConfig()) {\r\n <!-- Fixed Actions Bar (only when NOT page mode) -->\r\n @if (!isPage()) {\r\n <div\r\n class=\"fixed bottom-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-2 bg-surface-0 rounded-full shadow-lg px-4 py-2 border border-surface-200\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"actionsTemplate; context: { inPage: false }\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Gridster Container -->\r\n <gridster\r\n #gridsterContainer\r\n [options]=\"options\"\r\n class=\"h-full min-h-[500px] bg-surface-50!\"\r\n [class.is-page]=\"isPage()\"\r\n [class.pointer-events-none]=\"readonly()\"\r\n (dragover)=\"onGridDragOver($event)\"\r\n (drop)=\"onGridDrop($event)\"\r\n >\r\n @for (chart of charts() | filterByGroup: undefined; track $index) {\r\n <gridster-item\n [item]=\"chart\"\n class=\"db-gridster-item bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden hover:shadow-md hover:border-surface-300\"\n [class.db-gridster-item--properties-list]=\"\n isPropertiesListChart(chart)\n \"\n [class.ring-2]=\"isSelected(chart)\"\n [class.ring-primary]=\"isSelected(chart)\"\n [class.ring-offset-2]=\"isSelected(chart)\"\n [attr.data-chart-id]=\"chart.config?.serviceConfig?.dashboardId\"\r\n (click)=\"onSelect(chart, $event)\"\r\n >\r\n <!-- Chart Content -->\r\n <div class=\"h-full w-full relative group\">\r\n <!-- Drag Handle -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"drag-handler absolute top-0 left-0 right-0 h-6 cursor-move bg-gradient-to-b from-black/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center z-10\"\r\n >\r\n <i\r\n class=\"mti mti-grip-horizontal text-white/70 text-sm\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!--\r\n Pass 7 \u2014 Single top-end Manage menu per chart card.\r\n Layout widgets (header/topbar/group) keep their dedicated\r\n affordances; chart cards have **only** the kebab.\r\n -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"db-card-actions absolute top-1 end-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Single kebab for chart cards (Pass 7 sole owner). -->\r\n @if (showContextToolbar(chart)) {\r\n <mt-item-card-menu\r\n [allowDuplicate]=\"true\"\r\n [hasLinkedDialog]=\"hasLinkedDialog(chart)\"\r\n [canLinkDialog]=\"canLinkDialog(chart)\"\r\n (action)=\"onItemCardMenuAction(chart, $event)\"\r\n />\r\n }\r\n\r\n <!-- Topbar: breadcrumb editor (layout-specific). -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.slash-divider\"\r\n [tooltip]=\"t('manageBreadcrumb')\"\r\n (onClick)=\"openBreadcrumb(chart)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!--\r\n Header / topbar \u2014 quick style + delete.\r\n These widgets don't have a datasource so they don't\r\n use the chart kebab; the affordances stay minimal.\r\n -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"header\" ||\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('actions.editTitle')\"\r\n (onClick)=\"requestLayoutTitleEdit(chart, $event)\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('actions.style')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('actions.delete')\"\r\n (onClick)=\"deleteItem(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('removeGroup')\"\r\n (onClick)=\"removeGroup(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chart Rendering -->\r\n @if (!chart.loading) {\r\n <mt-dashboard-item\r\n [config]=\"chart.config\"\r\n [chartTypeId]=\"chart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"configureChart(chart)\"\r\n (titleEdited)=\"onChartTitleEdited(chart, $event)\"\r\n />\r\n } @else {\r\n <div class=\"flex items-center justify-center h-full\">\r\n <i\r\n class=\"mti mti-spinner-third mti-spin text-2xl text-primary\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!-- Group Children -->\r\n @if (chart.config?.clientConfig?.componentName === \"Group\") {\r\n <div class=\"h-full flex flex-col p-2\">\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n @if (idx === chart.selectedGroupIndex) {\r\n <div class=\"flex-1 min-h-0\">\r\n <mt-dashboard-item\r\n [config]=\"childChart.config\"\r\n [chartTypeId]=\"childChart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"\r\n editItem(childChart, chart, 'dataSource')\r\n \"\r\n (titleEdited)=\"\r\n onChartTitleEdited(childChart, $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Group Tabs -->\r\n <div\r\n class=\"absolute bottom-0 left-0 right-0 flex gap-1 p-1 bg-surface-100 rounded-b-lg overflow-x-auto\"\r\n >\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n <mt-button\r\n [label]=\"\r\n childChart.config?.clientConfig?.title?.[\r\n languageCode()\r\n ] ||\r\n childChart.config?.clientConfig?.title?.['en'] ||\r\n 'Chart ' + (idx + 1)\r\n \"\r\n [severity]=\"\r\n idx === chart.selectedGroupIndex\r\n ? 'primary'\r\n : 'secondary'\r\n \"\r\n [text]=\"idx !== chart.selectedGroupIndex\"\r\n size=\"small\"\r\n (onClick)=\"chart.selectedGroupIndex = idx\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </gridster-item>\r\n }\r\n </gridster>\r\n\r\n <!-- Context Menu -->\r\n <p-contextMenu #contextMenu [model]=\"menuItems()\" appendTo=\"body\" />\r\n }\r\n\r\n <!-- Empty State -->\r\n @if (!loading() && !pageConfig()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center h-64 text-muted-color\"\r\n >\r\n <i class=\"mti mti-layout text-6xl mb-4\"></i>\r\n <p class=\"text-lg\">{{ t(\"noPageSelected\") }}</p>\r\n <p class=\"text-sm\">{{ t(\"selectPageToStart\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}gridster{min-height:calc(100vh - 120px);height:100%}gridster .gridster-column{border-left:1px solid var(--p-primary-100)!important;border-right:1px solid var(--p-primary-100)!important}gridster .gridster-row{border-top:1px solid var(--p-primary-100)!important;border-bottom:1px solid var(--p-primary-100)!important}gridster.is-page{min-height:calc(100vh - 200px)}gridster-item.db-gridster-item{transition:none!important}gridster-item.db-gridster-item.db-gridster-item--properties-list{background:transparent!important;border-color:transparent!important;border-radius:0!important;box-shadow:none!important;overflow:visible!important}gridster-item.db-gridster-item.db-gridster-item--properties-list:hover{border-color:transparent!important;box-shadow:none!important}.mti-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gridster-drop-indicator{position:absolute;background:var(--p-primary-100);border:2px dashed var(--p-primary-400);border-radius:8px;pointer-events:none;z-index:100}.db-card-actions{pointer-events:auto;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.25rem;max-width:calc(100% - 2.5rem)}@media(max-width:640px){.db-card-actions{top:.25rem;right:.25rem}}.db-card-title-edit{background:transparent;border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.375rem;padding:.25rem .5rem;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);text-align:center;width:min(100%,22rem);outline:none}.db-card-title-edit:focus{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff)}.mt-item-config-popover-host .p-dialog-content{padding:0!important;height:clamp(420px,70vh,720px);max-height:80vh}.mt-item-config-popover-host .p-dialog-header{display:none}@media(max-width:768px){.mt-item-config-popover-host{width:100%!important;max-width:100%!important;margin:0!important;inset:auto 0 0!important;border-radius:1rem 1rem 0 0!important;transform:none!important}.mt-item-config-popover-host .p-dialog-content{height:80vh;border-radius:1rem 1rem 0 0}}.db-context-popover{--p-popover-content-padding: .4rem;min-width:200px}\n"] }]
35547
35670
  }], ctorParameters: () => [], propDecorators: { isPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "isPage", required: false }] }], pageTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageTitle", required: false }] }], backButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "backButton", required: false }] }], pageId: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageId", required: false }] }], standalone: [{ type: i0.Input, args: [{ isSignal: true, alias: "standalone", required: false }] }], services: [{ type: i0.Input, args: [{ isSignal: true, alias: "services", required: false }] }], dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: false }] }, { type: i0.Output, args: ["dashboardDataChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], informativeContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "informativeContext", required: false }] }], extraFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraFilters", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], chartsChange: [{ type: i0.Output, args: ["chartsChange"] }], onSave: [{ type: i0.Output, args: ["onSave"] }], onBack: [{ type: i0.Output, args: ["onBack"] }], onAddChart: [{ type: i0.Output, args: ["onAddChart"] }], onEditChart: [{ type: i0.Output, args: ["onEditChart"] }], contextMenu: [{ type: i0.ViewChild, args: ['contextMenu', { isSignal: true }] }], gridsterContainer: [{ type: i0.ViewChild, args: ['gridsterContainer', { isSignal: true }] }], onKeyDown: [{
35548
35671
  type: HostListener,
35549
35672
  args: ['window:keydown', ['$event']]