@masterteam/dashboard-builder 0.0.17 → 0.0.18

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.
@@ -45,6 +45,7 @@ import * as i4 from 'primeng/inputgroupaddon';
45
45
  import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
46
46
  import * as i6 from 'primeng/select';
47
47
  import { SelectModule } from 'primeng/select';
48
+ import { RadioCards } from '@masterteam/components/radio-cards';
48
49
  import { Router, ActivatedRoute } from '@angular/router';
49
50
  import { Tooltip as Tooltip$1 } from '@masterteam/components/tooltip';
50
51
  import * as mtIcons from '@masterteam/icons/assets/select-icons.json';
@@ -354,6 +355,16 @@ class DashboardBuilderService {
354
355
  data: (response.data?.items || []).map(mapBulkPropertiesResponseItem),
355
356
  })));
356
357
  }
358
+ /**
359
+ * Get context-aware dashboard targets for informative authoring.
360
+ */
361
+ getContextDashboardTargets(contextKey, instanceId) {
362
+ let url = `context/dashboard-targets?contextKey=${encodeURIComponent(contextKey)}`;
363
+ if (instanceId != null) {
364
+ url += `&instanceId=${encodeURIComponent(String(instanceId))}`;
365
+ }
366
+ return this.http.get(url);
367
+ }
357
368
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DashboardBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
358
369
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DashboardBuilderService, providedIn: 'root' });
359
370
  }
@@ -4393,6 +4404,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4393
4404
  class SelectionConfiguration {
4394
4405
  fb = inject(FormBuilder);
4395
4406
  dashboardService = inject(DashboardBuilderService);
4407
+ /** Lock selection structure while still allowing filter edits */
4408
+ structureLocked = input(false, ...(ngDevMode ? [{ debugName: "structureLocked" }] : /* istanbul ignore next */ []));
4396
4409
  /** Properties grouped by module */
4397
4410
  modulesProperties = input([], ...(ngDevMode ? [{ debugName: "modulesProperties" }] : /* istanbul ignore next */ []));
4398
4411
  /** Flat list of properties */
@@ -4616,10 +4629,16 @@ class SelectionConfiguration {
4616
4629
  }
4617
4630
  // ==================== Selection Actions ====================
4618
4631
  addSelection() {
4632
+ if (this.structureLocked()) {
4633
+ return;
4634
+ }
4619
4635
  const formGroup = this.createSelectionFormGroup();
4620
4636
  this.selectionsArray.push(formGroup);
4621
4637
  }
4622
4638
  removeSelection(index) {
4639
+ if (this.structureLocked()) {
4640
+ return;
4641
+ }
4623
4642
  const selection = this.selectionsArray.at(index);
4624
4643
  const selectionId = selection?.get('id')?.value;
4625
4644
  // Prevent removing fixed selections
@@ -4632,6 +4651,9 @@ class SelectionConfiguration {
4632
4651
  * Handle service change for a selection
4633
4652
  */
4634
4653
  onServiceChange(selectionIndex, _serviceName) {
4654
+ if (this.structureLocked()) {
4655
+ return;
4656
+ }
4635
4657
  const selection = this.selectionsArray.at(selectionIndex);
4636
4658
  // Clear module when service changes
4637
4659
  selection.patchValue({ selector: null });
@@ -4640,6 +4662,9 @@ class SelectionConfiguration {
4640
4662
  * Handle module selection change
4641
4663
  */
4642
4664
  onModuleChange(selectionIndex, selector) {
4665
+ if (this.structureLocked()) {
4666
+ return;
4667
+ }
4643
4668
  if (!selector)
4644
4669
  return;
4645
4670
  const selection = this.selectionsArray.at(selectionIndex);
@@ -4852,6 +4877,9 @@ class SelectionConfiguration {
4852
4877
  }));
4853
4878
  this.onChange(cleanValue);
4854
4879
  }
4880
+ isSelectionStructureLocked(selectionId) {
4881
+ return this.structureLocked() || this.isFixedSelection(selectionId);
4882
+ }
4855
4883
  trackBySelectionId(index, control) {
4856
4884
  return control.get('id')?.value || index;
4857
4885
  }
@@ -4859,7 +4887,7 @@ class SelectionConfiguration {
4859
4887
  return index;
4860
4888
  }
4861
4889
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SelectionConfiguration, deps: [], target: i0.ɵɵFactoryTarget.Component });
4862
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SelectionConfiguration, isStandalone: true, selector: "mt-selection-configuration", inputs: { modulesProperties: { classPropertyName: "modulesProperties", publicName: "modulesProperties", isSignal: true, isRequired: false, transformFunction: null }, propertiesFlat: { classPropertyName: "propertiesFlat", publicName: "propertiesFlat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleChange: "moduleChange" }, providers: [
4890
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SelectionConfiguration, isStandalone: true, selector: "mt-selection-configuration", inputs: { structureLocked: { classPropertyName: "structureLocked", publicName: "structureLocked", isSignal: true, isRequired: false, transformFunction: null }, modulesProperties: { classPropertyName: "modulesProperties", publicName: "modulesProperties", isSignal: true, isRequired: false, transformFunction: null }, propertiesFlat: { classPropertyName: "propertiesFlat", publicName: "propertiesFlat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleChange: "moduleChange" }, providers: [
4863
4891
  {
4864
4892
  provide: NG_VALUE_ACCESSOR,
4865
4893
  useExisting: forwardRef(() => SelectionConfiguration),
@@ -4870,7 +4898,7 @@ class SelectionConfiguration {
4870
4898
  useExisting: forwardRef(() => SelectionConfiguration),
4871
4899
  multi: true,
4872
4900
  },
4873
- ], 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 <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 </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 !isFixedSelection(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 [disabled]=\"isFixedSelection(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module (grouped by module type) -->\r\n <mt-select-field\r\n [label]=\"t('module')\"\r\n formControlName=\"selector\"\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 [loading]=\"loadingTree()\"\r\n [filter]=\"true\"\r\n [showClear]=\"!isFixedSelection(selection.value.id)\"\r\n [disabled]=\"isFixedSelection(selection.value.id)\"\r\n (ngModelChange)=\"onModuleChange(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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 <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 </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: "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", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required"] }, { kind: "component", type: FilterValueField, selector: "mt-filter-value-field", inputs: ["label", "placeholder", "extraProperties"] }, { 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 });
4901
+ ], 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 [disabled]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module (grouped by module type) -->\r\n <mt-select-field\r\n [label]=\"t('module')\"\r\n formControlName=\"selector\"\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 [loading]=\"loadingTree()\"\r\n [filter]=\"true\"\r\n [showClear]=\"!isSelectionStructureLocked(selection.value.id)\"\r\n [disabled]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onModuleChange(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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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: "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", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required"] }, { kind: "component", type: FilterValueField, selector: "mt-filter-value-field", inputs: ["label", "placeholder", "extraProperties"] }, { 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 });
4874
4902
  }
