@masterteam/dashboard-builder 0.0.29 → 0.0.31

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.
@@ -4,7 +4,7 @@ import * as i1$1 from '@angular/common';
4
4
  import { CommonModule, DatePipe, isPlatformBrowser, DecimalPipe } from '@angular/common';
5
5
  import * as i1 from '@angular/forms';
6
6
  import { FormsModule, NG_VALUE_ACCESSOR, FormBuilder, Validators, ReactiveFormsModule, NG_VALIDATORS } from '@angular/forms';
7
- import { TranslocoService, TranslocoDirective } from '@jsverse/transloco';
7
+ import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
8
8
  import * as i2$2 from 'angular-gridster2';
9
9
  import { GridsterModule } from 'angular-gridster2';
10
10
  import { Button } from '@masterteam/components/button';
@@ -584,68 +584,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
584
584
  }]
585
585
  }] });
586
586
 
587
- /**
588
- * Get dialog actions for a chart
589
- *
590
- * Returns menu items for dialog management (add, edit, delete)
591
- * Used in the "Advanced" popover menu
592
- */
593
- class GetChartActionsPipe {
594
- transloco = inject(TranslocoService);
595
- transform(chart, context) {
596
- if (!chart?.config?.clientConfig || !context) {
597
- return [];
598
- }
599
- const clientConfig = chart.config.clientConfig;
600
- const t = (key) => this.transloco.translate(`dashboardBuilder.${key}`);
601
- // Only return dialog actions for regular charts (not header, topbar, Group)
602
- if (clientConfig.componentName === 'topbar' ||
603
- clientConfig.componentName === 'header' ||
604
- clientConfig.componentName === 'Group') {
605
- return [];
606
- }
607
- const hasDialog = clientConfig.actions?.[0]?.actionType === 'openDialog' &&
608
- !clientConfig.filter?.configs?.length;
609
- const items = [];
610
- // Add Dialog - only show if no dialog exists
611
- if (!hasDialog) {
612
- items.push({
613
- label: t('addDialog'),
614
- icon: 'general.plus',
615
- command: () => context.addDialogForChart(chart),
616
- });
617
- }
618
- // Edit Dialog - only show if dialog exists
619
- if (hasDialog) {
620
- items.push({
621
- label: t('editDialog'),
622
- icon: 'general.edit-05',
623
- command: () => context.editOnDialogForChart(chart),
624
- });
625
- }
626
- // Delete Dialog - only show if dialog exists
627
- if (hasDialog) {
628
- items.push({
629
- label: t('deleteDialog'),
630
- icon: 'general.trash-01',
631
- severity: 'danger',
632
- command: () => context.deleteDialogFromChart(chart),
633
- });
634
- }
635
- return items;
636
- }
637
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GetChartActionsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
638
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.8", ngImport: i0, type: GetChartActionsPipe, isStandalone: true, name: "getChartActions" });
639
- }
640
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GetChartActionsPipe, decorators: [{
641
- type: Pipe,
642
- args: [{
643
- name: 'getChartActions',
644
- standalone: true,
645
- pure: true,
646
- }]
647
- }] });
648
-
649
587
  /**
650
588
  * Generate a UUID v4
651
589
  */
@@ -10565,7 +10503,7 @@ class ChartSettingsDrawer {
10565
10503
  return componentName === 'header' || componentName === 'topbar';
10566
10504
  }
10567
10505
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ChartSettingsDrawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
10568
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ChartSettingsDrawer, isStandalone: true, selector: "mt-chart-settings-drawer", ngImport: i0, template: "<div\r\n [class]=\"modal.contentClass + ' flex h-full min-h-0 flex-col p-0'\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <div\r\n class=\"sticky top-0 z-10 border-b border-surface-200 bg-surface-0 px-4 pb-3 pt-4\"\r\n >\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3\">\r\n @if (showDisplayTab()) {\r\n <!-- Display Tab -->\r\n <div [hidden]=\"activeTab() !== 'display'\" class=\"flex flex-col gap-3\">\r\n <mt-display-settings\r\n [config]=\"itemConfig()\"\r\n [chartType]=\"resolvedChartType()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Chart Controls Tab -->\r\n <div [hidden]=\"activeTab() !== 'chartControls'\" class=\"flex flex-col gap-3\">\r\n @switch (manageType()) {\r\n @case (\"default\") {\r\n <mt-default-control-ui\r\n [ngModel]=\"defaultControlConfig()\"\r\n [showIconSettings]=\"isLayoutItem()\"\r\n [layoutComponent]=\"layoutComponentName()\"\r\n (ngModelChange)=\"onDefaultConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"pie\") {\r\n <mt-pie-control-ui\r\n [ngModel]=\"pieConfig()\"\r\n (ngModelChange)=\"onPieConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"bar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"barConfig()\"\r\n (ngModelChange)=\"onBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"stackBar\") {\r\n <mt-stack-bar-control-ui\r\n [ngModel]=\"stackBarConfig()\"\r\n (ngModelChange)=\"onStackBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"snapshotBar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"snapshotBarConfig()\"\r\n (ngModelChange)=\"onSnapshotBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @default {\r\n <!-- Pass-4: schema-driven controls fill the gap for chart/item types\r\n that don't have a bespoke quick-control component. Every supported\r\n chart in the manifest has a control schema in the registry, so\r\n this branch always renders real controls instead of\r\n noSettingsAvailable. -->\r\n <mt-schema-control-renderer\r\n [schema]=\"schemaForItem()\"\r\n [persisted]=\"itemConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Advanced Override (JSON) \u2014 Pass-2 -->\r\n <div [hidden]=\"activeTab() !== 'advanced'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"advanced\") {\r\n <ng-container>\r\n <p class=\"text-xs text-muted-color\">\r\n Edit the chart's clientConfig as JSON. Use this only when the UI\r\n controls don't expose the field you need. JSON is validated and\r\n merged into existing clientConfig (top-level keys overwrite).\r\n Invalid JSON is never persisted.\r\n </p>\r\n <textarea\r\n class=\"font-mono text-xs w-full p-2 rounded border border-surface-300 bg-surface-50\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"text-xs text-red-600\">{{ advancedJsonError() }}</p>\r\n }\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"'Apply JSON'\"\r\n icon=\"general.check\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n [class]=\"\r\n modal.footerClass + ' border-t border-surface-200 bg-surface-0 px-4 py-3'\r\n \"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('apply')\" icon=\"general.check\" (onClick)=\"apply()\" />\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: DisplaySettings, selector: "mt-display-settings", inputs: ["config", "chartType", "availableProperties", "selectedProperties", "lookups"], outputs: ["clientConfigChange"] }, { kind: "component", type: DefaultControlUi, selector: "mt-default-control-ui", inputs: ["showIconSettings", "layoutComponent"] }, { kind: "component", type: PieControlUi, selector: "mt-pie-control-ui" }, { kind: "component", type: BarControlUi, selector: "mt-bar-control-ui" }, { kind: "component", type: StackBarControlUi, selector: "mt-stack-bar-control-ui" }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
10506
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ChartSettingsDrawer, isStandalone: true, selector: "mt-chart-settings-drawer", ngImport: i0, template: "<div\r\n [class]=\"modal.contentClass + ' flex h-full min-h-0 flex-col p-0'\"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <div\r\n class=\"sticky top-0 z-10 border-b border-surface-200 bg-surface-0 px-4 pb-3 pt-4\"\r\n >\r\n <mt-tabs\r\n [options]=\"tabOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3\">\r\n @if (showDisplayTab()) {\r\n <!-- Display Tab -->\r\n <div [hidden]=\"activeTab() !== 'display'\" class=\"flex flex-col gap-3\">\r\n <mt-display-settings\r\n [config]=\"itemConfig()\"\r\n [chartType]=\"resolvedChartType()\"\r\n (clientConfigChange)=\"onClientConfigUpdate($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Chart Controls Tab -->\r\n <div [hidden]=\"activeTab() !== 'chartControls'\" class=\"flex flex-col gap-3\">\r\n @switch (manageType()) {\r\n @case (\"default\") {\r\n <mt-default-control-ui\r\n [ngModel]=\"defaultControlConfig()\"\r\n [showIconSettings]=\"isLayoutItem()\"\r\n [layoutComponent]=\"layoutComponentName()\"\r\n (ngModelChange)=\"onDefaultConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"pie\") {\r\n <mt-pie-control-ui\r\n [ngModel]=\"pieConfig()\"\r\n (ngModelChange)=\"onPieConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"bar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"barConfig()\"\r\n (ngModelChange)=\"onBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"stackBar\") {\r\n <mt-stack-bar-control-ui\r\n [ngModel]=\"stackBarConfig()\"\r\n (ngModelChange)=\"onStackBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @case (\"snapshotBar\") {\r\n <mt-bar-control-ui\r\n [ngModel]=\"snapshotBarConfig()\"\r\n (ngModelChange)=\"onSnapshotBarConfigChange($event)\"\r\n />\r\n }\r\n\r\n @default {\r\n <!-- Pass-4: schema-driven controls fill the gap for chart/item types\r\n that don't have a bespoke quick-control component. Every supported\r\n chart in the manifest has a control schema in the registry, so\r\n this branch always renders real controls instead of\r\n noSettingsAvailable. -->\r\n <mt-schema-control-renderer\r\n [schema]=\"schemaForItem()\"\r\n [persisted]=\"itemConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Advanced Override (JSON) \u2014 Pass-2 -->\r\n <div [hidden]=\"activeTab() !== 'advanced'\" class=\"flex flex-col gap-3\">\r\n @if (activeTab() === \"advanced\") {\r\n <ng-container>\r\n <p class=\"text-xs text-muted-color\">\r\n Edit the chart's clientConfig as JSON. Use this only when the UI\r\n controls don't expose the field you need. JSON is validated and\r\n merged into existing clientConfig (top-level keys overwrite).\r\n Invalid JSON is never persisted.\r\n </p>\r\n <textarea\r\n class=\"font-mono text-xs w-full p-2 rounded border border-surface-300 bg-surface-50\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"text-xs text-red-600\">{{ advancedJsonError() }}</p>\r\n }\r\n <div class=\"flex justify-end\">\r\n <mt-button\r\n [label]=\"'Apply JSON'\"\r\n icon=\"general.check\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n [class]=\"\r\n modal.footerClass + ' border-t border-surface-200 bg-surface-0 px-4 py-3'\r\n \"\r\n *transloco=\"let t; prefix: 'dashboardBuilder'\"\r\n>\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n <mt-button [label]=\"t('apply')\" icon=\"general.check\" (onClick)=\"apply()\" />\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: DisplaySettings, selector: "mt-display-settings", inputs: ["config", "chartType", "availableProperties", "selectedProperties", "lookups"], outputs: ["clientConfigChange"] }, { kind: "component", type: DefaultControlUi, selector: "mt-default-control-ui", inputs: ["showIconSettings", "layoutComponent"] }, { kind: "component", type: PieControlUi, selector: "mt-pie-control-ui" }, { kind: "component", type: BarControlUi, selector: "mt-bar-control-ui" }, { kind: "component", type: StackBarControlUi, selector: "mt-stack-bar-control-ui" }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
10569
10507
  }