4875
4903
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SelectionConfiguration, decorators: [{
4876
4904
  type: Component,
@@ -4898,8 +4926,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4898
4926
  useExisting: forwardRef(() => SelectionConfiguration),
4899
4927
  multi: true,
4900
4928
  },
4901
- ], 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 <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 </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 !isFixedSelection(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 [disabled]=\"isFixedSelection(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module (grouped by module type) -->\r\n <mt-select-field\r\n [label]=\"t('module')\"\r\n formControlName=\"selector\"\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 [loading]=\"loadingTree()\"\r\n [filter]=\"true\"\r\n [showClear]=\"!isFixedSelection(selection.value.id)\"\r\n [disabled]=\"isFixedSelection(selection.value.id)\"\r\n (ngModelChange)=\"onModuleChange(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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 <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 </div>\r\n }\r\n </div>\r\n }\r\n </mt-card>\r\n</div>\r\n" }]
4902
- }], ctorParameters: () => [], propDecorators: { 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"] }] } });
4929
+ ], 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 [disabled]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onServiceChange(i, $event)\"\r\n />\r\n }\r\n\r\n <!-- Module (grouped by module type) -->\r\n <mt-select-field\r\n [label]=\"t('module')\"\r\n formControlName=\"selector\"\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 [loading]=\"loadingTree()\"\r\n [filter]=\"true\"\r\n [showClear]=\"!isSelectionStructureLocked(selection.value.id)\"\r\n [disabled]=\"isSelectionStructureLocked(selection.value.id)\"\r\n (ngModelChange)=\"onModuleChange(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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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 [disabled]=\"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" }]
4930
+ }], ctorParameters: () => [], propDecorators: { structureLocked: [{ type: i0.Input, args: [{ isSignal: true, alias: "structureLocked", 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"] }] } });
4903
4931
 
4904
4932
  /**
4905
4933
  * Source Link Configuration Component
@@ -6196,6 +6224,184 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
6196
6224
  ], template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Pivot Property -->\r\n <mt-select-field\r\n [label]=\"t('pivotProperty')\"\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('selectProperty')\"\r\n [ngModel]=\"query().pivotProperty\"\r\n (ngModelChange)=\"updateField('pivotProperty', $event)\"\r\n [disabled]=\"disabled\"\r\n />\r\n\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <!-- Positive Values -->\r\n <mt-text-field\r\n [label]=\"t('positiveValues')\"\r\n [placeholder]=\"t('enterValuesCommaSeparated')\"\r\n [ngModel]=\"getArrayAsString('PositiveValues')\"\r\n (ngModelChange)=\"updateArrayFromString('PositiveValues', $event)\"\r\n [disabled]=\"disabled\"\r\n />\r\n\r\n <!-- Negative Values -->\r\n <mt-text-field\r\n [label]=\"t('negativeValues')\"\r\n [placeholder]=\"t('enterValuesCommaSeparated')\"\r\n [ngModel]=\"getArrayAsString('NegativeValues')\"\r\n (ngModelChange)=\"updateArrayFromString('NegativeValues', $event)\"\r\n [disabled]=\"disabled\"\r\n />\r\n </div>\r\n</div>\r\n" }]
6197
6225
  }], propDecorators: { propertiesFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesFlat", required: false }] }], propertiesGrouped: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesGrouped", required: false }] }] } });
6198
6226
 
6227
+ class InformativeContextSelection {
6228
+ dashboardService = inject(DashboardBuilderService);
6229
+ lastApplyToken = -1;
6230
+ informativeContext = input(null, ...(ngDevMode ? [{ debugName: "informativeContext" }] : /* istanbul ignore next */ []));
6231
+ currentSelection = input([], ...(ngDevMode ? [{ debugName: "currentSelection" }] : /* istanbul ignore next */ []));
6232
+ preferredTargetSelector = input(null, ...(ngDevMode ? [{ debugName: "preferredTargetSelector" }] : /* istanbul ignore next */ []));
6233
+ applyToken = input(0, ...(ngDevMode ? [{ debugName: "applyToken" }] : /* istanbul ignore next */ []));
6234
+ templateApply = output();
6235
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
6236
+ targets = signal([], ...(ngDevMode ? [{ debugName: "targets" }] : /* istanbul ignore next */ []));
6237
+ activeTargetSelector = signal(null, ...(ngDevMode ? [{ debugName: "activeTargetSelector" }] : /* istanbul ignore next */ []));
6238
+ requestId = 0;
6239
+ compatibleTargets = computed(() => this.targets().filter((target) => target.isChartCompatible), ...(ngDevMode ? [{ debugName: "compatibleTargets" }] : /* istanbul ignore next */ []));
6240
+ targetCards = computed(() => this.compatibleTargets().map((target) => ({
6241
+ ...target,
6242
+ id: target.selector,
6243
+ name: target.name,
6244
+ pathLabel: target.path?.map((step) => step.name || step.selector).join(' / ') ||
6245
+ target.selector,
6246
+ relationshipLabel: `${target.relationship} target`,
6247
+ })), ...(ngDevMode ? [{ debugName: "targetCards" }] : /* istanbul ignore next */ []));
6248
+ unsupportedTargetsCount = computed(() => this.targets().filter((target) => !target.isChartCompatible).length, ...(ngDevMode ? [{ debugName: "unsupportedTargetsCount" }] : /* istanbul ignore next */ []));
6249
+ selectedTarget = computed(() => {
6250
+ const selector = this.activeTargetSelector();
6251
+ if (!selector) {
6252
+ return null;
6253
+ }
6254
+ return (this.compatibleTargets().find((target) => target.selector === selector) ??
6255
+ null);
6256
+ }, ...(ngDevMode ? [{ debugName: "selectedTarget" }] : /* istanbul ignore next */ []));
6257
+ selectedTargetPath = computed(() => {
6258
+ const target = this.selectedTarget();
6259
+ if (!target?.path?.length) {
6260
+ return '';
6261
+ }
6262
+ return target.path.map((step) => step.name || step.selector).join(' / ');
6263
+ }, ...(ngDevMode ? [{ debugName: "selectedTargetPath" }] : /* istanbul ignore next */ []));
6264
+ constructor() {
6265
+ effect(() => {
6266
+ const context = this.informativeContext();
6267
+ if (!context?.contextKey) {
6268
+ this.targets.set([]);
6269
+ this.activeTargetSelector.set(null);
6270
+ this.loading.set(false);
6271
+ return;
6272
+ }
6273
+ this.loadTargets(context);
6274
+ }, { allowSignalWrites: true });
6275
+ effect(() => {
6276
+ const token = this.applyToken();
6277
+ const compatibleTargets = this.compatibleTargets();
6278
+ if (this.lastApplyToken === -1) {
6279
+ this.lastApplyToken = token;
6280
+ return;
6281
+ }
6282
+ if (token === this.lastApplyToken ||
6283
+ this.loading() ||
6284
+ compatibleTargets.length === 0) {
6285
+ return;
6286
+ }
6287
+ this.lastApplyToken = token;
6288
+ const selector = this.activeTargetSelector() ?? compatibleTargets[0]?.selector ?? null;
6289
+ if (selector) {
6290
+ this.onTargetChange(selector);
6291
+ }
6292
+ }, { allowSignalWrites: true });
6293
+ }
6294
+ onTargetChange(selector) {
6295
+ this.activeTargetSelector.set(selector);
6296
+ this.applyTargetBySelector(selector);
6297
+ }
6298
+ onTargetSelectionChange(selectedItem) {
6299
+ this.onTargetChange(String(selectedItem.id));
6300
+ }
6301
+ loadTargets(context) {
6302
+ const requestId = ++this.requestId;
6303
+ this.loading.set(true);
6304
+ this.dashboardService
6305
+ .getContextDashboardTargets(context.contextKey, context.instanceId)
6306
+ .subscribe({
6307
+ next: (response) => {
6308
+ if (requestId !== this.requestId) {
6309
+ return;
6310
+ }
6311
+ const targets = response.data?.targets ?? [];
6312
+ const compatibleTargets = targets.filter((target) => target.isChartCompatible);
6313
+ const preferredSelector = this.preferredTargetSelector();
6314
+ const resolvedTarget = compatibleTargets.find((target) => target.selector === preferredSelector) ??
6315
+ compatibleTargets.find((target) => target.selector === this.activeTargetSelector()) ??
6316
+ compatibleTargets[0] ??
6317
+ null;
6318
+ this.targets.set(targets);
6319
+ this.activeTargetSelector.set(resolvedTarget?.selector ?? null);
6320
+ this.loading.set(false);
6321
+ if (resolvedTarget?.chartTemplate &&
6322
+ (!this.currentSelection().length ||
6323
+ resolvedTarget.selector !== preferredSelector)) {
6324
+ this.emitTemplate(resolvedTarget);
6325
+ }
6326
+ },
6327
+ error: () => {
6328
+ if (requestId !== this.requestId) {
6329
+ return;
6330
+ }
6331
+ this.targets.set([]);
6332
+ this.activeTargetSelector.set(null);
6333
+ this.loading.set(false);
6334
+ },
6335
+ });
6336
+ }
6337
+ mapChartTemplate(template) {
6338
+ return {
6339
+ selection: template.selection.map((selection) => ({
6340
+ id: selection.id,
6341
+ service: 'pplus',
6342
+ selector: selection.selector,
6343
+ selectorName: this.dashboardService.resolveSelectorName(selection.selector) ??
6344
+ selection.selector,
6345
+ filters: (selection.filters ?? []).map((filter) => ({
6346
+ propertyKey: filter.propertyKey,
6347
+ propertyValue: filter.propertyValue,
6348
+ operation: 'Equals',
6349
+ logical: 'And',
6350
+ operationLevel: 1,
6351
+ })),
6352
+ })),
6353
+ sourceLinks: template.sourceLinks.map((link) => {
6354
+ if (link.sourceLinkId2 != null) {
6355
+ return {
6356
+ sourceLinkId: link.sourceLinkId2,
6357
+ source1SelectionId: null,
6358
+ source2SelectionId: link.sourceId1,
6359
+ source1PropertyKey: link.source2LinkProperty,
6360
+ source2PropertyKey: link.source1LinkProperty,
6361
+ isFilterLinkage: link.isFilterLinkage,
6362
+ isLeftJoin: link.isLeftJoin,
6363
+ };
6364
+ }
6365
+ return {
6366
+ source1SelectionId: link.sourceId1,
6367
+ source2SelectionId: link.sourceId2,
6368
+ source1PropertyKey: link.source1LinkProperty,
6369
+ source2PropertyKey: link.source2LinkProperty,
6370
+ isFilterLinkage: link.isFilterLinkage,
6371
+ isLeftJoin: link.isLeftJoin,
6372
+ };
6373
+ }),
6374
+ };
6375
+ }
6376
+ applyTargetBySelector(selector) {
6377
+ if (!selector) {
6378
+ return;
6379
+ }
6380
+ const target = this.compatibleTargets().find((item) => item.selector === selector);
6381
+ if (!target?.chartTemplate) {
6382
+ return;
6383
+ }
6384
+ this.emitTemplate(target);
6385
+ }
6386
+ emitTemplate(target) {
6387
+ if (!target.chartTemplate) {
6388
+ return;
6389
+ }
6390
+ this.templateApply.emit({
6391
+ targetSelector: target.selector,
6392
+ ...this.mapChartTemplate(target.chartTemplate),
6393
+ });
6394
+ }
6395
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: InformativeContextSelection, deps: [], target: i0.ɵɵFactoryTarget.Component });
6396
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: InformativeContextSelection, isStandalone: true, selector: "mt-informative-context-selection", inputs: { informativeContext: { classPropertyName: "informativeContext", publicName: "informativeContext", isSignal: true, isRequired: false, transformFunction: null }, currentSelection: { classPropertyName: "currentSelection", publicName: "currentSelection", isSignal: true, isRequired: false, transformFunction: null }, preferredTargetSelector: { classPropertyName: "preferredTargetSelector", publicName: "preferredTargetSelector", isSignal: true, isRequired: false, transformFunction: null }, applyToken: { classPropertyName: "applyToken", publicName: "applyToken", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { templateApply: "templateApply" }, host: { classAttribute: "block" }, ngImport: i0, template: "<mt-card title=\"Context Target\">\r\n @if (loading()) {\r\n <div class=\"flex flex-col gap-3\">\r\n <p-skeleton height=\"2.5rem\" borderRadius=\"8px\" />\r\n <p-skeleton height=\"5rem\" borderRadius=\"12px\" />\r\n </div>\r\n } @else if (compatibleTargets().length === 0) {\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\r\n <p class=\"text-sm font-medium text-surface-700\">\r\n No compatible targets available for this context.\r\n </p>\r\n <p class=\"mt-1 text-xs text-muted-color\">\r\n Switch to advanced selection to configure selections manually.\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-radio-cards\r\n [options]=\"targetCards()\"\r\n [activeId]=\"activeTargetSelector()\"\r\n [columns]=\"1\"\r\n size=\"small\"\r\n (selectionChange)=\"onTargetSelectionChange($event)\"\r\n >\r\n <ng-template #option let-target let-active=\"active\">\r\n <div class=\"flex w-full flex-col gap-2\">\r\n <div class=\"flex items-start justify-between gap-3\">\r\n <div class=\"flex flex-col gap-1\">\r\n <span class=\"text-sm font-semibold text-surface-700\">\r\n {{ target.name }}\r\n </span>\r\n <span\r\n class=\"text-xs capitalize\"\r\n [class.text-primary-600]=\"active\"\r\n [class.text-muted-color]=\"!active\"\r\n >\r\n {{ target.relationshipLabel }}\r\n </span>\r\n </div>\r\n <span\r\n class=\"rounded-full px-2 py-0.5 text-[11px] font-medium\"\r\n [class.bg-primary-100]=\"active\"\r\n [class.text-primary-700]=\"active\"\r\n [class.bg-surface-100]=\"!active\"\r\n [class.text-surface-600]=\"!active\"\r\n >\r\n {{ target.contextType }}\r\n </span>\r\n </div>\r\n\r\n <span class=\"text-xs text-muted-color\">\r\n {{ target.pathLabel }}\r\n </span>\r\n </div>\r\n </ng-template>\r\n </mt-radio-cards>\r\n\r\n @if (selectedTarget()) {\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\r\n <div class=\"flex flex-col gap-1\">\r\n <span class=\"text-xs font-semibold uppercase text-slate-400\">\r\n Path\r\n </span>\r\n <span class=\"text-sm font-medium text-surface-700\">\r\n {{ selectedTargetPath() || selectedTarget()?.name }}\r\n </span>\r\n <span class=\"text-xs text-muted-color\">\r\n {{ selectedTarget()?.relationship }} target\r\n </span>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (unsupportedTargetsCount() > 0) {\r\n <span class=\"text-xs text-muted-color\">\r\n {{ unsupportedTargetsCount() }} target(s) still require advanced\r\n selection.\r\n </span>\r\n }\r\n </div>\r\n }\r\n</mt-card>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: RadioCards, selector: "mt-radio-cards", inputs: ["circle", "color", "size", "columns", "options", "activeId", "itemTemplate"], outputs: ["optionsChange", "activeIdChange", "selectionChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
6397
+ }
6398
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: InformativeContextSelection, decorators: [{
6399
+ type: Component,
6400
+ args: [{ selector: 'mt-informative-context-selection', standalone: true, imports: [CommonModule, Skeleton, Card, RadioCards], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
6401
+ class: 'block',
6402
+ }, template: "<mt-card title=\"Context Target\">\r\n @if (loading()) {\r\n <div class=\"flex flex-col gap-3\">\r\n <p-skeleton height=\"2.5rem\" borderRadius=\"8px\" />\r\n <p-skeleton height=\"5rem\" borderRadius=\"12px\" />\r\n </div>\r\n } @else if (compatibleTargets().length === 0) {\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\r\n <p class=\"text-sm font-medium text-surface-700\">\r\n No compatible targets available for this context.\r\n </p>\r\n <p class=\"mt-1 text-xs text-muted-color\">\r\n Switch to advanced selection to configure selections manually.\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-radio-cards\r\n [options]=\"targetCards()\"\r\n [activeId]=\"activeTargetSelector()\"\r\n [columns]=\"1\"\r\n size=\"small\"\r\n (selectionChange)=\"onTargetSelectionChange($event)\"\r\n >\r\n <ng-template #option let-target let-active=\"active\">\r\n <div class=\"flex w-full flex-col gap-2\">\r\n <div class=\"flex items-start justify-between gap-3\">\r\n <div class=\"flex flex-col gap-1\">\r\n <span class=\"text-sm font-semibold text-surface-700\">\r\n {{ target.name }}\r\n </span>\r\n <span\r\n class=\"text-xs capitalize\"\r\n [class.text-primary-600]=\"active\"\r\n [class.text-muted-color]=\"!active\"\r\n >\r\n {{ target.relationshipLabel }}\r\n </span>\r\n </div>\r\n <span\r\n class=\"rounded-full px-2 py-0.5 text-[11px] font-medium\"\r\n [class.bg-primary-100]=\"active\"\r\n [class.text-primary-700]=\"active\"\r\n [class.bg-surface-100]=\"!active\"\r\n [class.text-surface-600]=\"!active\"\r\n >\r\n {{ target.contextType }}\r\n </span>\r\n </div>\r\n\r\n <span class=\"text-xs text-muted-color\">\r\n {{ target.pathLabel }}\r\n </span>\r\n </div>\r\n </ng-template>\r\n </mt-radio-cards>\r\n\r\n @if (selectedTarget()) {\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\r\n <div class=\"flex flex-col gap-1\">\r\n <span class=\"text-xs font-semibold uppercase text-slate-400\">\r\n Path\r\n </span>\r\n <span class=\"text-sm font-medium text-surface-700\">\r\n {{ selectedTargetPath() || selectedTarget()?.name }}\r\n </span>\r\n <span class=\"text-xs text-muted-color\">\r\n {{ selectedTarget()?.relationship }} target\r\n </span>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (unsupportedTargetsCount() > 0) {\r\n <span class=\"text-xs text-muted-color\">\r\n {{ unsupportedTargetsCount() }} target(s) still require advanced\r\n selection.\r\n </span>\r\n }\r\n </div>\r\n }\r\n</mt-card>\r\n" }]
6403
+ }], ctorParameters: () => [], propDecorators: { informativeContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "informativeContext", required: false }] }], currentSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSelection", required: false }] }], preferredTargetSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "preferredTargetSelector", required: false }] }], applyToken: [{ type: i0.Input, args: [{ isSignal: true, alias: "applyToken", required: false }] }], templateApply: [{ type: i0.Output, args: ["templateApply"] }] } });
6404
+
6199
6405
  /**
6200
6406
  * Data Source Settings Component
6201
6407
  *
@@ -6210,6 +6416,8 @@ class DataSourceSettings {
6210
6416
  config = input(null, ...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
6211
6417
  /** Selected chart type */
6212
6418
  chartType = input(null, ...(ngDevMode ? [{ debugName: "chartType" }] : /* istanbul ignore next */ []));
6419
+ /** Optional informative authoring context for context-aware source selection */
6420
+ informativeContext = input(null, ...(ngDevMode ? [{ debugName: "informativeContext" }] : /* istanbul ignore next */ []));
6213
6421
  /** Emit service config changes */
6214
6422
  serviceConfigChange = output();
6215
6423
  /** Properties grouped by module */
@@ -6339,6 +6547,10 @@ class DataSourceSettings {
6339
6547
  loadingProperties = signal(false, ...(ngDevMode ? [{ debugName: "loadingProperties" }] : /* istanbul ignore next */ []));
6340
6548
  /** Tab state: 'selection' or 'customApi' */
6341
6549
  activeTab = signal('selection', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
6550
+ /** Selection mode inside the selection tab */
6551
+ selectionMode = signal('context', ...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
6552
+ contextTargetSelector = signal(null, ...(ngDevMode ? [{ debugName: "contextTargetSelector" }] : /* istanbul ignore next */ []));
6553
+ contextTargetApplyToken = signal(0, ...(ngDevMode ? [{ debugName: "contextTargetApplyToken" }] : /* istanbul ignore next */ []));
6342
6554
  /** Tab options for display */
6343
6555
  tabOptions = [
6344
6556
  { id: 'selection', label: 'Selection' },
@@ -6368,6 +6580,10 @@ class DataSourceSettings {
6368
6580
  showGroupByMultiple = computed(() => {
6369
6581
  return this.queryComponentType() === 'table';
6370
6582
  }, ...(ngDevMode ? [{ debugName: "showGroupByMultiple" }] : /* istanbul ignore next */ []));
6583
+ /** Informative mode can offer a context-aware selection shortcut */
6584
+ showInformativeSelectionMode = computed(() => {
6585
+ return !!this.informativeContext();
6586
+ }, ...(ngDevMode ? [{ debugName: "showInformativeSelectionMode" }] : /* istanbul ignore next */ []));
6371
6587
  /**
6372
6588
  * Derived signal: Extract module keys from selections for change detection
6373
6589
  * Only changes when actual selectors change, not on every selection update
@@ -6385,6 +6601,7 @@ class DataSourceSettings {
6385
6601
  // Effect 1: Sync config to local state (without loading properties)
6386
6602
  effect(() => {
6387
6603
  const cfg = this.config();
6604
+ const hasInformativeSelectionMode = this.showInformativeSelectionMode();
6388
6605
  if (!cfg?.serviceConfig)
6389
6606
  return;
6390
6607
  const serviceConfig = cfg.serviceConfig;
@@ -6422,6 +6639,23 @@ class DataSourceSettings {
6422
6639
  if (groupByMultiple) {
6423
6640
  this.groupByMultiple.set(groupByMultiple);
6424
6641
  }
6642
+ const useContextTarget = serviceConfig.useContextTarget === true;
6643
+ this.contextTargetSelector.set(serviceConfig.contextTargetSelector ?? null);
6644
+ if (hasInformativeSelectionMode) {
6645
+ if (useContextTarget) {
6646
+ this.selectionMode.set('context');
6647
+ }
6648
+ else if (selection?.length) {
6649
+ this.selectionMode.set('advanced');
6650
+ }
6651
+ else {
6652
+ this.selectionMode.set('context');
6653
+ }
6654
+ }
6655
+ else {
6656
+ this.selectionMode.set('advanced');
6657
+ this.contextTargetSelector.set(null);
6658
+ }
6425
6659
  });
6426
6660
  });
6427
6661
  // Effect 2: Load properties when module signature changes
@@ -6484,7 +6718,23 @@ class DataSourceSettings {
6484
6718
  */
6485
6719
  onSelectionsChange(selections) {
6486
6720
  this.selections.set(selections);
6487
- this.serviceConfigChange.emit({ selection: selections });
6721
+ this.serviceConfigChange.emit({
6722
+ selection: selections,
6723
+ ...this.getContextTargetState(),
6724
+ });
6725
+ }
6726
+ /**
6727
+ * Handle context-aware template selection for informative mode.
6728
+ */
6729
+ onContextTemplateApply(event) {
6730
+ this.contextTargetSelector.set(event.targetSelector);
6731
+ this.selections.set(event.selection);
6732
+ this.sourceLinks.set(event.sourceLinks);
6733
+ this.serviceConfigChange.emit({
6734
+ selection: event.selection,
6735
+ sourceLinks: event.sourceLinks,
6736
+ ...this.getContextTargetState(),
6737
+ });
6488
6738
  }
6489
6739
  /**
6490
6740
  * Handle module change - update selections, effect handles property loading
@@ -6605,6 +6855,16 @@ class DataSourceSettings {
6605
6855
  this.customApi.set(customApi);
6606
6856
  this.serviceConfigChange.emit({ customApi: customApi ?? undefined });
6607
6857
  }
6858
+ /**
6859
+ * Toggle between context-aware and advanced manual selection.
6860
+ */
6861
+ onAdvancedSelectionToggle(useAdvanced) {
6862
+ this.selectionMode.set(useAdvanced ? 'advanced' : 'context');
6863
+ if (!useAdvanced) {
6864
+ this.contextTargetApplyToken.update((value) => value + 1);
6865
+ }
6866
+ this.serviceConfigChange.emit(this.getContextTargetState());
6867
+ }
6608
6868
  /**
6609
6869
  * Get chart type id for query component
6610
6870
  */
@@ -6628,8 +6888,17 @@ class DataSourceSettings {
6628
6888
  return 'treemap';
6629
6889
  return chartType.componentName || '';
6630
6890
  }
6891
+ getContextTargetState() {
6892
+ if (!this.showInformativeSelectionMode()) {
6893
+ return {};
6894
+ }
6895
+ return {
6896
+ useContextTarget: this.selectionMode() === 'context',
6897
+ contextTargetSelector: this.contextTargetSelector(),
6898
+ };
6899
+ }
6631
6900
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DataSourceSettings, deps: [], target: i0.ɵɵFactoryTarget.Component });
6632
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DataSourceSettings, isStandalone: true, selector: "mt-data-source-settings", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, chartType: { classPropertyName: "chartType", publicName: "chartType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { serviceConfigChange: "serviceConfigChange" }, ngImport: i0, template: "<div class=\"flex flex-col gap-6\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Data Source Type Tabs (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <mt-tabs\r\n [options]=\"tabOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"id\"\r\n [active]=\"activeTab()\"\r\n (onChange)=\"onTabChange($event)\"\r\n />\r\n }\r\n\r\n <!-- Custom API Configuration Tab -->\r\n @if (!hideSelectionConfig()) {\r\n <div [hidden]=\"activeTab() !== 'customApi'\">\r\n <mt-custom-api-configuration\r\n [ngModel]=\"customApi()\"\r\n (ngModelChange)=\"onCustomApiChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Selection Configuration Tab -->\r\n <div [hidden]=\"activeTab() !== 'selection'\">\r\n <!-- Selection Configuration (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <mt-selection-configuration\r\n [modulesProperties]=\"modulesProperties()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [ngModel]=\"selections()\"\r\n (ngModelChange)=\"onSelectionsChange($event)\"\r\n (moduleChange)=\"onModuleChange($event)\"\r\n />\r\n\r\n <!-- Source Link Configuration (shown when multiple selections) -->\r\n @if (showSourceLinks()) {\r\n <mt-source-link-configuration\r\n [selectionModules]=\"selectionModules()\"\r\n [ngModel]=\"sourceLinks()\"\r\n (ngModelChange)=\"onSourceLinksChange($event)\"\r\n />\r\n }\r\n }\r\n\r\n <!-- Loading Skeleton for Query Configuration -->\r\n @if (loadingProperties()) {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton for field labels and inputs -->\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"120px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"100px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"grid grid-cols-2 gap-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"90px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"140px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n </mt-card>\r\n } @else {\r\n <!-- Query Configuration based on chart type -->\r\n @switch (queryComponentType()) {\r\n @case (\"general\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"mb-4 flex items-center\">\r\n <mt-toggle-field\r\n [label]=\"t('isNormalized')\"\r\n [ngModel]=\"isNormalized()\"\r\n (ngModelChange)=\"onIsNormalizedChange($event)\"\r\n />\r\n </div>\r\n <mt-general-query\r\n [chartType]=\"getChartTypeId()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"table\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <!-- Group By Multiple (for non-report table views) -->\r\n @if (showGroupByMultiple()) {\r\n <div class=\"mb-4\">\r\n <mt-multi-select-field\r\n [label]=\"t('groupByMultiple')\"\r\n [options]=\"\r\n propertiesGrouped().length > 1\r\n ? propertiesGrouped()\r\n : propertiesFlat()\r\n \"\r\n [group]=\"propertiesGrouped().length > 1\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectGroupByProperties')\"\r\n [filter]=\"true\"\r\n [ngModel]=\"groupByMultiple()\"\r\n (ngModelChange)=\"onGroupByMultipleChange($event)\"\r\n />\r\n </div>\r\n }\r\n <mt-table-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTableQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timeline\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-timeline-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTimelineQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timelineMultiLevel\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-layers-three-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"timelineMultiLevelQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"map\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-map-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onMapQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"splitter\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-splitter-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSplitterQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"properties\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-properties-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onPropertiesQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"snapshot\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-snapshot-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSnapshotQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"phaseGate\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-git-branch-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"phaseGateQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"repeater\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-select-field\r\n [label]=\"t('selectDashboard')\"\r\n [options]=\"availableDashboards()\"\r\n optionLabel=\"name\"\r\n optionValue=\"id\"\r\n [placeholder]=\"t('selectDashboardPlaceholder')\"\r\n [ngModel]=\"repeaterDashboardId()\"\r\n (ngModelChange)=\"onRepeaterDashboardChange($event)\"\r\n />\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"repeaterDescription\") }}\r\n </p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"none\") {\r\n <!-- No query configuration needed for layout components -->\r\n }\r\n }\r\n }\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: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], 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: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: SelectionConfiguration, selector: "mt-selection-configuration", inputs: ["modulesProperties", "propertiesFlat"], outputs: ["moduleChange"] }, { kind: "component", type: SourceLinkConfiguration, selector: "mt-source-link-configuration", inputs: ["selectionModules"] }, { kind: "component", type: CustomApiConfiguration, selector: "mt-custom-api-configuration" }, { kind: "component", type: GeneralQuery, selector: "mt-general-query", inputs: ["chartType", "propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: TableQuery, selector: "mt-table-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: TimelineQuery, selector: "mt-timeline-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: PropertiesQuery, selector: "mt-properties-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: SnapshotQuery, selector: "mt-snapshot-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: MapQuery, selector: "mt-map-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: SplitterQuery, selector: "mt-splitter-query", inputs: ["propertiesFlat", "propertiesGrouped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
6901
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DataSourceSettings, isStandalone: true, selector: "mt-data-source-settings", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, chartType: { classPropertyName: "chartType", publicName: "chartType", isSignal: true, isRequired: false, transformFunction: null }, informativeContext: { classPropertyName: "informativeContext", publicName: "informativeContext", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { serviceConfigChange: "serviceConfigChange" }, ngImport: i0, template: "<div class=\"flex flex-col gap-6\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Data Source Type Tabs (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <mt-tabs\r\n [options]=\"tabOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"id\"\r\n [active]=\"activeTab()\"\r\n (onChange)=\"onTabChange($event)\"\r\n />\r\n }\r\n\r\n <!-- Custom API Configuration Tab -->\r\n @if (!hideSelectionConfig()) {\r\n <div [hidden]=\"activeTab() !== 'customApi'\">\r\n <mt-custom-api-configuration\r\n [ngModel]=\"customApi()\"\r\n (ngModelChange)=\"onCustomApiChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Selection Configuration Tab -->\r\n <div [hidden]=\"activeTab() !== 'selection'\" class=\"flex flex-col gap-6\">\r\n <!-- Selection Configuration (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n @if (showInformativeSelectionMode()) {\r\n <div class=\"flex items-center justify-end\">\r\n <mt-toggle-field\r\n [label]=\"'Advanced selection'\"\r\n [ngModel]=\"selectionMode() === 'advanced'\"\r\n (ngModelChange)=\"onAdvancedSelectionToggle($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (!showInformativeSelectionMode() || selectionMode() === \"advanced\") {\r\n <div class=\"flex flex-col gap-6\">\r\n <mt-selection-configuration\r\n [modulesProperties]=\"modulesProperties()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [ngModel]=\"selections()\"\r\n (ngModelChange)=\"onSelectionsChange($event)\"\r\n (moduleChange)=\"onModuleChange($event)\"\r\n />\r\n\r\n <!-- Source Link Configuration (shown when multiple selections) -->\r\n @if (showSourceLinks()) {\r\n <mt-source-link-configuration\r\n [selectionModules]=\"selectionModules()\"\r\n [ngModel]=\"sourceLinks()\"\r\n (ngModelChange)=\"onSourceLinksChange($event)\"\r\n />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-6\">\r\n <mt-informative-context-selection\r\n class=\"block\"\r\n [informativeContext]=\"informativeContext()\"\r\n [currentSelection]=\"selections()\"\r\n [preferredTargetSelector]=\"contextTargetSelector()\"\r\n [applyToken]=\"contextTargetApplyToken()\"\r\n (templateApply)=\"onContextTemplateApply($event)\"\r\n />\r\n\r\n @if (selections().length) {\r\n <mt-selection-configuration\r\n [modulesProperties]=\"modulesProperties()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [structureLocked]=\"true\"\r\n [ngModel]=\"selections()\"\r\n (ngModelChange)=\"onSelectionsChange($event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Loading Skeleton for Query Configuration -->\r\n @if (loadingProperties()) {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton for field labels and inputs -->\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"120px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"100px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"grid grid-cols-2 gap-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"90px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"140px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n </mt-card>\r\n } @else {\r\n <!-- Query Configuration based on chart type -->\r\n @switch (queryComponentType()) {\r\n @case (\"general\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"mb-4 flex items-center\">\r\n <mt-toggle-field\r\n [label]=\"t('isNormalized')\"\r\n [ngModel]=\"isNormalized()\"\r\n (ngModelChange)=\"onIsNormalizedChange($event)\"\r\n />\r\n </div>\r\n <mt-general-query\r\n [chartType]=\"getChartTypeId()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"table\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <!-- Group By Multiple (for non-report table views) -->\r\n @if (showGroupByMultiple()) {\r\n <div class=\"mb-4\">\r\n <mt-multi-select-field\r\n [label]=\"t('groupByMultiple')\"\r\n [options]=\"\r\n propertiesGrouped().length > 1\r\n ? propertiesGrouped()\r\n : propertiesFlat()\r\n \"\r\n [group]=\"propertiesGrouped().length > 1\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectGroupByProperties')\"\r\n [filter]=\"true\"\r\n [ngModel]=\"groupByMultiple()\"\r\n (ngModelChange)=\"onGroupByMultipleChange($event)\"\r\n />\r\n </div>\r\n }\r\n <mt-table-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTableQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timeline\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-timeline-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTimelineQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timelineMultiLevel\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-layers-three-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"timelineMultiLevelQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"map\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-map-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onMapQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"splitter\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-splitter-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSplitterQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"properties\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-properties-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onPropertiesQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"snapshot\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-snapshot-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSnapshotQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"phaseGate\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-git-branch-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"phaseGateQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"repeater\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-select-field\r\n [label]=\"t('selectDashboard')\"\r\n [options]=\"availableDashboards()\"\r\n optionLabel=\"name\"\r\n optionValue=\"id\"\r\n [placeholder]=\"t('selectDashboardPlaceholder')\"\r\n [ngModel]=\"repeaterDashboardId()\"\r\n (ngModelChange)=\"onRepeaterDashboardChange($event)\"\r\n />\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"repeaterDescription\") }}\r\n </p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"none\") {\r\n <!-- No query configuration needed for layout components -->\r\n }\r\n }\r\n }\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: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], 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: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: SelectionConfiguration, selector: "mt-selection-configuration", inputs: ["structureLocked", "modulesProperties", "propertiesFlat"], outputs: ["moduleChange"] }, { kind: "component", type: SourceLinkConfiguration, selector: "mt-source-link-configuration", inputs: ["selectionModules"] }, { kind: "component", type: CustomApiConfiguration, selector: "mt-custom-api-configuration" }, { kind: "component", type: GeneralQuery, selector: "mt-general-query", inputs: ["chartType", "propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: TableQuery, selector: "mt-table-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: TimelineQuery, selector: "mt-timeline-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: PropertiesQuery, selector: "mt-properties-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: SnapshotQuery, selector: "mt-snapshot-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: MapQuery, selector: "mt-map-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: SplitterQuery, selector: "mt-splitter-query", inputs: ["propertiesFlat", "propertiesGrouped"] }, { kind: "component", type: InformativeContextSelection, selector: "mt-informative-context-selection", inputs: ["informativeContext", "currentSelection", "preferredTargetSelector", "applyToken"], outputs: ["templateApply"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
6633
6902
  }
6634
6903
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DataSourceSettings, decorators: [{
6635
6904
  type: Component,
@@ -6654,8 +6923,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
6654
6923
  SnapshotQuery,
6655
6924
  MapQuery,
6656
6925
  SplitterQuery,
6657
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"flex flex-col gap-6\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Data Source Type Tabs (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <mt-tabs\r\n [options]=\"tabOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"id\"\r\n [active]=\"activeTab()\"\r\n (onChange)=\"onTabChange($event)\"\r\n />\r\n }\r\n\r\n <!-- Custom API Configuration Tab -->\r\n @if (!hideSelectionConfig()) {\r\n <div [hidden]=\"activeTab() !== 'customApi'\">\r\n <mt-custom-api-configuration\r\n [ngModel]=\"customApi()\"\r\n (ngModelChange)=\"onCustomApiChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Selection Configuration Tab -->\r\n <div [hidden]=\"activeTab() !== 'selection'\">\r\n <!-- Selection Configuration (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <mt-selection-configuration\r\n [modulesProperties]=\"modulesProperties()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [ngModel]=\"selections()\"\r\n (ngModelChange)=\"onSelectionsChange($event)\"\r\n (moduleChange)=\"onModuleChange($event)\"\r\n />\r\n\r\n <!-- Source Link Configuration (shown when multiple selections) -->\r\n @if (showSourceLinks()) {\r\n <mt-source-link-configuration\r\n [selectionModules]=\"selectionModules()\"\r\n [ngModel]=\"sourceLinks()\"\r\n (ngModelChange)=\"onSourceLinksChange($event)\"\r\n />\r\n }\r\n }\r\n\r\n <!-- Loading Skeleton for Query Configuration -->\r\n @if (loadingProperties()) {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton for field labels and inputs -->\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"120px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"100px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"grid grid-cols-2 gap-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"90px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"140px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n </mt-card>\r\n } @else {\r\n <!-- Query Configuration based on chart type -->\r\n @switch (queryComponentType()) {\r\n @case (\"general\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"mb-4 flex items-center\">\r\n <mt-toggle-field\r\n [label]=\"t('isNormalized')\"\r\n [ngModel]=\"isNormalized()\"\r\n (ngModelChange)=\"onIsNormalizedChange($event)\"\r\n />\r\n </div>\r\n <mt-general-query\r\n [chartType]=\"getChartTypeId()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"table\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <!-- Group By Multiple (for non-report table views) -->\r\n @if (showGroupByMultiple()) {\r\n <div class=\"mb-4\">\r\n <mt-multi-select-field\r\n [label]=\"t('groupByMultiple')\"\r\n [options]=\"\r\n propertiesGrouped().length > 1\r\n ? propertiesGrouped()\r\n : propertiesFlat()\r\n \"\r\n [group]=\"propertiesGrouped().length > 1\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectGroupByProperties')\"\r\n [filter]=\"true\"\r\n [ngModel]=\"groupByMultiple()\"\r\n (ngModelChange)=\"onGroupByMultipleChange($event)\"\r\n />\r\n </div>\r\n }\r\n <mt-table-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTableQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timeline\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-timeline-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTimelineQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timelineMultiLevel\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-layers-three-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"timelineMultiLevelQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"map\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-map-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onMapQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"splitter\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-splitter-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSplitterQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"properties\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-properties-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onPropertiesQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"snapshot\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-snapshot-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSnapshotQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"phaseGate\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-git-branch-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"phaseGateQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"repeater\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-select-field\r\n [label]=\"t('selectDashboard')\"\r\n [options]=\"availableDashboards()\"\r\n optionLabel=\"name\"\r\n optionValue=\"id\"\r\n [placeholder]=\"t('selectDashboardPlaceholder')\"\r\n [ngModel]=\"repeaterDashboardId()\"\r\n (ngModelChange)=\"onRepeaterDashboardChange($event)\"\r\n />\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"repeaterDescription\") }}\r\n </p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"none\") {\r\n <!-- No query configuration needed for layout components -->\r\n }\r\n }\r\n }\r\n </div>\r\n</div>\r\n" }]
6658
- }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], chartType: [{ type: i0.Input, args: [{ isSignal: true, alias: "chartType", required: false }] }], serviceConfigChange: [{ type: i0.Output, args: ["serviceConfigChange"] }] } });
6926
+ InformativeContextSelection,
6927
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"flex flex-col gap-6\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Data Source Type Tabs (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <mt-tabs\r\n [options]=\"tabOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"id\"\r\n [active]=\"activeTab()\"\r\n (onChange)=\"onTabChange($event)\"\r\n />\r\n }\r\n\r\n <!-- Custom API Configuration Tab -->\r\n @if (!hideSelectionConfig()) {\r\n <div [hidden]=\"activeTab() !== 'customApi'\">\r\n <mt-custom-api-configuration\r\n [ngModel]=\"customApi()\"\r\n (ngModelChange)=\"onCustomApiChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Selection Configuration Tab -->\r\n <div [hidden]=\"activeTab() !== 'selection'\" class=\"flex flex-col gap-6\">\r\n <!-- Selection Configuration (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n @if (showInformativeSelectionMode()) {\r\n <div class=\"flex items-center justify-end\">\r\n <mt-toggle-field\r\n [label]=\"'Advanced selection'\"\r\n [ngModel]=\"selectionMode() === 'advanced'\"\r\n (ngModelChange)=\"onAdvancedSelectionToggle($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (!showInformativeSelectionMode() || selectionMode() === \"advanced\") {\r\n <div class=\"flex flex-col gap-6\">\r\n <mt-selection-configuration\r\n [modulesProperties]=\"modulesProperties()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [ngModel]=\"selections()\"\r\n (ngModelChange)=\"onSelectionsChange($event)\"\r\n (moduleChange)=\"onModuleChange($event)\"\r\n />\r\n\r\n <!-- Source Link Configuration (shown when multiple selections) -->\r\n @if (showSourceLinks()) {\r\n <mt-source-link-configuration\r\n [selectionModules]=\"selectionModules()\"\r\n [ngModel]=\"sourceLinks()\"\r\n (ngModelChange)=\"onSourceLinksChange($event)\"\r\n />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-6\">\r\n <mt-informative-context-selection\r\n class=\"block\"\r\n [informativeContext]=\"informativeContext()\"\r\n [currentSelection]=\"selections()\"\r\n [preferredTargetSelector]=\"contextTargetSelector()\"\r\n [applyToken]=\"contextTargetApplyToken()\"\r\n (templateApply)=\"onContextTemplateApply($event)\"\r\n />\r\n\r\n @if (selections().length) {\r\n <mt-selection-configuration\r\n [modulesProperties]=\"modulesProperties()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [structureLocked]=\"true\"\r\n [ngModel]=\"selections()\"\r\n (ngModelChange)=\"onSelectionsChange($event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Loading Skeleton for Query Configuration -->\r\n @if (loadingProperties()) {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <!-- Skeleton for field labels and inputs -->\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"120px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"100px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"grid grid-cols-2 gap-4\">\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"80px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"90px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-skeleton width=\"140px\" height=\"16px\" />\r\n <p-skeleton width=\"100%\" height=\"40px\" borderRadius=\"8px\" />\r\n </div>\r\n </div>\r\n </mt-card>\r\n } @else {\r\n <!-- Query Configuration based on chart type -->\r\n @switch (queryComponentType()) {\r\n @case (\"general\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"mb-4 flex items-center\">\r\n <mt-toggle-field\r\n [label]=\"t('isNormalized')\"\r\n [ngModel]=\"isNormalized()\"\r\n (ngModelChange)=\"onIsNormalizedChange($event)\"\r\n />\r\n </div>\r\n <mt-general-query\r\n [chartType]=\"getChartTypeId()\"\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"table\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <!-- Group By Multiple (for non-report table views) -->\r\n @if (showGroupByMultiple()) {\r\n <div class=\"mb-4\">\r\n <mt-multi-select-field\r\n [label]=\"t('groupByMultiple')\"\r\n [options]=\"\r\n propertiesGrouped().length > 1\r\n ? propertiesGrouped()\r\n : propertiesFlat()\r\n \"\r\n [group]=\"propertiesGrouped().length > 1\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectGroupByProperties')\"\r\n [filter]=\"true\"\r\n [ngModel]=\"groupByMultiple()\"\r\n (ngModelChange)=\"onGroupByMultipleChange($event)\"\r\n />\r\n </div>\r\n }\r\n <mt-table-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTableQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timeline\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-timeline-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onTimelineQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"timelineMultiLevel\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-layers-three-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"timelineMultiLevelQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"map\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-map-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onMapQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"splitter\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-splitter-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSplitterQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"properties\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-properties-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onPropertiesQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"snapshot\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <mt-snapshot-query\r\n [propertiesFlat]=\"propertiesFlat()\"\r\n [propertiesGrouped]=\"propertiesGrouped()\"\r\n [ngModel]=\"query()\"\r\n (ngModelChange)=\"onSnapshotQueryChange($event)\"\r\n />\r\n </mt-card>\r\n }\r\n @case (\"phaseGate\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-git-branch-01 text-3xl mb-2 block\"></i>\r\n <p>{{ t(\"phaseGateQueryPlaceholder\") }}</p>\r\n <p class=\"text-sm mt-2\">{{ t(\"comingSoon\") }}</p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"repeater\") {\r\n <mt-card [title]=\"t('queryConfiguration')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-select-field\r\n [label]=\"t('selectDashboard')\"\r\n [options]=\"availableDashboards()\"\r\n optionLabel=\"name\"\r\n optionValue=\"id\"\r\n [placeholder]=\"t('selectDashboardPlaceholder')\"\r\n [ngModel]=\"repeaterDashboardId()\"\r\n (ngModelChange)=\"onRepeaterDashboardChange($event)\"\r\n />\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"repeaterDescription\") }}\r\n </p>\r\n </div>\r\n </mt-card>\r\n }\r\n @case (\"none\") {\r\n <!-- No query configuration needed for layout components -->\r\n }\r\n }\r\n }\r\n </div>\r\n</div>\r\n" }]
6928
+ }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], chartType: [{ type: i0.Input, args: [{ isSignal: true, alias: "chartType", required: false }] }], informativeContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "informativeContext", required: false }] }], serviceConfigChange: [{ type: i0.Output, args: ["serviceConfigChange"] }] } });
6659
6929
 