10570
10508
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ChartSettingsDrawer, decorators: [{
10571
10509
  type: Component,
@@ -11029,7 +10967,7 @@ class FilterValueField {
11029
10967
  useExisting: forwardRef(() => FilterValueField),
11030
10968
  multi: true,
11031
10969
  },
11032
- ], viewQueries: [{ propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Label -->\r\n @if (label()) {\r\n <label class=\"block text-sm font-medium text-color mb-1\">\r\n {{ label() }}\r\n </label>\r\n }\r\n\r\n <!-- Input Group with Popover Trigger -->\r\n <p-inputgroup>\r\n <input\r\n type=\"text\"\r\n pInputText\r\n class=\"w-full\"\r\n [value]=\"value()\"\r\n (input)=\"onInputChange($any($event.target).value)\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n />\r\n <p-inputgroup-addon class=\"!p-0\">\r\n <mt-button\r\n icon=\"arrow.chevron-down\"\r\n variant=\"text\"\r\n [disabled]=\"disabled()\"\r\n size=\"small\"\r\n (click)=\"togglePopover($event)\"\r\n />\r\n </p-inputgroup-addon>\r\n </p-inputgroup>\r\n\r\n <!-- Popover Panel -->\r\n <p-popover #popover appendTo=\"body\" [style]=\"{ width: '360px' }\">\r\n <div class=\"flex flex-col gap-3\">\r\n <!-- Tabs -->\r\n @if (tabOptions().length > 0) {\r\n <mt-tabs [(active)]=\"activeTab\" [options]=\"tabOptions()\" size=\"small\" />\r\n }\r\n\r\n <!-- Options Grid -->\r\n <div class=\"max-h-64 overflow-y-auto\">\r\n <div class=\"grid grid-cols-2 gap-2\">\r\n @for (option of currentTabOptions; track option.value) {\r\n <div\r\n class=\"col-span-1\"\r\n [class.col-span-2]=\"option.isDate && isOptionSelected(option)\"\r\n >\r\n <div\r\n class=\"border rounded-lg transition-all cursor-pointer\"\r\n [class.border-primary-500]=\"isOptionSelected(option)\"\r\n [class.bg-primary-50]=\"isOptionSelected(option)\"\r\n [class.border-surface-200]=\"!isOptionSelected(option)\"\r\n [class.hover:border-primary-300]=\"!isOptionSelected(option)\"\r\n >\r\n <!-- Option Button -->\r\n <div\r\n class=\"px-3 py-2 text-sm flex items-center gap-2\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n @if (option.icon) {\r\n <mt-icon [icon]=\"option.icon\" class=\"text-muted-color\" />\r\n }\r\n <span class=\"flex-1 truncate\">{{ option.label }}</span>\r\n @if (isOptionSelected(option)) {\r\n <mt-icon icon=\"general.check\" class=\"text-primary-600\" />\r\n }\r\n </div>\r\n\r\n <!-- Date Modifier (shown when date option is selected) -->\r\n @if (option.isDate && isOptionSelected(option)) {\r\n <div\r\n class=\"px-3 py-2 border-t border-surface-200 bg-surface-50 rounded-b-lg\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <!-- Sign Toggle -->\r\n <mt-button\r\n [label]=\"option.modifier?.isPositive ? '+' : '-'\"\r\n [variant]=\"\r\n option.modifier?.isPositive ? 'outlined' : 'outlined'\r\n \"\r\n size=\"small\"\r\n [class.!border-green-500]=\"option.modifier?.isPositive\"\r\n [class.!text-green-600]=\"option.modifier?.isPositive\"\r\n [class.!border-red-500]=\"!option.modifier?.isPositive\"\r\n [class.!text-red-600]=\"!option.modifier?.isPositive\"\r\n (click)=\"toggleSign(option, $event)\"\r\n />\r\n\r\n <!-- Count Input -->\r\n <mt-number-field\r\n class=\"w-20\"\r\n [ngModel]=\"option.modifier?.count\"\r\n (ngModelChange)=\"updateCount(option, $event)\"\r\n [min]=\"0\"\r\n [showButtons]=\"false\"\r\n size=\"small\"\r\n />\r\n\r\n <!-- Unit Select -->\r\n <p-select\r\n [ngModel]=\"option.modifier?.unit\"\r\n (ngModelChange)=\"updateUnit(option, $event)\"\r\n [options]=\"unitOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n size=\"small\"\r\n class=\"w-24\"\r\n appendTo=\"body\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (currentTabOptions.length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n No options available\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n</ng-container>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i3.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }, { kind: "component", type: i4.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i5.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
10970
+ ], viewQueries: [{ propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Label -->\r\n @if (label()) {\r\n <label class=\"block text-sm font-medium text-color mb-1\">\r\n {{ label() }}\r\n </label>\r\n }\r\n\r\n <!-- Input Group with Popover Trigger -->\r\n <p-inputgroup>\r\n <input\r\n type=\"text\"\r\n pInputText\r\n class=\"w-full\"\r\n [value]=\"value()\"\r\n (input)=\"onInputChange($any($event.target).value)\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n />\r\n <p-inputgroup-addon class=\"!p-0\">\r\n <mt-button\r\n icon=\"arrow.chevron-down\"\r\n variant=\"text\"\r\n [disabled]=\"disabled()\"\r\n size=\"small\"\r\n (click)=\"togglePopover($event)\"\r\n />\r\n </p-inputgroup-addon>\r\n </p-inputgroup>\r\n\r\n <!-- Popover Panel -->\r\n <p-popover #popover appendTo=\"body\" [style]=\"{ width: '360px' }\">\r\n <div class=\"flex flex-col gap-3\">\r\n <!-- Tabs -->\r\n @if (tabOptions().length > 0) {\r\n <mt-tabs [(active)]=\"activeTab\" [options]=\"tabOptions()\" size=\"small\" />\r\n }\r\n\r\n <!-- Options Grid -->\r\n <div class=\"max-h-64 overflow-y-auto\">\r\n <div class=\"grid grid-cols-2 gap-2\">\r\n @for (option of currentTabOptions; track option.value) {\r\n <div\r\n class=\"col-span-1\"\r\n [class.col-span-2]=\"option.isDate && isOptionSelected(option)\"\r\n >\r\n <div\r\n class=\"border rounded-lg transition-all cursor-pointer\"\r\n [class.border-primary-500]=\"isOptionSelected(option)\"\r\n [class.bg-primary-50]=\"isOptionSelected(option)\"\r\n [class.border-surface-200]=\"!isOptionSelected(option)\"\r\n [class.hover:border-primary-300]=\"!isOptionSelected(option)\"\r\n >\r\n <!-- Option Button -->\r\n <div\r\n class=\"px-3 py-2 text-sm flex items-center gap-2\"\r\n (click)=\"toggleOption(option)\"\r\n >\r\n @if (option.icon) {\r\n <mt-icon [icon]=\"option.icon\" class=\"text-muted-color\" />\r\n }\r\n <span class=\"flex-1 truncate\">{{ option.label }}</span>\r\n @if (isOptionSelected(option)) {\r\n <mt-icon icon=\"general.check\" class=\"text-primary-600\" />\r\n }\r\n </div>\r\n\r\n <!-- Date Modifier (shown when date option is selected) -->\r\n @if (option.isDate && isOptionSelected(option)) {\r\n <div\r\n class=\"px-3 py-2 border-t border-surface-200 bg-surface-50 rounded-b-lg\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <!-- Sign Toggle -->\r\n <mt-button\r\n [label]=\"option.modifier?.isPositive ? '+' : '-'\"\r\n [variant]=\"\r\n option.modifier?.isPositive ? 'outlined' : 'outlined'\r\n \"\r\n size=\"small\"\r\n [class.!border-green-500]=\"option.modifier?.isPositive\"\r\n [class.!text-green-600]=\"option.modifier?.isPositive\"\r\n [class.!border-red-500]=\"!option.modifier?.isPositive\"\r\n [class.!text-red-600]=\"!option.modifier?.isPositive\"\r\n (click)=\"toggleSign(option, $event)\"\r\n />\r\n\r\n <!-- Count Input -->\r\n <mt-number-field\r\n class=\"w-20\"\r\n [ngModel]=\"option.modifier?.count\"\r\n (ngModelChange)=\"updateCount(option, $event)\"\r\n [min]=\"0\"\r\n [showButtons]=\"false\"\r\n size=\"small\"\r\n />\r\n\r\n <!-- Unit Select -->\r\n <p-select\r\n [ngModel]=\"option.modifier?.unit\"\r\n (ngModelChange)=\"updateUnit(option, $event)\"\r\n [options]=\"unitOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n size=\"small\"\r\n class=\"w-24\"\r\n appendTo=\"body\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (currentTabOptions.length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n No options available\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n</ng-container>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i3.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }, { kind: "component", type: i4.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i5.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11033
10971
  }
11034
10972
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FilterValueField, decorators: [{
11035
10973
  type: Component,
@@ -11886,7 +11824,7 @@ class SourceLinkConfiguration {
11886
11824
  useExisting: forwardRef(() => SourceLinkConfiguration),
11887
11825
  multi: true,
11888
11826
  },
11889
- ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <mt-card [title]=\"t('sourceLinks')\">\r\n <ng-template #cardEnd>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"addSourceLink()\"\r\n [disabled]=\"disabled\"\r\n [pTooltip]=\"t('addSourceLink')\"\r\n />\r\n </ng-template>\r\n\r\n <div class=\"flex flex-col gap-4\" [formGroup]=\"sourceLinksForm\">\r\n <div formArrayName=\"sourceLinks\">\r\n @for (\r\n link of sourceLinksArray.controls;\r\n track trackByIndex(i);\r\n let i = $index;\r\n let first = $first\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]=\"link.invalid\"\r\n [class.border-surface-200]=\"!link.invalid\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Link Header with Type Tabs -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-3\">\r\n <span\r\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full bg-primary-100 text-primary-600 text-sm font-semibold\"\r\n >\r\n {{ i + 1 }}\r\n </span>\r\n\r\n <!-- Link Type Tabs (only show for non-first links) -->\r\n @if (!first) {\r\n <mt-tabs\r\n [active]=\"getLinkType(i)\"\r\n (activeChange)=\"onLinkTypeChange(i, $event)\"\r\n [options]=\"getLinkTypeOptions(i)\"\r\n size=\"small\"\r\n />\r\n } @else {\r\n <span class=\"text-sm font-medium text-muted-color\">\r\n {{ t(\"selectionToSelection\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeSourceLink(i)\"\r\n />\r\n </div>\r\n\r\n <!-- Source Selections based on link type -->\r\n @if (getLinkType(i) === \"selection\") {\r\n <!-- Selection to Selection Mode -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\r\n <!-- Source 1 Selection -->\r\n <mt-select-field\r\n [label]=\"t('source1')\"\r\n formControlName=\"source1SelectionId\"\r\n [options]=\"selectionOptions()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"selectionId\"\r\n [placeholder]=\"t('selectSource')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n\r\n <!-- Source 2 Selection -->\r\n <mt-select-field\r\n [label]=\"t('source2')\"\r\n formControlName=\"source2SelectionId\"\r\n [options]=\"selectionOptions()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"selectionId\"\r\n [placeholder]=\"t('selectSource')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n </div>\r\n } @else {\r\n <!-- Chained Mode: Previous Link to Selection -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\r\n <!-- Source Link (previous link) -->\r\n <mt-select-field\r\n [label]=\"t('previousLink')\"\r\n formControlName=\"sourceLinkId\"\r\n [options]=\"getAvailableSourceLinks(i)\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"index\"\r\n [placeholder]=\"t('selectPreviousLink')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n\r\n <!-- Source 2 Selection -->\r\n <mt-select-field\r\n [label]=\"t('source2')\"\r\n formControlName=\"source2SelectionId\"\r\n [options]=\"selectionOptions()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"selectionId\"\r\n [placeholder]=\"t('selectSource')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Link Properties -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\r\n <!-- Source 1 Property -->\r\n <mt-select-field\r\n [label]=\"t('source1LinkProperty')\"\r\n formControlName=\"source1PropertyKey\"\r\n [options]=\"getSource1PropertiesGrouped(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n\r\n <!-- Source 2 Property -->\r\n <mt-select-field\r\n [label]=\"t('source2LinkProperty')\"\r\n formControlName=\"source2PropertyKey\"\r\n [options]=\"getSource2PropertiesGrouped(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- Join Options -->\r\n <div class=\"flex items-center gap-6\">\r\n <mt-toggle-field\r\n [label]=\"t('isLeftJoin')\"\r\n formControlName=\"isLeftJoin\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('isFilterLinkage')\"\r\n formControlName=\"isFilterLinkage\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (sourceLinksArray.length === 0) {\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-link-01 text-3xl mb-2 block\"></i>\r\n <p class=\"mb-2\">{{ t(\"noSourceLinksConfigured\") }}</p>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [label]=\"t('addSourceLink')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addSourceLink()\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], 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", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11827
+ ], ngImport: i0, template: "<div class=\"flex flex-col gap-4\" *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <mt-card [title]=\"t('sourceLinks')\">\r\n <ng-template #cardEnd>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n (onClick)=\"addSourceLink()\"\r\n [disabled]=\"disabled\"\r\n [pTooltip]=\"t('addSourceLink')\"\r\n />\r\n </ng-template>\r\n\r\n <div class=\"flex flex-col gap-4\" [formGroup]=\"sourceLinksForm\">\r\n <div formArrayName=\"sourceLinks\">\r\n @for (\r\n link of sourceLinksArray.controls;\r\n track trackByIndex(i);\r\n let i = $index;\r\n let first = $first\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]=\"link.invalid\"\r\n [class.border-surface-200]=\"!link.invalid\"\r\n [formGroupName]=\"i\"\r\n >\r\n <!-- Link Header with Type Tabs -->\r\n <div class=\"flex items-center justify-between mb-4\">\r\n <div class=\"flex items-center gap-3\">\r\n <span\r\n class=\"inline-flex items-center justify-center w-6 h-6 rounded-full bg-primary-100 text-primary-600 text-sm font-semibold\"\r\n >\r\n {{ i + 1 }}\r\n </span>\r\n\r\n <!-- Link Type Tabs (only show for non-first links) -->\r\n @if (!first) {\r\n <mt-tabs\r\n [active]=\"getLinkType(i)\"\r\n (activeChange)=\"onLinkTypeChange(i, $event)\"\r\n [options]=\"getLinkTypeOptions(i)\"\r\n size=\"small\"\r\n />\r\n } @else {\r\n <span class=\"text-sm font-medium text-muted-color\">\r\n {{ t(\"selectionToSelection\") }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"removeSourceLink(i)\"\r\n />\r\n </div>\r\n\r\n <!-- Source Selections based on link type -->\r\n @if (getLinkType(i) === \"selection\") {\r\n <!-- Selection to Selection Mode -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\r\n <!-- Source 1 Selection -->\r\n <mt-select-field\r\n [label]=\"t('source1')\"\r\n formControlName=\"source1SelectionId\"\r\n [options]=\"selectionOptions()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"selectionId\"\r\n [placeholder]=\"t('selectSource')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n\r\n <!-- Source 2 Selection -->\r\n <mt-select-field\r\n [label]=\"t('source2')\"\r\n formControlName=\"source2SelectionId\"\r\n [options]=\"selectionOptions()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"selectionId\"\r\n [placeholder]=\"t('selectSource')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n </div>\r\n } @else {\r\n <!-- Chained Mode: Previous Link to Selection -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\r\n <!-- Source Link (previous link) -->\r\n <mt-select-field\r\n [label]=\"t('previousLink')\"\r\n formControlName=\"sourceLinkId\"\r\n [options]=\"getAvailableSourceLinks(i)\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"index\"\r\n [placeholder]=\"t('selectPreviousLink')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n\r\n <!-- Source 2 Selection -->\r\n <mt-select-field\r\n [label]=\"t('source2')\"\r\n formControlName=\"source2SelectionId\"\r\n [options]=\"selectionOptions()\"\r\n optionLabel=\"displayName\"\r\n optionValue=\"selectionId\"\r\n [placeholder]=\"t('selectSource')\"\r\n (ngModelChange)=\"onSourceChange(i)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Link Properties -->\r\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\r\n <!-- Source 1 Property -->\r\n <mt-select-field\r\n [label]=\"t('source1LinkProperty')\"\r\n formControlName=\"source1PropertyKey\"\r\n [options]=\"getSource1PropertiesGrouped(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n\r\n <!-- Source 2 Property -->\r\n <mt-select-field\r\n [label]=\"t('source2LinkProperty')\"\r\n formControlName=\"source2PropertyKey\"\r\n [options]=\"getSource2PropertiesGrouped(i)\"\r\n [group]=\"true\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n [placeholder]=\"t('selectProperty')\"\r\n [filter]=\"true\"\r\n />\r\n </div>\r\n\r\n <!-- Join Options -->\r\n <div class=\"flex items-center gap-6\">\r\n <mt-toggle-field\r\n [label]=\"t('isLeftJoin')\"\r\n formControlName=\"isLeftJoin\"\r\n />\r\n <mt-toggle-field\r\n [label]=\"t('isFilterLinkage')\"\r\n formControlName=\"isFilterLinkage\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (sourceLinksArray.length === 0) {\r\n <div class=\"text-center py-8 text-muted-color\">\r\n <i class=\"mti mti-link-01 text-3xl mb-2 block\"></i>\r\n <p class=\"mb-2\">{{ t(\"noSourceLinksConfigured\") }}</p>\r\n <mt-button\r\n icon=\"general.plus\"\r\n [label]=\"t('addSourceLink')\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [disabled]=\"disabled\"\r\n (onClick)=\"addSourceLink()\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], 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", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11890
11828
  }
11891
11829
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SourceLinkConfiguration, decorators: [{
11892
11830
  type: Component,
@@ -13727,7 +13665,7 @@ class DataSourceSettings {
13727
13665
  };
13728
13666
  }
13729
13667
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DataSourceSettings, deps: [], target: i0.ɵɵFactoryTarget.Component });
13730
- 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 <!-- Pass-2: Simple/Advanced toggle for progressive disclosure -->\r\n @if (!hideSelectionConfig()) {\r\n <div\r\n class=\"flex items-center justify-between rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"flex flex-col\">\r\n <span class=\"text-sm font-semibold text-surface-700\">\r\n {{ isAdvanced() ? \"Advanced data source\" : \"Simple data source\" }}\r\n </span>\r\n <span class=\"text-xs text-muted-color\">\r\n {{\r\n isAdvanced()\r\n ? \"All options are visible, including custom API, multi-selection joins, and advanced filters.\"\r\n : \"Only the essential fields are shown. Switch to Advanced for full power.\"\r\n }}\r\n </span>\r\n </div>\r\n <mt-toggle-field\r\n label=\"Advanced\"\r\n [ngModel]=\"isAdvanced()\"\r\n (ngModelChange)=\"onDisclosureToggle($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Data Source Type Tabs (visible only in Advanced \u2014 hidden for layout/snapshot/phaseGate) -->\r\n @if (!hideSelectionConfig() && isAdvanced()) {\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 (Advanced only) -->\r\n @if (!hideSelectionConfig() && isAdvanced()) {\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 (always visible in Simple; switches between Selection/Custom-API only in Advanced) -->\r\n <div\r\n [hidden]=\"isAdvanced() && activeTab() !== 'selection'\"\r\n class=\"flex flex-col gap-6\"\r\n >\r\n <!-- Selection Configuration (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <!-- Step 1 label -->\r\n <div\r\n class=\"flex items-center gap-2 text-sm font-semibold text-surface-700\"\r\n >\r\n <span\r\n class=\"w-6 h-6 inline-flex items-center justify-center rounded-full bg-primary-100 text-primary-600 text-xs font-bold\"\r\n >1</span\r\n >\r\n {{ \"Source / Entity\" }}\r\n </div>\r\n\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 (Advanced only, when multiple selections) -->\r\n @if (showSourceLinks() && isAdvanced()) {\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 <!-- Step 2 label (only shown when there is a query editor to render) -->\r\n @if (queryComponentType() !== \"none\" && !hideSelectionConfig()) {\r\n <div\r\n class=\"flex items-center gap-2 text-sm font-semibold text-surface-700\"\r\n >\r\n <span\r\n class=\"w-6 h-6 inline-flex items-center justify-center rounded-full bg-primary-100 text-primary-600 text-xs font-bold\"\r\n >2</span\r\n >\r\n {{ \"Fields & query\" }}\r\n </div>\r\n }\r\n\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=\"flex flex-col gap-6\">\r\n <div class=\"flex items-center justify-between\">\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"timelineMultiLevelDescription\") }}\r\n </p>\r\n <mt-button\r\n size=\"small\"\r\n severity=\"secondary\"\r\n icon=\"general.plus\"\r\n [label]=\"t('addLevel')\"\r\n (onClick)=\"addTimelineLevel()\"\r\n />\r\n </div>\r\n\r\n @for (level of timelineLevels(); track $index) {\r\n <div\r\n class=\"border border-surface-300 rounded-md p-4 flex flex-col gap-3\"\r\n >\r\n <div class=\"flex items-center justify-between\">\r\n <span class=\"font-medium\">\r\n {{ t(\"level\") }} {{ level.levelNumber || $index + 1 }}\r\n </span>\r\n <mt-button\r\n size=\"small\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n icon=\"general.trash-02\"\r\n (onClick)=\"removeTimelineLevel($index)\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid grid-cols-2 gap-3\">\r\n <mt-select-field\r\n [label]=\"t('pivotProperty')\"\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 [ngModel]=\"level.pivotProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'pivotProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('lookupProperty')\"\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 [ngModel]=\"level.lookupProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'lookupProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('timeFrame')\"\r\n [options]=\"timeFrameOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [ngModel]=\"level.timeFrame\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField($index, 'timeFrame', $event)\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('startTimeProperty')\"\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 [ngModel]=\"level.startPoint_timeProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'startPoint_timeProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('endTimeProperty')\"\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 [ngModel]=\"level.endPoint_timeProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'endPoint_timeProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('parentProperty')\"\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 [ngModel]=\"level.parentProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'parentProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n </div>\r\n\r\n <mt-multi-select-field\r\n [label]=\"t('extraProperties')\"\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 [ngModel]=\"level.extras || []\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField($index, 'extras', $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n\r\n @if (timelineLevels().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noTimelineLevelsHint\") }}\r\n </div>\r\n }\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=\"flex flex-col gap-3\">\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"phaseGateLevelIdHint\") }}\r\n </p>\r\n <mt-text-field\r\n [label]=\"t('levelId')\"\r\n [placeholder]=\"'{{levelId}}'\"\r\n [ngModel]=\"phaseGateLevelId()\"\r\n (ngModelChange)=\"onPhaseGateLevelIdChange($event)\"\r\n />\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 <mt-multi-select-field\r\n [label]=\"t('repeaterSelectedProperties')\"\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('repeaterSelectedPropertiesPlaceholder')\"\r\n [filter]=\"true\"\r\n [ngModel]=\"repeaterSelectedProperties()\"\r\n (ngModelChange)=\"onRepeaterSelectedPropertiesChange($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", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: 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", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { 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: 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 });
13668
+ 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 <!-- Pass-2: Simple/Advanced toggle for progressive disclosure -->\r\n @if (!hideSelectionConfig()) {\r\n <div\r\n class=\"flex items-center justify-between rounded-md border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"flex flex-col\">\r\n <span class=\"text-sm font-semibold text-surface-700\">\r\n {{ isAdvanced() ? \"Advanced data source\" : \"Simple data source\" }}\r\n </span>\r\n <span class=\"text-xs text-muted-color\">\r\n {{\r\n isAdvanced()\r\n ? \"All options are visible, including custom API, multi-selection joins, and advanced filters.\"\r\n : \"Only the essential fields are shown. Switch to Advanced for full power.\"\r\n }}\r\n </span>\r\n </div>\r\n <mt-toggle-field\r\n label=\"Advanced\"\r\n [ngModel]=\"isAdvanced()\"\r\n (ngModelChange)=\"onDisclosureToggle($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Data Source Type Tabs (visible only in Advanced \u2014 hidden for layout/snapshot/phaseGate) -->\r\n @if (!hideSelectionConfig() && isAdvanced()) {\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 (Advanced only) -->\r\n @if (!hideSelectionConfig() && isAdvanced()) {\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 (always visible in Simple; switches between Selection/Custom-API only in Advanced) -->\r\n <div\r\n [hidden]=\"isAdvanced() && activeTab() !== 'selection'\"\r\n class=\"flex flex-col gap-6\"\r\n >\r\n <!-- Selection Configuration (hidden for layout, snapshot, phaseGate types) -->\r\n @if (!hideSelectionConfig()) {\r\n <!-- Step 1 label -->\r\n <div\r\n class=\"flex items-center gap-2 text-sm font-semibold text-surface-700\"\r\n >\r\n <span\r\n class=\"w-6 h-6 inline-flex items-center justify-center rounded-full bg-primary-100 text-primary-600 text-xs font-bold\"\r\n >1</span\r\n >\r\n {{ \"Source / Entity\" }}\r\n </div>\r\n\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 (Advanced only, when multiple selections) -->\r\n @if (showSourceLinks() && isAdvanced()) {\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 <!-- Step 2 label (only shown when there is a query editor to render) -->\r\n @if (queryComponentType() !== \"none\" && !hideSelectionConfig()) {\r\n <div\r\n class=\"flex items-center gap-2 text-sm font-semibold text-surface-700\"\r\n >\r\n <span\r\n class=\"w-6 h-6 inline-flex items-center justify-center rounded-full bg-primary-100 text-primary-600 text-xs font-bold\"\r\n >2</span\r\n >\r\n {{ \"Fields & query\" }}\r\n </div>\r\n }\r\n\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=\"flex flex-col gap-6\">\r\n <div class=\"flex items-center justify-between\">\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"timelineMultiLevelDescription\") }}\r\n </p>\r\n <mt-button\r\n size=\"small\"\r\n severity=\"secondary\"\r\n icon=\"general.plus\"\r\n [label]=\"t('addLevel')\"\r\n (onClick)=\"addTimelineLevel()\"\r\n />\r\n </div>\r\n\r\n @for (level of timelineLevels(); track $index) {\r\n <div\r\n class=\"border border-surface-300 rounded-md p-4 flex flex-col gap-3\"\r\n >\r\n <div class=\"flex items-center justify-between\">\r\n <span class=\"font-medium\">\r\n {{ t(\"level\") }} {{ level.levelNumber || $index + 1 }}\r\n </span>\r\n <mt-button\r\n size=\"small\"\r\n severity=\"danger\"\r\n [text]=\"true\"\r\n icon=\"general.trash-02\"\r\n (onClick)=\"removeTimelineLevel($index)\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid grid-cols-2 gap-3\">\r\n <mt-select-field\r\n [label]=\"t('pivotProperty')\"\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 [ngModel]=\"level.pivotProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'pivotProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('lookupProperty')\"\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 [ngModel]=\"level.lookupProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'lookupProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('timeFrame')\"\r\n [options]=\"timeFrameOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [ngModel]=\"level.timeFrame\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField($index, 'timeFrame', $event)\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('startTimeProperty')\"\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 [ngModel]=\"level.startPoint_timeProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'startPoint_timeProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('endTimeProperty')\"\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 [ngModel]=\"level.endPoint_timeProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'endPoint_timeProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n <mt-select-field\r\n [label]=\"t('parentProperty')\"\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 [ngModel]=\"level.parentProperty\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField(\r\n $index,\r\n 'parentProperty',\r\n $event\r\n )\r\n \"\r\n />\r\n </div>\r\n\r\n <mt-multi-select-field\r\n [label]=\"t('extraProperties')\"\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 [ngModel]=\"level.extras || []\"\r\n (ngModelChange)=\"\r\n updateTimelineLevelField($index, 'extras', $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n\r\n @if (timelineLevels().length === 0) {\r\n <div class=\"text-center py-4 text-muted-color text-sm\">\r\n {{ t(\"noTimelineLevelsHint\") }}\r\n </div>\r\n }\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=\"flex flex-col gap-3\">\r\n <p class=\"text-sm text-muted-color\">\r\n {{ t(\"phaseGateLevelIdHint\") }}\r\n </p>\r\n <mt-text-field\r\n [label]=\"t('levelId')\"\r\n [placeholder]=\"'{{levelId}}'\"\r\n [ngModel]=\"phaseGateLevelId()\"\r\n (ngModelChange)=\"onPhaseGateLevelIdChange($event)\"\r\n />\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 <mt-multi-select-field\r\n [label]=\"t('repeaterSelectedProperties')\"\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('repeaterSelectedPropertiesPlaceholder')\"\r\n [filter]=\"true\"\r\n [ngModel]=\"repeaterSelectedProperties()\"\r\n (ngModelChange)=\"onRepeaterSelectedPropertiesChange($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", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: 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", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { 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: 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 });
13731
13669
  }
13732
13670
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DataSourceSettings, decorators: [{
13733
13671
  type: Component,
@@ -26240,7 +26178,7 @@ class PropertiesCardComponent {
26240
26178
  return '';
26241
26179
  }
26242
26180
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertiesCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
26243
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PropertiesCardComponent, isStandalone: true, selector: "mt-properties-card, mt-entities-preview-card", inputs: { dashboardId: { classPropertyName: "dashboardId", publicName: "dashboardId", isSignal: true, isRequired: true, transformFunction: null }, inGroup: { classPropertyName: "inGroup", publicName: "inGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\n @if (showTabs()) {\n <div class=\"mb-3\">\n <mt-tabs [(active)]=\"tabSelected\" [options]=\"tabOptions()\" size=\"small\" />\n </div>\n }\n\n <div\n class=\"overflow-y-auto overflow-x-hidden\"\n [style.max-height]=\"inGroup() ? '500px' : '90%'\"\n >\n @if (currentTabCards().length === 0) {\n <div class=\"py-6 text-center text-sm text-gray-400\">\n {{ t(\"noData\") }}\n </div>\n } @else {\n <div class=\"flex flex-wrap\">\n @for (cardView of currentTabCards(); track cardView.trackId) {\n <div\n class=\"mb-2 p-2\"\n [class.card-col]=\"!galleryMode()\"\n [class.gallery-card-col]=\"galleryMode()\"\n [class.w-full]=\"!galleryMode()\"\n [class.md:w-1/2]=\"!galleryMode()\"\n [class.lg:w-1/3]=\"!galleryMode()\"\n >\n <div\n class=\"h-full cursor-pointer rounded-lg bg-white p-3 shadow-sm transition-all hover:shadow-md\"\n (click)=\"onCardClick(cardView.card)\"\n >\n @if (cardView.entities.length > 0) {\n <mt-entities-preview [entities]=\"cardView.entities\" />\n } @else {\n <div class=\"py-6 text-center text-sm text-gray-400\">\n {{ t(\"noData\") }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n</ng-container>\n", styles: [":host{display:block;height:100%}.card-col{flex:0 0 100%}@media(min-width:768px){.card-col{flex:0 0 50%}}@media(min-width:1024px){.card-col{flex:0 0 33.333%}}.gallery-card-col{flex:0 0 100%}@media(min-width:640px){.gallery-card-col{flex:0 0 50%}}@media(min-width:1024px){.gallery-card-col{flex:0 0 25%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: EntitiesPreview, selector: "mt-entities-preview", inputs: ["entities", "attachmentShape", "clickableKeys", "activeKeys", "clickableTooltip", "activeTooltip"], outputs: ["entityClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
26181
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PropertiesCardComponent, isStandalone: true, selector: "mt-properties-card, mt-entities-preview-card", inputs: { dashboardId: { classPropertyName: "dashboardId", publicName: "dashboardId", isSignal: true, isRequired: true, transformFunction: null }, inGroup: { classPropertyName: "inGroup", publicName: "inGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\n @if (showTabs()) {\n <div class=\"mb-3\">\n <mt-tabs [(active)]=\"tabSelected\" [options]=\"tabOptions()\" size=\"small\" />\n </div>\n }\n\n <div\n class=\"overflow-y-auto overflow-x-hidden\"\n [style.max-height]=\"inGroup() ? '500px' : '90%'\"\n >\n @if (currentTabCards().length === 0) {\n <div class=\"py-6 text-center text-sm text-gray-400\">\n {{ t(\"noData\") }}\n </div>\n } @else {\n <div class=\"flex flex-wrap\">\n @for (cardView of currentTabCards(); track cardView.trackId) {\n <div\n class=\"mb-2 p-2\"\n [class.card-col]=\"!galleryMode()\"\n [class.gallery-card-col]=\"galleryMode()\"\n [class.w-full]=\"!galleryMode()\"\n [class.md:w-1/2]=\"!galleryMode()\"\n [class.lg:w-1/3]=\"!galleryMode()\"\n >\n <div\n class=\"h-full cursor-pointer rounded-lg bg-white p-3 shadow-sm transition-all hover:shadow-md\"\n (click)=\"onCardClick(cardView.card)\"\n >\n @if (cardView.entities.length > 0) {\n <mt-entities-preview [entities]=\"cardView.entities\" />\n } @else {\n <div class=\"py-6 text-center text-sm text-gray-400\">\n {{ t(\"noData\") }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n</ng-container>\n", styles: [":host{display:block;height:100%}.card-col{flex:0 0 100%}@media(min-width:768px){.card-col{flex:0 0 50%}}@media(min-width:1024px){.card-col{flex:0 0 33.333%}}.gallery-card-col{flex:0 0 100%}@media(min-width:640px){.gallery-card-col{flex:0 0 50%}}@media(min-width:1024px){.gallery-card-col{flex:0 0 25%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: EntitiesPreview, selector: "mt-entities-preview", inputs: ["entities", "attachmentShape", "clickableKeys", "activeKeys", "clickableTooltip", "activeTooltip"], outputs: ["entityClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
26244
26182
  }
26245
26183
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PropertiesCardComponent, decorators: [{
26246
26184
  type: Component,
@@ -27266,7 +27204,7 @@ class ManageItem {
27266
27204
  this._manageItemService.updateClientConfig(partialConfig);
27267
27205
  }
27268
27206
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
27269
- 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 [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"cancel()\" />\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", "mode", "moreLabel", "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 });
27207
+ 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 [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"cancel()\" />\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", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: GeneralSettings, selector: "mt-general-settings", inputs: ["config", "isDialog", "hasPreselectedType"], outputs: ["configChange", "chartTypeChange"] }, { kind: "component", type: DataSourceSettings, selector: "mt-data-source-settings", inputs: ["config", "chartType", "informativeContext"], outputs: ["serviceConfigChange"] }, { kind: "component", type: ActionsSettings, selector: "mt-actions-settings", inputs: ["config"], outputs: ["clientConfigChange"] }, { kind: "component", type: ChartViewer, selector: "mt-chart-viewer", inputs: ["config", "chartTypeId"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
27270
27208
  }
27271
27209
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ManageItem, decorators: [{
27272
27210
  type: Component,
@@ -29317,7 +29255,7 @@ class ItemConfigPopoverComponent {
29317
29255
  return JSON.parse(JSON.stringify(item));
29318
29256
  }
29319
29257
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ItemConfigPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29320
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ItemConfigPopoverComponent, isStandalone: true, selector: "mt-item-config-popover", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder.pass4'\">\r\n @if (item(); as currentItem) {\r\n <div class=\"db-config-popover\">\r\n <header class=\"db-config-popover__header\">\r\n <div class=\"db-config-popover__title-row\">\r\n <mt-icon\r\n [icon]=\"capability()?.icon ?? 'general.settings-02'\"\r\n class=\"db-config-popover__icon\"\r\n />\r\n <div class=\"db-config-popover__title\">\r\n <input\r\n type=\"text\"\r\n class=\"db-config-popover__title-input\"\r\n [ngModel]=\"ui()?.title?.title ?? ''\"\r\n (ngModelChange)=\"onTitleChange($event)\"\r\n [placeholder]=\"t('header.titlePlaceholder') || 'Untitled'\"\r\n />\r\n <span class=\"db-config-popover__chart-type\">\r\n {{ capability()?.name }}\r\n </span>\r\n </div>\r\n </div>\r\n <div class=\"db-config-popover__close\">\r\n <mt-button\r\n icon=\"general.x-close\"\r\n [tooltip]=\"t('header.close') || 'Close'\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n (onClick)=\"cancel()\"\r\n />\r\n </div>\r\n </header>\r\n\r\n <mt-tabs\r\n [options]=\"tabs()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n class=\"db-config-popover__tabs\"\r\n />\r\n\r\n <main class=\"db-config-popover__main\">\r\n <!-- DATA TAB -->\r\n <section [hidden]=\"activeTab() !== 'data'\" class=\"db-config-section\">\r\n <mt-datasource-panel\r\n [item]=\"currentItem\"\r\n (serviceConfigChange)=\"onServiceConfigPatch($event)\"\r\n (openAdvanced)=\"openAdvancedEditor('dataSource')\"\r\n />\r\n\r\n @if (issuesByDomain().datasource.length) {\r\n <ul class=\"db-config-issues\">\r\n @for (issue of issuesByDomain().datasource; track issue.code) {\r\n <li\r\n class=\"db-config-issue\"\r\n [attr.data-severity]=\"issue.severity\"\r\n >\r\n <i class=\"mti mti-general.alert-circle\"></i>\r\n <span>{{ issue.message }}</span>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n @if (issuesByDomain().fields.length) {\r\n <ul class=\"db-config-issues\">\r\n @for (issue of issuesByDomain().fields; track issue.code) {\r\n <li\r\n class=\"db-config-issue\"\r\n [attr.data-severity]=\"issue.severity\"\r\n >\r\n <i class=\"mti mti-general.alert-circle\"></i>\r\n <span>{{ issue.message }}</span>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </section>\r\n\r\n <!-- FILTERS TAB -->\r\n <section [hidden]=\"activeTab() !== 'filters'\" class=\"db-config-section\">\r\n <mt-filter-builder\r\n [chips]=\"chips()\"\r\n [persisted]=\"currentItem.config\"\r\n (chipsChange)=\"onChipsChange($event)\"\r\n />\r\n @if (issuesByDomain().filters.length) {\r\n <ul class=\"db-config-issues\">\r\n @for (issue of issuesByDomain().filters; track issue.code) {\r\n <li\r\n class=\"db-config-issue\"\r\n [attr.data-severity]=\"issue.severity\"\r\n >\r\n <i class=\"mti mti-general.alert-circle\"></i>\r\n <span>{{ issue.message }}</span>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </section>\r\n\r\n <!-- STYLE TAB -->\r\n <section [hidden]=\"activeTab() !== 'style'\" class=\"db-config-section\">\r\n <h4 class=\"db-config-section__title\">\r\n {{ t(\"style.presets\") || \"Presets\" }}\r\n </h4>\r\n <div class=\"db-style-presets\">\r\n @for (preset of presets(); track preset.key) {\r\n <button\r\n type=\"button\"\r\n class=\"db-style-preset\"\r\n [class.is-selected]=\"selectedPresetKey() === preset.key\"\r\n (click)=\"onApplyPreset(preset)\"\r\n >\r\n <span class=\"db-style-preset__label\">{{ preset.label }}</span>\r\n <span class=\"db-style-preset__desc\">{{\r\n preset.description\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"db-config-section__actions db-config-section__actions--scope\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"db-scope-toggle\"\r\n (click)=\"toggleControlScope()\"\r\n >\r\n <i\r\n [class]=\"\r\n 'mti mti-' +\r\n (controlScope() === 'advanced'\r\n ? 'general.eye'\r\n : 'general.eye-off')\r\n \"\r\n ></i>\r\n <span>\r\n {{\r\n controlScope() === \"advanced\"\r\n ? t(\"controls.simpleMode\") || \"Show simple controls\"\r\n : t(\"controls.advancedMode\") || \"Show all controls\"\r\n }}\r\n </span>\r\n </button>\r\n </div>\r\n\r\n <mt-schema-control-renderer\r\n [schema]=\"schema()\"\r\n [persisted]=\"persistedConfig()\"\r\n [capability]=\"capability()\"\r\n [scope]=\"controlScope()\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n\r\n <div class=\"db-config-section__actions\">\r\n <mt-button\r\n [label]=\"\r\n t('style.openLegacyDrawer') || 'Power user: open legacy drawer'\r\n \"\r\n icon=\"general.settings-02\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"openChartSettingsDrawer()\"\r\n />\r\n </div>\r\n </section>\r\n\r\n <!-- BEHAVIOR TAB -->\r\n <section\r\n [hidden]=\"activeTab() !== 'behavior'\"\r\n class=\"db-config-section\"\r\n >\r\n <h4 class=\"db-config-section__title\">\r\n {{ t(\"behavior.title\") || \"Card behavior\" }}\r\n </h4>\r\n <label class=\"db-style-row\">\r\n <span>\r\n {{ t(\"behavior.showFiltersBar\") || \"Show per-card filter bar\" }}\r\n </span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"ui()?.behavior?.filtersBarVisible || false\"\r\n (change)=\"onShowFiltersBarChange($any($event.target).checked)\"\r\n />\r\n </label>\r\n <p class=\"db-config-summary__hint\">\r\n {{\r\n t(\"behavior.actionsCount\") ||\r\n ui()?.behavior?.cardActions + \" click action(s) configured\"\r\n }}\r\n ({{ ui()?.behavior?.cardActions || 0 }})\r\n </p>\r\n\r\n <div class=\"db-config-section__actions\">\r\n <mt-button\r\n [label]=\"t('behavior.openAdvanced') || 'Manage card actions'\"\r\n icon=\"general.cursor-click-02\"\r\n severity=\"help\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"openAdvancedEditor('actions')\"\r\n />\r\n </div>\r\n </section>\r\n\r\n <!-- ADVANCED TAB -->\r\n <section\r\n [hidden]=\"activeTab() !== 'advanced'\"\r\n class=\"db-config-section\"\r\n >\r\n <p class=\"db-config-summary__hint\">\r\n {{\r\n t(\"advanced.hint\") ||\r\n \"Edit clientConfig as JSON for fields the controls do not expose. Validated and merged. Invalid JSON is never persisted.\"\r\n }}\r\n </p>\r\n\r\n <mt-schema-control-renderer\r\n [schema]=\"schema()\"\r\n [persisted]=\"persistedConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n\r\n <h4 class=\"db-config-section__title\">\r\n {{ t(\"advanced.json\") || \"Raw clientConfig JSON\" }}\r\n </h4>\r\n <textarea\r\n class=\"db-config-advanced-editor\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"db-config-advanced-editor__error\">\r\n {{ advancedJsonError() }}\r\n </p>\r\n }\r\n <div class=\"db-config-section__actions\">\r\n <mt-button\r\n [label]=\"t('advanced.apply') || 'Apply JSON'\"\r\n icon=\"general.check\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </section>\r\n </main>\r\n\r\n <footer class=\"db-config-popover__footer\">\r\n @if (hasErrors()) {\r\n <span\r\n class=\"db-config-popover__status db-config-popover__status--error\"\r\n >\r\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\r\n {{ t(\"footer.errors\") || \"Resolve the issues above before saving\" }}\r\n </span>\r\n } @else {\r\n <span class=\"db-config-popover__status db-config-popover__status--ok\">\r\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\r\n {{ t(\"footer.ready\") || \"Ready\" }}\r\n </span>\r\n }\r\n <mt-button\r\n [label]=\"t('footer.cancel') || 'Cancel'\"\r\n severity=\"secondary\"\r\n [outlined]=\"true\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('footer.apply') || 'Apply'\"\r\n icon=\"general.check\"\r\n severity=\"primary\"\r\n [disabled]=\"hasErrors()\"\r\n (onClick)=\"apply()\"\r\n />\r\n </footer>\r\n </div>\r\n }\r\n</ng-container>\r\n", styles: [".db-config-popover{display:flex;flex-direction:column;height:100%;width:100%;background:var(--p-surface-0, #fff)}.db-config-popover__header{display:flex;align-items:flex-start;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);gap:.75rem}.db-config-popover__title-row{display:flex;align-items:center;gap:.5rem;min-width:0;flex:1}.db-config-popover__icon{color:var(--p-primary-600, #2563eb);font-size:1.4rem}.db-config-popover__title{display:flex;flex-direction:column;gap:.15rem;min-width:0;flex:1}.db-config-popover__title-input{background:transparent;border:0;border-bottom:1px dashed transparent;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);padding:.05rem 0;width:100%;outline:none}.db-config-popover__title-input:hover{border-bottom-color:var(--p-surface-300, #d1d5db)}.db-config-popover__title-input:focus{border-bottom-color:var(--p-primary-500, #3b82f6)}.db-config-popover__chart-type{font-size:.7rem;color:var(--p-text-muted-color, #6b7280);text-transform:uppercase;letter-spacing:.05em}.db-config-popover__close{flex-shrink:0}.db-config-popover__tabs{border-bottom:1px solid var(--p-surface-200, #e5e7eb);padding:0 1rem}.db-config-popover__main{flex:1 1 0;min-height:0;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:1rem}.db-config-popover__footer{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-0, #fff);position:sticky;bottom:0}.db-config-popover__status{flex:1;display:inline-flex;align-items:center;gap:.4rem;font-size:.8rem}.db-config-popover__status--ok{color:var(--p-green-600, #16a34a)}.db-config-popover__status--error{color:var(--p-amber-600, #d97706)}.db-config-section{display:flex;flex-direction:column;gap:.75rem}.db-config-section__title{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--p-text-muted-color, #6b7280);margin:0}.db-config-section__actions{display:flex;justify-content:flex-end;gap:.5rem;padding-top:.5rem;border-top:1px dashed var(--p-surface-200, #e5e7eb)}.db-config-summary{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.db-config-summary__row{display:grid;grid-template-columns:7rem 1fr;align-items:start;gap:.75rem;font-size:.8rem}.db-config-summary__key{color:var(--p-text-muted-color, #6b7280);font-weight:500}.db-config-summary__value{color:var(--p-text-color, #1f2937);word-break:break-word;display:inline-flex;flex-wrap:wrap;gap:.25rem}.db-config-summary__value--ok{color:var(--p-green-600, #16a34a);font-weight:600}.db-config-summary__value--missing{color:var(--p-amber-600, #d97706);font-weight:600}.db-config-summary__formula{background:var(--p-surface-50, #f9fafb);padding:.25rem .4rem;border-radius:.25rem;font-size:.75rem;word-break:break-all}.db-config-summary__hint{font-size:.78rem;color:var(--p-text-muted-color, #6b7280);margin:0}.db-config-chip{background:var(--p-surface-100, #f3f4f6);border:1px solid var(--p-surface-200, #e5e7eb);padding:.1rem .5rem;border-radius:999px;font-size:.75rem;color:var(--p-text-color, #1f2937)}.db-config-issues{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.25rem}.db-config-issue{display:flex;align-items:center;gap:.4rem;font-size:.78rem;padding:.4rem .55rem;border-radius:.4rem}.db-config-issue i{font-size:.85rem}.db-config-issue[data-severity=error]{color:var(--p-red-700, #b91c1c);background:var(--p-red-50, #fef2f2);border:1px solid var(--p-red-100, #fee2e2)}.db-config-issue[data-severity=warning]{color:var(--p-amber-700, #b45309);background:var(--p-amber-50, #fffbeb);border:1px solid var(--p-amber-100, #fef3c7)}.db-config-issue[data-severity=info]{color:var(--p-blue-700, #1d4ed8);background:var(--p-blue-50, #eff6ff);border:1px solid var(--p-blue-100, #dbeafe)}.db-style-presets{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:.5rem}.db-style-preset{display:flex;flex-direction:column;gap:.2rem;padding:.6rem .7rem;background:var(--p-surface-0, #fff);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.5rem;text-align:left;cursor:pointer;transition:all .12s ease}.db-style-preset:hover{border-color:var(--p-primary-300, #93c5fd);background:var(--p-primary-50, #eff6ff)}.db-style-preset.is-selected{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff);box-shadow:0 0 0 2px var(--p-primary-100, #dbeafe)}.db-style-preset__label{font-size:.85rem;font-weight:600;color:var(--p-text-color, #1f2937)}.db-style-preset__desc{font-size:.72rem;color:var(--p-text-muted-color, #6b7280)}.db-style-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.5rem .75rem}.db-style-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.5rem;font-size:.8rem;color:var(--p-text-color, #1f2937)}.db-style-row input[type=color]{width:2.5rem;height:1.6rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.25rem;cursor:pointer;background:transparent;padding:0}.db-style-row input[type=number]{width:4.5rem;padding:.25rem .4rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.25rem;font-size:.78rem}.db-style-row input[type=checkbox]{width:1rem;height:1rem}.db-style-select{padding:.25rem .4rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.25rem;font-size:.78rem;background:var(--p-surface-0, #fff)}.db-config-section__actions--scope{border-top:0;padding-top:0;justify-content:flex-end}.db-scope-toggle{display:inline-flex;align-items:center;gap:.4rem;padding:.3rem .55rem;font-size:.75rem;border-radius:999px;border:1px solid var(--p-surface-300, #d1d5db);background:var(--p-surface-0, #fff);color:var(--p-text-color, #1f2937);cursor:pointer}.db-scope-toggle:hover{background:var(--p-surface-100, #f3f4f6)}.db-config-advanced-editor{width:100%;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.75rem;padding:.6rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.4rem;background:var(--p-surface-50, #f9fafb);resize:vertical}.db-config-advanced-editor__error{color:var(--p-red-600, #dc2626);font-size:.78rem;margin:0}@media(max-width:768px){.db-config-popover__header{padding:.6rem .75rem}.db-config-popover__main{padding:.75rem}.db-style-grid,.db-style-presets,.db-config-summary__row{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: FilterBuilderComponent, selector: "mt-filter-builder", inputs: ["chips", "persisted"], outputs: ["chipsChange"] }, { kind: "component", type: DatasourcePanelComponent, selector: "mt-datasource-panel", inputs: ["item"], outputs: ["serviceConfigChange", "openAdvanced"] }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
29258
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ItemConfigPopoverComponent, isStandalone: true, selector: "mt-item-config-popover", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder.pass4'\">\r\n @if (item(); as currentItem) {\r\n <div class=\"db-config-popover\">\r\n <header class=\"db-config-popover__header\">\r\n <div class=\"db-config-popover__title-row\">\r\n <mt-icon\r\n [icon]=\"capability()?.icon ?? 'general.settings-02'\"\r\n class=\"db-config-popover__icon\"\r\n />\r\n <div class=\"db-config-popover__title\">\r\n <input\r\n type=\"text\"\r\n class=\"db-config-popover__title-input\"\r\n [ngModel]=\"ui()?.title?.title ?? ''\"\r\n (ngModelChange)=\"onTitleChange($event)\"\r\n [placeholder]=\"t('header.titlePlaceholder') || 'Untitled'\"\r\n />\r\n <span class=\"db-config-popover__chart-type\">\r\n {{ capability()?.name }}\r\n </span>\r\n </div>\r\n </div>\r\n <div class=\"db-config-popover__close\">\r\n <mt-button\r\n icon=\"general.x-close\"\r\n [tooltip]=\"t('header.close') || 'Close'\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n (onClick)=\"cancel()\"\r\n />\r\n </div>\r\n </header>\r\n\r\n <mt-tabs\r\n [options]=\"tabs()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(active)]=\"activeTab\"\r\n class=\"db-config-popover__tabs\"\r\n />\r\n\r\n <main class=\"db-config-popover__main\">\r\n <!-- DATA TAB -->\r\n <section [hidden]=\"activeTab() !== 'data'\" class=\"db-config-section\">\r\n <mt-datasource-panel\r\n [item]=\"currentItem\"\r\n (serviceConfigChange)=\"onServiceConfigPatch($event)\"\r\n (openAdvanced)=\"openAdvancedEditor('dataSource')\"\r\n />\r\n\r\n @if (issuesByDomain().datasource.length) {\r\n <ul class=\"db-config-issues\">\r\n @for (issue of issuesByDomain().datasource; track issue.code) {\r\n <li\r\n class=\"db-config-issue\"\r\n [attr.data-severity]=\"issue.severity\"\r\n >\r\n <i class=\"mti mti-general.alert-circle\"></i>\r\n <span>{{ issue.message }}</span>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n @if (issuesByDomain().fields.length) {\r\n <ul class=\"db-config-issues\">\r\n @for (issue of issuesByDomain().fields; track issue.code) {\r\n <li\r\n class=\"db-config-issue\"\r\n [attr.data-severity]=\"issue.severity\"\r\n >\r\n <i class=\"mti mti-general.alert-circle\"></i>\r\n <span>{{ issue.message }}</span>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </section>\r\n\r\n <!-- FILTERS TAB -->\r\n <section [hidden]=\"activeTab() !== 'filters'\" class=\"db-config-section\">\r\n <mt-filter-builder\r\n [chips]=\"chips()\"\r\n [persisted]=\"currentItem.config\"\r\n (chipsChange)=\"onChipsChange($event)\"\r\n />\r\n @if (issuesByDomain().filters.length) {\r\n <ul class=\"db-config-issues\">\r\n @for (issue of issuesByDomain().filters; track issue.code) {\r\n <li\r\n class=\"db-config-issue\"\r\n [attr.data-severity]=\"issue.severity\"\r\n >\r\n <i class=\"mti mti-general.alert-circle\"></i>\r\n <span>{{ issue.message }}</span>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </section>\r\n\r\n <!-- STYLE TAB -->\r\n <section [hidden]=\"activeTab() !== 'style'\" class=\"db-config-section\">\r\n <h4 class=\"db-config-section__title\">\r\n {{ t(\"style.presets\") || \"Presets\" }}\r\n </h4>\r\n <div class=\"db-style-presets\">\r\n @for (preset of presets(); track preset.key) {\r\n <button\r\n type=\"button\"\r\n class=\"db-style-preset\"\r\n [class.is-selected]=\"selectedPresetKey() === preset.key\"\r\n (click)=\"onApplyPreset(preset)\"\r\n >\r\n <span class=\"db-style-preset__label\">{{ preset.label }}</span>\r\n <span class=\"db-style-preset__desc\">{{\r\n preset.description\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"db-config-section__actions db-config-section__actions--scope\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"db-scope-toggle\"\r\n (click)=\"toggleControlScope()\"\r\n >\r\n <i\r\n [class]=\"\r\n 'mti mti-' +\r\n (controlScope() === 'advanced'\r\n ? 'general.eye'\r\n : 'general.eye-off')\r\n \"\r\n ></i>\r\n <span>\r\n {{\r\n controlScope() === \"advanced\"\r\n ? t(\"controls.simpleMode\") || \"Show simple controls\"\r\n : t(\"controls.advancedMode\") || \"Show all controls\"\r\n }}\r\n </span>\r\n </button>\r\n </div>\r\n\r\n <mt-schema-control-renderer\r\n [schema]=\"schema()\"\r\n [persisted]=\"persistedConfig()\"\r\n [capability]=\"capability()\"\r\n [scope]=\"controlScope()\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n\r\n <div class=\"db-config-section__actions\">\r\n <mt-button\r\n [label]=\"\r\n t('style.openLegacyDrawer') || 'Power user: open legacy drawer'\r\n \"\r\n icon=\"general.settings-02\"\r\n severity=\"secondary\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"openChartSettingsDrawer()\"\r\n />\r\n </div>\r\n </section>\r\n\r\n <!-- BEHAVIOR TAB -->\r\n <section\r\n [hidden]=\"activeTab() !== 'behavior'\"\r\n class=\"db-config-section\"\r\n >\r\n <h4 class=\"db-config-section__title\">\r\n {{ t(\"behavior.title\") || \"Card behavior\" }}\r\n </h4>\r\n <label class=\"db-style-row\">\r\n <span>\r\n {{ t(\"behavior.showFiltersBar\") || \"Show per-card filter bar\" }}\r\n </span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"ui()?.behavior?.filtersBarVisible || false\"\r\n (change)=\"onShowFiltersBarChange($any($event.target).checked)\"\r\n />\r\n </label>\r\n <p class=\"db-config-summary__hint\">\r\n {{\r\n t(\"behavior.actionsCount\") ||\r\n ui()?.behavior?.cardActions + \" click action(s) configured\"\r\n }}\r\n ({{ ui()?.behavior?.cardActions || 0 }})\r\n </p>\r\n\r\n <div class=\"db-config-section__actions\">\r\n <mt-button\r\n [label]=\"t('behavior.openAdvanced') || 'Manage card actions'\"\r\n icon=\"general.cursor-click-02\"\r\n severity=\"help\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"openAdvancedEditor('actions')\"\r\n />\r\n </div>\r\n </section>\r\n\r\n <!-- ADVANCED TAB -->\r\n <section\r\n [hidden]=\"activeTab() !== 'advanced'\"\r\n class=\"db-config-section\"\r\n >\r\n <p class=\"db-config-summary__hint\">\r\n {{\r\n t(\"advanced.hint\") ||\r\n \"Edit clientConfig as JSON for fields the controls do not expose. Validated and merged. Invalid JSON is never persisted.\"\r\n }}\r\n </p>\r\n\r\n <mt-schema-control-renderer\r\n [schema]=\"schema()\"\r\n [persisted]=\"persistedConfig()\"\r\n [capability]=\"capability()\"\r\n scope=\"advanced\"\r\n (patch)=\"onSchemaPatch($event)\"\r\n />\r\n\r\n <h4 class=\"db-config-section__title\">\r\n {{ t(\"advanced.json\") || \"Raw clientConfig JSON\" }}\r\n </h4>\r\n <textarea\r\n class=\"db-config-advanced-editor\"\r\n rows=\"14\"\r\n spellcheck=\"false\"\r\n (focus)=\"initAdvancedJsonIfNeeded()\"\r\n [value]=\"advancedJsonDraft()\"\r\n (input)=\"onAdvancedJsonChange($any($event.target).value)\"\r\n ></textarea>\r\n @if (advancedJsonError()) {\r\n <p class=\"db-config-advanced-editor__error\">\r\n {{ advancedJsonError() }}\r\n </p>\r\n }\r\n <div class=\"db-config-section__actions\">\r\n <mt-button\r\n [label]=\"t('advanced.apply') || 'Apply JSON'\"\r\n icon=\"general.check\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n (onClick)=\"applyAdvancedJson()\"\r\n />\r\n </div>\r\n </section>\r\n </main>\r\n\r\n <footer class=\"db-config-popover__footer\">\r\n @if (hasErrors()) {\r\n <span\r\n class=\"db-config-popover__status db-config-popover__status--error\"\r\n >\r\n <mt-icon icon=\"general.alert-circle\" class=\"text-base\" />\r\n {{ t(\"footer.errors\") || \"Resolve the issues above before saving\" }}\r\n </span>\r\n } @else {\r\n <span class=\"db-config-popover__status db-config-popover__status--ok\">\r\n <mt-icon icon=\"general.check-circle\" class=\"text-base\" />\r\n {{ t(\"footer.ready\") || \"Ready\" }}\r\n </span>\r\n }\r\n <mt-button\r\n [label]=\"t('footer.cancel') || 'Cancel'\"\r\n severity=\"secondary\"\r\n [outlined]=\"true\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('footer.apply') || 'Apply'\"\r\n icon=\"general.check\"\r\n severity=\"primary\"\r\n [disabled]=\"hasErrors()\"\r\n (onClick)=\"apply()\"\r\n />\r\n </footer>\r\n </div>\r\n }\r\n</ng-container>\r\n", styles: [".db-config-popover{display:flex;flex-direction:column;height:100%;width:100%;background:var(--p-surface-0, #fff)}.db-config-popover__header{display:flex;align-items:flex-start;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--p-surface-200, #e5e7eb);gap:.75rem}.db-config-popover__title-row{display:flex;align-items:center;gap:.5rem;min-width:0;flex:1}.db-config-popover__icon{color:var(--p-primary-600, #2563eb);font-size:1.4rem}.db-config-popover__title{display:flex;flex-direction:column;gap:.15rem;min-width:0;flex:1}.db-config-popover__title-input{background:transparent;border:0;border-bottom:1px dashed transparent;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);padding:.05rem 0;width:100%;outline:none}.db-config-popover__title-input:hover{border-bottom-color:var(--p-surface-300, #d1d5db)}.db-config-popover__title-input:focus{border-bottom-color:var(--p-primary-500, #3b82f6)}.db-config-popover__chart-type{font-size:.7rem;color:var(--p-text-muted-color, #6b7280);text-transform:uppercase;letter-spacing:.05em}.db-config-popover__close{flex-shrink:0}.db-config-popover__tabs{border-bottom:1px solid var(--p-surface-200, #e5e7eb);padding:0 1rem}.db-config-popover__main{flex:1 1 0;min-height:0;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:1rem}.db-config-popover__footer{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--p-surface-200, #e5e7eb);background:var(--p-surface-0, #fff);position:sticky;bottom:0}.db-config-popover__status{flex:1;display:inline-flex;align-items:center;gap:.4rem;font-size:.8rem}.db-config-popover__status--ok{color:var(--p-green-600, #16a34a)}.db-config-popover__status--error{color:var(--p-amber-600, #d97706)}.db-config-section{display:flex;flex-direction:column;gap:.75rem}.db-config-section__title{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--p-text-muted-color, #6b7280);margin:0}.db-config-section__actions{display:flex;justify-content:flex-end;gap:.5rem;padding-top:.5rem;border-top:1px dashed var(--p-surface-200, #e5e7eb)}.db-config-summary{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.db-config-summary__row{display:grid;grid-template-columns:7rem 1fr;align-items:start;gap:.75rem;font-size:.8rem}.db-config-summary__key{color:var(--p-text-muted-color, #6b7280);font-weight:500}.db-config-summary__value{color:var(--p-text-color, #1f2937);word-break:break-word;display:inline-flex;flex-wrap:wrap;gap:.25rem}.db-config-summary__value--ok{color:var(--p-green-600, #16a34a);font-weight:600}.db-config-summary__value--missing{color:var(--p-amber-600, #d97706);font-weight:600}.db-config-summary__formula{background:var(--p-surface-50, #f9fafb);padding:.25rem .4rem;border-radius:.25rem;font-size:.75rem;word-break:break-all}.db-config-summary__hint{font-size:.78rem;color:var(--p-text-muted-color, #6b7280);margin:0}.db-config-chip{background:var(--p-surface-100, #f3f4f6);border:1px solid var(--p-surface-200, #e5e7eb);padding:.1rem .5rem;border-radius:999px;font-size:.75rem;color:var(--p-text-color, #1f2937)}.db-config-issues{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.25rem}.db-config-issue{display:flex;align-items:center;gap:.4rem;font-size:.78rem;padding:.4rem .55rem;border-radius:.4rem}.db-config-issue i{font-size:.85rem}.db-config-issue[data-severity=error]{color:var(--p-red-700, #b91c1c);background:var(--p-red-50, #fef2f2);border:1px solid var(--p-red-100, #fee2e2)}.db-config-issue[data-severity=warning]{color:var(--p-amber-700, #b45309);background:var(--p-amber-50, #fffbeb);border:1px solid var(--p-amber-100, #fef3c7)}.db-config-issue[data-severity=info]{color:var(--p-blue-700, #1d4ed8);background:var(--p-blue-50, #eff6ff);border:1px solid var(--p-blue-100, #dbeafe)}.db-style-presets{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:.5rem}.db-style-preset{display:flex;flex-direction:column;gap:.2rem;padding:.6rem .7rem;background:var(--p-surface-0, #fff);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.5rem;text-align:left;cursor:pointer;transition:all .12s ease}.db-style-preset:hover{border-color:var(--p-primary-300, #93c5fd);background:var(--p-primary-50, #eff6ff)}.db-style-preset.is-selected{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff);box-shadow:0 0 0 2px var(--p-primary-100, #dbeafe)}.db-style-preset__label{font-size:.85rem;font-weight:600;color:var(--p-text-color, #1f2937)}.db-style-preset__desc{font-size:.72rem;color:var(--p-text-muted-color, #6b7280)}.db-style-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.5rem .75rem}.db-style-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.5rem;font-size:.8rem;color:var(--p-text-color, #1f2937)}.db-style-row input[type=color]{width:2.5rem;height:1.6rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.25rem;cursor:pointer;background:transparent;padding:0}.db-style-row input[type=number]{width:4.5rem;padding:.25rem .4rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.25rem;font-size:.78rem}.db-style-row input[type=checkbox]{width:1rem;height:1rem}.db-style-select{padding:.25rem .4rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.25rem;font-size:.78rem;background:var(--p-surface-0, #fff)}.db-config-section__actions--scope{border-top:0;padding-top:0;justify-content:flex-end}.db-scope-toggle{display:inline-flex;align-items:center;gap:.4rem;padding:.3rem .55rem;font-size:.75rem;border-radius:999px;border:1px solid var(--p-surface-300, #d1d5db);background:var(--p-surface-0, #fff);color:var(--p-text-color, #1f2937);cursor:pointer}.db-scope-toggle:hover{background:var(--p-surface-100, #f3f4f6)}.db-config-advanced-editor{width:100%;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.75rem;padding:.6rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.4rem;background:var(--p-surface-50, #f9fafb);resize:vertical}.db-config-advanced-editor__error{color:var(--p-red-600, #dc2626);font-size:.78rem;margin:0}@media(max-width:768px){.db-config-popover__header{padding:.6rem .75rem}.db-config-popover__main{padding:.75rem}.db-style-grid,.db-style-presets,.db-config-summary__row{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: FilterBuilderComponent, selector: "mt-filter-builder", inputs: ["chips", "persisted"], outputs: ["chipsChange"] }, { kind: "component", type: DatasourcePanelComponent, selector: "mt-datasource-panel", inputs: ["item"], outputs: ["serviceConfigChange", "openAdvanced"] }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
29321
29259
  }
29322
29260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ItemConfigPopoverComponent, decorators: [{
29323
29261
  type: Component,
@@ -29931,7 +29869,7 @@ class GuidedConfigDialogComponent {
29931
29869
  </div>
29932
29870
  }
29933
29871
  </ng-container>
29934
- `, isInline: true, styles: [":host{display:block}.db-guided{display:flex;flex-direction:column;gap:.75rem;background:var(--p-surface-0, #fff);border-radius:.75rem;max-height:80vh}.db-guided__header{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:1rem 1.25rem .5rem}.db-guided__heading{display:flex;align-items:center;gap:.75rem}.db-guided__heading-icon{font-size:1.5rem;color:var(--p-primary-500, #2563eb)}.db-guided__title{margin:0;font-size:1rem;font-weight:700}.db-guided__subtitle{margin:0;font-size:.75rem;color:var(--p-text-muted-color, #6b7280)}.db-guided__progress{height:3px;background:var(--p-surface-100, #f3f4f6);border-radius:3px;margin:0 1.25rem;overflow:hidden}.db-guided__progress-bar{height:100%;background:var(--p-primary-500, #2563eb);transition:width .22s ease}.db-guided__stepper{padding:0 1.25rem}.db-guided__main{flex:1;overflow-y:auto;padding:1rem 1.25rem;min-height:240px}.db-guided__section{display:flex;flex-direction:column;gap:.75rem}.db-guided__section-title{margin:0;font-size:.95rem;font-weight:700}.db-guided__section-hint{margin:0;font-size:.8rem;line-height:1.45;color:var(--p-text-muted-color, #6b7280)}.db-guided__summary{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.4rem}.db-guided__summary-title{margin:.5rem 0 0;font-size:.85rem;font-weight:600}.db-guided__summary-chip--ok .p-chip{background:var(--p-green-50, #f0fdf4);border-color:var(--p-green-200, #bbf7d0);color:var(--p-green-700, #15803d)}.db-guided__summary-chip--missing .p-chip{background:var(--p-amber-50, #fffbeb);border-color:var(--p-amber-200, #fde68a);color:var(--p-amber-700, #b45309)}.db-guided__title-field{display:block;margin-top:.75rem}.db-guided__issues{list-style:none;padding:0;margin:.75rem 0 0;display:flex;flex-direction:column;gap:.4rem}.db-guided__issue{display:flex;align-items:center;gap:.4rem;padding:.5rem .75rem;font-size:.8rem;background:var(--p-amber-50, #fffbeb);border:1px solid var(--p-amber-200, #fde68a);border-radius:.5rem;color:var(--p-amber-700, #b45309)}.db-guided__issue[data-severity=error]{background:var(--p-red-50, #fef2f2);border-color:var(--p-red-200, #fecaca);color:var(--p-red-700, #b91c1c)}.db-guided__advanced-json{margin-top:1rem;background:var(--p-surface-50, #f9fafb);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.5rem;padding:.75rem}.db-guided__advanced-json summary{cursor:pointer;font-weight:600;font-size:.85rem}.db-guided__advanced-json-editor{width:100%;margin-top:.5rem;font-family:ui-monospace,SFMono-Regular,monospace;font-size:.75rem;padding:.6rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.4rem;background:var(--p-surface-0, #fff)}.db-guided__advanced-json-error{color:var(--p-red-600, #dc2626);font-size:.75rem;margin:.4rem 0 0}.db-guided__advanced-json-actions{display:flex;justify-content:flex-end;margin-top:.5rem}.db-guided__footer{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.75rem 1.25rem 1rem;border-top:1px solid var(--p-surface-200, #e5e7eb)}.db-guided__footer-actions{display:flex;align-items:center;gap:.5rem}.db-guided__state-chip--info .p-chip{background:var(--p-blue-50, #eff6ff);border-color:var(--p-blue-200, #bfdbfe);color:var(--p-blue-700, #1d4ed8)}.db-guided__state-chip--warn .p-chip{background:var(--p-amber-50, #fffbeb);border-color:var(--p-amber-200, #fde68a);color:var(--p-amber-700, #b45309)}.db-guided__state-chip--error .p-chip{background:var(--p-red-50, #fef2f2);border-color:var(--p-red-200, #fecaca);color:var(--p-red-700, #b91c1c)}.db-guided__state-chip--success .p-chip{background:var(--p-green-50, #f0fdf4);border-color:var(--p-green-200, #bbf7d0);color:var(--p-green-700, #15803d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Chip, selector: "mt-chip", inputs: ["label", "icon", "image", "removable", "removeIcon", "styleClass"], outputs: ["onRemove", "onImageError"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: FilterBuilderComponent, selector: "mt-filter-builder", inputs: ["chips", "persisted"], outputs: ["chipsChange"] }, { kind: "component", type: DatasourcePanelComponent, selector: "mt-datasource-panel", inputs: ["item"], outputs: ["serviceConfigChange", "openAdvanced"] }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
29872
+ `, isInline: true, styles: [":host{display:block}.db-guided{display:flex;flex-direction:column;gap:.75rem;background:var(--p-surface-0, #fff);border-radius:.75rem;max-height:80vh}.db-guided__header{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:1rem 1.25rem .5rem}.db-guided__heading{display:flex;align-items:center;gap:.75rem}.db-guided__heading-icon{font-size:1.5rem;color:var(--p-primary-500, #2563eb)}.db-guided__title{margin:0;font-size:1rem;font-weight:700}.db-guided__subtitle{margin:0;font-size:.75rem;color:var(--p-text-muted-color, #6b7280)}.db-guided__progress{height:3px;background:var(--p-surface-100, #f3f4f6);border-radius:3px;margin:0 1.25rem;overflow:hidden}.db-guided__progress-bar{height:100%;background:var(--p-primary-500, #2563eb);transition:width .22s ease}.db-guided__stepper{padding:0 1.25rem}.db-guided__main{flex:1;overflow-y:auto;padding:1rem 1.25rem;min-height:240px}.db-guided__section{display:flex;flex-direction:column;gap:.75rem}.db-guided__section-title{margin:0;font-size:.95rem;font-weight:700}.db-guided__section-hint{margin:0;font-size:.8rem;line-height:1.45;color:var(--p-text-muted-color, #6b7280)}.db-guided__summary{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.4rem}.db-guided__summary-title{margin:.5rem 0 0;font-size:.85rem;font-weight:600}.db-guided__summary-chip--ok .p-chip{background:var(--p-green-50, #f0fdf4);border-color:var(--p-green-200, #bbf7d0);color:var(--p-green-700, #15803d)}.db-guided__summary-chip--missing .p-chip{background:var(--p-amber-50, #fffbeb);border-color:var(--p-amber-200, #fde68a);color:var(--p-amber-700, #b45309)}.db-guided__title-field{display:block;margin-top:.75rem}.db-guided__issues{list-style:none;padding:0;margin:.75rem 0 0;display:flex;flex-direction:column;gap:.4rem}.db-guided__issue{display:flex;align-items:center;gap:.4rem;padding:.5rem .75rem;font-size:.8rem;background:var(--p-amber-50, #fffbeb);border:1px solid var(--p-amber-200, #fde68a);border-radius:.5rem;color:var(--p-amber-700, #b45309)}.db-guided__issue[data-severity=error]{background:var(--p-red-50, #fef2f2);border-color:var(--p-red-200, #fecaca);color:var(--p-red-700, #b91c1c)}.db-guided__advanced-json{margin-top:1rem;background:var(--p-surface-50, #f9fafb);border:1px solid var(--p-surface-200, #e5e7eb);border-radius:.5rem;padding:.75rem}.db-guided__advanced-json summary{cursor:pointer;font-weight:600;font-size:.85rem}.db-guided__advanced-json-editor{width:100%;margin-top:.5rem;font-family:ui-monospace,SFMono-Regular,monospace;font-size:.75rem;padding:.6rem;border:1px solid var(--p-surface-300, #d1d5db);border-radius:.4rem;background:var(--p-surface-0, #fff)}.db-guided__advanced-json-error{color:var(--p-red-600, #dc2626);font-size:.75rem;margin:.4rem 0 0}.db-guided__advanced-json-actions{display:flex;justify-content:flex-end;margin-top:.5rem}.db-guided__footer{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.75rem 1.25rem 1rem;border-top:1px solid var(--p-surface-200, #e5e7eb)}.db-guided__footer-actions{display:flex;align-items:center;gap:.5rem}.db-guided__state-chip--info .p-chip{background:var(--p-blue-50, #eff6ff);border-color:var(--p-blue-200, #bfdbfe);color:var(--p-blue-700, #1d4ed8)}.db-guided__state-chip--warn .p-chip{background:var(--p-amber-50, #fffbeb);border-color:var(--p-amber-200, #fde68a);color:var(--p-amber-700, #b45309)}.db-guided__state-chip--error .p-chip{background:var(--p-red-50, #fef2f2);border-color:var(--p-red-200, #fecaca);color:var(--p-red-700, #b91c1c)}.db-guided__state-chip--success .p-chip{background:var(--p-green-50, #f0fdf4);border-color:var(--p-green-200, #bbf7d0);color:var(--p-green-700, #15803d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Chip, selector: "mt-chip", inputs: ["label", "icon", "image", "removable", "removeIcon", "styleClass"], outputs: ["onRemove", "onImageError"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: FilterBuilderComponent, selector: "mt-filter-builder", inputs: ["chips", "persisted"], outputs: ["chipsChange"] }, { kind: "component", type: DatasourcePanelComponent, selector: "mt-datasource-panel", inputs: ["item"], outputs: ["serviceConfigChange", "openAdvanced"] }, { kind: "component", type: SchemaControlRendererComponent, selector: "mt-schema-control-renderer", inputs: ["schema", "persisted", "capability", "scope"], outputs: ["patch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
29935
29873
  }
29936
29874
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GuidedConfigDialogComponent, decorators: [{
29937
29875
  type: Component,
@@ -30772,7 +30710,7 @@ class WidgetPaletteComponent {
30772
30710
  this.ref?.close(null);
30773
30711
  }
30774
30712
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WidgetPaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
30775
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WidgetPaletteComponent, isStandalone: true, selector: "mt-widget-palette", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Content -->\r\n <div class=\"flex flex-col gap-4 p-4\" [class]=\"modal.contentClass\">\r\n <!-- Search -->\r\n <mt-text-field\r\n [placeholder]=\"t('widgetPalette.searchPlaceholder')\"\r\n [icon]=\"'general.search-lg'\"\r\n [(value)]=\"searchTerm\"\r\n />\r\n\r\n <!-- Category Tabs -->\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabOptions()\"\r\n size=\"small\"\r\n fluid\r\n />\r\n\r\n <!-- Widgets Grid -->\r\n <div class=\"flex-1 overflow-y-auto\">\r\n <div class=\"grid grid-cols-3 gap-3\">\r\n @for (widget of widgets(); track widget.id) {\r\n <div\r\n class=\"flex flex-col items-center justify-center gap-2 p-4 rounded-lg cursor-pointer border border-surface-200 bg-white select-none transition-all hover:border-primary-400 hover:shadow-md hover:bg-primary-50\"\r\n draggable=\"true\"\r\n (dragstart)=\"onDragStart($event, widget)\"\r\n (click)=\"onWidgetClick(widget)\"\r\n [title]=\"widget.name\"\r\n >\r\n <div\r\n class=\"w-10 h-10 flex items-center justify-center text-primary-500\"\r\n >\r\n <mt-icon [icon]=\"widget.icon\" class=\"text-2xl\" />\r\n </div>\r\n <span\r\n class=\"text-xs font-medium text-color text-center leading-tight\"\r\n >{{ widget.name }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (widgets().length === 0) {\r\n <div class=\"p-8 text-center text-muted-color\">\r\n <mt-icon icon=\"general.search-lg\" class=\"text-3xl mb-2\" />\r\n <p>{{ t(\"widgetPalette.noResults\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hint -->\r\n <div\r\n class=\"text-xs text-muted-color text-center py-2 border-t border-surface-200\"\r\n >\r\n {{ t(\"widgetPalette.dragHint\") }}\r\n </div>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
30713
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WidgetPaletteComponent, isStandalone: true, selector: "mt-widget-palette", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'dashboardBuilder'\">\r\n <!-- Content -->\r\n <div class=\"flex flex-col gap-4 p-4\" [class]=\"modal.contentClass\">\r\n <!-- Search -->\r\n <mt-text-field\r\n [placeholder]=\"t('widgetPalette.searchPlaceholder')\"\r\n [icon]=\"'general.search-lg'\"\r\n [(value)]=\"searchTerm\"\r\n />\r\n\r\n <!-- Category Tabs -->\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabOptions()\"\r\n size=\"small\"\r\n fluid\r\n />\r\n\r\n <!-- Widgets Grid -->\r\n <div class=\"flex-1 overflow-y-auto\">\r\n <div class=\"grid grid-cols-3 gap-3\">\r\n @for (widget of widgets(); track widget.id) {\r\n <div\r\n class=\"flex flex-col items-center justify-center gap-2 p-4 rounded-lg cursor-pointer border border-surface-200 bg-white select-none transition-all hover:border-primary-400 hover:shadow-md hover:bg-primary-50\"\r\n draggable=\"true\"\r\n (dragstart)=\"onDragStart($event, widget)\"\r\n (click)=\"onWidgetClick(widget)\"\r\n [title]=\"widget.name\"\r\n >\r\n <div\r\n class=\"w-10 h-10 flex items-center justify-center text-primary-500\"\r\n >\r\n <mt-icon [icon]=\"widget.icon\" class=\"text-2xl\" />\r\n </div>\r\n <span\r\n class=\"text-xs font-medium text-color text-center leading-tight\"\r\n >{{ widget.name }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (widgets().length === 0) {\r\n <div class=\"p-8 text-center text-muted-color\">\r\n <mt-icon icon=\"general.search-lg\" class=\"text-3xl mb-2\" />\r\n <p>{{ t(\"widgetPalette.noResults\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hint -->\r\n <div\r\n class=\"text-xs text-muted-color text-center py-2 border-t border-surface-200\"\r\n >\r\n {{ t(\"widgetPalette.dragHint\") }}\r\n </div>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button [label]=\"t('cancel')\" variant=\"outlined\" (onClick)=\"close()\" />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
30776
30714
  }
30777
30715
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WidgetPaletteComponent, decorators: [{
30778
30716
  type: Component,
@@ -32314,7 +32252,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
32314
32252
  Page,
32315
32253
  ContextMenuModule,
32316
32254
  FilterByGroupPipe,
32317
- GetChartActionsPipe,
32318
32255
  DashboardItem,
32319
32256
  ItemCardMenuComponent,
32320
32257
  ], 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 [attr.data-chart-id]=\"chart.config?.serviceConfig?.dashboardId\"\r\n (click)=\"onSelect(chart, $event)\"\r\n >\r\n <!-- Chart Content -->\r\n <div class=\"h-full w-full relative group\">\r\n <!-- Drag Handle -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"drag-handler absolute top-0 left-0 right-0 h-6 cursor-move bg-gradient-to-b from-black/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center z-10\"\r\n >\r\n <i\r\n class=\"mti mti-grip-horizontal text-white/70 text-sm\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!--\r\n Pass 7 \u2014 Single top-end Manage menu per chart card.\r\n Layout widgets (header/topbar/group) keep their dedicated\r\n affordances; chart cards have **only** the kebab.\r\n -->\r\n @if (!readonly()) {\r\n <div\r\n class=\"db-card-actions absolute top-1 end-1 flex items-center gap-1 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity z-20\"\r\n >\r\n <!-- Single kebab for chart cards (Pass 7 sole owner). -->\r\n @if (showContextToolbar(chart)) {\r\n <mt-item-card-menu\r\n [allowDuplicate]=\"true\"\r\n [hasLinkedDialog]=\"hasLinkedDialog(chart)\"\r\n [canLinkDialog]=\"canLinkDialog(chart)\"\r\n (action)=\"onItemCardMenuAction(chart, $event)\"\r\n />\r\n }\r\n\r\n <!-- Topbar: breadcrumb editor (layout-specific). -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"general.slash-divider\"\r\n [tooltip]=\"t('manageBreadcrumb')\"\r\n (onClick)=\"openBreadcrumb(chart)\"\r\n severity=\"info\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n <!--\r\n Header / topbar \u2014 quick style + delete.\r\n These widgets don't have a datasource so they don't\r\n use the chart kebab; the affordances stay minimal.\r\n -->\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"header\" ||\r\n chart.config?.clientConfig?.componentName === \"topbar\"\r\n ) {\r\n <mt-button\r\n icon=\"editor.palette\"\r\n [tooltip]=\"t('actions.style')\"\r\n (onClick)=\"openQuickManage($event, chart)\"\r\n severity=\"primary\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('actions.delete')\"\r\n (onClick)=\"deleteItem(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n\r\n @if (\r\n chart.config?.clientConfig?.componentName === \"Group\"\r\n ) {\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('removeGroup')\"\r\n (onClick)=\"removeGroup(chart)\"\r\n severity=\"danger\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chart Rendering -->\r\n @if (!chart.loading) {\r\n <mt-dashboard-item\r\n [config]=\"chart.config\"\r\n [chartTypeId]=\"chart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"configureChart(chart)\"\r\n (titleEdited)=\"onChartTitleEdited(chart, $event)\"\r\n />\r\n } @else {\r\n <div class=\"flex items-center justify-center h-full\">\r\n <i\r\n class=\"mti mti-spinner-third mti-spin text-2xl text-primary\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n <!-- Group Children -->\r\n @if (chart.config?.clientConfig?.componentName === \"Group\") {\r\n <div class=\"h-full flex flex-col p-2\">\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n @if (idx === chart.selectedGroupIndex) {\r\n <div class=\"flex-1 min-h-0\">\r\n <mt-dashboard-item\r\n [config]=\"childChart.config\"\r\n [chartTypeId]=\"childChart.chartTypeId\"\r\n [readonly]=\"readonly()\"\r\n [builderMode]=\"!readonly()\"\r\n [extraFilters]=\"extraFilters()\"\r\n [pageName]=\"\r\n pageConfig()?.name?.[languageCode()] ||\r\n pageConfig()?.name?.['en'] ||\r\n pageConfig()?.name?.['ar'] ||\r\n ''\r\n \"\r\n (configureRequested)=\"\r\n editItem(childChart, chart, 'dataSource')\r\n \"\r\n (titleEdited)=\"\r\n onChartTitleEdited(childChart, $event)\r\n \"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Group Tabs -->\r\n <div\r\n class=\"absolute bottom-0 left-0 right-0 flex gap-1 p-1 bg-surface-100 rounded-b-lg overflow-x-auto\"\r\n >\r\n @for (\r\n childChart of charts()\r\n | filterByGroup\r\n : chart.config?.serviceConfig?.dashboardId;\r\n track childChart.config?.serviceConfig?.dashboardId;\r\n let idx = $index\r\n ) {\r\n <mt-button\r\n [label]=\"\r\n childChart.config?.clientConfig?.title?.[\r\n languageCode()\r\n ] ||\r\n childChart.config?.clientConfig?.title?.['en'] ||\r\n 'Chart ' + (idx + 1)\r\n \"\r\n [severity]=\"\r\n idx === chart.selectedGroupIndex\r\n ? 'primary'\r\n : 'secondary'\r\n \"\r\n [text]=\"idx !== chart.selectedGroupIndex\"\r\n size=\"small\"\r\n (onClick)=\"chart.selectedGroupIndex = idx\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </gridster-item>\r\n }\r\n </gridster>\r\n\r\n <!-- Context Menu -->\r\n <p-contextMenu #contextMenu [model]=\"menuItems()\" appendTo=\"body\" />\r\n }\r\n\r\n <!-- Empty State -->\r\n @if (!loading() && !pageConfig()) {\r\n <div\r\n class=\"flex flex-col items-center justify-center h-64 text-muted-color\"\r\n >\r\n <i class=\"mti mti-layout text-6xl mb-4\"></i>\r\n <p class=\"text-lg\">{{ t(\"noPageSelected\") }}</p>\r\n <p class=\"text-sm\">{{ t(\"selectPageToStart\") }}</p>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [":host{display:block;height:100%}gridster{min-height:calc(100vh - 120px);height:100%}gridster .gridster-column{border-left:1px solid var(--p-primary-100)!important;border-right:1px solid var(--p-primary-100)!important}gridster .gridster-row{border-top:1px solid var(--p-primary-100)!important;border-bottom:1px solid var(--p-primary-100)!important}gridster.is-page{min-height:calc(100vh - 200px)}.mti-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gridster-drop-indicator{position:absolute;background:var(--p-primary-100);border:2px dashed var(--p-primary-400);border-radius:8px;pointer-events:none;z-index:100}.db-card-actions{pointer-events:auto;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.25rem;max-width:calc(100% - 2.5rem)}@media(max-width:640px){.db-card-actions{top:.25rem;right:.25rem}}.db-card-title-edit{background:transparent;border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.375rem;padding:.25rem .5rem;font-size:.95rem;font-weight:600;color:var(--p-text-color, #1f2937);text-align:center;width:min(100%,22rem);outline:none}.db-card-title-edit:focus{border-color:var(--p-primary-500, #3b82f6);background:var(--p-primary-50, #eff6ff)}.mt-item-config-popover-host .p-dialog-content{padding:0!important;height:clamp(420px,70vh,720px);max-height:80vh}.mt-item-config-popover-host .p-dialog-header{display:none}@media(max-width:768px){.mt-item-config-popover-host{width:100%!important;max-width:100%!important;margin:0!important;inset:auto 0 0!important;border-radius:1rem 1rem 0 0!important;transform:none!important}.mt-item-config-popover-host .p-dialog-content{height:80vh;border-radius:1rem 1rem 0 0}}.db-context-popover{--p-popover-content-padding: .4rem;min-width:200px}\n"] }]
@@ -33186,6 +33123,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
33186
33123
  * Dashboard List Module Index
33187
33124
  */
33188
33125
 
33126
+ /**
33127
+ * Get dialog actions for a chart
33128
+ *
33129
+ * Returns menu items for dialog management (add, edit, delete)
33130
+ * Used in the "Advanced" popover menu
33131
+ */
33132
+ class GetChartActionsPipe {
33133
+ transloco = inject(TranslocoService);
33134
+ transform(chart, context) {
33135
+ if (!chart?.config?.clientConfig || !context) {
33136
+ return [];
33137
+ }
33138
+ const clientConfig = chart.config.clientConfig;
33139
+ const t = (key) => this.transloco.translate(`dashboardBuilder.${key}`);
33140
+ // Only return dialog actions for regular charts (not header, topbar, Group)
33141
+ if (clientConfig.componentName === 'topbar' ||
33142
+ clientConfig.componentName === 'header' ||
33143
+ clientConfig.componentName === 'Group') {
33144
+ return [];
33145
+ }
33146
+ const hasDialog = clientConfig.actions?.[0]?.actionType === 'openDialog' &&
33147
+ !clientConfig.filter?.configs?.length;
33148
+ const items = [];
33149
+ // Add Dialog - only show if no dialog exists
33150
+ if (!hasDialog) {
33151
+ items.push({
33152
+ label: t('addDialog'),
33153
+ icon: 'general.plus',
33154
+ command: () => context.addDialogForChart(chart),
33155
+ });
33156
+ }
33157
+ // Edit Dialog - only show if dialog exists
33158
+ if (hasDialog) {
33159
+ items.push({
33160
+ label: t('editDialog'),
33161
+ icon: 'general.edit-05',
33162
+ command: () => context.editOnDialogForChart(chart),
33163
+ });
33164
+ }
33165
+ // Delete Dialog - only show if dialog exists
33166
+ if (hasDialog) {
33167
+ items.push({
33168
+ label: t('deleteDialog'),
33169
+ icon: 'general.trash-01',
33170
+ severity: 'danger',
33171
+ command: () => context.deleteDialogFromChart(chart),
33172
+ });
33173
+ }
33174
+ return items;
33175
+ }
33176
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GetChartActionsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
33177
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.8", ngImport: i0, type: GetChartActionsPipe, isStandalone: true, name: "getChartActions" });
33178
+ }
33179
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: GetChartActionsPipe, decorators: [{
33180
+ type: Pipe,
33181
+ args: [{
33182
+ name: 'getChartActions',
33183
+ standalone: true,
33184
+ pure: true,
33185
+ }]
33186
+ }] });
33187
+
33189
33188
  /**
33190
33189
  * Public API Surface of @masterteam/dashboard-builder
33191
33190
  *