6660
6930
  /**
6661
6931
  * Actions Settings Component
@@ -19167,6 +19437,12 @@ class ManageItem {
19167
19437
  const dialogData = this._dialogConfig?.data;
19168
19438
  return inputData?.isNew ?? dialogData?.isNew ?? false;
19169
19439
  }, ...(ngDevMode ? [{ debugName: "isNew" }] : /* istanbul ignore next */ []));
19440
+ /** Optional informative authoring context */
19441
+ informativeContext = computed(() => {
19442
+ const inputData = this.data();
19443
+ const dialogData = this._dialogConfig?.data;
19444
+ return (inputData?.informativeContext ?? dialogData?.informativeContext ?? null);
19445
+ }, ...(ngDevMode ? [{ debugName: "informativeContext" }] : /* istanbul ignore next */ []));
19170
19446
  /** Saving state */
19171
19447
  saving = signal(false, ...(ngDevMode ? [{ debugName: "saving" }] : /* istanbul ignore next */ []));
19172
19448
  /** Validation state */
@@ -19245,7 +19521,7 @@ class ManageItem {
19245
19521
  this._manageItemService.updateClientConfig(partialConfig);
19246
19522
  }
19247
19523
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
19248
- 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'\">\r\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\r\n <!-- Main Layout: 60% Config | 40% Preview -->\r\n <div class=\"flex flex-1\">\r\n <!-- Left Side: Configuration (60%) -->\r\n <div class=\"w-[60%] flex flex-col border-r border-surface-200\">\r\n <!-- Content -->\r\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\r\n <!-- Chart Type Badge -->\r\n @if (selectedChartType()) {\r\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\r\n <span\r\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\r\n >\r\n <mt-icon\r\n [icon]=\"selectedChartType()?.icon\"\r\n class=\"text-xl\"\r\n ></mt-icon>\r\n </span>\r\n <div class=\"flex-1\">\r\n <h3 class=\"text-sm font-semibold text-surface-700\">\r\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\r\n </h3>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ selectedChartType()?.name }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Tabs -->\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n\r\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\r\n <div [hidden]=\"activeTab() !== 'general'\">\r\n <mt-general-settings\r\n [config]=\"config()\"\r\n [isDialog]=\"isDialog()\"\r\n [hasPreselectedType]=\"hasPreselectedType()\"\r\n (configChange)=\"onConfigUpdate($event)\"\r\n (chartTypeChange)=\"onChartTypeChange($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'dataSource'\">\r\n <mt-data-source-settings\r\n [config]=\"config()\"\r\n [chartType]=\"selectedChartType()\"\r\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'actions'\">\r\n <mt-actions-settings\r\n [config]=\"config()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Chart Preview (40%) -->\r\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\r\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Footer -->\r\n <div [class]=\"modal.footerClass\">\r\n <!-- Validation Status -->\r\n <div class=\"flex items-center gap-2 text-sm flex-1\">\r\n @if (isValid()) {\r\n <span class=\"flex items-center gap-1 text-green-600\">\r\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\r\n {{ t(\"ready\") }}\r\n </span>\r\n } @else {\r\n <span class=\"flex items-center gap-1 text-amber-600\">\r\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\r\n {{ t(\"incomplete\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <mt-button\r\n [text]=\"true\"\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"!isValid()\"\r\n (onClick)=\"save()\"\r\n />\r\n </div>\r\n</ng-container>\r\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", "size", "fluid", "disabled"], 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"], 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 });
19524
+ 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'\">\r\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\r\n <!-- Main Layout: 60% Config | 40% Preview -->\r\n <div class=\"flex flex-1\">\r\n <!-- Left Side: Configuration (60%) -->\r\n <div class=\"w-[60%] flex flex-col border-r border-surface-200\">\r\n <!-- Content -->\r\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\r\n <!-- Chart Type Badge -->\r\n @if (selectedChartType()) {\r\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\r\n <span\r\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\r\n >\r\n <mt-icon\r\n [icon]=\"selectedChartType()?.icon\"\r\n class=\"text-xl\"\r\n ></mt-icon>\r\n </span>\r\n <div class=\"flex-1\">\r\n <h3 class=\"text-sm font-semibold text-surface-700\">\r\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\r\n </h3>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ selectedChartType()?.name }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Tabs -->\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n\r\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\r\n <div [hidden]=\"activeTab() !== 'general'\">\r\n <mt-general-settings\r\n [config]=\"config()\"\r\n [isDialog]=\"isDialog()\"\r\n [hasPreselectedType]=\"hasPreselectedType()\"\r\n (configChange)=\"onConfigUpdate($event)\"\r\n (chartTypeChange)=\"onChartTypeChange($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'dataSource'\">\r\n <mt-data-source-settings\r\n [config]=\"config()\"\r\n [chartType]=\"selectedChartType()\"\r\n [informativeContext]=\"informativeContext()\"\r\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'actions'\">\r\n <mt-actions-settings\r\n [config]=\"config()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Chart Preview (40%) -->\r\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\r\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Footer -->\r\n <div [class]=\"modal.footerClass\">\r\n <!-- Validation Status -->\r\n <div class=\"flex items-center gap-2 text-sm flex-1\">\r\n @if (isValid()) {\r\n <span class=\"flex items-center gap-1 text-green-600\">\r\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\r\n {{ t(\"ready\") }}\r\n </span>\r\n } @else {\r\n <span class=\"flex items-center gap-1 text-amber-600\">\r\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\r\n {{ t(\"incomplete\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <mt-button\r\n [text]=\"true\"\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"!isValid()\"\r\n (onClick)=\"save()\"\r\n />\r\n </div>\r\n</ng-container>\r\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", "size", "fluid", "disabled"], 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 });
19249
19525
  }
19250
19526
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageItem, decorators: [{
19251
19527
  type: Component,
@@ -19260,7 +19536,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
19260
19536
  ActionsSettings,
19261
19537
  ChartViewer,
19262
19538
  Icon,
19263
- ], providers: [ManageItemService], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\r\n <!-- Main Layout: 60% Config | 40% Preview -->\r\n <div class=\"flex flex-1\">\r\n <!-- Left Side: Configuration (60%) -->\r\n <div class=\"w-[60%] flex flex-col border-r border-surface-200\">\r\n <!-- Content -->\r\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\r\n <!-- Chart Type Badge -->\r\n @if (selectedChartType()) {\r\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\r\n <span\r\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\r\n >\r\n <mt-icon\r\n [icon]=\"selectedChartType()?.icon\"\r\n class=\"text-xl\"\r\n ></mt-icon>\r\n </span>\r\n <div class=\"flex-1\">\r\n <h3 class=\"text-sm font-semibold text-surface-700\">\r\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\r\n </h3>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ selectedChartType()?.name }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Tabs -->\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n\r\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\r\n <div [hidden]=\"activeTab() !== 'general'\">\r\n <mt-general-settings\r\n [config]=\"config()\"\r\n [isDialog]=\"isDialog()\"\r\n [hasPreselectedType]=\"hasPreselectedType()\"\r\n (configChange)=\"onConfigUpdate($event)\"\r\n (chartTypeChange)=\"onChartTypeChange($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'dataSource'\">\r\n <mt-data-source-settings\r\n [config]=\"config()\"\r\n [chartType]=\"selectedChartType()\"\r\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'actions'\">\r\n <mt-actions-settings\r\n [config]=\"config()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Chart Preview (40%) -->\r\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\r\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Footer -->\r\n <div [class]=\"modal.footerClass\">\r\n <!-- Validation Status -->\r\n <div class=\"flex items-center gap-2 text-sm flex-1\">\r\n @if (isValid()) {\r\n <span class=\"flex items-center gap-1 text-green-600\">\r\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\r\n {{ t(\"ready\") }}\r\n </span>\r\n } @else {\r\n <span class=\"flex items-center gap-1 text-amber-600\">\r\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\r\n {{ t(\"incomplete\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <mt-button\r\n [text]=\"true\"\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"!isValid()\"\r\n (onClick)=\"save()\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
19539
+ ], providers: [ManageItemService], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <div class=\"flex flex-col h-full\" [class]=\"modal.contentClass\">\r\n <!-- Main Layout: 60% Config | 40% Preview -->\r\n <div class=\"flex flex-1\">\r\n <!-- Left Side: Configuration (60%) -->\r\n <div class=\"w-[60%] flex flex-col border-r border-surface-200\">\r\n <!-- Content -->\r\n <div class=\"flex-1 flex flex-col gap-4 p-4 overflow-auto\">\r\n <!-- Chart Type Badge -->\r\n @if (selectedChartType()) {\r\n <div class=\"flex items-center gap-2 p-3 bg-surface-50 rounded-lg\">\r\n <span\r\n class=\"w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600\"\r\n >\r\n <mt-icon\r\n [icon]=\"selectedChartType()?.icon\"\r\n class=\"text-xl\"\r\n ></mt-icon>\r\n </span>\r\n <div class=\"flex-1\">\r\n <h3 class=\"text-sm font-semibold text-surface-700\">\r\n {{ isNew() ? t(\"newItem\") : t(\"editItem\") }}\r\n </h3>\r\n <p class=\"text-xs text-muted-color\">\r\n {{ selectedChartType()?.name }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Tabs -->\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n\r\n <!-- Tab Content - All tabs rendered but hidden, prevents re-initialization -->\r\n <div [hidden]=\"activeTab() !== 'general'\">\r\n <mt-general-settings\r\n [config]=\"config()\"\r\n [isDialog]=\"isDialog()\"\r\n [hasPreselectedType]=\"hasPreselectedType()\"\r\n (configChange)=\"onConfigUpdate($event)\"\r\n (chartTypeChange)=\"onChartTypeChange($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'dataSource'\">\r\n <mt-data-source-settings\r\n [config]=\"config()\"\r\n [chartType]=\"selectedChartType()\"\r\n [informativeContext]=\"informativeContext()\"\r\n (serviceConfigChange)=\"onServiceConfigUpdate($event)\"\r\n />\r\n </div>\r\n\r\n <div [hidden]=\"activeTab() !== 'actions'\">\r\n <mt-actions-settings\r\n [config]=\"config()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Chart Preview (40%) -->\r\n <div class=\"w-[40%] min-w-[350px] h-[500px]\">\r\n <mt-chart-viewer [config]=\"config()\" [chartTypeId]=\"chartTypeId()\" />\r\n </div>\r\n </div>\r\n </div>\r\n <!-- Footer -->\r\n <div [class]=\"modal.footerClass\">\r\n <!-- Validation Status -->\r\n <div class=\"flex items-center gap-2 text-sm flex-1\">\r\n @if (isValid()) {\r\n <span class=\"flex items-center gap-1 text-green-600\">\r\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\r\n {{ t(\"ready\") }}\r\n </span>\r\n } @else {\r\n <span class=\"flex items-center gap-1 text-amber-600\">\r\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\r\n {{ t(\"incomplete\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <mt-button\r\n [text]=\"true\"\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n [loading]=\"saving()\"\r\n [disabled]=\"!isValid()\"\r\n (onClick)=\"save()\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
19264
19540
  }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
19265
19541
 
19266
19542
  /**
@@ -19432,6 +19708,8 @@ class DashboardBuilder {
19432
19708
  dashboardData = model(null, ...(ngDevMode ? [{ debugName: "dashboardData" }] : /* istanbul ignore next */ []));
19433
19709
  /** Read-only mode */
19434
19710
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
19711
+ /** Optional informative authoring context for context-aware selection */
19712
+ informativeContext = input(null, ...(ngDevMode ? [{ debugName: "informativeContext" }] : /* istanbul ignore next */ []));
19435
19713
  // ============================================
19436
19714
  // Outputs
19437
19715
  // ============================================
@@ -19919,6 +20197,7 @@ class DashboardBuilder {
19919
20197
  data: {
19920
20198
  isNew: true,
19921
20199
  services: this.services(),
20200
+ informativeContext: this.informativeContext(),
19922
20201
  },
19923
20202
  },
19924
20203
  });
@@ -19943,6 +20222,7 @@ class DashboardBuilder {
19943
20222
  isDialog: false,
19944
20223
  isNew: false,
19945
20224
  services: this.services(),
20225
+ informativeContext: this.informativeContext(),
19946
20226
  },
19947
20227
  },
19948
20228
  });
@@ -20207,6 +20487,7 @@ class DashboardBuilder {
20207
20487
  chartType: widgetType, // Pass the pre-selected type
20208
20488
  defaultSize: widgetType.defaultSize,
20209
20489
  services: this.services(),
20490
+ informativeContext: this.informativeContext(),
20210
20491
  },
20211
20492
  },
20212
20493
  });
@@ -20354,6 +20635,7 @@ class DashboardBuilder {
20354
20635
  isDialog: true,
20355
20636
  isNew: false,
20356
20637
  services: this.services(),
20638
+ informativeContext: this.informativeContext(),
20357
20639
  },
20358
20640
  },
20359
20641
  });
@@ -20554,11 +20836,12 @@ class DashboardBuilder {
20554
20836
  });
20555
20837
  }
20556
20838
  applyDashboardData(data) {
20839
+ const filters = data.filters ?? data.page?.dashboardConfig?.filters;
20557
20840
  this.applyingDashboardData = true;
20558
20841
  this.pageConfig.set(data.page ?? null);
20559
20842
  this.charts.set(data.charts ?? []);
20560
20843
  this.dialogs.set(data.dialogs ?? []);
20561
- this.filtersConfig.set(data.filters ?? []);
20844
+ this.filtersConfig.set(Array.isArray(filters) ? [...filters] : filters ? [filters] : []);
20562
20845
  this.dashboardService.filters.set(this.filtersConfig());
20563
20846
  this.applyingDashboardData = false;
20564
20847
  this.cdr.detectChanges();
@@ -20576,7 +20859,7 @@ class DashboardBuilder {
20576
20859
  this.emittingDashboardData = false;
20577
20860
  }
20578
20861
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DashboardBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
20579
- 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 } }, 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=\"bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden transition-all duration-200 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 (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 <!-- Action Buttons -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"absolute top-1 right-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Quick Manage Button -->\r\n @if (showQuickManageButton(chart)) {\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('quickManage')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!-- Breadcrumb Button (for topbar) -->\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 <!-- Edit Button -->\r\n @if (\r\n chart.config?.clientConfig?.componentName !== \"header\" &&\r\n chart.config?.clientConfig?.componentName !== \"topbar\" &&\r\n chart.config?.clientConfig?.componentName !== \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('edit')\"\r\n (onClick)=\"editItem(chart)\"\r\n severity=\"warn\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!-- Delete Button -->\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 } @else {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('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 <!-- Advanced/Dialog Actions Button (pipe handles all conditions) -->\r\n @let dialogActions =\r\n chart | getChartActions: chartActionsContext;\r\n @if (dialogActions.length > 0) {\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n [tooltip]=\"t('advanced')\"\r\n (onClick)=\"advancedPopover.toggle($event)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <p-popover #advancedPopover appendTo=\"body\">\r\n <div class=\"flex flex-col gap-1 min-w-[160px]\">\r\n @for (action of dialogActions; track action.label) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [icon]=\"action.icon\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n action.command?.({\r\n originalEvent: $event,\r\n item: action,\r\n });\r\n advancedPopover.hide()\r\n \"\r\n />\r\n }\r\n </div>\r\n </p-popover>\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 [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\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 [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\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)}.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}\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: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { 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"], outputs: ["actionTriggered"] }, { kind: "pipe", type: FilterByGroupPipe, name: "filterByGroup" }, { kind: "pipe", type: GetChartActionsPipe, name: "getChartActions" }], encapsulation: i0.ViewEncapsulation.None });
20862
+ 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 } }, 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=\"bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden transition-all duration-200 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 (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 <!-- Action Buttons -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"absolute top-1 right-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Quick Manage Button -->\r\n @if (showQuickManageButton(chart)) {\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('quickManage')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!-- Breadcrumb Button (for topbar) -->\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 <!-- Edit Button -->\r\n @if (\r\n chart.config?.clientConfig?.componentName !== \"header\" &&\r\n chart.config?.clientConfig?.componentName !== \"topbar\" &&\r\n chart.config?.clientConfig?.componentName !== \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('edit')\"\r\n (onClick)=\"editItem(chart)\"\r\n severity=\"warn\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!-- Delete Button -->\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 } @else {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('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 <!-- Advanced/Dialog Actions Button (pipe handles all conditions) -->\r\n @let dialogActions =\r\n chart | getChartActions: chartActionsContext;\r\n @if (dialogActions.length > 0) {\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n [tooltip]=\"t('advanced')\"\r\n (onClick)=\"advancedPopover.toggle($event)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <p-popover #advancedPopover appendTo=\"body\">\r\n <div class=\"flex flex-col gap-1 min-w-[160px]\">\r\n @for (action of dialogActions; track action.label) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [icon]=\"action.icon\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n action.command?.({\r\n originalEvent: $event,\r\n item: action,\r\n });\r\n advancedPopover.hide()\r\n \"\r\n />\r\n }\r\n </div>\r\n </p-popover>\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 [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\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 [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\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)}.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}\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: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { 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"], outputs: ["actionTriggered"] }, { kind: "pipe", type: FilterByGroupPipe, name: "filterByGroup" }, { kind: "pipe", type: GetChartActionsPipe, name: "getChartActions" }], encapsulation: i0.ViewEncapsulation.None });
20580
20863
  }
20581
20864
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DashboardBuilder, decorators: [{
20582
20865
  type: Component,
@@ -20593,7 +20876,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
20593
20876
  GetChartActionsPipe,
20594
20877
  DashboardItem,
20595
20878
  ], 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=\"bg-surface-0 rounded-lg shadow-sm border border-surface-200 overflow-hidden transition-all duration-200 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 (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 <!-- Action Buttons -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"absolute top-1 right-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Quick Manage Button -->\r\n @if (showQuickManageButton(chart)) {\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('quickManage')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!-- Breadcrumb Button (for topbar) -->\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 <!-- Edit Button -->\r\n @if (\r\n chart.config?.clientConfig?.componentName !== \"header\" &&\r\n chart.config?.clientConfig?.componentName !== \"topbar\" &&\r\n chart.config?.clientConfig?.componentName !== \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('edit')\"\r\n (onClick)=\"editItem(chart)\"\r\n severity=\"warn\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!-- Delete Button -->\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 } @else {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('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 <!-- Advanced/Dialog Actions Button (pipe handles all conditions) -->\r\n @let dialogActions =\r\n chart | getChartActions: chartActionsContext;\r\n @if (dialogActions.length > 0) {\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n [tooltip]=\"t('advanced')\"\r\n (onClick)=\"advancedPopover.toggle($event)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <p-popover #advancedPopover appendTo=\"body\">\r\n <div class=\"flex flex-col gap-1 min-w-[160px]\">\r\n @for (action of dialogActions; track action.label) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [icon]=\"action.icon\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"\r\n action.command?.({\r\n originalEvent: $event,\r\n item: action,\r\n });\r\n advancedPopover.hide()\r\n \"\r\n />\r\n }\r\n </div>\r\n </p-popover>\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 [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\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 [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\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)}.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}\n"] }]
20596
- }], 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 }] }], 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: [{
20879
+ }], 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 }] }], 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: [{
20597
20880
  type: HostListener,
20598
20881
  args: ['window:keydown', ['$event']]
20599
20882
  }] } });
@@ -20836,10 +21119,11 @@ class DashboardViewer {
20836
21119
  });
20837
21120
  }
20838
21121
  applyDashboardData(data) {
21122
+ const filters = data.filters ?? data.page?.dashboardConfig?.filters;
20839
21123
  this.pageConfig.set(data.page ?? null);
20840
21124
  this.charts.set(data.charts ?? []);
20841
21125
  this.dialogs.set(data.dialogs ?? []);
20842
- this.filters.set(data.filters ?? []);
21126
+ this.filters.set(Array.isArray(filters) ? [...filters] : filters ? [filters] : []);
20843
21127
  this.dashboardService.filters.set(this.filters());
20844
21128
  this.loading.set(false);
20845
21129
  if (data.page) {