@meshmakers/octo-meshboard 3.3.690 → 3.3.700
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.
|
@@ -5,14 +5,14 @@ import { Injectable, inject, EventEmitter, forwardRef, Output, Input, ViewChild,
|
|
|
5
5
|
import * as i1$1 from '@angular/forms';
|
|
6
6
|
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
7
7
|
import { firstValueFrom, from, map, Observable, of, catchError, interval, filter } from 'rxjs';
|
|
8
|
-
import * as i1$
|
|
8
|
+
import * as i1$8 from '@meshmakers/shared-ui';
|
|
9
9
|
import { EntitySelectInputComponent, WindowStateService, ListViewComponent, FetchResultTyped, DataSourceBase, TimeRangePickerComponent, ImportStrategyDialogService, TimeRangeUtils, HAS_UNSAVED_CHANGES, UnsavedChangesDirective } from '@meshmakers/shared-ui';
|
|
10
10
|
import * as i1 from 'apollo-angular';
|
|
11
11
|
import { gql, Apollo } from 'apollo-angular';
|
|
12
12
|
import * as i1$3 from '@angular/common';
|
|
13
13
|
import { CommonModule } from '@angular/common';
|
|
14
14
|
import { CkTypeSelectorInputComponent, FieldFilterEditorComponent, AttributeValueTypeDto, PropertyGridComponent, OctoGraphQlDataSource, AttributeSelectorDialogService, AttributeSortSelectorDialogService } from '@meshmakers/octo-ui';
|
|
15
|
-
import * as i1$
|
|
15
|
+
import * as i1$5 from '@progress/kendo-angular-dialog';
|
|
16
16
|
import { WindowService, WindowCloseResult, WindowRef, DialogsModule, DialogRef, DialogModule, DialogService } from '@progress/kendo-angular-dialog';
|
|
17
17
|
import * as i2 from '@progress/kendo-angular-buttons';
|
|
18
18
|
import { ButtonsModule, ButtonModule } from '@progress/kendo-angular-buttons';
|
|
@@ -20,27 +20,27 @@ import * as i3 from '@progress/kendo-angular-inputs';
|
|
|
20
20
|
import { InputsModule, CheckBoxModule, NumericTextBoxModule, TextBoxModule, FormFieldModule } from '@progress/kendo-angular-inputs';
|
|
21
21
|
import * as i1$2 from '@progress/kendo-angular-indicators';
|
|
22
22
|
import { LoaderModule } from '@progress/kendo-angular-indicators';
|
|
23
|
-
import * as
|
|
23
|
+
import * as i1$4 from '@progress/kendo-angular-icons';
|
|
24
24
|
import { SVGIconModule } from '@progress/kendo-angular-icons';
|
|
25
|
-
import { arrowUpIcon, arrowDownIcon, minusIcon, arrowRightIcon, arrowLeftIcon, linkIcon, chevronDownIcon, chevronRightIcon, columnsIcon, sortAscIcon, filterIcon, searchIcon, chartPieIcon, plusIcon, trashIcon, pencilIcon,
|
|
25
|
+
import { arrowUpIcon, arrowDownIcon, minusIcon, arrowRightIcon, arrowLeftIcon, linkIcon, chevronDownIcon, chevronRightIcon, circleIcon, questionCircleIcon, minusCircleIcon, warningTriangleIcon, exclamationCircleIcon, xCircleIcon, checkCircleIcon, columnsIcon, sortAscIcon, filterIcon, searchIcon, chartPieIcon, infoCircleIcon, plusIcon, trashIcon, pencilIcon, chartLineIcon, gearsIcon, clipboardMarkdownIcon, copyIcon, gridIcon, heartIcon, gridLayoutIcon, chartLineMarkersIcon, chartColumnStackedIcon, chartDoughnutIcon, tableIcon, shareIcon, fileTxtIcon, checkIcon, xIcon, downloadIcon, uploadIcon, gearIcon, saveIcon, arrowRotateCwIcon, undoIcon } from '@progress/kendo-svg-icons';
|
|
26
26
|
import * as i4 from '@progress/kendo-angular-dropdowns';
|
|
27
27
|
import { DropDownsModule, DropDownListModule } from '@progress/kendo-angular-dropdowns';
|
|
28
28
|
import { map as map$1, catchError as catchError$1 } from 'rxjs/operators';
|
|
29
29
|
import { NotificationService } from '@progress/kendo-angular-notification';
|
|
30
|
-
import * as i1$
|
|
30
|
+
import * as i1$6 from '@progress/kendo-angular-gauges';
|
|
31
31
|
import { CollectionChangesService, KENDO_GAUGES } from '@progress/kendo-angular-gauges';
|
|
32
|
-
import * as i1$
|
|
32
|
+
import * as i1$7 from '@progress/kendo-angular-charts';
|
|
33
33
|
import { ChartsModule } from '@progress/kendo-angular-charts';
|
|
34
34
|
import * as i3$1 from '@angular/router';
|
|
35
35
|
import { Router, ActivatedRoute, NavigationEnd, RouterModule } from '@angular/router';
|
|
36
|
-
import * as i2$
|
|
36
|
+
import * as i2$1 from 'ngx-markdown';
|
|
37
37
|
import { MarkdownModule } from 'ngx-markdown';
|
|
38
|
+
import * as i4$1 from '@progress/kendo-angular-label';
|
|
39
|
+
import { LabelModule, KENDO_LABELS } from '@progress/kendo-angular-label';
|
|
38
40
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
39
41
|
import { GetProcessDiagramDtoGQL, GetProcessDiagramsDtoGQL, CreateProcessDiagramDtoGQL, UpdateProcessDiagramDtoGQL, SymbolLibraryService, ExpressionEvaluatorService, renderAnimations, getFlowParticlesAnimation, renderFlowParticles } from '@meshmakers/octo-process-diagrams';
|
|
40
42
|
import * as i5 from '@progress/kendo-angular-layout';
|
|
41
43
|
import { LayoutModule, TabStripModule, TileLayoutModule } from '@progress/kendo-angular-layout';
|
|
42
|
-
import * as i4$1 from '@progress/kendo-angular-label';
|
|
43
|
-
import { LabelModule, KENDO_LABELS } from '@progress/kendo-angular-label';
|
|
44
44
|
import * as i4$2 from '@progress/kendo-angular-dateinputs';
|
|
45
45
|
import { DatePickerModule, DateTimePickerModule } from '@progress/kendo-angular-dateinputs';
|
|
46
46
|
import { BreadCrumbService } from '@meshmakers/shared-services';
|
|
@@ -1120,6 +1120,7 @@ class WidgetRegistryService {
|
|
|
1120
1120
|
* Builds base configuration from persisted data.
|
|
1121
1121
|
*/
|
|
1122
1122
|
buildBaseConfig(data) {
|
|
1123
|
+
const parsedConfig = data.config ? (typeof data.config === 'string' ? JSON.parse(data.config) : data.config) : {};
|
|
1123
1124
|
return {
|
|
1124
1125
|
id: data.rtId,
|
|
1125
1126
|
title: data.name,
|
|
@@ -1127,7 +1128,8 @@ class WidgetRegistryService {
|
|
|
1127
1128
|
row: data.row,
|
|
1128
1129
|
colSpan: data.colSpan,
|
|
1129
1130
|
rowSpan: data.rowSpan,
|
|
1130
|
-
configurable: true
|
|
1131
|
+
configurable: true,
|
|
1132
|
+
chromeless: parsedConfig['chromeless'] === true ? true : undefined
|
|
1131
1133
|
};
|
|
1132
1134
|
}
|
|
1133
1135
|
/**
|
|
@@ -1549,7 +1551,10 @@ class MeshBoardPersistenceService {
|
|
|
1549
1551
|
dataSourceType,
|
|
1550
1552
|
dataSourceCkTypeId: persistenceData.dataSourceCkTypeId ?? '',
|
|
1551
1553
|
dataSourceRtId: persistenceData.dataSourceRtId ?? '',
|
|
1552
|
-
config: JSON.stringify(
|
|
1554
|
+
config: JSON.stringify({
|
|
1555
|
+
...persistenceData.config,
|
|
1556
|
+
...(widget.chromeless ? { chromeless: true } : {})
|
|
1557
|
+
})
|
|
1553
1558
|
};
|
|
1554
1559
|
// Only include parent if there are association changes
|
|
1555
1560
|
if (parentAssociations.length > 0) {
|
|
@@ -4019,6 +4024,12 @@ class KpiWidgetComponent {
|
|
|
4019
4024
|
default: return 'trend-neutral';
|
|
4020
4025
|
}
|
|
4021
4026
|
}, ...(ngDevMode ? [{ debugName: "trendClass" }] : /* istanbul ignore next */ []));
|
|
4027
|
+
comparisonText = computed(() => {
|
|
4028
|
+
if (!this.config?.comparisonText)
|
|
4029
|
+
return null;
|
|
4030
|
+
const variables = this.stateService.getVariables();
|
|
4031
|
+
return this.variableService.resolveVariables(this.config.comparisonText, variables);
|
|
4032
|
+
}, ...(ngDevMode ? [{ debugName: "comparisonText" }] : /* istanbul ignore next */ []));
|
|
4022
4033
|
ngOnInit() {
|
|
4023
4034
|
this.loadData();
|
|
4024
4035
|
}
|
|
@@ -4265,11 +4276,11 @@ class KpiWidgetComponent {
|
|
|
4265
4276
|
return this.variableService.convertToFieldFilterDto(filters, variables);
|
|
4266
4277
|
}
|
|
4267
4278
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: KpiWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4268
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: KpiWidgetComponent, isStandalone: true, selector: "mm-kpi-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"kpi-widget\" [class.loading]=\"isLoading()\" [class.error]=\"error()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured></mm-widget-not-configured>\n } @else if (isLoading()) {\n <div class=\"loading-indicator\">\n <span>...</span>\n </div>\n } @else if (error()) {\n <div class=\"error-message\">\n <span>{{ error() }}</span>\n </div>\n } @else {\n <div class=\"kpi-content\">\n <div class=\"kpi-value-container\">\n @if (config.prefix) {\n <span class=\"kpi-prefix\">{{ config.prefix }}</span>\n }\n <span class=\"kpi-value\">{{ value() }}</span>\n @if (config.suffix) {\n <span class=\"kpi-suffix\">{{ config.suffix }}</span>\n }\n </div>\n\n @if (label()) {\n <div class=\"kpi-label\">{{ label() }}</div>\n }\n </div>\n\n @if (config.trend) {\n <div class=\"kpi-trend\" [ngClass]=\"trendClass()\">\n <kendo-svg-icon [icon]=\"trendIcon()\" size=\"medium\"></kendo-svg-icon>\n </div>\n }\n }\n</div>\n", styles: [".kpi-widget{display:flex;align-items:center;justify-content:center;height:100%;padding:16px;gap:16px}.kpi-content{display:flex;flex-direction:column;align-items:center;text-align:center}.kpi-value-container{display:flex;align-items:baseline;gap:4px}.kpi-prefix,.kpi-suffix{font-size:1.25rem;font-weight:500;color:var(--kendo-color-subtle, #6c757d)}.kpi-value{font-size:2.5rem;font-weight:700;color:var(--kendo-color-on-surface, #212529);line-height:1}.kpi-label{margin-top:8px;font-size:.875rem;color:var(--kendo-color-subtle, #6c757d)}.kpi-trend{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%}.kpi-trend.trend-up{background:#28a74526;color:var(--kendo-color-success, #28a745)}.kpi-trend.trend-down{background:#dc354526;color:var(--kendo-color-error, #dc3545)}.kpi-trend.trend-neutral{background:#6c757d26;color:var(--kendo-color-subtle, #6c757d)}@media(max-width:768px){.kpi-value{font-size:1.75rem}.kpi-prefix,.kpi-suffix{font-size:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type:
|
|
4279
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: KpiWidgetComponent, isStandalone: true, selector: "mm-kpi-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"kpi-widget\" [class.loading]=\"isLoading()\" [class.error]=\"error()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured></mm-widget-not-configured>\n } @else if (isLoading()) {\n <div class=\"loading-indicator\">\n <span>...</span>\n </div>\n } @else if (error()) {\n <div class=\"error-message\">\n <span>{{ error() }}</span>\n </div>\n } @else {\n <div class=\"kpi-content\">\n <div class=\"kpi-value-container\">\n @if (config.prefix) {\n <span class=\"kpi-prefix\">{{ config.prefix }}</span>\n }\n <span class=\"kpi-value\">{{ value() }}</span>\n @if (config.suffix) {\n <span class=\"kpi-suffix\">{{ config.suffix }}</span>\n }\n </div>\n\n @if (comparisonText()) {\n <div class=\"kpi-comparison\" [ngClass]=\"trendClass()\">\n @if (config.trend) {\n <kendo-svg-icon [icon]=\"trendIcon()\" size=\"xsmall\"></kendo-svg-icon>\n }\n {{ comparisonText() }}\n </div>\n }\n\n @if (label()) {\n <div class=\"kpi-label\">{{ label() }}</div>\n }\n </div>\n\n @if (config.trend) {\n <div class=\"kpi-trend\" [ngClass]=\"trendClass()\">\n <kendo-svg-icon [icon]=\"trendIcon()\" size=\"medium\"></kendo-svg-icon>\n </div>\n }\n }\n</div>\n", styles: [".kpi-widget{display:flex;align-items:center;justify-content:center;height:100%;padding:16px;gap:16px}.kpi-content{display:flex;flex-direction:column;align-items:center;text-align:center}.kpi-value-container{display:flex;align-items:baseline;gap:4px}.kpi-prefix,.kpi-suffix{font-size:1.25rem;font-weight:500;color:var(--kendo-color-subtle, #6c757d)}.kpi-value{font-size:2.5rem;font-weight:700;color:var(--kendo-color-on-surface, #212529);line-height:1}.kpi-comparison{margin-top:4px;font-size:.75rem;font-weight:500;display:flex;align-items:center;gap:4px;justify-content:center}.kpi-comparison.trend-up{color:var(--kendo-color-success, #28a745)}.kpi-comparison.trend-down{color:var(--kendo-color-error, #dc3545)}.kpi-comparison.trend-neutral{color:var(--kendo-color-subtle, #6c757d)}.kpi-label{margin-top:8px;font-size:.875rem;color:var(--kendo-color-subtle, #6c757d)}.kpi-trend{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%}.kpi-trend.trend-up{background:#28a74526;color:var(--kendo-color-success, #28a745)}.kpi-trend.trend-down{background:#dc354526;color:var(--kendo-color-error, #dc3545)}.kpi-trend.trend-neutral{background:#6c757d26;color:var(--kendo-color-subtle, #6c757d)}@media(max-width:768px){.kpi-value{font-size:1.75rem}.kpi-prefix,.kpi-suffix{font-size:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
4269
4280
|
}
|
|
4270
4281
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: KpiWidgetComponent, decorators: [{
|
|
4271
4282
|
type: Component,
|
|
4272
|
-
args: [{ selector: 'mm-kpi-widget', standalone: true, imports: [CommonModule, SVGIconModule, WidgetNotConfiguredComponent], template: "<div class=\"kpi-widget\" [class.loading]=\"isLoading()\" [class.error]=\"error()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured></mm-widget-not-configured>\n } @else if (isLoading()) {\n <div class=\"loading-indicator\">\n <span>...</span>\n </div>\n } @else if (error()) {\n <div class=\"error-message\">\n <span>{{ error() }}</span>\n </div>\n } @else {\n <div class=\"kpi-content\">\n <div class=\"kpi-value-container\">\n @if (config.prefix) {\n <span class=\"kpi-prefix\">{{ config.prefix }}</span>\n }\n <span class=\"kpi-value\">{{ value() }}</span>\n @if (config.suffix) {\n <span class=\"kpi-suffix\">{{ config.suffix }}</span>\n }\n </div>\n\n @if (label()) {\n <div class=\"kpi-label\">{{ label() }}</div>\n }\n </div>\n\n @if (config.trend) {\n <div class=\"kpi-trend\" [ngClass]=\"trendClass()\">\n <kendo-svg-icon [icon]=\"trendIcon()\" size=\"medium\"></kendo-svg-icon>\n </div>\n }\n }\n</div>\n", styles: [".kpi-widget{display:flex;align-items:center;justify-content:center;height:100%;padding:16px;gap:16px}.kpi-content{display:flex;flex-direction:column;align-items:center;text-align:center}.kpi-value-container{display:flex;align-items:baseline;gap:4px}.kpi-prefix,.kpi-suffix{font-size:1.25rem;font-weight:500;color:var(--kendo-color-subtle, #6c757d)}.kpi-value{font-size:2.5rem;font-weight:700;color:var(--kendo-color-on-surface, #212529);line-height:1}.kpi-label{margin-top:8px;font-size:.875rem;color:var(--kendo-color-subtle, #6c757d)}.kpi-trend{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%}.kpi-trend.trend-up{background:#28a74526;color:var(--kendo-color-success, #28a745)}.kpi-trend.trend-down{background:#dc354526;color:var(--kendo-color-error, #dc3545)}.kpi-trend.trend-neutral{background:#6c757d26;color:var(--kendo-color-subtle, #6c757d)}@media(max-width:768px){.kpi-value{font-size:1.75rem}.kpi-prefix,.kpi-suffix{font-size:1rem}}\n"] }]
|
|
4283
|
+
args: [{ selector: 'mm-kpi-widget', standalone: true, imports: [CommonModule, SVGIconModule, WidgetNotConfiguredComponent], template: "<div class=\"kpi-widget\" [class.loading]=\"isLoading()\" [class.error]=\"error()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured></mm-widget-not-configured>\n } @else if (isLoading()) {\n <div class=\"loading-indicator\">\n <span>...</span>\n </div>\n } @else if (error()) {\n <div class=\"error-message\">\n <span>{{ error() }}</span>\n </div>\n } @else {\n <div class=\"kpi-content\">\n <div class=\"kpi-value-container\">\n @if (config.prefix) {\n <span class=\"kpi-prefix\">{{ config.prefix }}</span>\n }\n <span class=\"kpi-value\">{{ value() }}</span>\n @if (config.suffix) {\n <span class=\"kpi-suffix\">{{ config.suffix }}</span>\n }\n </div>\n\n @if (comparisonText()) {\n <div class=\"kpi-comparison\" [ngClass]=\"trendClass()\">\n @if (config.trend) {\n <kendo-svg-icon [icon]=\"trendIcon()\" size=\"xsmall\"></kendo-svg-icon>\n }\n {{ comparisonText() }}\n </div>\n }\n\n @if (label()) {\n <div class=\"kpi-label\">{{ label() }}</div>\n }\n </div>\n\n @if (config.trend) {\n <div class=\"kpi-trend\" [ngClass]=\"trendClass()\">\n <kendo-svg-icon [icon]=\"trendIcon()\" size=\"medium\"></kendo-svg-icon>\n </div>\n }\n }\n</div>\n", styles: [".kpi-widget{display:flex;align-items:center;justify-content:center;height:100%;padding:16px;gap:16px}.kpi-content{display:flex;flex-direction:column;align-items:center;text-align:center}.kpi-value-container{display:flex;align-items:baseline;gap:4px}.kpi-prefix,.kpi-suffix{font-size:1.25rem;font-weight:500;color:var(--kendo-color-subtle, #6c757d)}.kpi-value{font-size:2.5rem;font-weight:700;color:var(--kendo-color-on-surface, #212529);line-height:1}.kpi-comparison{margin-top:4px;font-size:.75rem;font-weight:500;display:flex;align-items:center;gap:4px;justify-content:center}.kpi-comparison.trend-up{color:var(--kendo-color-success, #28a745)}.kpi-comparison.trend-down{color:var(--kendo-color-error, #dc3545)}.kpi-comparison.trend-neutral{color:var(--kendo-color-subtle, #6c757d)}.kpi-label{margin-top:8px;font-size:.875rem;color:var(--kendo-color-subtle, #6c757d)}.kpi-trend{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%}.kpi-trend.trend-up{background:#28a74526;color:var(--kendo-color-success, #28a745)}.kpi-trend.trend-down{background:#dc354526;color:var(--kendo-color-error, #dc3545)}.kpi-trend.trend-neutral{background:#6c757d26;color:var(--kendo-color-subtle, #6c757d)}@media(max-width:768px){.kpi-value{font-size:1.75rem}.kpi-prefix,.kpi-suffix{font-size:1rem}}\n"] }]
|
|
4273
4284
|
}], propDecorators: { config: [{
|
|
4274
4285
|
type: Input
|
|
4275
4286
|
}] } });
|
|
@@ -4296,6 +4307,7 @@ class KpiConfigDialogComponent {
|
|
|
4296
4307
|
initialPrefix;
|
|
4297
4308
|
initialSuffix;
|
|
4298
4309
|
initialTrend;
|
|
4310
|
+
initialComparisonText;
|
|
4299
4311
|
// Initial values for editing - Persistent Query
|
|
4300
4312
|
initialDataSourceType;
|
|
4301
4313
|
initialQueryRtId;
|
|
@@ -4338,6 +4350,7 @@ class KpiConfigDialogComponent {
|
|
|
4338
4350
|
prefix: '',
|
|
4339
4351
|
suffix: '',
|
|
4340
4352
|
trend: undefined,
|
|
4353
|
+
comparisonText: '',
|
|
4341
4354
|
// Query-specific form fields
|
|
4342
4355
|
queryValueField: '',
|
|
4343
4356
|
queryCategoryField: '',
|
|
@@ -4395,6 +4408,7 @@ class KpiConfigDialogComponent {
|
|
|
4395
4408
|
this.form.prefix = this.initialPrefix || '';
|
|
4396
4409
|
this.form.suffix = this.initialSuffix || '';
|
|
4397
4410
|
this.form.trend = this.initialTrend;
|
|
4411
|
+
this.form.comparisonText = this.initialComparisonText || '';
|
|
4398
4412
|
this.form.queryValueField = this.initialQueryValueField || '';
|
|
4399
4413
|
this.form.queryCategoryField = this.initialQueryCategoryField || '';
|
|
4400
4414
|
this.form.queryCategoryValue = this.initialQueryCategoryValue || '';
|
|
@@ -4557,7 +4571,8 @@ class KpiConfigDialogComponent {
|
|
|
4557
4571
|
staticValue: this.form.staticValue,
|
|
4558
4572
|
prefix: this.form.prefix || undefined,
|
|
4559
4573
|
suffix: this.form.suffix || undefined,
|
|
4560
|
-
trend: this.form.trend
|
|
4574
|
+
trend: this.form.trend,
|
|
4575
|
+
comparisonText: this.form.comparisonText || undefined
|
|
4561
4576
|
});
|
|
4562
4577
|
return;
|
|
4563
4578
|
}
|
|
@@ -4576,6 +4591,7 @@ class KpiConfigDialogComponent {
|
|
|
4576
4591
|
prefix: this.form.prefix || undefined,
|
|
4577
4592
|
suffix: this.form.suffix || undefined,
|
|
4578
4593
|
trend: this.form.trend,
|
|
4594
|
+
comparisonText: this.form.comparisonText || undefined,
|
|
4579
4595
|
filters: filtersDto
|
|
4580
4596
|
});
|
|
4581
4597
|
}
|
|
@@ -4589,6 +4605,7 @@ class KpiConfigDialogComponent {
|
|
|
4589
4605
|
prefix: this.form.prefix || undefined,
|
|
4590
4606
|
suffix: this.form.suffix || undefined,
|
|
4591
4607
|
trend: this.form.trend,
|
|
4608
|
+
comparisonText: this.form.comparisonText || undefined,
|
|
4592
4609
|
filters: filtersDto
|
|
4593
4610
|
});
|
|
4594
4611
|
}
|
|
@@ -4734,7 +4751,7 @@ class KpiConfigDialogComponent {
|
|
|
4734
4751
|
this.filters = updatedFilters;
|
|
4735
4752
|
}
|
|
4736
4753
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: KpiConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4737
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: KpiConfigDialogComponent, isStandalone: true, selector: "mm-kpi-config-dialog", inputs: { initialCkTypeId: "initialCkTypeId", initialRtId: "initialRtId", initialValueAttribute: "initialValueAttribute", initialLabelAttribute: "initialLabelAttribute", initialPrefix: "initialPrefix", initialSuffix: "initialSuffix", initialTrend: "initialTrend", initialDataSourceType: "initialDataSourceType", initialQueryRtId: "initialQueryRtId", initialQueryName: "initialQueryName", initialQueryMode: "initialQueryMode", initialQueryValueField: "initialQueryValueField", initialQueryCategoryField: "initialQueryCategoryField", initialQueryCategoryValue: "initialQueryCategoryValue", initialStaticValue: "initialStaticValue", initialFilters: "initialFilters" }, viewQueries: [{ propertyName: "ckTypeSelectorInput", first: true, predicate: ["ckTypeSelector"], descendants: true }, { propertyName: "entitySelectorInput", first: true, predicate: ["entitySelector"], descendants: true }, { propertyName: "querySelector", first: true, predicate: ["querySelector"], descendants: true }], ngImport: i0, template: `
|
|
4754
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: KpiConfigDialogComponent, isStandalone: true, selector: "mm-kpi-config-dialog", inputs: { initialCkTypeId: "initialCkTypeId", initialRtId: "initialRtId", initialValueAttribute: "initialValueAttribute", initialLabelAttribute: "initialLabelAttribute", initialPrefix: "initialPrefix", initialSuffix: "initialSuffix", initialTrend: "initialTrend", initialComparisonText: "initialComparisonText", initialDataSourceType: "initialDataSourceType", initialQueryRtId: "initialQueryRtId", initialQueryName: "initialQueryName", initialQueryMode: "initialQueryMode", initialQueryValueField: "initialQueryValueField", initialQueryCategoryField: "initialQueryCategoryField", initialQueryCategoryValue: "initialQueryCategoryValue", initialStaticValue: "initialStaticValue", initialFilters: "initialFilters" }, viewQueries: [{ propertyName: "ckTypeSelectorInput", first: true, predicate: ["ckTypeSelector"], descendants: true }, { propertyName: "entitySelectorInput", first: true, predicate: ["entitySelector"], descendants: true }, { propertyName: "querySelector", first: true, predicate: ["querySelector"], descendants: true }], ngImport: i0, template: `
|
|
4738
4755
|
<div class="config-container">
|
|
4739
4756
|
|
|
4740
4757
|
<div class="config-form" [class.loading]="isLoadingInitial">
|
|
@@ -5070,6 +5087,11 @@ class KpiConfigDialogComponent {
|
|
|
5070
5087
|
[(ngModel)]="form.trend">
|
|
5071
5088
|
</kendo-dropdownlist>
|
|
5072
5089
|
</div>
|
|
5090
|
+
<div class="form-field">
|
|
5091
|
+
<label>Comparison Text</label>
|
|
5092
|
+
<kendo-textbox [(ngModel)]="form.comparisonText" placeholder="e.g. +3,1% vs. last week"></kendo-textbox>
|
|
5093
|
+
<p class="section-hint">Displayed below the value in the trend color. Supports {{ variableSyntaxHint }}</p>
|
|
5094
|
+
</div>
|
|
5073
5095
|
</div>
|
|
5074
5096
|
|
|
5075
5097
|
<!-- Filters Section -->
|
|
@@ -5450,6 +5472,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
5450
5472
|
[(ngModel)]="form.trend">
|
|
5451
5473
|
</kendo-dropdownlist>
|
|
5452
5474
|
</div>
|
|
5475
|
+
<div class="form-field">
|
|
5476
|
+
<label>Comparison Text</label>
|
|
5477
|
+
<kendo-textbox [(ngModel)]="form.comparisonText" placeholder="e.g. +3,1% vs. last week"></kendo-textbox>
|
|
5478
|
+
<p class="section-hint">Displayed below the value in the trend color. Supports {{ variableSyntaxHint }}</p>
|
|
5479
|
+
</div>
|
|
5453
5480
|
</div>
|
|
5454
5481
|
|
|
5455
5482
|
<!-- Filters Section -->
|
|
@@ -5503,6 +5530,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
5503
5530
|
type: Input
|
|
5504
5531
|
}], initialTrend: [{
|
|
5505
5532
|
type: Input
|
|
5533
|
+
}], initialComparisonText: [{
|
|
5534
|
+
type: Input
|
|
5506
5535
|
}], initialDataSourceType: [{
|
|
5507
5536
|
type: Input
|
|
5508
5537
|
}], initialQueryRtId: [{
|
|
@@ -5688,7 +5717,7 @@ class EntityDetailDialogComponent {
|
|
|
5688
5717
|
<button kendoButton (click)="onClose()">Close</button>
|
|
5689
5718
|
</kendo-dialog-actions>
|
|
5690
5719
|
</kendo-dialog>
|
|
5691
|
-
`, isInline: true, styles: [".entity-detail-content{display:flex;flex-direction:column;gap:16px;min-height:400px}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:200px;color:var(--kendo-color-subtle, #6c757d)}.error-message{color:var(--kendo-color-error, #dc3545)}.entity-header{padding:12px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.entity-info{display:flex;flex-direction:column;gap:6px}.info-row{display:flex;gap:8px;font-size:.875rem}.info-row .label{font-weight:600;color:var(--kendo-color-subtle, #6c757d);min-width:80px}.info-row .value{color:var(--kendo-color-on-surface, #212529);word-break:break-all}.attributes-section{flex:1;display:flex;flex-direction:column}.attributes-section h4{margin:0 0 8px;font-size:.9rem;color:var(--kendo-color-primary, #0d6efd)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DialogsModule }, { kind: "component", type: i1$
|
|
5720
|
+
`, isInline: true, styles: [".entity-detail-content{display:flex;flex-direction:column;gap:16px;min-height:400px}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:200px;color:var(--kendo-color-subtle, #6c757d)}.error-message{color:var(--kendo-color-error, #dc3545)}.entity-header{padding:12px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.entity-info{display:flex;flex-direction:column;gap:6px}.info-row{display:flex;gap:8px;font-size:.875rem}.info-row .label{font-weight:600;color:var(--kendo-color-subtle, #6c757d);min-width:80px}.info-row .value{color:var(--kendo-color-on-surface, #212529);word-break:break-all}.attributes-section{flex:1;display:flex;flex-direction:column}.attributes-section h4{margin:0 0 8px;font-size:.9rem;color:var(--kendo-color-primary, #0d6efd)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DialogsModule }, { kind: "component", type: i1$5.DialogComponent, selector: "kendo-dialog", inputs: ["actions", "actionsLayout", "autoFocusedElement", "title", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "animation", "themeColor"], outputs: ["action", "close"], exportAs: ["kendoDialog"] }, { kind: "component", type: i1$5.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: PropertyGridComponent, selector: "mm-property-grid", inputs: ["data", "config", "showTypeColumn"], outputs: ["propertyChange", "saveRequested", "binaryDownload"] }] });
|
|
5692
5721
|
}
|
|
5693
5722
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EntityDetailDialogComponent, decorators: [{
|
|
5694
5723
|
type: Component,
|
|
@@ -6061,7 +6090,7 @@ class EntityAssociationsWidgetComponent {
|
|
|
6061
6090
|
.trim();
|
|
6062
6091
|
}
|
|
6063
6092
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EntityAssociationsWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6064
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: EntityAssociationsWidgetComponent, isStandalone: true, selector: "mm-entity-associations-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"associations-widget\" [class.no-data]=\"!data()\" [class.loading]=\"isLoading()\" [class.error]=\"error()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured></mm-widget-not-configured>\n } @else if (isLoading()) {\n <div class=\"loading-indicator\">\n <span>Loading...</span>\n </div>\n } @else if (error()) {\n <div class=\"error-message\">\n <span>{{ error() }}</span>\n </div>\n } @else if (data()) {\n <!-- Entity Info Header -->\n <div class=\"entity-header\">\n <div class=\"entity-box\">\n <span class=\"entity-name\">{{ entityName() }}</span>\n </div>\n <div class=\"entity-details\">\n <span class=\"entity-id\" title=\"{{ entityCkTypeId() }}\">{{ entityRtId() }}</span>\n </div>\n </div>\n\n <!-- Entity Attributes (Source) -->\n @if (filteredEntityAttributes().length > 0) {\n <div class=\"entity-attributes\">\n @for (attr of filteredEntityAttributes(); track attr.attributeName) {\n <div class=\"attribute-row\">\n <span class=\"attribute-name\">{{ formatAttributeName(attr.attributeName) }}</span>\n <span class=\"attribute-value\">{{ formatValue(attr.value) }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Associations List -->\n <div class=\"associations-container\">\n @for (group of groupedAssociations(); track group.roleId + group.direction) {\n <div class=\"association-group\" [class.expanded]=\"isGroupExpanded(group)\">\n <!-- Group Header -->\n <div class=\"group-header\"\n [class.clickable]=\"displayMode() === 'expandable'\"\n (click)=\"toggleGroup(group)\">\n <div class=\"direction-indicator\">\n @if (group.direction === 'out') {\n <kendo-svg-icon [icon]=\"arrowRightIcon\" size=\"small\"></kendo-svg-icon>\n } @else {\n <kendo-svg-icon [icon]=\"arrowLeftIcon\" size=\"small\"></kendo-svg-icon>\n }\n </div>\n <div class=\"group-info\">\n <span class=\"role-name\">{{ group.roleName }}</span>\n <span class=\"target-type\">{{ group.targetType }}</span>\n <span class=\"count-badge\">{{ group.count }}</span>\n </div>\n @if (displayMode() === 'expandable') {\n <div class=\"expand-icon\">\n @if (isGroupExpanded(group)) {\n <kendo-svg-icon [icon]=\"chevronDownIcon\" size=\"small\"></kendo-svg-icon>\n } @else {\n <kendo-svg-icon [icon]=\"chevronRightIcon\" size=\"small\"></kendo-svg-icon>\n }\n </div>\n }\n </div>\n\n <!-- Expanded Target List -->\n @if (displayMode() === 'expandable' && isGroupExpanded(group)) {\n <div class=\"target-list\">\n @if (isLoadingTargets(group)) {\n <div class=\"target-loading\">Loading attributes...</div>\n }\n @for (target of getTargetEntities(group); track target.rtId) {\n <div class=\"target-entry\">\n <div class=\"target-item\" (click)=\"onTargetClick(target)\">\n <span class=\"target-id\">{{ target.displayName }}</span>\n <span class=\"target-type-hint\" [title]=\"target.ckTypeId\">{{ target.ckTypeId }}</span>\n </div>\n @if (target.attributes?.length) {\n <div class=\"target-attributes\">\n @for (attr of target.attributes; track attr.attributeName) {\n <div class=\"target-attr-row\">\n <span class=\"target-attr-name\">{{ formatAttributeName(attr.attributeName) }}</span>\n <span class=\"target-attr-value\">{{ formatValue(attr.value) }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Summary Footer -->\n <div class=\"associations-summary\">\n <kendo-svg-icon [icon]=\"linkIcon\" size=\"small\"></kendo-svg-icon>\n <span>{{ totalAssociations() }} relationship(s)</span>\n </div>\n } @else {\n <mm-widget-not-configured></mm-widget-not-configured>\n }\n</div>\n\n<!-- Entity Detail Dialog -->\n@if (showDetailDialog) {\n <mm-entity-detail-dialog\n [rtId]=\"detailEntityRtId\"\n [ckTypeId]=\"detailEntityCkTypeId\"\n (closed)=\"onDetailDialogClosed()\">\n </mm-entity-detail-dialog>\n}\n", styles: [".associations-widget{display:flex;flex-direction:column;height:100%}.associations-widget.no-data{justify-content:center;align-items:center;color:var(--kendo-color-subtle, #6c757d)}.entity-header{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--kendo-color-surface-alt, #f8f9fa);border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.entity-header .entity-box{display:flex;align-items:center;justify-content:center;padding:8px 16px;background:var(--kendo-color-primary, #0d6efd);color:var(--kendo-color-on-primary, #fff);border-radius:4px;font-weight:600;font-size:.875rem}.entity-header .entity-details{display:flex;flex-direction:column;gap:2px}.entity-header .entity-id{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace}.entity-attributes{padding:4px 12px 8px;border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.entity-attributes .attribute-row{display:flex;justify-content:space-between;padding:2px 0;font-size:.8125rem}.entity-attributes .attribute-name{color:var(--kendo-color-subtle, #6c757d)}.entity-attributes .attribute-value{font-weight:500;color:var(--kendo-color-on-surface, #212529)}.associations-container{flex:1;overflow:auto;padding:8px;display:flex;flex-direction:column;gap:4px}.association-group{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;overflow:hidden}.association-group.expanded .group-header{border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.group-header{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--kendo-color-surface-alt, #f8f9fa)}.group-header.clickable{cursor:pointer}.group-header.clickable:hover{background:var(--kendo-color-surface, #ffffff)}.direction-indicator{color:var(--kendo-color-subtle, #6c757d);display:flex;align-items:center;width:20px}.group-info{display:flex;align-items:center;gap:8px;flex:1;font-size:.8125rem}.group-info .role-name{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.group-info .target-type{font-weight:500;color:var(--kendo-color-on-surface, #212529)}.group-info .count-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;background:var(--kendo-color-primary, #0d6efd);color:var(--kendo-color-on-primary, #fff);border-radius:10px;font-size:.6875rem;font-weight:600}.expand-icon{color:var(--kendo-color-subtle, #6c757d);display:flex;align-items:center}.target-list{padding:4px 0;max-height:200px;overflow-y:auto}.target-entry+.target-entry{border-top:1px solid var(--kendo-color-border, #dee2e6)}.target-item{display:flex;align-items:center;gap:8px;padding:6px 12px 6px 40px;cursor:pointer;font-size:.8125rem;transition:background .15s ease}.target-item:hover{background:var(--kendo-color-surface-alt, #f8f9fa)}.target-item .target-id{font-family:monospace;color:var(--kendo-color-on-surface, #212529);flex-shrink:0}.target-item .target-type-hint{font-size:.6875rem;color:var(--kendo-color-subtle, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex-shrink:1}.target-attributes{padding:2px 12px 6px 56px}.target-attributes .target-attr-row{display:flex;justify-content:space-between;padding:1px 0;font-size:.75rem}.target-attributes .target-attr-name{color:var(--kendo-color-subtle, #6c757d)}.target-attributes .target-attr-value{color:var(--kendo-color-on-surface, #212529);font-weight:500}.target-loading{padding:6px 12px 6px 40px;font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.associations-summary{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--kendo-color-surface-alt, #f8f9fa);border-top:1px solid var(--kendo-color-border, #dee2e6);font-size:.75rem;color:var(--kendo-color-subtle, #6c757d)}.no-data-message{font-size:.875rem}.loading-indicator{display:flex;align-items:center;justify-content:center;height:100%;color:var(--kendo-color-subtle, #6c757d)}.error-message{display:flex;align-items:center;justify-content:center;height:100%;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type:
|
|
6093
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: EntityAssociationsWidgetComponent, isStandalone: true, selector: "mm-entity-associations-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"associations-widget\" [class.no-data]=\"!data()\" [class.loading]=\"isLoading()\" [class.error]=\"error()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured></mm-widget-not-configured>\n } @else if (isLoading()) {\n <div class=\"loading-indicator\">\n <span>Loading...</span>\n </div>\n } @else if (error()) {\n <div class=\"error-message\">\n <span>{{ error() }}</span>\n </div>\n } @else if (data()) {\n <!-- Entity Info Header -->\n <div class=\"entity-header\">\n <div class=\"entity-box\">\n <span class=\"entity-name\">{{ entityName() }}</span>\n </div>\n <div class=\"entity-details\">\n <span class=\"entity-id\" title=\"{{ entityCkTypeId() }}\">{{ entityRtId() }}</span>\n </div>\n </div>\n\n <!-- Entity Attributes (Source) -->\n @if (filteredEntityAttributes().length > 0) {\n <div class=\"entity-attributes\">\n @for (attr of filteredEntityAttributes(); track attr.attributeName) {\n <div class=\"attribute-row\">\n <span class=\"attribute-name\">{{ formatAttributeName(attr.attributeName) }}</span>\n <span class=\"attribute-value\">{{ formatValue(attr.value) }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Associations List -->\n <div class=\"associations-container\">\n @for (group of groupedAssociations(); track group.roleId + group.direction) {\n <div class=\"association-group\" [class.expanded]=\"isGroupExpanded(group)\">\n <!-- Group Header -->\n <div class=\"group-header\"\n [class.clickable]=\"displayMode() === 'expandable'\"\n (click)=\"toggleGroup(group)\">\n <div class=\"direction-indicator\">\n @if (group.direction === 'out') {\n <kendo-svg-icon [icon]=\"arrowRightIcon\" size=\"small\"></kendo-svg-icon>\n } @else {\n <kendo-svg-icon [icon]=\"arrowLeftIcon\" size=\"small\"></kendo-svg-icon>\n }\n </div>\n <div class=\"group-info\">\n <span class=\"role-name\">{{ group.roleName }}</span>\n <span class=\"target-type\">{{ group.targetType }}</span>\n <span class=\"count-badge\">{{ group.count }}</span>\n </div>\n @if (displayMode() === 'expandable') {\n <div class=\"expand-icon\">\n @if (isGroupExpanded(group)) {\n <kendo-svg-icon [icon]=\"chevronDownIcon\" size=\"small\"></kendo-svg-icon>\n } @else {\n <kendo-svg-icon [icon]=\"chevronRightIcon\" size=\"small\"></kendo-svg-icon>\n }\n </div>\n }\n </div>\n\n <!-- Expanded Target List -->\n @if (displayMode() === 'expandable' && isGroupExpanded(group)) {\n <div class=\"target-list\">\n @if (isLoadingTargets(group)) {\n <div class=\"target-loading\">Loading attributes...</div>\n }\n @for (target of getTargetEntities(group); track target.rtId) {\n <div class=\"target-entry\">\n <div class=\"target-item\" (click)=\"onTargetClick(target)\">\n <span class=\"target-id\">{{ target.displayName }}</span>\n <span class=\"target-type-hint\" [title]=\"target.ckTypeId\">{{ target.ckTypeId }}</span>\n </div>\n @if (target.attributes?.length) {\n <div class=\"target-attributes\">\n @for (attr of target.attributes; track attr.attributeName) {\n <div class=\"target-attr-row\">\n <span class=\"target-attr-name\">{{ formatAttributeName(attr.attributeName) }}</span>\n <span class=\"target-attr-value\">{{ formatValue(attr.value) }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Summary Footer -->\n <div class=\"associations-summary\">\n <kendo-svg-icon [icon]=\"linkIcon\" size=\"small\"></kendo-svg-icon>\n <span>{{ totalAssociations() }} relationship(s)</span>\n </div>\n } @else {\n <mm-widget-not-configured></mm-widget-not-configured>\n }\n</div>\n\n<!-- Entity Detail Dialog -->\n@if (showDetailDialog) {\n <mm-entity-detail-dialog\n [rtId]=\"detailEntityRtId\"\n [ckTypeId]=\"detailEntityCkTypeId\"\n (closed)=\"onDetailDialogClosed()\">\n </mm-entity-detail-dialog>\n}\n", styles: [".associations-widget{display:flex;flex-direction:column;height:100%}.associations-widget.no-data{justify-content:center;align-items:center;color:var(--kendo-color-subtle, #6c757d)}.entity-header{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--kendo-color-surface-alt, #f8f9fa);border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.entity-header .entity-box{display:flex;align-items:center;justify-content:center;padding:8px 16px;background:var(--kendo-color-primary, #0d6efd);color:var(--kendo-color-on-primary, #fff);border-radius:4px;font-weight:600;font-size:.875rem}.entity-header .entity-details{display:flex;flex-direction:column;gap:2px}.entity-header .entity-id{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace}.entity-attributes{padding:4px 12px 8px;border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.entity-attributes .attribute-row{display:flex;justify-content:space-between;padding:2px 0;font-size:.8125rem}.entity-attributes .attribute-name{color:var(--kendo-color-subtle, #6c757d)}.entity-attributes .attribute-value{font-weight:500;color:var(--kendo-color-on-surface, #212529)}.associations-container{flex:1;overflow:auto;padding:8px;display:flex;flex-direction:column;gap:4px}.association-group{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;overflow:hidden}.association-group.expanded .group-header{border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.group-header{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--kendo-color-surface-alt, #f8f9fa)}.group-header.clickable{cursor:pointer}.group-header.clickable:hover{background:var(--kendo-color-surface, #ffffff)}.direction-indicator{color:var(--kendo-color-subtle, #6c757d);display:flex;align-items:center;width:20px}.group-info{display:flex;align-items:center;gap:8px;flex:1;font-size:.8125rem}.group-info .role-name{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.group-info .target-type{font-weight:500;color:var(--kendo-color-on-surface, #212529)}.group-info .count-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;background:var(--kendo-color-primary, #0d6efd);color:var(--kendo-color-on-primary, #fff);border-radius:10px;font-size:.6875rem;font-weight:600}.expand-icon{color:var(--kendo-color-subtle, #6c757d);display:flex;align-items:center}.target-list{padding:4px 0;max-height:200px;overflow-y:auto}.target-entry+.target-entry{border-top:1px solid var(--kendo-color-border, #dee2e6)}.target-item{display:flex;align-items:center;gap:8px;padding:6px 12px 6px 40px;cursor:pointer;font-size:.8125rem;transition:background .15s ease}.target-item:hover{background:var(--kendo-color-surface-alt, #f8f9fa)}.target-item .target-id{font-family:monospace;color:var(--kendo-color-on-surface, #212529);flex-shrink:0}.target-item .target-type-hint{font-size:.6875rem;color:var(--kendo-color-subtle, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex-shrink:1}.target-attributes{padding:2px 12px 6px 56px}.target-attributes .target-attr-row{display:flex;justify-content:space-between;padding:1px 0;font-size:.75rem}.target-attributes .target-attr-name{color:var(--kendo-color-subtle, #6c757d)}.target-attributes .target-attr-value{color:var(--kendo-color-on-surface, #212529);font-weight:500}.target-loading{padding:6px 12px 6px 40px;font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.associations-summary{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--kendo-color-surface-alt, #f8f9fa);border-top:1px solid var(--kendo-color-border, #dee2e6);font-size:.75rem;color:var(--kendo-color-subtle, #6c757d)}.no-data-message{font-size:.875rem}.loading-indicator{display:flex;align-items:center;justify-content:center;height:100%;color:var(--kendo-color-subtle, #6c757d)}.error-message{display:flex;align-items:center;justify-content:center;height:100%;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: EntityDetailDialogComponent, selector: "mm-entity-detail-dialog", inputs: ["rtId", "ckTypeId"], outputs: ["closed"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
6065
6094
|
}
|
|
6066
6095
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EntityAssociationsWidgetComponent, decorators: [{
|
|
6067
6096
|
type: Component,
|
|
@@ -7205,6 +7234,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
7205
7234
|
type: Input
|
|
7206
7235
|
}] } });
|
|
7207
7236
|
|
|
7237
|
+
const ICON_MAP = {
|
|
7238
|
+
'check-circle': checkCircleIcon,
|
|
7239
|
+
'x-circle': xCircleIcon,
|
|
7240
|
+
'exclamation-circle': exclamationCircleIcon,
|
|
7241
|
+
'warning-triangle': warningTriangleIcon,
|
|
7242
|
+
'minus-circle': minusCircleIcon,
|
|
7243
|
+
'question-circle': questionCircleIcon,
|
|
7244
|
+
'circle': circleIcon,
|
|
7245
|
+
};
|
|
7246
|
+
function resolveStatusMapping(config) {
|
|
7247
|
+
return Object.fromEntries(Object.entries(config).map(([key, val]) => [
|
|
7248
|
+
key,
|
|
7249
|
+
{ icon: ICON_MAP[val.icon] ?? questionCircleIcon, tooltip: val.tooltip, color: val.color }
|
|
7250
|
+
]));
|
|
7251
|
+
}
|
|
7208
7252
|
class TableWidgetComponent {
|
|
7209
7253
|
config;
|
|
7210
7254
|
dataSource;
|
|
@@ -7235,25 +7279,25 @@ class TableWidgetComponent {
|
|
|
7235
7279
|
* For persistent queries, uses dynamically derived columns from the query response.
|
|
7236
7280
|
*/
|
|
7237
7281
|
listViewColumns = computed(() => {
|
|
7238
|
-
//
|
|
7282
|
+
// If explicit columns are configured, use them (works for both data source types)
|
|
7283
|
+
if (this.config?.columns && this.config.columns.length > 0) {
|
|
7284
|
+
return this.config.columns.map(col => ({
|
|
7285
|
+
field: col.field,
|
|
7286
|
+
displayName: col.title,
|
|
7287
|
+
dataType: (col.dataType ?? 'text'),
|
|
7288
|
+
width: col.width,
|
|
7289
|
+
...(col.statusMapping ? { statusMapping: resolveStatusMapping(col.statusMapping) } : {})
|
|
7290
|
+
}));
|
|
7291
|
+
}
|
|
7292
|
+
// For persistent query without explicit columns, use derived columns
|
|
7239
7293
|
if (this.config?.dataSource?.type === 'persistentQuery') {
|
|
7240
|
-
// Return query-derived columns if available
|
|
7241
7294
|
const queryColumns = this._queryColumnsForView();
|
|
7242
7295
|
if (queryColumns.length > 0) {
|
|
7243
7296
|
return queryColumns;
|
|
7244
7297
|
}
|
|
7245
|
-
// Return empty array while waiting for first data load
|
|
7246
7298
|
return [];
|
|
7247
7299
|
}
|
|
7248
|
-
|
|
7249
|
-
if (!this.config?.columns)
|
|
7250
|
-
return [];
|
|
7251
|
-
return this.config.columns.map(col => ({
|
|
7252
|
-
field: col.field,
|
|
7253
|
-
displayName: col.title,
|
|
7254
|
-
dataType: 'text',
|
|
7255
|
-
width: col.width
|
|
7256
|
-
}));
|
|
7300
|
+
return [];
|
|
7257
7301
|
}, ...(ngDevMode ? [{ debugName: "listViewColumns" }] : /* istanbul ignore next */ []));
|
|
7258
7302
|
/**
|
|
7259
7303
|
* Checks if the widget has a valid configuration.
|
|
@@ -7847,7 +7891,7 @@ class TableConfigDialogComponent {
|
|
|
7847
7891
|
</button>
|
|
7848
7892
|
</div>
|
|
7849
7893
|
</div>
|
|
7850
|
-
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:16px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.form-field{display:flex;flex-direction:column;gap:6px}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.config-card{padding:12px 16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.card-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.card-header kendo-svgicon{color:var(--kendo-color-primary, #0d6efd)}.card-title{font-weight:600;font-size:.95rem;color:var(--kendo-color-primary, #0d6efd)}.card-count{color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.card-content{display:flex;align-items:center;justify-content:space-between;gap:16px}.config-summary{margin:0;font-size:.85rem;color:var(--kendo-color-on-app-surface, #212529);flex:1}.filters-card .card-content{flex-direction:column;align-items:stretch}.filter-content{width:100%}.options-card .options-content{display:flex;gap:24px;align-items:flex-end}.checkbox-field{flex-direction:row;align-items:center}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--kendo-color-on-app-surface, #212529)}.data-source-type .radio-group{display:flex;gap:24px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400;color:var(--kendo-color-on-app-surface, #212529)}.radio-label span{color:var(--kendo-color-on-app-surface, #212529)}.query-info{flex-direction:column;align-items:stretch;gap:8px}.info-row{display:flex;gap:8px}.info-label{font-weight:600;min-width:100px;color:var(--kendo-color-subtle, #6c757d)}.info-value{flex:1;color:var(--kendo-color-on-app-surface, #212529)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: i3.RadioButtonDirective, selector: "input[kendoRadioButton]", inputs: ["size"] }, { kind: "ngmodule", type: NumericTextBoxModule }, { kind: "ngmodule", type: DropDownsModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type:
|
|
7894
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:16px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.form-field{display:flex;flex-direction:column;gap:6px}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.config-card{padding:12px 16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.card-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.card-header kendo-svgicon{color:var(--kendo-color-primary, #0d6efd)}.card-title{font-weight:600;font-size:.95rem;color:var(--kendo-color-primary, #0d6efd)}.card-count{color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.card-content{display:flex;align-items:center;justify-content:space-between;gap:16px}.config-summary{margin:0;font-size:.85rem;color:var(--kendo-color-on-app-surface, #212529);flex:1}.filters-card .card-content{flex-direction:column;align-items:stretch}.filter-content{width:100%}.options-card .options-content{display:flex;gap:24px;align-items:flex-end}.checkbox-field{flex-direction:row;align-items:center}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--kendo-color-on-app-surface, #212529)}.data-source-type .radio-group{display:flex;gap:24px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400;color:var(--kendo-color-on-app-surface, #212529)}.radio-label span{color:var(--kendo-color-on-app-surface, #212529)}.query-info{flex-direction:column;align-items:stretch;gap:8px}.info-row{display:flex;gap:8px}.info-label{font-weight:600;min-width:100px;color:var(--kendo-color-subtle, #6c757d)}.info-value{flex:1;color:var(--kendo-color-on-app-surface, #212529)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: i3.RadioButtonDirective, selector: "input[kendoRadioButton]", inputs: ["size"] }, { kind: "ngmodule", type: NumericTextBoxModule }, { kind: "ngmodule", type: DropDownsModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: CkTypeSelectorInputComponent, selector: "mm-ck-type-selector-input", inputs: ["placeholder", "minSearchLength", "maxResults", "debounceMs", "ckModelIds", "allowAbstract", "dialogTitle", "advancedSearchLabel", "derivedFromRtCkTypeId", "disabled", "required"], outputs: ["ckTypeSelected", "ckTypeCleared"] }, { kind: "component", type: FieldFilterEditorComponent, selector: "mm-field-filter-editor", inputs: ["availableAttributes", "ckTypeId", "hideNavigationProperties", "attributePaths", "enableVariables", "availableVariables", "filters"], outputs: ["filtersChange"] }, { kind: "component", type: QuerySelectorComponent, selector: "mm-query-selector", inputs: ["placeholder", "hint", "disabled"], outputs: ["querySelected", "queriesLoaded"] }, { kind: "component", type: LoadingOverlayComponent, selector: "mm-loading-overlay", inputs: ["loading"] }] });
|
|
7851
7895
|
}
|
|
7852
7896
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: TableConfigDialogComponent, decorators: [{
|
|
7853
7897
|
type: Component,
|
|
@@ -8521,7 +8565,7 @@ class GaugeWidgetComponent {
|
|
|
8521
8565
|
</div>
|
|
8522
8566
|
}
|
|
8523
8567
|
</div>
|
|
8524
|
-
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.gauge-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.gauge-widget.loading,.gauge-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.gauge-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%}.gauge-center-label{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}.gauge-center-label .value-text{font-size:1.25rem;font-weight:600;color:var(--kendo-color-on-surface,
|
|
8568
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.gauge-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.gauge-widget.loading,.gauge-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.gauge-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%}.gauge-center-label{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}.gauge-center-label .value-text{font-size:1.25rem;font-weight:600;color:var(--kendo-color-on-surface, inherit)}.gauge-center-label .label-text{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);margin-top:2px}.gauge-value-label{display:flex;flex-direction:column;align-items:center;margin-top:8px;font-size:1.1rem;font-weight:600;color:var(--kendo-color-on-surface, inherit)}.gauge-value-label .label-text{font-size:.75rem;font-weight:400;color:var(--kendo-color-subtle, #6c757d);margin-top:2px}kendo-arcgauge,kendo-circulargauge,kendo-radialgauge{width:100%;max-width:200px;height:auto}.linear-gauge-wrapper{display:flex;flex-direction:row;align-items:center;justify-content:center;height:100%;width:100%;gap:8px}.linear-gauge-wrapper .gauge-value-label{margin-top:0;writing-mode:horizontal-tb}kendo-lineargauge{height:100%;max-height:180px;width:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: i1$6.ArcGaugeComponent, selector: "kendo-arcgauge", inputs: ["value", "color", "colors", "opacity", "scale"], exportAs: ["kendoArcGauge"] }, { kind: "directive", type: i1$6.ArcCenterTemplateDirective, selector: "[kendoArcGaugeCenterTemplate]" }, { kind: "component", type: i1$6.ArcScaleComponent, selector: "kendo-arcgauge-scale", inputs: ["labels", "rangeDistance", "rangeLineCap", "startAngle", "endAngle"] }, { kind: "component", type: i1$6.ColorsComponent, selector: "kendo-arcgauge-colors" }, { kind: "component", type: i1$6.ColorComponent, selector: "kendo-arcgauge-color", inputs: ["color", "opacity", "from", "to"] }, { kind: "component", type: i1$6.CircularGaugeComponent, selector: "kendo-circulargauge", inputs: ["scale"], exportAs: ["kendoCircularGauge"] }, { kind: "directive", type: i1$6.CircularGaugeCenterTemplateDirective, selector: "[kendoCircularGaugeCenterTemplate]" }, { kind: "component", type: i1$6.CircularGaugeScaleComponent, selector: "kendo-circulargauge-scale" }, { kind: "component", type: i1$6.LinearGaugeComponent, selector: "kendo-lineargauge", inputs: ["pointer", "scale"], exportAs: ["kendoLinearGauge"] }, { kind: "component", type: i1$6.LinearScaleComponent, selector: "kendo-lineargauge-scale", inputs: ["line", "ranges", "mirror", "vertical"] }, { kind: "component", type: i1$6.LinearLabelsComponent, selector: "kendo-lineargauge-scale-labels" }, { kind: "component", type: i1$6.LinearPointersComponent, selector: "kendo-lineargauge-pointers" }, { kind: "component", type: i1$6.LinearPointerComponent, selector: "kendo-lineargauge-pointer", inputs: ["border", "color", "margin", "opacity", "shape", "size", "value"] }, { kind: "component", type: i1$6.LinearRangeComponent, selector: "kendo-lineargauge-scale-range" }, { kind: "component", type: i1$6.LinearRangesComponent, selector: "kendo-lineargauge-scale-ranges" }, { kind: "component", type: i1$6.RadialGaugeComponent, selector: "kendo-radialgauge", inputs: ["pointer", "scale"], exportAs: ["kendoRadialGauge"] }, { kind: "component", type: i1$6.RadialScaleComponent, selector: "kendo-radialgauge-scale", inputs: ["labels", "rangeDistance", "ranges", "startAngle", "endAngle"] }, { kind: "component", type: i1$6.RadialPointerComponent, selector: "kendo-radialgauge-pointer", inputs: ["cap", "color", "length", "value"] }, { kind: "component", type: i1$6.RadialRangeComponent, selector: "kendo-radialgauge-scale-range" }, { kind: "component", type: i1$6.RadialRangesComponent, selector: "kendo-radialgauge-scale-ranges" }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
8525
8569
|
}
|
|
8526
8570
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: GaugeWidgetComponent, decorators: [{
|
|
8527
8571
|
type: Component,
|
|
@@ -8698,7 +8742,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
8698
8742
|
</div>
|
|
8699
8743
|
}
|
|
8700
8744
|
</div>
|
|
8701
|
-
`, styles: [":host{display:block;width:100%;height:100%}.gauge-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.gauge-widget.loading,.gauge-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.gauge-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%}.gauge-center-label{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}.gauge-center-label .value-text{font-size:1.25rem;font-weight:600;color:var(--kendo-color-on-surface,
|
|
8745
|
+
`, styles: [":host{display:block;width:100%;height:100%}.gauge-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.gauge-widget.loading,.gauge-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.gauge-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%}.gauge-center-label{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}.gauge-center-label .value-text{font-size:1.25rem;font-weight:600;color:var(--kendo-color-on-surface, inherit)}.gauge-center-label .label-text{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);margin-top:2px}.gauge-value-label{display:flex;flex-direction:column;align-items:center;margin-top:8px;font-size:1.1rem;font-weight:600;color:var(--kendo-color-on-surface, inherit)}.gauge-value-label .label-text{font-size:.75rem;font-weight:400;color:var(--kendo-color-subtle, #6c757d);margin-top:2px}kendo-arcgauge,kendo-circulargauge,kendo-radialgauge{width:100%;max-width:200px;height:auto}.linear-gauge-wrapper{display:flex;flex-direction:row;align-items:center;justify-content:center;height:100%;width:100%;gap:8px}.linear-gauge-wrapper .gauge-value-label{margin-top:0;writing-mode:horizontal-tb}kendo-lineargauge{height:100%;max-height:180px;width:auto}\n"] }]
|
|
8702
8746
|
}], propDecorators: { config: [{
|
|
8703
8747
|
type: Input
|
|
8704
8748
|
}] } });
|
|
@@ -10241,8 +10285,8 @@ class PieChartWidgetComponent {
|
|
|
10241
10285
|
<span>{{ error() }}</span>
|
|
10242
10286
|
</div>
|
|
10243
10287
|
} @else {
|
|
10244
|
-
<kendo-chart class="chart-container">
|
|
10245
|
-
<kendo-chart-
|
|
10288
|
+
<kendo-chart class="chart-container" [plotArea]="{ background: 'transparent', margin: plotAreaMargin }">
|
|
10289
|
+
<kendo-chart-area [background]="'transparent'"></kendo-chart-area>
|
|
10246
10290
|
<kendo-chart-series>
|
|
10247
10291
|
<kendo-chart-series-item
|
|
10248
10292
|
[type]="config.chartType"
|
|
@@ -10266,7 +10310,7 @@ class PieChartWidgetComponent {
|
|
|
10266
10310
|
</kendo-chart>
|
|
10267
10311
|
}
|
|
10268
10312
|
</div>
|
|
10269
|
-
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.pie-chart-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.pie-chart-widget.loading,.pie-chart-widget.error{opacity:.7}.loading-indicator,.error-message,.no-config-overlay{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.no-config-overlay span{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$
|
|
10313
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.pie-chart-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.pie-chart-widget.loading,.pie-chart-widget.error{opacity:.7}.loading-indicator,.error-message,.no-config-overlay{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.no-config-overlay span{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$7.ChartComponent, selector: "kendo-chart", inputs: ["pannable", "renderAs", "seriesColors", "subtitle", "title", "noData", "observeStyles", "transitions", "zoomable", "axisDefaults", "categoryAxis", "chartArea", "legend", "panes", "paneDefaults", "plotArea", "series", "seriesDefaults", "tooltip", "valueAxis", "xAxis", "yAxis", "resizeRateLimit", "popupSettings", "drilldownLevel"], outputs: ["axisLabelClick", "drag", "dragEnd", "dragStart", "legendItemHover", "legendItemLeave", "noteClick", "noteHover", "noteLeave", "paneRender", "plotAreaClick", "plotAreaHover", "plotAreaLeave", "render", "select", "selectEnd", "selectStart", "seriesClick", "drilldown", "seriesHover", "seriesOver", "seriesLeave", "zoom", "zoomEnd", "zoomStart", "legendItemClick", "drilldownLevelChange"], exportAs: ["kendoChart"] }, { kind: "directive", type: i1$7.SeriesTooltipTemplateDirective, selector: "[kendoChartSeriesTooltipTemplate]" }, { kind: "component", type: i1$7.ChartAreaComponent, selector: "kendo-chart-area", inputs: ["background", "border", "height", "margin", "opacity", "width"] }, { kind: "component", type: i1$7.LegendComponent, selector: "kendo-chart-legend", inputs: ["align", "background", "border", "height", "labels", "margin", "offsetX", "offsetY", "orientation", "padding", "position", "reverse", "visible", "width", "markers", "spacing", "inactiveItems", "item", "title", "focusHighlight"] }, { kind: "component", type: i1$7.SeriesComponent, selector: "kendo-chart-series" }, { kind: "component", type: i1$7.SeriesItemComponent, selector: "kendo-chart-series-item", inputs: ["aggregate", "autoFit", "axis", "border", "categoryAxis", "categoryField", "closeField", "color", "colorField", "connectors", "currentField", "dashType", "data", "downColor", "downColorField", "drilldownField", "dynamicHeight", "dynamicSlope", "errorHighField", "errorLowField", "explodeField", "field", "fromField", "gap", "highField", "holeSize", "line", "lowField", "lowerField", "margin", "maxSize", "mean", "meanField", "median", "medianField", "minSize", "missingValues", "name", "neckRatio", "negativeColor", "negativeValues", "noteTextField", "opacity", "openField", "outliersField", "overlay", "padding", "q1Field", "q3Field", "segmentSpacing", "size", "sizeField", "spacing", "stack", "startAngle", "style", "summaryField", "target", "toField", "type", "upperField", "visible", "visibleInLegend", "visibleInLegendField", "visual", "width", "whiskers", "xAxis", "xErrorHighField", "xErrorLowField", "xField", "yAxis", "yErrorHighField", "yErrorLowField", "yField", "zIndex", "trendline", "for", "legendItem", "pattern", "patternField", "errorBars", "extremes", "highlight", "labels", "markers", "notes", "outliers", "tooltip"] }, { kind: "component", type: i1$7.TooltipComponent, selector: "kendo-chart-tooltip", inputs: ["background", "border", "color", "font", "format", "opacity", "padding", "shared", "visible"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
10270
10314
|
}
|
|
10271
10315
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: PieChartWidgetComponent, decorators: [{
|
|
10272
10316
|
type: Component,
|
|
@@ -10287,8 +10331,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
10287
10331
|
<span>{{ error() }}</span>
|
|
10288
10332
|
</div>
|
|
10289
10333
|
} @else {
|
|
10290
|
-
<kendo-chart class="chart-container">
|
|
10291
|
-
<kendo-chart-
|
|
10334
|
+
<kendo-chart class="chart-container" [plotArea]="{ background: 'transparent', margin: plotAreaMargin }">
|
|
10335
|
+
<kendo-chart-area [background]="'transparent'"></kendo-chart-area>
|
|
10292
10336
|
<kendo-chart-series>
|
|
10293
10337
|
<kendo-chart-series-item
|
|
10294
10338
|
[type]="config.chartType"
|
|
@@ -11195,7 +11239,7 @@ class BarChartWidgetComponent {
|
|
|
11195
11239
|
continue;
|
|
11196
11240
|
const sanitizedPath = this.sanitizeFieldName(cell.attributePath);
|
|
11197
11241
|
if (sanitizedPath === this.sanitizeFieldName(this.config.categoryField)) {
|
|
11198
|
-
categoryValue =
|
|
11242
|
+
categoryValue = this.formatCategoryValue(cell.value);
|
|
11199
11243
|
}
|
|
11200
11244
|
// Check if this cell is one of our series fields
|
|
11201
11245
|
for (const seriesConfig of (this.config.series ?? [])) {
|
|
@@ -11215,11 +11259,14 @@ class BarChartWidgetComponent {
|
|
|
11215
11259
|
}
|
|
11216
11260
|
}
|
|
11217
11261
|
// Convert to series data array
|
|
11218
|
-
const seriesData = (this.config.series ?? []).map(seriesConfig =>
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11262
|
+
const seriesData = (this.config.series ?? []).map(seriesConfig => {
|
|
11263
|
+
const rawData = seriesMap.get(seriesConfig.field) ?? [];
|
|
11264
|
+
return {
|
|
11265
|
+
name: seriesConfig.name ?? seriesConfig.field,
|
|
11266
|
+
data: this.hasColorThresholds() ? this.applyColorThresholds(rawData) : rawData,
|
|
11267
|
+
color: seriesConfig.color
|
|
11268
|
+
};
|
|
11269
|
+
});
|
|
11223
11270
|
this._categories.set(categories);
|
|
11224
11271
|
this._seriesData.set(seriesData);
|
|
11225
11272
|
}
|
|
@@ -11257,7 +11304,7 @@ class BarChartWidgetComponent {
|
|
|
11257
11304
|
continue;
|
|
11258
11305
|
const sanitizedPath = this.sanitizeFieldName(cell.attributePath);
|
|
11259
11306
|
if (sanitizedPath === this.sanitizeFieldName(categoryField)) {
|
|
11260
|
-
categoryValue =
|
|
11307
|
+
categoryValue = this.formatCategoryValue(cell.value);
|
|
11261
11308
|
}
|
|
11262
11309
|
else if (sanitizedPath === this.sanitizeFieldName(seriesGroupField)) {
|
|
11263
11310
|
seriesGroupValue = String(cell.value ?? '');
|
|
@@ -11283,12 +11330,12 @@ class BarChartWidgetComponent {
|
|
|
11283
11330
|
const seriesGroups = Array.from(allSeriesGroups);
|
|
11284
11331
|
// Build series data
|
|
11285
11332
|
const seriesData = seriesGroups.map(seriesGroup => {
|
|
11286
|
-
const
|
|
11333
|
+
const rawData = categories.map(category => {
|
|
11287
11334
|
return dataMap.get(category)?.get(seriesGroup) ?? 0;
|
|
11288
11335
|
});
|
|
11289
11336
|
return {
|
|
11290
11337
|
name: seriesGroup,
|
|
11291
|
-
data
|
|
11338
|
+
data: this.hasColorThresholds() ? this.applyColorThresholds(rawData) : rawData
|
|
11292
11339
|
};
|
|
11293
11340
|
});
|
|
11294
11341
|
this._categories.set(categories);
|
|
@@ -11298,6 +11345,42 @@ class BarChartWidgetComponent {
|
|
|
11298
11345
|
* Sanitizes field names for comparison.
|
|
11299
11346
|
* Replaces dots with underscores (same as table widget).
|
|
11300
11347
|
*/
|
|
11348
|
+
dataLabelFormat = computed(() => {
|
|
11349
|
+
const suffix = this.config?.dataLabelSuffix ?? '';
|
|
11350
|
+
return `{0:n0}${suffix}`;
|
|
11351
|
+
}, ...(ngDevMode ? [{ debugName: "dataLabelFormat" }] : /* istanbul ignore next */ []));
|
|
11352
|
+
hasColorThresholds() {
|
|
11353
|
+
return (this.config?.colorThresholds?.length ?? 0) > 0;
|
|
11354
|
+
}
|
|
11355
|
+
applyColorThresholds(data) {
|
|
11356
|
+
const thresholds = this.config.colorThresholds ?? [];
|
|
11357
|
+
const defaultColor = this.config.defaultBarColor ?? '#6b7280';
|
|
11358
|
+
return data.map(val => ({
|
|
11359
|
+
value: val,
|
|
11360
|
+
_color: this.getColorForValue(val, thresholds, defaultColor)
|
|
11361
|
+
}));
|
|
11362
|
+
}
|
|
11363
|
+
getColorForValue(val, thresholds, defaultColor) {
|
|
11364
|
+
for (const t of thresholds) {
|
|
11365
|
+
if (val <= t.value)
|
|
11366
|
+
return t.color;
|
|
11367
|
+
}
|
|
11368
|
+
return defaultColor;
|
|
11369
|
+
}
|
|
11370
|
+
formatCategoryValue(value) {
|
|
11371
|
+
const str = String(value ?? '');
|
|
11372
|
+
// Detect ISO 8601 timestamps and format as readable date/time
|
|
11373
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(str)) {
|
|
11374
|
+
const date = new Date(str);
|
|
11375
|
+
if (!isNaN(date.getTime())) {
|
|
11376
|
+
return date.toLocaleString('de-AT', {
|
|
11377
|
+
day: '2-digit', month: '2-digit',
|
|
11378
|
+
hour: '2-digit', minute: '2-digit'
|
|
11379
|
+
});
|
|
11380
|
+
}
|
|
11381
|
+
}
|
|
11382
|
+
return str;
|
|
11383
|
+
}
|
|
11301
11384
|
sanitizeFieldName(fieldName) {
|
|
11302
11385
|
return fieldName.replace(/\./g, '_');
|
|
11303
11386
|
}
|
|
@@ -11323,10 +11406,13 @@ class BarChartWidgetComponent {
|
|
|
11323
11406
|
<span>{{ error() }}</span>
|
|
11324
11407
|
</div>
|
|
11325
11408
|
} @else {
|
|
11326
|
-
<kendo-chart class="chart-container">
|
|
11327
|
-
<kendo-chart-
|
|
11409
|
+
<kendo-chart class="chart-container" [plotArea]="{ background: 'transparent', margin: plotAreaMargin() }">
|
|
11410
|
+
<kendo-chart-area [background]="'transparent'"></kendo-chart-area>
|
|
11328
11411
|
<kendo-chart-category-axis>
|
|
11329
|
-
<kendo-chart-category-axis-item
|
|
11412
|
+
<kendo-chart-category-axis-item
|
|
11413
|
+
[categories]="categories()"
|
|
11414
|
+
[line]="{ visible: false }"
|
|
11415
|
+
[majorGridLines]="{ visible: false }">
|
|
11330
11416
|
<kendo-chart-category-axis-item-labels
|
|
11331
11417
|
[rotation]="labelRotation()"
|
|
11332
11418
|
[content]="categoryLabelContent">
|
|
@@ -11334,6 +11420,13 @@ class BarChartWidgetComponent {
|
|
|
11334
11420
|
</kendo-chart-category-axis-item>
|
|
11335
11421
|
</kendo-chart-category-axis>
|
|
11336
11422
|
|
|
11423
|
+
<kendo-chart-value-axis>
|
|
11424
|
+
<kendo-chart-value-axis-item
|
|
11425
|
+
[line]="{ visible: false }"
|
|
11426
|
+
[majorGridLines]="{ color: 'rgba(255,255,255,0.06)' }">
|
|
11427
|
+
</kendo-chart-value-axis-item>
|
|
11428
|
+
</kendo-chart-value-axis>
|
|
11429
|
+
|
|
11337
11430
|
<kendo-chart-series>
|
|
11338
11431
|
@for (series of seriesData(); track series.name) {
|
|
11339
11432
|
<kendo-chart-series-item
|
|
@@ -11341,11 +11434,15 @@ class BarChartWidgetComponent {
|
|
|
11341
11434
|
[data]="series.data"
|
|
11342
11435
|
[name]="series.name"
|
|
11343
11436
|
[color]="series.color"
|
|
11437
|
+
[field]="hasColorThresholds() ? 'value' : ''"
|
|
11438
|
+
[colorField]="hasColorThresholds() ? '_color' : ''"
|
|
11439
|
+
[border]="{ width: 0 }"
|
|
11440
|
+
[gap]="0.8"
|
|
11344
11441
|
[stack]="stackConfig()">
|
|
11345
11442
|
@if (config.showDataLabels) {
|
|
11346
11443
|
<kendo-chart-series-item-labels
|
|
11347
11444
|
[visible]="true"
|
|
11348
|
-
[format]="
|
|
11445
|
+
[format]="dataLabelFormat()">
|
|
11349
11446
|
</kendo-chart-series-item-labels>
|
|
11350
11447
|
}
|
|
11351
11448
|
</kendo-chart-series-item>
|
|
@@ -11368,7 +11465,7 @@ class BarChartWidgetComponent {
|
|
|
11368
11465
|
</kendo-chart>
|
|
11369
11466
|
}
|
|
11370
11467
|
</div>
|
|
11371
|
-
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.bar-chart-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.bar-chart-widget.loading,.bar-chart-widget.error{opacity:.7}.loading-indicator,.error-message,.no-config-overlay{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.no-config-overlay span{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$
|
|
11468
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.bar-chart-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.bar-chart-widget.loading,.bar-chart-widget.error{opacity:.7}.loading-indicator,.error-message,.no-config-overlay{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.no-config-overlay span{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$7.ChartComponent, selector: "kendo-chart", inputs: ["pannable", "renderAs", "seriesColors", "subtitle", "title", "noData", "observeStyles", "transitions", "zoomable", "axisDefaults", "categoryAxis", "chartArea", "legend", "panes", "paneDefaults", "plotArea", "series", "seriesDefaults", "tooltip", "valueAxis", "xAxis", "yAxis", "resizeRateLimit", "popupSettings", "drilldownLevel"], outputs: ["axisLabelClick", "drag", "dragEnd", "dragStart", "legendItemHover", "legendItemLeave", "noteClick", "noteHover", "noteLeave", "paneRender", "plotAreaClick", "plotAreaHover", "plotAreaLeave", "render", "select", "selectEnd", "selectStart", "seriesClick", "drilldown", "seriesHover", "seriesOver", "seriesLeave", "zoom", "zoomEnd", "zoomStart", "legendItemClick", "drilldownLevelChange"], exportAs: ["kendoChart"] }, { kind: "directive", type: i1$7.SeriesTooltipTemplateDirective, selector: "[kendoChartSeriesTooltipTemplate]" }, { kind: "component", type: i1$7.CategoryAxisComponent, selector: "kendo-chart-category-axis" }, { kind: "component", type: i1$7.CategoryAxisItemComponent, selector: "kendo-chart-category-axis-item", inputs: ["autoBaseUnitSteps", "axisCrossingValue", "background", "baseUnit", "baseUnitStep", "categories", "color", "justified", "line", "majorGridLines", "majorTicks", "max", "maxDateGroups", "maxDivisions", "min", "minorGridLines", "minorTicks", "name", "pane", "plotBands", "reverse", "roundToBaseUnit", "startAngle", "type", "visible", "weekStartDay", "crosshair", "labels", "notes", "select", "title", "rangeLabels"] }, { kind: "component", type: i1$7.CategoryAxisLabelsComponent, selector: "kendo-chart-category-axis-item-labels", inputs: ["background", "border", "color", "content", "culture", "dateFormats", "font", "format", "margin", "mirror", "padding", "position", "rotation", "skip", "step", "visible", "visual"] }, { kind: "component", type: i1$7.ChartAreaComponent, selector: "kendo-chart-area", inputs: ["background", "border", "height", "margin", "opacity", "width"] }, { kind: "component", type: i1$7.LegendComponent, selector: "kendo-chart-legend", inputs: ["align", "background", "border", "height", "labels", "margin", "offsetX", "offsetY", "orientation", "padding", "position", "reverse", "visible", "width", "markers", "spacing", "inactiveItems", "item", "title", "focusHighlight"] }, { kind: "component", type: i1$7.SeriesComponent, selector: "kendo-chart-series" }, { kind: "component", type: i1$7.SeriesItemComponent, selector: "kendo-chart-series-item", inputs: ["aggregate", "autoFit", "axis", "border", "categoryAxis", "categoryField", "closeField", "color", "colorField", "connectors", "currentField", "dashType", "data", "downColor", "downColorField", "drilldownField", "dynamicHeight", "dynamicSlope", "errorHighField", "errorLowField", "explodeField", "field", "fromField", "gap", "highField", "holeSize", "line", "lowField", "lowerField", "margin", "maxSize", "mean", "meanField", "median", "medianField", "minSize", "missingValues", "name", "neckRatio", "negativeColor", "negativeValues", "noteTextField", "opacity", "openField", "outliersField", "overlay", "padding", "q1Field", "q3Field", "segmentSpacing", "size", "sizeField", "spacing", "stack", "startAngle", "style", "summaryField", "target", "toField", "type", "upperField", "visible", "visibleInLegend", "visibleInLegendField", "visual", "width", "whiskers", "xAxis", "xErrorHighField", "xErrorLowField", "xField", "yAxis", "yErrorHighField", "yErrorLowField", "yField", "zIndex", "trendline", "for", "legendItem", "pattern", "patternField", "errorBars", "extremes", "highlight", "labels", "markers", "notes", "outliers", "tooltip"] }, { kind: "component", type: i1$7.SeriesLabelsComponent, selector: "kendo-chart-series-item-labels", inputs: ["align", "background", "border", "color", "content", "ariaContent", "distance", "font", "format", "margin", "padding", "position", "rotation", "visible", "visual", "from", "to"] }, { kind: "component", type: i1$7.TooltipComponent, selector: "kendo-chart-tooltip", inputs: ["background", "border", "color", "font", "format", "opacity", "padding", "shared", "visible"] }, { kind: "component", type: i1$7.ValueAxisComponent, selector: "kendo-chart-value-axis" }, { kind: "component", type: i1$7.ValueAxisItemComponent, selector: "kendo-chart-value-axis-item", inputs: ["axisCrossingValue", "background", "color", "line", "majorGridLines", "majorTicks", "majorUnit", "max", "min", "minorGridLines", "minorTicks", "minorUnit", "name", "narrowRange", "pane", "plotBands", "reverse", "type", "visible", "crosshair", "labels", "notes", "title"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
11372
11469
|
}
|
|
11373
11470
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BarChartWidgetComponent, decorators: [{
|
|
11374
11471
|
type: Component,
|
|
@@ -11389,10 +11486,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
11389
11486
|
<span>{{ error() }}</span>
|
|
11390
11487
|
</div>
|
|
11391
11488
|
} @else {
|
|
11392
|
-
<kendo-chart class="chart-container">
|
|
11393
|
-
<kendo-chart-
|
|
11489
|
+
<kendo-chart class="chart-container" [plotArea]="{ background: 'transparent', margin: plotAreaMargin() }">
|
|
11490
|
+
<kendo-chart-area [background]="'transparent'"></kendo-chart-area>
|
|
11394
11491
|
<kendo-chart-category-axis>
|
|
11395
|
-
<kendo-chart-category-axis-item
|
|
11492
|
+
<kendo-chart-category-axis-item
|
|
11493
|
+
[categories]="categories()"
|
|
11494
|
+
[line]="{ visible: false }"
|
|
11495
|
+
[majorGridLines]="{ visible: false }">
|
|
11396
11496
|
<kendo-chart-category-axis-item-labels
|
|
11397
11497
|
[rotation]="labelRotation()"
|
|
11398
11498
|
[content]="categoryLabelContent">
|
|
@@ -11400,6 +11500,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
11400
11500
|
</kendo-chart-category-axis-item>
|
|
11401
11501
|
</kendo-chart-category-axis>
|
|
11402
11502
|
|
|
11503
|
+
<kendo-chart-value-axis>
|
|
11504
|
+
<kendo-chart-value-axis-item
|
|
11505
|
+
[line]="{ visible: false }"
|
|
11506
|
+
[majorGridLines]="{ color: 'rgba(255,255,255,0.06)' }">
|
|
11507
|
+
</kendo-chart-value-axis-item>
|
|
11508
|
+
</kendo-chart-value-axis>
|
|
11509
|
+
|
|
11403
11510
|
<kendo-chart-series>
|
|
11404
11511
|
@for (series of seriesData(); track series.name) {
|
|
11405
11512
|
<kendo-chart-series-item
|
|
@@ -11407,11 +11514,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
11407
11514
|
[data]="series.data"
|
|
11408
11515
|
[name]="series.name"
|
|
11409
11516
|
[color]="series.color"
|
|
11517
|
+
[field]="hasColorThresholds() ? 'value' : ''"
|
|
11518
|
+
[colorField]="hasColorThresholds() ? '_color' : ''"
|
|
11519
|
+
[border]="{ width: 0 }"
|
|
11520
|
+
[gap]="0.8"
|
|
11410
11521
|
[stack]="stackConfig()">
|
|
11411
11522
|
@if (config.showDataLabels) {
|
|
11412
11523
|
<kendo-chart-series-item-labels
|
|
11413
11524
|
[visible]="true"
|
|
11414
|
-
[format]="
|
|
11525
|
+
[format]="dataLabelFormat()">
|
|
11415
11526
|
</kendo-chart-series-item-labels>
|
|
11416
11527
|
}
|
|
11417
11528
|
</kendo-chart-series-item>
|
|
@@ -11459,6 +11570,8 @@ class BarChartConfigDialogComponent {
|
|
|
11459
11570
|
initialShowLegend;
|
|
11460
11571
|
initialLegendPosition;
|
|
11461
11572
|
initialShowDataLabels;
|
|
11573
|
+
initialColorThresholds;
|
|
11574
|
+
initialDefaultBarColor;
|
|
11462
11575
|
initialFilters;
|
|
11463
11576
|
// State
|
|
11464
11577
|
isLoadingInitial = false;
|
|
@@ -11495,7 +11608,9 @@ class BarChartConfigDialogComponent {
|
|
|
11495
11608
|
categoryField: '',
|
|
11496
11609
|
showLegend: true,
|
|
11497
11610
|
legendPosition: 'right',
|
|
11498
|
-
showDataLabels: false
|
|
11611
|
+
showDataLabels: false,
|
|
11612
|
+
colorThresholds: [],
|
|
11613
|
+
defaultBarColor: ''
|
|
11499
11614
|
};
|
|
11500
11615
|
get isValid() {
|
|
11501
11616
|
if (this.selectedPersistentQuery === null || this.form.categoryField === '') {
|
|
@@ -11521,6 +11636,8 @@ class BarChartConfigDialogComponent {
|
|
|
11521
11636
|
this.form.showLegend = this.initialShowLegend ?? true;
|
|
11522
11637
|
this.form.legendPosition = this.initialLegendPosition ?? 'right';
|
|
11523
11638
|
this.form.showDataLabels = this.initialShowDataLabels ?? false;
|
|
11639
|
+
this.form.colorThresholds = this.initialColorThresholds ? [...this.initialColorThresholds] : [];
|
|
11640
|
+
this.form.defaultBarColor = this.initialDefaultBarColor ?? '';
|
|
11524
11641
|
// Determine series mode from initial values
|
|
11525
11642
|
if (this.initialSeriesGroupField && this.initialValueField) {
|
|
11526
11643
|
this.seriesMode = 'dynamic';
|
|
@@ -11664,6 +11781,8 @@ class BarChartConfigDialogComponent {
|
|
|
11664
11781
|
showLegend: this.form.showLegend,
|
|
11665
11782
|
legendPosition: this.form.legendPosition,
|
|
11666
11783
|
showDataLabels: this.form.showDataLabels,
|
|
11784
|
+
colorThresholds: this.form.colorThresholds.length > 0 ? this.form.colorThresholds : undefined,
|
|
11785
|
+
defaultBarColor: this.form.defaultBarColor || undefined,
|
|
11667
11786
|
filters: filtersDto
|
|
11668
11787
|
};
|
|
11669
11788
|
// Add dynamic series fields if in dynamic mode
|
|
@@ -11673,11 +11792,17 @@ class BarChartConfigDialogComponent {
|
|
|
11673
11792
|
}
|
|
11674
11793
|
this.windowRef.close(result);
|
|
11675
11794
|
}
|
|
11795
|
+
addColorThreshold() {
|
|
11796
|
+
this.form.colorThresholds.push({ value: 0, color: '#10b981' });
|
|
11797
|
+
}
|
|
11798
|
+
removeColorThreshold(index) {
|
|
11799
|
+
this.form.colorThresholds.splice(index, 1);
|
|
11800
|
+
}
|
|
11676
11801
|
onCancel() {
|
|
11677
11802
|
this.windowRef.close();
|
|
11678
11803
|
}
|
|
11679
11804
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BarChartConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11680
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: BarChartConfigDialogComponent, isStandalone: true, selector: "mm-bar-chart-config-dialog", inputs: { initialQueryRtId: "initialQueryRtId", initialQueryName: "initialQueryName", initialChartType: "initialChartType", initialCategoryField: "initialCategoryField", initialSeries: "initialSeries", initialSeriesGroupField: "initialSeriesGroupField", initialValueField: "initialValueField", initialShowLegend: "initialShowLegend", initialLegendPosition: "initialLegendPosition", initialShowDataLabels: "initialShowDataLabels", initialFilters: "initialFilters" }, viewQueries: [{ propertyName: "querySelector", first: true, predicate: ["querySelector"], descendants: true }], ngImport: i0, template: `
|
|
11805
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: BarChartConfigDialogComponent, isStandalone: true, selector: "mm-bar-chart-config-dialog", inputs: { initialQueryRtId: "initialQueryRtId", initialQueryName: "initialQueryName", initialChartType: "initialChartType", initialCategoryField: "initialCategoryField", initialSeries: "initialSeries", initialSeriesGroupField: "initialSeriesGroupField", initialValueField: "initialValueField", initialShowLegend: "initialShowLegend", initialLegendPosition: "initialLegendPosition", initialShowDataLabels: "initialShowDataLabels", initialColorThresholds: "initialColorThresholds", initialDefaultBarColor: "initialDefaultBarColor", initialFilters: "initialFilters" }, viewQueries: [{ propertyName: "querySelector", first: true, predicate: ["querySelector"], descendants: true }], ngImport: i0, template: `
|
|
11681
11806
|
<div class="config-container">
|
|
11682
11807
|
|
|
11683
11808
|
<div class="config-form" [class.loading]="isLoadingInitial">
|
|
@@ -11907,6 +12032,24 @@ class BarChartConfigDialogComponent {
|
|
|
11907
12032
|
</div>
|
|
11908
12033
|
}
|
|
11909
12034
|
</div>
|
|
12035
|
+
|
|
12036
|
+
<div class="form-section">
|
|
12037
|
+
<h4>Conditional Colors</h4>
|
|
12038
|
+
<p class="section-hint">Color bars based on value thresholds (sorted ascending).</p>
|
|
12039
|
+
@for (threshold of form.colorThresholds; track $index) {
|
|
12040
|
+
<div class="threshold-row">
|
|
12041
|
+
<label>Values ≤</label>
|
|
12042
|
+
<kendo-numerictextbox [(ngModel)]="threshold.value" [format]="'n0'" [spinners]="false" style="width: 100px;"></kendo-numerictextbox>
|
|
12043
|
+
<kendo-textbox [(ngModel)]="threshold.color" [placeholder]="'Color (#10b981)'" style="width: 120px;"></kendo-textbox>
|
|
12044
|
+
<button kendoButton fillMode="flat" (click)="removeColorThreshold($index)">Remove</button>
|
|
12045
|
+
</div>
|
|
12046
|
+
}
|
|
12047
|
+
<div class="threshold-row">
|
|
12048
|
+
<label>Default color</label>
|
|
12049
|
+
<kendo-textbox [(ngModel)]="form.defaultBarColor" [placeholder]="'#ef4444'" style="width: 120px;"></kendo-textbox>
|
|
12050
|
+
</div>
|
|
12051
|
+
<button kendoButton fillMode="flat" (click)="addColorThreshold()">+ Add Threshold</button>
|
|
12052
|
+
</div>
|
|
11910
12053
|
</div>
|
|
11911
12054
|
|
|
11912
12055
|
<div class="action-bar mm-dialog-actions">
|
|
@@ -11920,7 +12063,7 @@ class BarChartConfigDialogComponent {
|
|
|
11920
12063
|
</button>
|
|
11921
12064
|
</div>
|
|
11922
12065
|
</div>
|
|
11923
|
-
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px}.checkbox-field{flex-direction:row;align-items:center}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.query-item{display:flex;flex-direction:column;gap:2px}.query-name{font-weight:500}.query-description{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: i3.RadioButtonDirective, selector: "input[kendoRadioButton]", inputs: ["size"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "directive", type: i4.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "component", type: i4.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "component", type: i4.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "component", type: i4.MultiSelectComponent, selector: "kendo-multiselect", inputs: ["showStickyHeader", "focusableId", "autoClose", "loading", "data", "value", "valueField", "textField", "tabindex", "tabIndex", "size", "rounded", "fillMode", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "disabled", "itemDisabled", "checkboxes", "readonly", "filterable", "virtual", "popupSettings", "listHeight", "valuePrimitive", "clearButton", "tagMapper", "allowCustom", "valueNormalizer", "inputAttributes"], outputs: ["filterChange", "valueChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "removeTag"], exportAs: ["kendoMultiSelect"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: FieldFilterEditorComponent, selector: "mm-field-filter-editor", inputs: ["availableAttributes", "ckTypeId", "hideNavigationProperties", "attributePaths", "enableVariables", "availableVariables", "filters"], outputs: ["filtersChange"] }, { kind: "component", type: QuerySelectorComponent, selector: "mm-query-selector", inputs: ["placeholder", "hint", "disabled"], outputs: ["querySelected", "queriesLoaded"] }, { kind: "component", type: LoadingOverlayComponent, selector: "mm-loading-overlay", inputs: ["loading"] }] });
|
|
12066
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px}.checkbox-field{flex-direction:row;align-items:center}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.query-item{display:flex;flex-direction:column;gap:2px}.query-name{font-weight:500}.query-description{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.form-section{margin-top:8px}.form-section h4{margin:0 0 4px;font-size:.95rem;font-weight:600}.threshold-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}.threshold-row label{font-size:.85rem;min-width:70px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: i3.RadioButtonDirective, selector: "input[kendoRadioButton]", inputs: ["size"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "directive", type: i4.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "component", type: i4.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "component", type: i4.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "component", type: i4.MultiSelectComponent, selector: "kendo-multiselect", inputs: ["showStickyHeader", "focusableId", "autoClose", "loading", "data", "value", "valueField", "textField", "tabindex", "tabIndex", "size", "rounded", "fillMode", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "disabled", "itemDisabled", "checkboxes", "readonly", "filterable", "virtual", "popupSettings", "listHeight", "valuePrimitive", "clearButton", "tagMapper", "allowCustom", "valueNormalizer", "inputAttributes"], outputs: ["filterChange", "valueChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "removeTag"], exportAs: ["kendoMultiSelect"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: FieldFilterEditorComponent, selector: "mm-field-filter-editor", inputs: ["availableAttributes", "ckTypeId", "hideNavigationProperties", "attributePaths", "enableVariables", "availableVariables", "filters"], outputs: ["filtersChange"] }, { kind: "component", type: QuerySelectorComponent, selector: "mm-query-selector", inputs: ["placeholder", "hint", "disabled"], outputs: ["querySelected", "queriesLoaded"] }, { kind: "component", type: LoadingOverlayComponent, selector: "mm-loading-overlay", inputs: ["loading"] }] });
|
|
11924
12067
|
}
|
|
11925
12068
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BarChartConfigDialogComponent, decorators: [{
|
|
11926
12069
|
type: Component,
|
|
@@ -12164,6 +12307,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
12164
12307
|
</div>
|
|
12165
12308
|
}
|
|
12166
12309
|
</div>
|
|
12310
|
+
|
|
12311
|
+
<div class="form-section">
|
|
12312
|
+
<h4>Conditional Colors</h4>
|
|
12313
|
+
<p class="section-hint">Color bars based on value thresholds (sorted ascending).</p>
|
|
12314
|
+
@for (threshold of form.colorThresholds; track $index) {
|
|
12315
|
+
<div class="threshold-row">
|
|
12316
|
+
<label>Values ≤</label>
|
|
12317
|
+
<kendo-numerictextbox [(ngModel)]="threshold.value" [format]="'n0'" [spinners]="false" style="width: 100px;"></kendo-numerictextbox>
|
|
12318
|
+
<kendo-textbox [(ngModel)]="threshold.color" [placeholder]="'Color (#10b981)'" style="width: 120px;"></kendo-textbox>
|
|
12319
|
+
<button kendoButton fillMode="flat" (click)="removeColorThreshold($index)">Remove</button>
|
|
12320
|
+
</div>
|
|
12321
|
+
}
|
|
12322
|
+
<div class="threshold-row">
|
|
12323
|
+
<label>Default color</label>
|
|
12324
|
+
<kendo-textbox [(ngModel)]="form.defaultBarColor" [placeholder]="'#ef4444'" style="width: 120px;"></kendo-textbox>
|
|
12325
|
+
</div>
|
|
12326
|
+
<button kendoButton fillMode="flat" (click)="addColorThreshold()">+ Add Threshold</button>
|
|
12327
|
+
</div>
|
|
12167
12328
|
</div>
|
|
12168
12329
|
|
|
12169
12330
|
<div class="action-bar mm-dialog-actions">
|
|
@@ -12177,7 +12338,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
12177
12338
|
</button>
|
|
12178
12339
|
</div>
|
|
12179
12340
|
</div>
|
|
12180
|
-
`, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px}.checkbox-field{flex-direction:row;align-items:center}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.query-item{display:flex;flex-direction:column;gap:2px}.query-name{font-weight:500}.query-description{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}\n"] }]
|
|
12341
|
+
`, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px}.checkbox-field{flex-direction:row;align-items:center}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.query-item{display:flex;flex-direction:column;gap:2px}.query-name{font-weight:500}.query-description{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.form-section{margin-top:8px}.form-section h4{margin:0 0 4px;font-size:.95rem;font-weight:600}.threshold-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}.threshold-row label{font-size:.85rem;min-width:70px}\n"] }]
|
|
12181
12342
|
}], propDecorators: { querySelector: [{
|
|
12182
12343
|
type: ViewChild,
|
|
12183
12344
|
args: ['querySelector']
|
|
@@ -12201,6 +12362,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
12201
12362
|
type: Input
|
|
12202
12363
|
}], initialShowDataLabels: [{
|
|
12203
12364
|
type: Input
|
|
12365
|
+
}], initialColorThresholds: [{
|
|
12366
|
+
type: Input
|
|
12367
|
+
}], initialDefaultBarColor: [{
|
|
12368
|
+
type: Input
|
|
12204
12369
|
}], initialFilters: [{
|
|
12205
12370
|
type: Input
|
|
12206
12371
|
}] } });
|
|
@@ -12223,6 +12388,28 @@ class LineChartWidgetComponent {
|
|
|
12223
12388
|
valueAxes = this._valueAxes.asReadonly();
|
|
12224
12389
|
error = this._error.asReadonly();
|
|
12225
12390
|
data = computed(() => this._seriesData(), ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
12391
|
+
plotBands = computed(() => {
|
|
12392
|
+
if (!this.config?.referenceLines?.length)
|
|
12393
|
+
return [];
|
|
12394
|
+
return this.config.referenceLines.map(ref => {
|
|
12395
|
+
const lineColor = ref.color ?? '#ef4444';
|
|
12396
|
+
const bandWidth = ref.value * 0.002 || 1;
|
|
12397
|
+
return {
|
|
12398
|
+
from: ref.value - bandWidth,
|
|
12399
|
+
to: ref.value + bandWidth,
|
|
12400
|
+
color: lineColor,
|
|
12401
|
+
opacity: ref.opacity ?? 0.8,
|
|
12402
|
+
label: ref.label ? {
|
|
12403
|
+
text: ref.label,
|
|
12404
|
+
position: 'top',
|
|
12405
|
+
align: 'right',
|
|
12406
|
+
color: lineColor,
|
|
12407
|
+
font: '500 0.8rem sans-serif',
|
|
12408
|
+
padding: { top: 2, right: 4, bottom: 2, left: 4 }
|
|
12409
|
+
} : undefined
|
|
12410
|
+
};
|
|
12411
|
+
});
|
|
12412
|
+
}, ...(ngDevMode ? [{ debugName: "plotBands" }] : /* istanbul ignore next */ []));
|
|
12226
12413
|
chartType = computed(() => {
|
|
12227
12414
|
return this.config?.chartType ?? 'line';
|
|
12228
12415
|
}, ...(ngDevMode ? [{ debugName: "chartType" }] : /* istanbul ignore next */ []));
|
|
@@ -12482,11 +12669,14 @@ class LineChartWidgetComponent {
|
|
|
12482
12669
|
<span>{{ error() }}</span>
|
|
12483
12670
|
</div>
|
|
12484
12671
|
} @else {
|
|
12485
|
-
<kendo-chart class="chart-container">
|
|
12486
|
-
<kendo-chart-
|
|
12672
|
+
<kendo-chart class="chart-container" [plotArea]="{ background: 'transparent', margin: { top: 0, right: 0, bottom: 0, left: 0 } }">
|
|
12673
|
+
<kendo-chart-area [background]="'transparent'"></kendo-chart-area>
|
|
12487
12674
|
|
|
12488
12675
|
<kendo-chart-category-axis>
|
|
12489
|
-
<kendo-chart-category-axis-item
|
|
12676
|
+
<kendo-chart-category-axis-item
|
|
12677
|
+
[categories]="categories()"
|
|
12678
|
+
[line]="{ visible: false }"
|
|
12679
|
+
[majorGridLines]="{ visible: false }">
|
|
12490
12680
|
<kendo-chart-category-axis-item-labels
|
|
12491
12681
|
[rotation]="labelRotation()"
|
|
12492
12682
|
[step]="labelStep()"
|
|
@@ -12500,19 +12690,36 @@ class LineChartWidgetComponent {
|
|
|
12500
12690
|
@for (axis of valueAxes(); track axis.name) {
|
|
12501
12691
|
<kendo-chart-value-axis-item
|
|
12502
12692
|
[name]="axis.name"
|
|
12503
|
-
[title]="{ text: axis.unit }"
|
|
12693
|
+
[title]="{ text: axis.unit }"
|
|
12694
|
+
[line]="{ visible: false }"
|
|
12695
|
+
[majorGridLines]="{ color: 'rgba(255,255,255,0.06)' }"
|
|
12696
|
+
[plotBands]="plotBands()">
|
|
12504
12697
|
</kendo-chart-value-axis-item>
|
|
12505
12698
|
}
|
|
12506
12699
|
</kendo-chart-value-axis>
|
|
12507
12700
|
}
|
|
12508
12701
|
|
|
12702
|
+
@if (valueAxes().length === 0) {
|
|
12703
|
+
<kendo-chart-value-axis>
|
|
12704
|
+
<kendo-chart-value-axis-item
|
|
12705
|
+
[name]="''"
|
|
12706
|
+
[title]="{ text: config.valueAxisTitle ?? '' }"
|
|
12707
|
+
[line]="{ visible: false }"
|
|
12708
|
+
[majorGridLines]="{ color: 'rgba(255,255,255,0.06)' }"
|
|
12709
|
+
[plotBands]="plotBands()">
|
|
12710
|
+
</kendo-chart-value-axis-item>
|
|
12711
|
+
</kendo-chart-value-axis>
|
|
12712
|
+
}
|
|
12713
|
+
|
|
12509
12714
|
<kendo-chart-series>
|
|
12510
12715
|
@for (series of seriesData(); track series.name) {
|
|
12511
12716
|
<kendo-chart-series-item
|
|
12512
12717
|
[type]="chartType()"
|
|
12718
|
+
[style]="'smooth'"
|
|
12513
12719
|
[data]="series.data"
|
|
12514
12720
|
[name]="series.name"
|
|
12515
12721
|
[axis]="series.axisName ?? ''"
|
|
12722
|
+
[opacity]="0.7"
|
|
12516
12723
|
[markers]="{ visible: config.showMarkers ?? false }">
|
|
12517
12724
|
</kendo-chart-series-item>
|
|
12518
12725
|
}
|
|
@@ -12534,7 +12741,7 @@ class LineChartWidgetComponent {
|
|
|
12534
12741
|
</kendo-chart>
|
|
12535
12742
|
}
|
|
12536
12743
|
</div>
|
|
12537
|
-
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.line-chart-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.line-chart-widget.loading,.line-chart-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$
|
|
12744
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.line-chart-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.line-chart-widget.loading,.line-chart-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$7.ChartComponent, selector: "kendo-chart", inputs: ["pannable", "renderAs", "seriesColors", "subtitle", "title", "noData", "observeStyles", "transitions", "zoomable", "axisDefaults", "categoryAxis", "chartArea", "legend", "panes", "paneDefaults", "plotArea", "series", "seriesDefaults", "tooltip", "valueAxis", "xAxis", "yAxis", "resizeRateLimit", "popupSettings", "drilldownLevel"], outputs: ["axisLabelClick", "drag", "dragEnd", "dragStart", "legendItemHover", "legendItemLeave", "noteClick", "noteHover", "noteLeave", "paneRender", "plotAreaClick", "plotAreaHover", "plotAreaLeave", "render", "select", "selectEnd", "selectStart", "seriesClick", "drilldown", "seriesHover", "seriesOver", "seriesLeave", "zoom", "zoomEnd", "zoomStart", "legendItemClick", "drilldownLevelChange"], exportAs: ["kendoChart"] }, { kind: "directive", type: i1$7.SeriesTooltipTemplateDirective, selector: "[kendoChartSeriesTooltipTemplate]" }, { kind: "component", type: i1$7.CategoryAxisComponent, selector: "kendo-chart-category-axis" }, { kind: "component", type: i1$7.CategoryAxisItemComponent, selector: "kendo-chart-category-axis-item", inputs: ["autoBaseUnitSteps", "axisCrossingValue", "background", "baseUnit", "baseUnitStep", "categories", "color", "justified", "line", "majorGridLines", "majorTicks", "max", "maxDateGroups", "maxDivisions", "min", "minorGridLines", "minorTicks", "name", "pane", "plotBands", "reverse", "roundToBaseUnit", "startAngle", "type", "visible", "weekStartDay", "crosshair", "labels", "notes", "select", "title", "rangeLabels"] }, { kind: "component", type: i1$7.CategoryAxisLabelsComponent, selector: "kendo-chart-category-axis-item-labels", inputs: ["background", "border", "color", "content", "culture", "dateFormats", "font", "format", "margin", "mirror", "padding", "position", "rotation", "skip", "step", "visible", "visual"] }, { kind: "component", type: i1$7.ChartAreaComponent, selector: "kendo-chart-area", inputs: ["background", "border", "height", "margin", "opacity", "width"] }, { kind: "component", type: i1$7.LegendComponent, selector: "kendo-chart-legend", inputs: ["align", "background", "border", "height", "labels", "margin", "offsetX", "offsetY", "orientation", "padding", "position", "reverse", "visible", "width", "markers", "spacing", "inactiveItems", "item", "title", "focusHighlight"] }, { kind: "component", type: i1$7.SeriesComponent, selector: "kendo-chart-series" }, { kind: "component", type: i1$7.SeriesItemComponent, selector: "kendo-chart-series-item", inputs: ["aggregate", "autoFit", "axis", "border", "categoryAxis", "categoryField", "closeField", "color", "colorField", "connectors", "currentField", "dashType", "data", "downColor", "downColorField", "drilldownField", "dynamicHeight", "dynamicSlope", "errorHighField", "errorLowField", "explodeField", "field", "fromField", "gap", "highField", "holeSize", "line", "lowField", "lowerField", "margin", "maxSize", "mean", "meanField", "median", "medianField", "minSize", "missingValues", "name", "neckRatio", "negativeColor", "negativeValues", "noteTextField", "opacity", "openField", "outliersField", "overlay", "padding", "q1Field", "q3Field", "segmentSpacing", "size", "sizeField", "spacing", "stack", "startAngle", "style", "summaryField", "target", "toField", "type", "upperField", "visible", "visibleInLegend", "visibleInLegendField", "visual", "width", "whiskers", "xAxis", "xErrorHighField", "xErrorLowField", "xField", "yAxis", "yErrorHighField", "yErrorLowField", "yField", "zIndex", "trendline", "for", "legendItem", "pattern", "patternField", "errorBars", "extremes", "highlight", "labels", "markers", "notes", "outliers", "tooltip"] }, { kind: "component", type: i1$7.TooltipComponent, selector: "kendo-chart-tooltip", inputs: ["background", "border", "color", "font", "format", "opacity", "padding", "shared", "visible"] }, { kind: "component", type: i1$7.ValueAxisComponent, selector: "kendo-chart-value-axis" }, { kind: "component", type: i1$7.ValueAxisItemComponent, selector: "kendo-chart-value-axis-item", inputs: ["axisCrossingValue", "background", "color", "line", "majorGridLines", "majorTicks", "majorUnit", "max", "min", "minorGridLines", "minorTicks", "minorUnit", "name", "narrowRange", "pane", "plotBands", "reverse", "type", "visible", "crosshair", "labels", "notes", "title"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
12538
12745
|
}
|
|
12539
12746
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: LineChartWidgetComponent, decorators: [{
|
|
12540
12747
|
type: Component,
|
|
@@ -12555,11 +12762,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
12555
12762
|
<span>{{ error() }}</span>
|
|
12556
12763
|
</div>
|
|
12557
12764
|
} @else {
|
|
12558
|
-
<kendo-chart class="chart-container">
|
|
12559
|
-
<kendo-chart-
|
|
12765
|
+
<kendo-chart class="chart-container" [plotArea]="{ background: 'transparent', margin: { top: 0, right: 0, bottom: 0, left: 0 } }">
|
|
12766
|
+
<kendo-chart-area [background]="'transparent'"></kendo-chart-area>
|
|
12560
12767
|
|
|
12561
12768
|
<kendo-chart-category-axis>
|
|
12562
|
-
<kendo-chart-category-axis-item
|
|
12769
|
+
<kendo-chart-category-axis-item
|
|
12770
|
+
[categories]="categories()"
|
|
12771
|
+
[line]="{ visible: false }"
|
|
12772
|
+
[majorGridLines]="{ visible: false }">
|
|
12563
12773
|
<kendo-chart-category-axis-item-labels
|
|
12564
12774
|
[rotation]="labelRotation()"
|
|
12565
12775
|
[step]="labelStep()"
|
|
@@ -12573,19 +12783,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
12573
12783
|
@for (axis of valueAxes(); track axis.name) {
|
|
12574
12784
|
<kendo-chart-value-axis-item
|
|
12575
12785
|
[name]="axis.name"
|
|
12576
|
-
[title]="{ text: axis.unit }"
|
|
12786
|
+
[title]="{ text: axis.unit }"
|
|
12787
|
+
[line]="{ visible: false }"
|
|
12788
|
+
[majorGridLines]="{ color: 'rgba(255,255,255,0.06)' }"
|
|
12789
|
+
[plotBands]="plotBands()">
|
|
12577
12790
|
</kendo-chart-value-axis-item>
|
|
12578
12791
|
}
|
|
12579
12792
|
</kendo-chart-value-axis>
|
|
12580
12793
|
}
|
|
12581
12794
|
|
|
12795
|
+
@if (valueAxes().length === 0) {
|
|
12796
|
+
<kendo-chart-value-axis>
|
|
12797
|
+
<kendo-chart-value-axis-item
|
|
12798
|
+
[name]="''"
|
|
12799
|
+
[title]="{ text: config.valueAxisTitle ?? '' }"
|
|
12800
|
+
[line]="{ visible: false }"
|
|
12801
|
+
[majorGridLines]="{ color: 'rgba(255,255,255,0.06)' }"
|
|
12802
|
+
[plotBands]="plotBands()">
|
|
12803
|
+
</kendo-chart-value-axis-item>
|
|
12804
|
+
</kendo-chart-value-axis>
|
|
12805
|
+
}
|
|
12806
|
+
|
|
12582
12807
|
<kendo-chart-series>
|
|
12583
12808
|
@for (series of seriesData(); track series.name) {
|
|
12584
12809
|
<kendo-chart-series-item
|
|
12585
12810
|
[type]="chartType()"
|
|
12811
|
+
[style]="'smooth'"
|
|
12586
12812
|
[data]="series.data"
|
|
12587
12813
|
[name]="series.name"
|
|
12588
12814
|
[axis]="series.axisName ?? ''"
|
|
12815
|
+
[opacity]="0.7"
|
|
12589
12816
|
[markers]="{ visible: config.showMarkers ?? false }">
|
|
12590
12817
|
</kendo-chart-series-item>
|
|
12591
12818
|
}
|
|
@@ -12632,6 +12859,7 @@ class LineChartConfigDialogComponent {
|
|
|
12632
12859
|
initialShowLegend;
|
|
12633
12860
|
initialLegendPosition;
|
|
12634
12861
|
initialShowMarkers;
|
|
12862
|
+
initialReferenceLines;
|
|
12635
12863
|
initialFilters;
|
|
12636
12864
|
// State
|
|
12637
12865
|
isLoadingInitial = false;
|
|
@@ -12660,7 +12888,8 @@ class LineChartConfigDialogComponent {
|
|
|
12660
12888
|
unitField: '',
|
|
12661
12889
|
showLegend: true,
|
|
12662
12890
|
legendPosition: 'right',
|
|
12663
|
-
showMarkers: false
|
|
12891
|
+
showMarkers: false,
|
|
12892
|
+
referenceLines: []
|
|
12664
12893
|
};
|
|
12665
12894
|
get isValid() {
|
|
12666
12895
|
return this.selectedPersistentQuery !== null
|
|
@@ -12684,6 +12913,7 @@ class LineChartConfigDialogComponent {
|
|
|
12684
12913
|
this.form.showLegend = this.initialShowLegend ?? true;
|
|
12685
12914
|
this.form.legendPosition = this.initialLegendPosition ?? 'right';
|
|
12686
12915
|
this.form.showMarkers = this.initialShowMarkers ?? false;
|
|
12916
|
+
this.form.referenceLines = this.initialReferenceLines ? [...this.initialReferenceLines] : [];
|
|
12687
12917
|
// Initialize filters
|
|
12688
12918
|
if (this.initialFilters && this.initialFilters.length > 0) {
|
|
12689
12919
|
this.filters = this.initialFilters.map((f, index) => ({
|
|
@@ -12784,15 +13014,22 @@ class LineChartConfigDialogComponent {
|
|
|
12784
13014
|
showLegend: this.form.showLegend,
|
|
12785
13015
|
legendPosition: this.form.legendPosition,
|
|
12786
13016
|
showMarkers: this.form.showMarkers,
|
|
13017
|
+
referenceLines: this.form.referenceLines.length > 0 ? this.form.referenceLines : undefined,
|
|
12787
13018
|
filters: filtersDto
|
|
12788
13019
|
};
|
|
12789
13020
|
this.windowRef.close(result);
|
|
12790
13021
|
}
|
|
13022
|
+
addReferenceLine() {
|
|
13023
|
+
this.form.referenceLines.push({ value: 0, label: '', color: '#ef4444' });
|
|
13024
|
+
}
|
|
13025
|
+
removeReferenceLine(index) {
|
|
13026
|
+
this.form.referenceLines.splice(index, 1);
|
|
13027
|
+
}
|
|
12791
13028
|
onCancel() {
|
|
12792
13029
|
this.windowRef.close();
|
|
12793
13030
|
}
|
|
12794
13031
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: LineChartConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12795
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: LineChartConfigDialogComponent, isStandalone: true, selector: "mm-line-chart-config-dialog", inputs: { initialQueryRtId: "initialQueryRtId", initialQueryName: "initialQueryName", initialChartType: "initialChartType", initialCategoryField: "initialCategoryField", initialSeriesGroupField: "initialSeriesGroupField", initialValueField: "initialValueField", initialUnitField: "initialUnitField", initialShowLegend: "initialShowLegend", initialLegendPosition: "initialLegendPosition", initialShowMarkers: "initialShowMarkers", initialFilters: "initialFilters" }, viewQueries: [{ propertyName: "querySelector", first: true, predicate: ["querySelector"], descendants: true }], ngImport: i0, template: `
|
|
13032
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: LineChartConfigDialogComponent, isStandalone: true, selector: "mm-line-chart-config-dialog", inputs: { initialQueryRtId: "initialQueryRtId", initialQueryName: "initialQueryName", initialChartType: "initialChartType", initialCategoryField: "initialCategoryField", initialSeriesGroupField: "initialSeriesGroupField", initialValueField: "initialValueField", initialUnitField: "initialUnitField", initialShowLegend: "initialShowLegend", initialLegendPosition: "initialLegendPosition", initialShowMarkers: "initialShowMarkers", initialReferenceLines: "initialReferenceLines", initialFilters: "initialFilters" }, viewQueries: [{ propertyName: "querySelector", first: true, predicate: ["querySelector"], descendants: true }], ngImport: i0, template: `
|
|
12796
13033
|
<div class="config-container">
|
|
12797
13034
|
|
|
12798
13035
|
<div class="config-form" [class.loading]="isLoadingInitial">
|
|
@@ -12968,6 +13205,20 @@ class LineChartConfigDialogComponent {
|
|
|
12968
13205
|
</div>
|
|
12969
13206
|
}
|
|
12970
13207
|
</div>
|
|
13208
|
+
|
|
13209
|
+
<div class="form-section">
|
|
13210
|
+
<h4>Reference Lines</h4>
|
|
13211
|
+
<p class="section-hint">Add horizontal threshold lines to the chart.</p>
|
|
13212
|
+
@for (refLine of form.referenceLines; track $index) {
|
|
13213
|
+
<div class="reference-line-row">
|
|
13214
|
+
<kendo-numerictextbox [(ngModel)]="refLine.value" [format]="'n0'" [placeholder]="'Value'" [spinners]="false" style="width: 100px;"></kendo-numerictextbox>
|
|
13215
|
+
<kendo-textbox [(ngModel)]="refLine.label" [placeholder]="'Label (e.g. Limit)'" style="flex: 1;"></kendo-textbox>
|
|
13216
|
+
<kendo-textbox [(ngModel)]="refLine.color" [placeholder]="'Color (#ef4444)'" style="width: 110px;"></kendo-textbox>
|
|
13217
|
+
<button kendoButton fillMode="flat" (click)="removeReferenceLine($index)">Remove</button>
|
|
13218
|
+
</div>
|
|
13219
|
+
}
|
|
13220
|
+
<button kendoButton fillMode="flat" (click)="addReferenceLine()">+ Add Reference Line</button>
|
|
13221
|
+
</div>
|
|
12971
13222
|
</div>
|
|
12972
13223
|
|
|
12973
13224
|
<div class="action-bar mm-dialog-actions">
|
|
@@ -12981,7 +13232,7 @@ class LineChartConfigDialogComponent {
|
|
|
12981
13232
|
</button>
|
|
12982
13233
|
</div>
|
|
12983
13234
|
</div>
|
|
12984
|
-
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px;align-items:center}.checkbox-field{flex-direction:row;align-items:center;margin-bottom:0}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: i3.RadioButtonDirective, selector: "input[kendoRadioButton]", inputs: ["size"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "directive", type: i4.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "component", type: i4.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "component", type: i4.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: FieldFilterEditorComponent, selector: "mm-field-filter-editor", inputs: ["availableAttributes", "ckTypeId", "hideNavigationProperties", "attributePaths", "enableVariables", "availableVariables", "filters"], outputs: ["filtersChange"] }, { kind: "component", type: QuerySelectorComponent, selector: "mm-query-selector", inputs: ["placeholder", "hint", "disabled"], outputs: ["querySelected", "queriesLoaded"] }, { kind: "component", type: LoadingOverlayComponent, selector: "mm-loading-overlay", inputs: ["loading"] }] });
|
|
13235
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px;align-items:center}.checkbox-field{flex-direction:row;align-items:center;margin-bottom:0}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.form-section{margin-top:8px}.form-section h4{margin:0 0 4px;font-size:.95rem;font-weight:600}.reference-line-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: i3.RadioButtonDirective, selector: "input[kendoRadioButton]", inputs: ["size"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "directive", type: i4.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "component", type: i4.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "component", type: i4.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: FieldFilterEditorComponent, selector: "mm-field-filter-editor", inputs: ["availableAttributes", "ckTypeId", "hideNavigationProperties", "attributePaths", "enableVariables", "availableVariables", "filters"], outputs: ["filtersChange"] }, { kind: "component", type: QuerySelectorComponent, selector: "mm-query-selector", inputs: ["placeholder", "hint", "disabled"], outputs: ["querySelected", "queriesLoaded"] }, { kind: "component", type: LoadingOverlayComponent, selector: "mm-loading-overlay", inputs: ["loading"] }] });
|
|
12985
13236
|
}
|
|
12986
13237
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: LineChartConfigDialogComponent, decorators: [{
|
|
12987
13238
|
type: Component,
|
|
@@ -13171,6 +13422,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
13171
13422
|
</div>
|
|
13172
13423
|
}
|
|
13173
13424
|
</div>
|
|
13425
|
+
|
|
13426
|
+
<div class="form-section">
|
|
13427
|
+
<h4>Reference Lines</h4>
|
|
13428
|
+
<p class="section-hint">Add horizontal threshold lines to the chart.</p>
|
|
13429
|
+
@for (refLine of form.referenceLines; track $index) {
|
|
13430
|
+
<div class="reference-line-row">
|
|
13431
|
+
<kendo-numerictextbox [(ngModel)]="refLine.value" [format]="'n0'" [placeholder]="'Value'" [spinners]="false" style="width: 100px;"></kendo-numerictextbox>
|
|
13432
|
+
<kendo-textbox [(ngModel)]="refLine.label" [placeholder]="'Label (e.g. Limit)'" style="flex: 1;"></kendo-textbox>
|
|
13433
|
+
<kendo-textbox [(ngModel)]="refLine.color" [placeholder]="'Color (#ef4444)'" style="width: 110px;"></kendo-textbox>
|
|
13434
|
+
<button kendoButton fillMode="flat" (click)="removeReferenceLine($index)">Remove</button>
|
|
13435
|
+
</div>
|
|
13436
|
+
}
|
|
13437
|
+
<button kendoButton fillMode="flat" (click)="addReferenceLine()">+ Add Reference Line</button>
|
|
13438
|
+
</div>
|
|
13174
13439
|
</div>
|
|
13175
13440
|
|
|
13176
13441
|
<div class="action-bar mm-dialog-actions">
|
|
@@ -13184,7 +13449,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
13184
13449
|
</button>
|
|
13185
13450
|
</div>
|
|
13186
13451
|
</div>
|
|
13187
|
-
`, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px;align-items:center}.checkbox-field{flex-direction:row;align-items:center;margin-bottom:0}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}\n"] }]
|
|
13452
|
+
`, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:20px;flex:1;overflow-y:auto;padding:16px;position:relative}.config-form.loading{pointer-events:none}.config-section{padding:16px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.section-title{margin:0 0 16px;font-size:1rem;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.section-hint{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.form-field:last-child{margin-bottom:0}.form-field label{font-weight:600;font-size:.9rem;color:var(--kendo-color-on-app-surface, #212529)}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.chart-type-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.radio-label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.form-row{display:flex;gap:24px;align-items:center}.checkbox-field{flex-direction:row;align-items:center;margin-bottom:0}.checkbox-field label{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:400}.column-item{display:flex;justify-content:space-between;gap:16px}.column-path{font-weight:500}.column-type{font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.form-section{margin-top:8px}.form-section h4{margin:0 0 4px;font-size:.95rem;font-weight:600}.reference-line-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}\n"] }]
|
|
13188
13453
|
}], propDecorators: { querySelector: [{
|
|
13189
13454
|
type: ViewChild,
|
|
13190
13455
|
args: ['querySelector']
|
|
@@ -13208,6 +13473,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
13208
13473
|
type: Input
|
|
13209
13474
|
}], initialShowMarkers: [{
|
|
13210
13475
|
type: Input
|
|
13476
|
+
}], initialReferenceLines: [{
|
|
13477
|
+
type: Input
|
|
13211
13478
|
}], initialFilters: [{
|
|
13212
13479
|
type: Input
|
|
13213
13480
|
}] } });
|
|
@@ -13667,7 +13934,7 @@ class HeatmapWidgetComponent {
|
|
|
13667
13934
|
</kendo-chart>
|
|
13668
13935
|
}
|
|
13669
13936
|
</div>
|
|
13670
|
-
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.heatmap-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.heatmap-widget.loading,.heatmap-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px;color:#212529;background:#fff;border-radius:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$
|
|
13937
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.heatmap-widget{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:8px;box-sizing:border-box;overflow:hidden}.heatmap-widget.loading,.heatmap-widget.error{opacity:.7}.loading-indicator,.error-message{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.loading-indicator span{font-size:1.5rem;color:var(--kendo-color-subtle, #6c757d)}.error-message span{color:var(--kendo-color-error, #dc3545);font-size:.875rem}.chart-container{width:100%;height:100%}kendo-chart{width:100%;height:100%}.chart-tooltip{padding:4px 8px;color:#212529;background:#fff;border-radius:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ChartsModule }, { kind: "component", type: i1$7.ChartComponent, selector: "kendo-chart", inputs: ["pannable", "renderAs", "seriesColors", "subtitle", "title", "noData", "observeStyles", "transitions", "zoomable", "axisDefaults", "categoryAxis", "chartArea", "legend", "panes", "paneDefaults", "plotArea", "series", "seriesDefaults", "tooltip", "valueAxis", "xAxis", "yAxis", "resizeRateLimit", "popupSettings", "drilldownLevel"], outputs: ["axisLabelClick", "drag", "dragEnd", "dragStart", "legendItemHover", "legendItemLeave", "noteClick", "noteHover", "noteLeave", "paneRender", "plotAreaClick", "plotAreaHover", "plotAreaLeave", "render", "select", "selectEnd", "selectStart", "seriesClick", "drilldown", "seriesHover", "seriesOver", "seriesLeave", "zoom", "zoomEnd", "zoomStart", "legendItemClick", "drilldownLevelChange"], exportAs: ["kendoChart"] }, { kind: "component", type: i1$7.XAxisComponent, selector: "kendo-chart-x-axis" }, { kind: "component", type: i1$7.XAxisItemComponent, selector: "kendo-chart-x-axis-item", inputs: ["axisCrossingValue", "background", "baseUnit", "categories", "color", "line", "majorGridLines", "majorTicks", "majorUnit", "max", "min", "minorGridLines", "minorTicks", "minorUnit", "name", "narrowRange", "pane", "plotBands", "reverse", "startAngle", "type", "visible", "weekStartDay", "crosshair", "labels", "notes", "title"] }, { kind: "component", type: i1$7.XAxisLabelsComponent, selector: "kendo-chart-x-axis-item-labels", inputs: ["background", "border", "color", "content", "culture", "dateFormats", "font", "format", "margin", "mirror", "padding", "position", "rotation", "skip", "step", "visible", "visual"] }, { kind: "component", type: i1$7.YAxisComponent, selector: "kendo-chart-y-axis" }, { kind: "component", type: i1$7.YAxisItemComponent, selector: "kendo-chart-y-axis-item", inputs: ["axisCrossingValue", "background", "baseUnit", "categories", "color", "line", "majorGridLines", "majorTicks", "majorUnit", "max", "min", "minorGridLines", "minorTicks", "minorUnit", "name", "narrowRange", "pane", "plotBands", "reverse", "type", "visible", "crosshair", "labels", "notes", "title"] }, { kind: "directive", type: i1$7.SeriesTooltipTemplateDirective, selector: "[kendoChartSeriesTooltipTemplate]" }, { kind: "component", type: i1$7.LegendComponent, selector: "kendo-chart-legend", inputs: ["align", "background", "border", "height", "labels", "margin", "offsetX", "offsetY", "orientation", "padding", "position", "reverse", "visible", "width", "markers", "spacing", "inactiveItems", "item", "title", "focusHighlight"] }, { kind: "component", type: i1$7.SeriesComponent, selector: "kendo-chart-series" }, { kind: "component", type: i1$7.SeriesItemComponent, selector: "kendo-chart-series-item", inputs: ["aggregate", "autoFit", "axis", "border", "categoryAxis", "categoryField", "closeField", "color", "colorField", "connectors", "currentField", "dashType", "data", "downColor", "downColorField", "drilldownField", "dynamicHeight", "dynamicSlope", "errorHighField", "errorLowField", "explodeField", "field", "fromField", "gap", "highField", "holeSize", "line", "lowField", "lowerField", "margin", "maxSize", "mean", "meanField", "median", "medianField", "minSize", "missingValues", "name", "neckRatio", "negativeColor", "negativeValues", "noteTextField", "opacity", "openField", "outliersField", "overlay", "padding", "q1Field", "q3Field", "segmentSpacing", "size", "sizeField", "spacing", "stack", "startAngle", "style", "summaryField", "target", "toField", "type", "upperField", "visible", "visibleInLegend", "visibleInLegendField", "visual", "width", "whiskers", "xAxis", "xErrorHighField", "xErrorLowField", "xField", "yAxis", "yErrorHighField", "yErrorLowField", "yField", "zIndex", "trendline", "for", "legendItem", "pattern", "patternField", "errorBars", "extremes", "highlight", "labels", "markers", "notes", "outliers", "tooltip"] }, { kind: "component", type: i1$7.SeriesLabelsComponent, selector: "kendo-chart-series-item-labels", inputs: ["align", "background", "border", "color", "content", "ariaContent", "distance", "font", "format", "margin", "padding", "position", "rotation", "visible", "visual", "from", "to"] }, { kind: "component", type: i1$7.TooltipComponent, selector: "kendo-chart-tooltip", inputs: ["background", "border", "color", "font", "format", "opacity", "padding", "shared", "visible"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
13671
13938
|
}
|
|
13672
13939
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: HeatmapWidgetComponent, decorators: [{
|
|
13673
13940
|
type: Component,
|
|
@@ -17021,7 +17288,7 @@ class MarkdownWidgetComponent {
|
|
|
17021
17288
|
this._data.set(this.config?.content ?? '');
|
|
17022
17289
|
}
|
|
17023
17290
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarkdownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17024
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MarkdownWidgetComponent, isStandalone: true, selector: "mm-markdown-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"markdown-widget\"\n [class.loading]=\"isLoading()\"\n [class.error]=\"error()\"\n [ngStyle]=\"containerStyle()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured\n message=\"No markdown content configured.\">\n </mm-widget-not-configured>\n } @else {\n <div class=\"markdown-content mm-prose\">\n <markdown [data]=\"resolvedContent()\"></markdown>\n </div>\n }\n</div>\n", styles: [".markdown-widget{display:flex;flex-direction:column;height:100%;overflow:auto}.markdown-content{flex:1;overflow:auto}:host{--mm-prose-text: #333333;--mm-prose-heading: #1976d2;--mm-prose-link: #1565c0;--mm-prose-link-hover: #0d47a1;--mm-prose-code-bg: #f5f5f5;--mm-prose-code-text: #d32f2f;--mm-prose-pre-bg: #f5f5f5;--mm-prose-pre-border: #e0e0e0;--mm-prose-blockquote-border: #6c4da8;--mm-prose-blockquote-bg: rgba(108, 77, 168, .05);--mm-prose-table-header-bg: #f5f5f5;--mm-prose-table-header-text: #333333;--mm-prose-table-border: #e0e0e0;--mm-prose-table-row-even: rgba(0, 0, 0, .02);--mm-prose-strong: #111111;--mm-prose-em: #1565c0;--mm-prose-marker-ul: #1976d2;--mm-prose-marker-ol: #1565c0;--mm-prose-hr-start: #1976d2;--mm-prose-hr-end: #1565c0;--mm-prose-img-border: #e0e0e0;--mm-prose-font: \"Roboto\", sans-serif}:host ::ng-deep .mm-prose{color:var(--mm-prose-text);font-family:var(--mm-prose-font);line-height:1.6}:host ::ng-deep .mm-prose h1,:host ::ng-deep .mm-prose h2,:host ::ng-deep .mm-prose h3,:host ::ng-deep .mm-prose h4,:host ::ng-deep .mm-prose h5,:host ::ng-deep .mm-prose h6{color:var(--mm-prose-heading);font-weight:600;margin-top:1.5em;margin-bottom:.5em;letter-spacing:.5px}:host ::ng-deep .mm-prose h1:first-child,:host ::ng-deep .mm-prose h2:first-child,:host ::ng-deep .mm-prose h3:first-child,:host ::ng-deep .mm-prose h4:first-child,:host ::ng-deep .mm-prose h5:first-child,:host ::ng-deep .mm-prose h6:first-child{margin-top:0}:host ::ng-deep .mm-prose h1{font-size:1.75rem;border-bottom:2px solid var(--mm-prose-heading);padding-bottom:.25em}:host ::ng-deep .mm-prose h2{font-size:1.5rem;border-bottom:1px solid var(--mm-prose-table-border);padding-bottom:.2em}:host ::ng-deep .mm-prose h3{font-size:1.25rem}:host ::ng-deep .mm-prose h4{font-size:1.1rem}:host ::ng-deep .mm-prose h5,:host ::ng-deep .mm-prose h6{font-size:1rem}:host ::ng-deep .mm-prose p{margin-bottom:1em}:host ::ng-deep .mm-prose p:last-child{margin-bottom:0}:host ::ng-deep .mm-prose a{color:var(--mm-prose-link);text-decoration:none;border-bottom:1px solid transparent;transition:all .15s ease}:host ::ng-deep .mm-prose a:hover{color:var(--mm-prose-link-hover);border-bottom-color:var(--mm-prose-link-hover)}:host ::ng-deep .mm-prose ul,:host ::ng-deep .mm-prose ol{margin-bottom:1em;padding-left:1.5em}:host ::ng-deep .mm-prose li{margin-bottom:.25em}:host ::ng-deep .mm-prose ul li::marker{color:var(--mm-prose-marker-ul)}:host ::ng-deep .mm-prose ol li::marker{color:var(--mm-prose-marker-ol)}:host ::ng-deep .mm-prose code{font-family:Roboto Mono,monospace;background:var(--mm-prose-code-bg);color:var(--mm-prose-code-text);padding:.2em .4em;border-radius:4px;font-size:.9em}:host ::ng-deep .mm-prose pre{background:var(--mm-prose-pre-bg);border:1px solid var(--mm-prose-pre-border);border-radius:8px;padding:1em;overflow-x:auto;margin-bottom:1em}:host ::ng-deep .mm-prose pre code{background:transparent;padding:0;color:var(--mm-prose-text)}:host ::ng-deep .mm-prose blockquote{border-left:4px solid var(--mm-prose-blockquote-border);background:var(--mm-prose-blockquote-bg);padding:.75em 1em;margin:1em 0;border-radius:0 8px 8px 0}:host ::ng-deep .mm-prose blockquote p:last-child{margin-bottom:0}:host ::ng-deep .mm-prose table{width:100%;border-collapse:collapse;margin-bottom:1em}:host ::ng-deep .mm-prose th,:host ::ng-deep .mm-prose td{padding:.75em;border:1px solid var(--mm-prose-table-border);text-align:left}:host ::ng-deep .mm-prose th{background:var(--mm-prose-table-header-bg);color:var(--mm-prose-table-header-text);font-weight:600;text-transform:uppercase;font-size:.85em;letter-spacing:.5px}:host ::ng-deep .mm-prose tr:nth-child(2n){background:var(--mm-prose-table-row-even)}:host ::ng-deep .mm-prose hr{border:none;height:2px;background:linear-gradient(90deg,var(--mm-prose-hr-start),var(--mm-prose-hr-end),transparent);margin:1.5em 0}:host ::ng-deep .mm-prose img{max-width:100%;height:auto;border-radius:8px;border:1px solid var(--mm-prose-img-border)}:host ::ng-deep .mm-prose strong,:host ::ng-deep .mm-prose b{font-weight:600;color:var(--mm-prose-strong)}:host ::ng-deep .mm-prose em,:host ::ng-deep .mm-prose i{color:var(--mm-prose-em)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MarkdownModule }, { kind: "component", type: i2$
|
|
17291
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MarkdownWidgetComponent, isStandalone: true, selector: "mm-markdown-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"markdown-widget\"\n [class.loading]=\"isLoading()\"\n [class.error]=\"error()\"\n [ngStyle]=\"containerStyle()\">\n @if (isNotConfigured()) {\n <mm-widget-not-configured\n message=\"No markdown content configured.\">\n </mm-widget-not-configured>\n } @else {\n <div class=\"markdown-content mm-prose\">\n <markdown [data]=\"resolvedContent()\"></markdown>\n </div>\n }\n</div>\n", styles: [".markdown-widget{display:flex;flex-direction:column;height:100%;overflow:auto}.markdown-content{flex:1;overflow:auto}:host{--mm-prose-text: #333333;--mm-prose-heading: #1976d2;--mm-prose-link: #1565c0;--mm-prose-link-hover: #0d47a1;--mm-prose-code-bg: #f5f5f5;--mm-prose-code-text: #d32f2f;--mm-prose-pre-bg: #f5f5f5;--mm-prose-pre-border: #e0e0e0;--mm-prose-blockquote-border: #6c4da8;--mm-prose-blockquote-bg: rgba(108, 77, 168, .05);--mm-prose-table-header-bg: #f5f5f5;--mm-prose-table-header-text: #333333;--mm-prose-table-border: #e0e0e0;--mm-prose-table-row-even: rgba(0, 0, 0, .02);--mm-prose-strong: #111111;--mm-prose-em: #1565c0;--mm-prose-marker-ul: #1976d2;--mm-prose-marker-ol: #1565c0;--mm-prose-hr-start: #1976d2;--mm-prose-hr-end: #1565c0;--mm-prose-img-border: #e0e0e0;--mm-prose-font: \"Roboto\", sans-serif}:host ::ng-deep .mm-prose{color:var(--mm-prose-text);font-family:var(--mm-prose-font);line-height:1.6}:host ::ng-deep .mm-prose h1,:host ::ng-deep .mm-prose h2,:host ::ng-deep .mm-prose h3,:host ::ng-deep .mm-prose h4,:host ::ng-deep .mm-prose h5,:host ::ng-deep .mm-prose h6{color:var(--mm-prose-heading);font-weight:600;margin-top:1.5em;margin-bottom:.5em;letter-spacing:.5px}:host ::ng-deep .mm-prose h1:first-child,:host ::ng-deep .mm-prose h2:first-child,:host ::ng-deep .mm-prose h3:first-child,:host ::ng-deep .mm-prose h4:first-child,:host ::ng-deep .mm-prose h5:first-child,:host ::ng-deep .mm-prose h6:first-child{margin-top:0}:host ::ng-deep .mm-prose h1{font-size:1.75rem;border-bottom:2px solid var(--mm-prose-heading);padding-bottom:.25em}:host ::ng-deep .mm-prose h2{font-size:1.5rem;border-bottom:1px solid var(--mm-prose-table-border);padding-bottom:.2em}:host ::ng-deep .mm-prose h3{font-size:1.25rem}:host ::ng-deep .mm-prose h4{font-size:1.1rem}:host ::ng-deep .mm-prose h5,:host ::ng-deep .mm-prose h6{font-size:1rem}:host ::ng-deep .mm-prose p{margin-bottom:1em}:host ::ng-deep .mm-prose p:last-child{margin-bottom:0}:host ::ng-deep .mm-prose a{color:var(--mm-prose-link);text-decoration:none;border-bottom:1px solid transparent;transition:all .15s ease}:host ::ng-deep .mm-prose a:hover{color:var(--mm-prose-link-hover);border-bottom-color:var(--mm-prose-link-hover)}:host ::ng-deep .mm-prose ul,:host ::ng-deep .mm-prose ol{margin-bottom:1em;padding-left:1.5em}:host ::ng-deep .mm-prose li{margin-bottom:.25em}:host ::ng-deep .mm-prose ul li::marker{color:var(--mm-prose-marker-ul)}:host ::ng-deep .mm-prose ol li::marker{color:var(--mm-prose-marker-ol)}:host ::ng-deep .mm-prose code{font-family:Roboto Mono,monospace;background:var(--mm-prose-code-bg);color:var(--mm-prose-code-text);padding:.2em .4em;border-radius:4px;font-size:.9em}:host ::ng-deep .mm-prose pre{background:var(--mm-prose-pre-bg);border:1px solid var(--mm-prose-pre-border);border-radius:8px;padding:1em;overflow-x:auto;margin-bottom:1em}:host ::ng-deep .mm-prose pre code{background:transparent;padding:0;color:var(--mm-prose-text)}:host ::ng-deep .mm-prose blockquote{border-left:4px solid var(--mm-prose-blockquote-border);background:var(--mm-prose-blockquote-bg);padding:.75em 1em;margin:1em 0;border-radius:0 8px 8px 0}:host ::ng-deep .mm-prose blockquote p:last-child{margin-bottom:0}:host ::ng-deep .mm-prose table{width:100%;border-collapse:collapse;margin-bottom:1em}:host ::ng-deep .mm-prose th,:host ::ng-deep .mm-prose td{padding:.75em;border:1px solid var(--mm-prose-table-border);text-align:left}:host ::ng-deep .mm-prose th{background:var(--mm-prose-table-header-bg);color:var(--mm-prose-table-header-text);font-weight:600;text-transform:uppercase;font-size:.85em;letter-spacing:.5px}:host ::ng-deep .mm-prose tr:nth-child(2n){background:var(--mm-prose-table-row-even)}:host ::ng-deep .mm-prose hr{border:none;height:2px;background:linear-gradient(90deg,var(--mm-prose-hr-start),var(--mm-prose-hr-end),transparent);margin:1.5em 0}:host ::ng-deep .mm-prose img{max-width:100%;height:auto;border-radius:8px;border:1px solid var(--mm-prose-img-border)}:host ::ng-deep .mm-prose strong,:host ::ng-deep .mm-prose b{font-weight:600;color:var(--mm-prose-strong)}:host ::ng-deep .mm-prose em,:host ::ng-deep .mm-prose i{color:var(--mm-prose-em)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MarkdownModule }, { kind: "component", type: i2$1.MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
17025
17292
|
}
|
|
17026
17293
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarkdownWidgetComponent, decorators: [{
|
|
17027
17294
|
type: Component,
|
|
@@ -17159,7 +17426,7 @@ Variables: $variableName or \${variableName}">
|
|
|
17159
17426
|
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
17160
17427
|
</div>
|
|
17161
17428
|
</div>
|
|
17162
|
-
`, isInline: true, styles: [":host{display:block;height:100%;--mm-prose-editor-bg: #f5f5f5;--mm-prose-editor-text: #333333;--mm-prose-editor-placeholder: #999999;--mm-prose-editor-border: #e0e0e0;--mm-prose-preview-border: #e0e0e0;--mm-prose-form-bg: #f5f5f5;--mm-prose-form-border: #e0e0e0;--mm-prose-label-text: #333333;--mm-prose-hint-text: #666666}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:16px;height:100%;flex:1;overflow-y:auto}.mode-toggle{display:flex;gap:8px}.editor-area{flex:1;min-height:300px;display:flex;flex-direction:column}.markdown-editor{flex:1;width:100%;font-family:Roboto Mono,monospace;font-size:.9rem;padding:12px;border:1px solid var(--mm-prose-editor-border);border-radius:4px;resize:none;background:var(--mm-prose-editor-bg);color:var(--mm-prose-editor-text)}.markdown-editor::placeholder{color:var(--mm-prose-editor-placeholder)}.markdown-preview{flex:1;padding:12px;border:1px solid var(--mm-prose-preview-border);border-radius:4px;overflow:auto;background:var(--mm-prose-editor-bg)}.form-section{padding:12px;background:var(--mm-prose-form-bg);border:1px solid var(--mm-prose-form-border);border-radius:4px}.form-row{display:flex;gap:16px;align-items:flex-start}.form-field{display:flex;flex-direction:column;gap:4px}.form-field label{font-weight:500;display:flex;align-items:center;gap:8px;color:var(--mm-prose-label-text)}.field-hint{margin:0;font-size:.8rem;color:var(--mm-prose-hint-text)}.mm-prose{color:var(--mm-prose-text, #333333);line-height:1.6}.mm-prose h1,.mm-prose h2,.mm-prose h3,.mm-prose h4,.mm-prose h5,.mm-prose h6{color:var(--mm-prose-heading, #1976d2);font-weight:600;margin-top:1em;margin-bottom:.5em}.mm-prose h1{font-size:1.5rem}.mm-prose h2{font-size:1.25rem}.mm-prose h3{font-size:1.1rem}.mm-prose p{margin-bottom:.75em}.mm-prose a{color:var(--mm-prose-link, #1565c0)}.mm-prose code{background:var(--mm-prose-code-bg, #f5f5f5);color:var(--mm-prose-code-text, #d32f2f);padding:.2em .4em;border-radius:4px}.mm-prose pre{background:var(--mm-prose-pre-bg, #f5f5f5);color:var(--mm-prose-text, #333333);padding:1em;border-radius:8px;overflow-x:auto}.mm-prose pre code{background:transparent;color:var(--mm-prose-text, #333333)}.mm-prose blockquote{border-left:4px solid var(--mm-prose-blockquote-border, #6c4da8);background:var(--mm-prose-blockquote-bg, rgba(108, 77, 168, .05));padding:.75em 1em;margin:1em 0;border-radius:0 8px 8px 0}.mm-prose strong,.mm-prose b{color:var(--mm-prose-strong, #111111);font-weight:600}.mm-prose em,.mm-prose i{color:var(--mm-prose-em, #1565c0)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: i2.ButtonGroupComponent, selector: "kendo-buttongroup", inputs: ["disabled", "selection", "width", "tabIndex", "navigable"], outputs: ["navigate"], exportAs: ["kendoButtonGroup"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "ngmodule", type: MarkdownModule }, { kind: "component", type: i2$
|
|
17429
|
+
`, isInline: true, styles: [":host{display:block;height:100%;--mm-prose-editor-bg: #f5f5f5;--mm-prose-editor-text: #333333;--mm-prose-editor-placeholder: #999999;--mm-prose-editor-border: #e0e0e0;--mm-prose-preview-border: #e0e0e0;--mm-prose-form-bg: #f5f5f5;--mm-prose-form-border: #e0e0e0;--mm-prose-label-text: #333333;--mm-prose-hint-text: #666666}.config-container{display:flex;flex-direction:column;height:100%}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.config-form{display:flex;flex-direction:column;gap:16px;height:100%;flex:1;overflow-y:auto}.mode-toggle{display:flex;gap:8px}.editor-area{flex:1;min-height:300px;display:flex;flex-direction:column}.markdown-editor{flex:1;width:100%;font-family:Roboto Mono,monospace;font-size:.9rem;padding:12px;border:1px solid var(--mm-prose-editor-border);border-radius:4px;resize:none;background:var(--mm-prose-editor-bg);color:var(--mm-prose-editor-text)}.markdown-editor::placeholder{color:var(--mm-prose-editor-placeholder)}.markdown-preview{flex:1;padding:12px;border:1px solid var(--mm-prose-preview-border);border-radius:4px;overflow:auto;background:var(--mm-prose-editor-bg)}.form-section{padding:12px;background:var(--mm-prose-form-bg);border:1px solid var(--mm-prose-form-border);border-radius:4px}.form-row{display:flex;gap:16px;align-items:flex-start}.form-field{display:flex;flex-direction:column;gap:4px}.form-field label{font-weight:500;display:flex;align-items:center;gap:8px;color:var(--mm-prose-label-text)}.field-hint{margin:0;font-size:.8rem;color:var(--mm-prose-hint-text)}.mm-prose{color:var(--mm-prose-text, #333333);line-height:1.6}.mm-prose h1,.mm-prose h2,.mm-prose h3,.mm-prose h4,.mm-prose h5,.mm-prose h6{color:var(--mm-prose-heading, #1976d2);font-weight:600;margin-top:1em;margin-bottom:.5em}.mm-prose h1{font-size:1.5rem}.mm-prose h2{font-size:1.25rem}.mm-prose h3{font-size:1.1rem}.mm-prose p{margin-bottom:.75em}.mm-prose a{color:var(--mm-prose-link, #1565c0)}.mm-prose code{background:var(--mm-prose-code-bg, #f5f5f5);color:var(--mm-prose-code-text, #d32f2f);padding:.2em .4em;border-radius:4px}.mm-prose pre{background:var(--mm-prose-pre-bg, #f5f5f5);color:var(--mm-prose-text, #333333);padding:1em;border-radius:8px;overflow-x:auto}.mm-prose pre code{background:transparent;color:var(--mm-prose-text, #333333)}.mm-prose blockquote{border-left:4px solid var(--mm-prose-blockquote-border, #6c4da8);background:var(--mm-prose-blockquote-bg, rgba(108, 77, 168, .05));padding:.75em 1em;margin:1em 0;border-radius:0 8px 8px 0}.mm-prose strong,.mm-prose b{color:var(--mm-prose-strong, #111111);font-weight:600}.mm-prose em,.mm-prose i{color:var(--mm-prose-em, #1565c0)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: i2.ButtonGroupComponent, selector: "kendo-buttongroup", inputs: ["disabled", "selection", "width", "tabIndex", "navigable"], outputs: ["navigate"], exportAs: ["kendoButtonGroup"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: i3.CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "ngmodule", type: MarkdownModule }, { kind: "component", type: i2$1.MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }] });
|
|
17163
17430
|
}
|
|
17164
17431
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarkdownConfigDialogComponent, decorators: [{
|
|
17165
17432
|
type: Component,
|
|
@@ -17279,150 +17546,1621 @@ Variables: $variableName or \${variableName}">
|
|
|
17279
17546
|
type: Input
|
|
17280
17547
|
}] } });
|
|
17281
17548
|
|
|
17282
|
-
class
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
17289
|
-
|
|
17290
|
-
|
|
17291
|
-
|
|
17292
|
-
|
|
17293
|
-
|
|
17294
|
-
* @param searchText - Optional search text to filter diagrams
|
|
17295
|
-
* @returns List of process diagram summaries
|
|
17296
|
-
*/
|
|
17297
|
-
async loadDiagramList(searchText) {
|
|
17298
|
-
try {
|
|
17299
|
-
const result = await firstValueFrom(this.getProcessDiagramsGQL.fetch({
|
|
17300
|
-
first: 100,
|
|
17301
|
-
searchFilter: searchText ? { searchTerm: searchText, language: 'de' } : undefined
|
|
17302
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Apollo fetch requires flexible variable typing
|
|
17303
|
-
}));
|
|
17304
|
-
const items = result.data?.runtime?.systemUIProcessDiagram?.items || [];
|
|
17305
|
-
return items
|
|
17306
|
-
.filter((item) => item !== null)
|
|
17307
|
-
.map(item => ({
|
|
17308
|
-
rtId: item.rtId,
|
|
17309
|
-
name: item.name,
|
|
17310
|
-
description: item.description,
|
|
17311
|
-
version: item.version,
|
|
17312
|
-
canvasWidth: item.canvasWidth,
|
|
17313
|
-
canvasHeight: item.canvasHeight
|
|
17314
|
-
}));
|
|
17315
|
-
}
|
|
17316
|
-
catch (error) {
|
|
17317
|
-
console.error('Error loading process diagrams:', error);
|
|
17318
|
-
return [];
|
|
17319
|
-
}
|
|
17549
|
+
class StatusListWidgetComponent {
|
|
17550
|
+
getEntitiesByCkTypeGQL = inject(GetEntitiesByCkTypeDtoGQL);
|
|
17551
|
+
config;
|
|
17552
|
+
_isLoading = signal(false, ...(ngDevMode ? [{ debugName: "_isLoading" }] : /* istanbul ignore next */ []));
|
|
17553
|
+
_error = signal(null, ...(ngDevMode ? [{ debugName: "_error" }] : /* istanbul ignore next */ []));
|
|
17554
|
+
_items = signal([], ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
|
|
17555
|
+
isLoading = this._isLoading.asReadonly();
|
|
17556
|
+
error = this._error.asReadonly();
|
|
17557
|
+
data = this._items.asReadonly();
|
|
17558
|
+
items = this._items.asReadonly();
|
|
17559
|
+
isNotConfigured() {
|
|
17560
|
+
return !this.config?.ckTypeId || !this.config?.labelField || !this.config?.statusField;
|
|
17320
17561
|
}
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
*
|
|
17324
|
-
* @param rtId - The runtime ID of the process diagram
|
|
17325
|
-
* @returns The process diagram configuration
|
|
17326
|
-
*/
|
|
17327
|
-
async loadDiagram(rtId) {
|
|
17328
|
-
const result = await firstValueFrom(this.getProcessDiagramGQL.fetch({ variables: { rtId } }));
|
|
17329
|
-
const item = result.data?.runtime?.systemUIProcessDiagram?.items?.[0];
|
|
17330
|
-
if (!item) {
|
|
17331
|
-
throw new Error(`Process diagram not found: ${rtId}`);
|
|
17332
|
-
}
|
|
17333
|
-
// Parse JSON fields
|
|
17334
|
-
const elements = this.parseJsonField(item.elements, []);
|
|
17335
|
-
const itemWithExtensions = item;
|
|
17336
|
-
const primitives = itemWithExtensions.primitives
|
|
17337
|
-
? this.parseJsonField(itemWithExtensions.primitives, [])
|
|
17338
|
-
: undefined;
|
|
17339
|
-
const symbolInstances = itemWithExtensions.symbolInstances
|
|
17340
|
-
? this.parseJsonField(itemWithExtensions.symbolInstances, [])
|
|
17341
|
-
: undefined;
|
|
17342
|
-
const connections = this.parseJsonField(item.connections, []);
|
|
17343
|
-
const variables = item.variables ? this.parseJsonField(item.variables, []) : undefined;
|
|
17344
|
-
// Parse diagram-level property fields
|
|
17345
|
-
const transformProperties = itemWithExtensions.transformProperties
|
|
17346
|
-
? this.parseJsonField(itemWithExtensions.transformProperties, [])
|
|
17347
|
-
: undefined;
|
|
17348
|
-
const propertyBindings = itemWithExtensions.propertyBindings
|
|
17349
|
-
? this.parseJsonField(itemWithExtensions.propertyBindings, [])
|
|
17350
|
-
: undefined;
|
|
17351
|
-
const animations = itemWithExtensions.animations
|
|
17352
|
-
? this.parseJsonField(itemWithExtensions.animations, [])
|
|
17353
|
-
: undefined;
|
|
17354
|
-
return {
|
|
17355
|
-
id: item.rtId,
|
|
17356
|
-
name: item.name,
|
|
17357
|
-
description: item.description ?? undefined,
|
|
17358
|
-
version: item.version,
|
|
17359
|
-
canvas: {
|
|
17360
|
-
width: item.canvasWidth,
|
|
17361
|
-
height: item.canvasHeight,
|
|
17362
|
-
backgroundColor: item.canvasBackgroundColor ?? undefined
|
|
17363
|
-
},
|
|
17364
|
-
elements,
|
|
17365
|
-
primitives,
|
|
17366
|
-
symbolInstances,
|
|
17367
|
-
connections,
|
|
17368
|
-
variables,
|
|
17369
|
-
transformProperties,
|
|
17370
|
-
propertyBindings,
|
|
17371
|
-
animations,
|
|
17372
|
-
refreshInterval: item.refreshInterval ?? undefined
|
|
17373
|
-
};
|
|
17562
|
+
ngOnInit() {
|
|
17563
|
+
this.loadData();
|
|
17374
17564
|
}
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
* @param diagram - The process diagram configuration to create
|
|
17379
|
-
* @returns The created diagram with its new rtId
|
|
17380
|
-
*/
|
|
17381
|
-
async createDiagram(diagram) {
|
|
17382
|
-
const input = this.toInputDto(diagram);
|
|
17383
|
-
const result = await firstValueFrom(this.createProcessDiagramGQL.mutate({
|
|
17384
|
-
variables: { entities: [input] }
|
|
17385
|
-
}));
|
|
17386
|
-
const created = result.data?.runtime?.systemUIProcessDiagrams?.create?.[0];
|
|
17387
|
-
if (!created) {
|
|
17388
|
-
throw new Error('Failed to create process diagram');
|
|
17565
|
+
ngOnChanges(changes) {
|
|
17566
|
+
if (changes['config'] && !changes['config'].firstChange) {
|
|
17567
|
+
this.loadData();
|
|
17389
17568
|
}
|
|
17390
|
-
return {
|
|
17391
|
-
...diagram,
|
|
17392
|
-
id: created.rtId
|
|
17393
|
-
};
|
|
17394
17569
|
}
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
17398
|
-
|
|
17399
|
-
|
|
17400
|
-
|
|
17401
|
-
|
|
17402
|
-
|
|
17403
|
-
|
|
17570
|
+
refresh() {
|
|
17571
|
+
this.loadData();
|
|
17572
|
+
}
|
|
17573
|
+
async loadData() {
|
|
17574
|
+
if (this.isNotConfigured())
|
|
17575
|
+
return;
|
|
17576
|
+
this._isLoading.set(true);
|
|
17577
|
+
this._error.set(null);
|
|
17578
|
+
try {
|
|
17579
|
+
const result = await firstValueFrom(this.getEntitiesByCkTypeGQL.fetch({
|
|
17580
|
+
variables: {
|
|
17581
|
+
ckTypeId: this.config.ckTypeId,
|
|
17582
|
+
first: 50
|
|
17583
|
+
}
|
|
17584
|
+
}));
|
|
17585
|
+
const entities = result.data?.runtime?.runtimeEntities?.items ?? [];
|
|
17586
|
+
const items = [];
|
|
17587
|
+
for (const entity of entities) {
|
|
17588
|
+
if (!entity)
|
|
17589
|
+
continue;
|
|
17590
|
+
const attrs = (entity.attributes?.items ?? [])
|
|
17591
|
+
.filter((a) => a != null && a.attributeName != null);
|
|
17592
|
+
const label = this.getAttributeValue(attrs, this.config.labelField) ?? '';
|
|
17593
|
+
const status = this.getAttributeValue(attrs, this.config.statusField) ?? '';
|
|
17594
|
+
const colorConfig = this.config.statusColors?.[status];
|
|
17595
|
+
items.push({
|
|
17596
|
+
label,
|
|
17597
|
+
status,
|
|
17598
|
+
color: colorConfig?.color ?? '#6b7280',
|
|
17599
|
+
displayLabel: colorConfig?.label ?? status
|
|
17600
|
+
});
|
|
17601
|
+
}
|
|
17602
|
+
this._items.set(items);
|
|
17404
17603
|
}
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
variables: { entities: [input] }
|
|
17411
|
-
}));
|
|
17412
|
-
const updated = result.data?.runtime?.systemUIProcessDiagrams?.update?.[0];
|
|
17413
|
-
if (!updated) {
|
|
17414
|
-
throw new Error('Failed to update process diagram');
|
|
17604
|
+
catch (err) {
|
|
17605
|
+
this._error.set(err instanceof Error ? err.message : 'Failed to load data');
|
|
17606
|
+
}
|
|
17607
|
+
finally {
|
|
17608
|
+
this._isLoading.set(false);
|
|
17415
17609
|
}
|
|
17416
|
-
return diagram;
|
|
17417
17610
|
}
|
|
17418
|
-
|
|
17419
|
-
|
|
17420
|
-
|
|
17421
|
-
|
|
17422
|
-
|
|
17423
|
-
|
|
17424
|
-
|
|
17425
|
-
|
|
17611
|
+
getAttributeValue(attrs, field) {
|
|
17612
|
+
const attr = attrs.find(a => a.attributeName === field);
|
|
17613
|
+
return attr?.value != null ? String(attr.value) : null;
|
|
17614
|
+
}
|
|
17615
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: StatusListWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17616
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: StatusListWidgetComponent, isStandalone: true, selector: "mm-status-list-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: `
|
|
17617
|
+
<div class="status-list-widget">
|
|
17618
|
+
@if (isNotConfigured()) {
|
|
17619
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
17620
|
+
} @else if (error()) {
|
|
17621
|
+
<div class="error-message">{{ error() }}</div>
|
|
17622
|
+
} @else {
|
|
17623
|
+
<div class="status-list">
|
|
17624
|
+
@for (item of items(); track item.label) {
|
|
17625
|
+
<div class="status-list-item">
|
|
17626
|
+
<span class="item-label">{{ item.label }}</span>
|
|
17627
|
+
<span class="item-badge" [style.background-color]="item.color">
|
|
17628
|
+
{{ item.displayLabel }}
|
|
17629
|
+
</span>
|
|
17630
|
+
</div>
|
|
17631
|
+
}
|
|
17632
|
+
@if (!isLoading() && items().length === 0) {
|
|
17633
|
+
<div class="empty-message">No items found</div>
|
|
17634
|
+
}
|
|
17635
|
+
</div>
|
|
17636
|
+
}
|
|
17637
|
+
</div>
|
|
17638
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.status-list-widget{height:100%;display:flex;flex-direction:column;padding:8px 0;overflow-y:auto}.status-list{display:flex;flex-direction:column;gap:6px;padding:0 12px}.status-list-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:6px;background:var(--mm-status-list-item-bg, rgba(255, 255, 255, .04));border:1px solid var(--mm-status-list-item-border, rgba(255, 255, 255, .06))}.item-label{font-size:.9rem;font-weight:500;color:var(--kendo-color-on-app-surface, inherit)}.item-badge{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;padding:4px 10px;border-radius:4px;color:#fff;white-space:nowrap}.empty-message{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.error-message{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
17639
|
+
}
|
|
17640
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: StatusListWidgetComponent, decorators: [{
|
|
17641
|
+
type: Component,
|
|
17642
|
+
args: [{ selector: 'mm-status-list-widget', standalone: true, imports: [CommonModule, WidgetNotConfiguredComponent], template: `
|
|
17643
|
+
<div class="status-list-widget">
|
|
17644
|
+
@if (isNotConfigured()) {
|
|
17645
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
17646
|
+
} @else if (error()) {
|
|
17647
|
+
<div class="error-message">{{ error() }}</div>
|
|
17648
|
+
} @else {
|
|
17649
|
+
<div class="status-list">
|
|
17650
|
+
@for (item of items(); track item.label) {
|
|
17651
|
+
<div class="status-list-item">
|
|
17652
|
+
<span class="item-label">{{ item.label }}</span>
|
|
17653
|
+
<span class="item-badge" [style.background-color]="item.color">
|
|
17654
|
+
{{ item.displayLabel }}
|
|
17655
|
+
</span>
|
|
17656
|
+
</div>
|
|
17657
|
+
}
|
|
17658
|
+
@if (!isLoading() && items().length === 0) {
|
|
17659
|
+
<div class="empty-message">No items found</div>
|
|
17660
|
+
}
|
|
17661
|
+
</div>
|
|
17662
|
+
}
|
|
17663
|
+
</div>
|
|
17664
|
+
`, styles: [":host{display:block;width:100%;height:100%}.status-list-widget{height:100%;display:flex;flex-direction:column;padding:8px 0;overflow-y:auto}.status-list{display:flex;flex-direction:column;gap:6px;padding:0 12px}.status-list-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:6px;background:var(--mm-status-list-item-bg, rgba(255, 255, 255, .04));border:1px solid var(--mm-status-list-item-border, rgba(255, 255, 255, .06))}.item-label{font-size:.9rem;font-weight:500;color:var(--kendo-color-on-app-surface, inherit)}.item-badge{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;padding:4px 10px;border-radius:4px;color:#fff;white-space:nowrap}.empty-message{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.error-message{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"] }]
|
|
17665
|
+
}], propDecorators: { config: [{
|
|
17666
|
+
type: Input
|
|
17667
|
+
}] } });
|
|
17668
|
+
|
|
17669
|
+
class StatusListConfigDialogComponent {
|
|
17670
|
+
windowRef = inject(WindowRef);
|
|
17671
|
+
initialCkTypeId;
|
|
17672
|
+
initialLabelField;
|
|
17673
|
+
initialStatusField;
|
|
17674
|
+
initialStatusColors;
|
|
17675
|
+
form = {
|
|
17676
|
+
ckTypeId: '',
|
|
17677
|
+
labelField: '',
|
|
17678
|
+
statusField: ''
|
|
17679
|
+
};
|
|
17680
|
+
statusColorEntries = [];
|
|
17681
|
+
get isValid() {
|
|
17682
|
+
return !!this.form.ckTypeId && !!this.form.labelField && !!this.form.statusField;
|
|
17683
|
+
}
|
|
17684
|
+
ngOnInit() {
|
|
17685
|
+
this.form.ckTypeId = this.initialCkTypeId ?? '';
|
|
17686
|
+
this.form.labelField = this.initialLabelField ?? '';
|
|
17687
|
+
this.form.statusField = this.initialStatusField ?? '';
|
|
17688
|
+
if (this.initialStatusColors) {
|
|
17689
|
+
this.statusColorEntries = Object.entries(this.initialStatusColors).map(([key, val]) => ({
|
|
17690
|
+
key,
|
|
17691
|
+
color: val.color,
|
|
17692
|
+
label: val.label ?? ''
|
|
17693
|
+
}));
|
|
17694
|
+
}
|
|
17695
|
+
}
|
|
17696
|
+
addStatusColor() {
|
|
17697
|
+
this.statusColorEntries.push({ key: '', color: '#10b981', label: '' });
|
|
17698
|
+
}
|
|
17699
|
+
removeStatusColor(index) {
|
|
17700
|
+
this.statusColorEntries.splice(index, 1);
|
|
17701
|
+
}
|
|
17702
|
+
onSave() {
|
|
17703
|
+
const statusColors = {};
|
|
17704
|
+
for (const entry of this.statusColorEntries) {
|
|
17705
|
+
if (entry.key) {
|
|
17706
|
+
statusColors[entry.key] = { color: entry.color, label: entry.label || undefined };
|
|
17707
|
+
}
|
|
17708
|
+
}
|
|
17709
|
+
this.windowRef.close({
|
|
17710
|
+
ckTypeId: this.form.ckTypeId,
|
|
17711
|
+
labelField: this.form.labelField,
|
|
17712
|
+
statusField: this.form.statusField,
|
|
17713
|
+
statusColors: Object.keys(statusColors).length > 0 ? statusColors : undefined
|
|
17714
|
+
});
|
|
17715
|
+
}
|
|
17716
|
+
onCancel() {
|
|
17717
|
+
this.windowRef.close();
|
|
17718
|
+
}
|
|
17719
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: StatusListConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17720
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: StatusListConfigDialogComponent, isStandalone: true, selector: "mm-status-list-config-dialog", inputs: { initialCkTypeId: "initialCkTypeId", initialLabelField: "initialLabelField", initialStatusField: "initialStatusField", initialStatusColors: "initialStatusColors" }, ngImport: i0, template: `
|
|
17721
|
+
<div class="config-container">
|
|
17722
|
+
<div class="config-form">
|
|
17723
|
+
<div class="form-field">
|
|
17724
|
+
<label>Entity Type <span class="required">*</span></label>
|
|
17725
|
+
<kendo-textbox [(ngModel)]="form.ckTypeId" placeholder="e.g. Environment/ComplianceRecord"></kendo-textbox>
|
|
17726
|
+
<p class="field-hint">Full CK type ID</p>
|
|
17727
|
+
</div>
|
|
17728
|
+
|
|
17729
|
+
<div class="form-field">
|
|
17730
|
+
<label>Label Field <span class="required">*</span></label>
|
|
17731
|
+
<kendo-textbox [(ngModel)]="form.labelField" placeholder="e.g. name"></kendo-textbox>
|
|
17732
|
+
<p class="field-hint">Attribute name for the item label</p>
|
|
17733
|
+
</div>
|
|
17734
|
+
|
|
17735
|
+
<div class="form-field">
|
|
17736
|
+
<label>Status Field <span class="required">*</span></label>
|
|
17737
|
+
<kendo-textbox [(ngModel)]="form.statusField" placeholder="e.g. complianceStatus"></kendo-textbox>
|
|
17738
|
+
<p class="field-hint">Attribute name for the status value (enum)</p>
|
|
17739
|
+
</div>
|
|
17740
|
+
|
|
17741
|
+
<div class="form-section">
|
|
17742
|
+
<h4>Status Colors</h4>
|
|
17743
|
+
<p class="field-hint">Map status values to badge colors and labels.</p>
|
|
17744
|
+
@for (entry of statusColorEntries; track $index) {
|
|
17745
|
+
<div class="color-row">
|
|
17746
|
+
<kendo-textbox [(ngModel)]="entry.key" placeholder="Status value" style="width: 120px;"></kendo-textbox>
|
|
17747
|
+
<kendo-textbox [(ngModel)]="entry.color" placeholder="#10b981" style="width: 100px;"></kendo-textbox>
|
|
17748
|
+
<kendo-textbox [(ngModel)]="entry.label" placeholder="Badge label" style="flex: 1;"></kendo-textbox>
|
|
17749
|
+
<button kendoButton fillMode="flat" (click)="removeStatusColor($index)">Remove</button>
|
|
17750
|
+
</div>
|
|
17751
|
+
}
|
|
17752
|
+
<button kendoButton fillMode="flat" (click)="addStatusColor()">+ Add Status Color</button>
|
|
17753
|
+
</div>
|
|
17754
|
+
</div>
|
|
17755
|
+
|
|
17756
|
+
<div class="action-bar mm-dialog-actions">
|
|
17757
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
17758
|
+
<button kendoButton themeColor="primary" [disabled]="!isValid" (click)="onSave()">Save</button>
|
|
17759
|
+
</div>
|
|
17760
|
+
</div>
|
|
17761
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.config-form{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.form-field{display:flex;flex-direction:column;gap:6px}.form-field label{font-weight:600;font-size:.9rem}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.form-section{margin-top:8px}.form-section h4{margin:0 0 4px;font-size:.95rem;font-weight:600}.color-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }] });
|
|
17762
|
+
}
|
|
17763
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: StatusListConfigDialogComponent, decorators: [{
|
|
17764
|
+
type: Component,
|
|
17765
|
+
args: [{ selector: 'mm-status-list-config-dialog', standalone: true, imports: [CommonModule, FormsModule, ButtonsModule, InputsModule], template: `
|
|
17766
|
+
<div class="config-container">
|
|
17767
|
+
<div class="config-form">
|
|
17768
|
+
<div class="form-field">
|
|
17769
|
+
<label>Entity Type <span class="required">*</span></label>
|
|
17770
|
+
<kendo-textbox [(ngModel)]="form.ckTypeId" placeholder="e.g. Environment/ComplianceRecord"></kendo-textbox>
|
|
17771
|
+
<p class="field-hint">Full CK type ID</p>
|
|
17772
|
+
</div>
|
|
17773
|
+
|
|
17774
|
+
<div class="form-field">
|
|
17775
|
+
<label>Label Field <span class="required">*</span></label>
|
|
17776
|
+
<kendo-textbox [(ngModel)]="form.labelField" placeholder="e.g. name"></kendo-textbox>
|
|
17777
|
+
<p class="field-hint">Attribute name for the item label</p>
|
|
17778
|
+
</div>
|
|
17779
|
+
|
|
17780
|
+
<div class="form-field">
|
|
17781
|
+
<label>Status Field <span class="required">*</span></label>
|
|
17782
|
+
<kendo-textbox [(ngModel)]="form.statusField" placeholder="e.g. complianceStatus"></kendo-textbox>
|
|
17783
|
+
<p class="field-hint">Attribute name for the status value (enum)</p>
|
|
17784
|
+
</div>
|
|
17785
|
+
|
|
17786
|
+
<div class="form-section">
|
|
17787
|
+
<h4>Status Colors</h4>
|
|
17788
|
+
<p class="field-hint">Map status values to badge colors and labels.</p>
|
|
17789
|
+
@for (entry of statusColorEntries; track $index) {
|
|
17790
|
+
<div class="color-row">
|
|
17791
|
+
<kendo-textbox [(ngModel)]="entry.key" placeholder="Status value" style="width: 120px;"></kendo-textbox>
|
|
17792
|
+
<kendo-textbox [(ngModel)]="entry.color" placeholder="#10b981" style="width: 100px;"></kendo-textbox>
|
|
17793
|
+
<kendo-textbox [(ngModel)]="entry.label" placeholder="Badge label" style="flex: 1;"></kendo-textbox>
|
|
17794
|
+
<button kendoButton fillMode="flat" (click)="removeStatusColor($index)">Remove</button>
|
|
17795
|
+
</div>
|
|
17796
|
+
}
|
|
17797
|
+
<button kendoButton fillMode="flat" (click)="addStatusColor()">+ Add Status Color</button>
|
|
17798
|
+
</div>
|
|
17799
|
+
</div>
|
|
17800
|
+
|
|
17801
|
+
<div class="action-bar mm-dialog-actions">
|
|
17802
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
17803
|
+
<button kendoButton themeColor="primary" [disabled]="!isValid" (click)="onSave()">Save</button>
|
|
17804
|
+
</div>
|
|
17805
|
+
</div>
|
|
17806
|
+
`, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.config-form{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.form-field{display:flex;flex-direction:column;gap:6px}.form-field label{font-weight:600;font-size:.9rem}.required{color:var(--kendo-color-error, #dc3545)}.field-hint{margin:0;font-size:.8rem;color:var(--kendo-color-subtle, #6c757d)}.form-section{margin-top:8px}.form-section h4{margin:0 0 4px;font-size:.95rem;font-weight:600}.color-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}\n"] }]
|
|
17807
|
+
}], propDecorators: { initialCkTypeId: [{
|
|
17808
|
+
type: Input
|
|
17809
|
+
}], initialLabelField: [{
|
|
17810
|
+
type: Input
|
|
17811
|
+
}], initialStatusField: [{
|
|
17812
|
+
type: Input
|
|
17813
|
+
}], initialStatusColors: [{
|
|
17814
|
+
type: Input
|
|
17815
|
+
}] } });
|
|
17816
|
+
|
|
17817
|
+
class SummaryCardWidgetComponent {
|
|
17818
|
+
entityGQL = inject(GetDashboardEntityDtoGQL);
|
|
17819
|
+
dataService = inject(DashboardDataService);
|
|
17820
|
+
config;
|
|
17821
|
+
_isLoading = signal(false, ...(ngDevMode ? [{ debugName: "_isLoading" }] : /* istanbul ignore next */ []));
|
|
17822
|
+
_error = signal(null, ...(ngDevMode ? [{ debugName: "_error" }] : /* istanbul ignore next */ []));
|
|
17823
|
+
_tileValues = signal([], ...(ngDevMode ? [{ debugName: "_tileValues" }] : /* istanbul ignore next */ []));
|
|
17824
|
+
isLoading = this._isLoading.asReadonly();
|
|
17825
|
+
error = this._error.asReadonly();
|
|
17826
|
+
data = this._tileValues.asReadonly();
|
|
17827
|
+
tileValues = this._tileValues.asReadonly();
|
|
17828
|
+
isNotConfigured() {
|
|
17829
|
+
return !this.config?.tiles?.length;
|
|
17830
|
+
}
|
|
17831
|
+
ngOnInit() {
|
|
17832
|
+
this.loadData();
|
|
17833
|
+
}
|
|
17834
|
+
ngOnChanges(changes) {
|
|
17835
|
+
if (changes['config'] && !changes['config'].firstChange) {
|
|
17836
|
+
this.loadData();
|
|
17837
|
+
}
|
|
17838
|
+
}
|
|
17839
|
+
refresh() {
|
|
17840
|
+
this.loadData();
|
|
17841
|
+
}
|
|
17842
|
+
async loadData() {
|
|
17843
|
+
if (this.isNotConfigured())
|
|
17844
|
+
return;
|
|
17845
|
+
this._isLoading.set(true);
|
|
17846
|
+
this._error.set(null);
|
|
17847
|
+
try {
|
|
17848
|
+
// Cache entities by rtId to avoid duplicate fetches
|
|
17849
|
+
const entityCache = new Map();
|
|
17850
|
+
const results = await Promise.all(this.config.tiles.map(tile => this.fetchTileValue(tile, entityCache)));
|
|
17851
|
+
const tileValues = this.config.tiles.map((tile, i) => ({
|
|
17852
|
+
id: tile.id,
|
|
17853
|
+
label: tile.label,
|
|
17854
|
+
value: this.formatValue(results[i]),
|
|
17855
|
+
prefix: tile.prefix ?? '',
|
|
17856
|
+
suffix: tile.suffix ?? '',
|
|
17857
|
+
color: tile.color ?? 'default',
|
|
17858
|
+
fullWidth: tile.size === 'full'
|
|
17859
|
+
}));
|
|
17860
|
+
this._tileValues.set(tileValues);
|
|
17861
|
+
}
|
|
17862
|
+
catch (err) {
|
|
17863
|
+
this._error.set(err instanceof Error ? err.message : 'Failed to load data');
|
|
17864
|
+
}
|
|
17865
|
+
finally {
|
|
17866
|
+
this._isLoading.set(false);
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
async fetchTileValue(tile, entityCache) {
|
|
17870
|
+
if (tile.entitySource) {
|
|
17871
|
+
const { rtId, ckTypeId, attributePath } = tile.entitySource;
|
|
17872
|
+
if (!entityCache.has(rtId)) {
|
|
17873
|
+
const attrs = await this.fetchEntityAttributes(rtId, ckTypeId);
|
|
17874
|
+
entityCache.set(rtId, attrs);
|
|
17875
|
+
}
|
|
17876
|
+
return entityCache.get(rtId)?.get(attributePath) ?? null;
|
|
17877
|
+
}
|
|
17878
|
+
if (tile.aggregationSource) {
|
|
17879
|
+
const query = {
|
|
17880
|
+
id: tile.id,
|
|
17881
|
+
ckTypeId: tile.aggregationSource.ckTypeId,
|
|
17882
|
+
aggregation: tile.aggregationSource.aggregation,
|
|
17883
|
+
attribute: tile.aggregationSource.attribute,
|
|
17884
|
+
filters: tile.aggregationSource.filters
|
|
17885
|
+
};
|
|
17886
|
+
const results = await this.dataService.fetchAggregations([query]);
|
|
17887
|
+
return results.get(tile.id) ?? null;
|
|
17888
|
+
}
|
|
17889
|
+
return null;
|
|
17890
|
+
}
|
|
17891
|
+
async fetchEntityAttributes(rtId, ckTypeId) {
|
|
17892
|
+
const result = await firstValueFrom(this.entityGQL.fetch({
|
|
17893
|
+
variables: { rtId, ckTypeId }
|
|
17894
|
+
}));
|
|
17895
|
+
const attrs = new Map();
|
|
17896
|
+
const items = result.data?.runtime?.runtimeEntities?.items?.[0]?.attributes?.items ?? [];
|
|
17897
|
+
for (const item of items) {
|
|
17898
|
+
if (item?.attributeName) {
|
|
17899
|
+
attrs.set(item.attributeName, item.value);
|
|
17900
|
+
}
|
|
17901
|
+
}
|
|
17902
|
+
return attrs;
|
|
17903
|
+
}
|
|
17904
|
+
formatValue(value) {
|
|
17905
|
+
if (value == null)
|
|
17906
|
+
return '-';
|
|
17907
|
+
if (typeof value === 'number') {
|
|
17908
|
+
return value.toLocaleString('de-AT', {
|
|
17909
|
+
minimumFractionDigits: value % 1 !== 0 ? 1 : 0,
|
|
17910
|
+
maximumFractionDigits: 2
|
|
17911
|
+
});
|
|
17912
|
+
}
|
|
17913
|
+
return String(value);
|
|
17914
|
+
}
|
|
17915
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SummaryCardWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17916
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SummaryCardWidgetComponent, isStandalone: true, selector: "mm-summary-card-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: `
|
|
17917
|
+
<div class="summary-card-widget">
|
|
17918
|
+
@if (isNotConfigured()) {
|
|
17919
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
17920
|
+
} @else if (error()) {
|
|
17921
|
+
<div class="error-message">{{ error() }}</div>
|
|
17922
|
+
} @else {
|
|
17923
|
+
<div class="summary-grid" [style.--columns]="config.columns ?? 2">
|
|
17924
|
+
@for (tile of tileValues(); track tile.id) {
|
|
17925
|
+
<div class="tile" [class]="tile.color" [class.full-width]="tile.fullWidth">
|
|
17926
|
+
<div class="tile-value">
|
|
17927
|
+
{{ tile.prefix }}{{ tile.value }}{{ tile.suffix }}
|
|
17928
|
+
</div>
|
|
17929
|
+
<div class="tile-label">{{ tile.label }}</div>
|
|
17930
|
+
</div>
|
|
17931
|
+
}
|
|
17932
|
+
</div>
|
|
17933
|
+
}
|
|
17934
|
+
</div>
|
|
17935
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.summary-card-widget{height:100%;display:flex;align-items:center;justify-content:center}.summary-grid{display:grid;grid-template-columns:repeat(var(--columns, 2),1fr);gap:8px;padding:8px 12px;width:100%}.tile{text-align:center;padding:12px 8px;border-radius:6px;background:var(--mm-summary-tile-bg, rgba(255, 255, 255, .03))}.tile-value{font-size:1.5rem;font-weight:700;color:inherit}.tile-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.5px;margin-top:4px;opacity:.6}.tile.full-width{grid-column:1 / -1}.tile.primary .tile-value{color:var(--kendo-color-primary, #06b6d4)}.tile.success .tile-value{color:var(--kendo-color-success, #10b981)}.tile.warning .tile-value{color:var(--kendo-color-warning, #f59e0b)}.tile.error .tile-value{color:var(--kendo-color-error, #ef4444)}.error-message{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
17936
|
+
}
|
|
17937
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SummaryCardWidgetComponent, decorators: [{
|
|
17938
|
+
type: Component,
|
|
17939
|
+
args: [{ selector: 'mm-summary-card-widget', standalone: true, imports: [CommonModule, WidgetNotConfiguredComponent], template: `
|
|
17940
|
+
<div class="summary-card-widget">
|
|
17941
|
+
@if (isNotConfigured()) {
|
|
17942
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
17943
|
+
} @else if (error()) {
|
|
17944
|
+
<div class="error-message">{{ error() }}</div>
|
|
17945
|
+
} @else {
|
|
17946
|
+
<div class="summary-grid" [style.--columns]="config.columns ?? 2">
|
|
17947
|
+
@for (tile of tileValues(); track tile.id) {
|
|
17948
|
+
<div class="tile" [class]="tile.color" [class.full-width]="tile.fullWidth">
|
|
17949
|
+
<div class="tile-value">
|
|
17950
|
+
{{ tile.prefix }}{{ tile.value }}{{ tile.suffix }}
|
|
17951
|
+
</div>
|
|
17952
|
+
<div class="tile-label">{{ tile.label }}</div>
|
|
17953
|
+
</div>
|
|
17954
|
+
}
|
|
17955
|
+
</div>
|
|
17956
|
+
}
|
|
17957
|
+
</div>
|
|
17958
|
+
`, styles: [":host{display:block;width:100%;height:100%}.summary-card-widget{height:100%;display:flex;align-items:center;justify-content:center}.summary-grid{display:grid;grid-template-columns:repeat(var(--columns, 2),1fr);gap:8px;padding:8px 12px;width:100%}.tile{text-align:center;padding:12px 8px;border-radius:6px;background:var(--mm-summary-tile-bg, rgba(255, 255, 255, .03))}.tile-value{font-size:1.5rem;font-weight:700;color:inherit}.tile-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.5px;margin-top:4px;opacity:.6}.tile.full-width{grid-column:1 / -1}.tile.primary .tile-value{color:var(--kendo-color-primary, #06b6d4)}.tile.success .tile-value{color:var(--kendo-color-success, #10b981)}.tile.warning .tile-value{color:var(--kendo-color-warning, #f59e0b)}.tile.error .tile-value{color:var(--kendo-color-error, #ef4444)}.error-message{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"] }]
|
|
17959
|
+
}], propDecorators: { config: [{
|
|
17960
|
+
type: Input
|
|
17961
|
+
}] } });
|
|
17962
|
+
|
|
17963
|
+
class SummaryCardConfigDialogComponent {
|
|
17964
|
+
windowRef = inject(WindowRef);
|
|
17965
|
+
initialColumns;
|
|
17966
|
+
initialTiles;
|
|
17967
|
+
form = {
|
|
17968
|
+
columns: 2,
|
|
17969
|
+
tiles: []
|
|
17970
|
+
};
|
|
17971
|
+
colorOptions = ['default', 'primary', 'success', 'warning', 'error'];
|
|
17972
|
+
sizeOptions = ['normal', 'full'];
|
|
17973
|
+
sourceTypeOptions = ['entity', 'aggregation'];
|
|
17974
|
+
aggregationOptions = ['count', 'sum', 'avg', 'min', 'max'];
|
|
17975
|
+
get isValid() {
|
|
17976
|
+
return this.form.tiles.length > 0 && this.form.tiles.every(t => t.label && t.ckTypeId);
|
|
17977
|
+
}
|
|
17978
|
+
ngOnInit() {
|
|
17979
|
+
this.form.columns = this.initialColumns ?? 2;
|
|
17980
|
+
if (this.initialTiles) {
|
|
17981
|
+
this.form.tiles = this.initialTiles.map((t, i) => ({
|
|
17982
|
+
id: t.id || `tile-${i}`,
|
|
17983
|
+
label: t.label,
|
|
17984
|
+
prefix: t.prefix ?? '',
|
|
17985
|
+
suffix: t.suffix ?? '',
|
|
17986
|
+
color: t.color ?? 'default',
|
|
17987
|
+
size: t.size ?? 'normal',
|
|
17988
|
+
sourceType: t.entitySource ? 'entity' : 'aggregation',
|
|
17989
|
+
rtId: t.entitySource?.rtId ?? '',
|
|
17990
|
+
ckTypeId: t.entitySource?.ckTypeId ?? t.aggregationSource?.ckTypeId ?? '',
|
|
17991
|
+
attributePath: t.entitySource?.attributePath ?? '',
|
|
17992
|
+
aggregation: t.aggregationSource?.aggregation ?? 'count',
|
|
17993
|
+
aggAttribute: t.aggregationSource?.attribute ?? ''
|
|
17994
|
+
}));
|
|
17995
|
+
}
|
|
17996
|
+
}
|
|
17997
|
+
addTile() {
|
|
17998
|
+
this.form.tiles.push({
|
|
17999
|
+
id: `tile-${Date.now()}`,
|
|
18000
|
+
label: '', prefix: '', suffix: '',
|
|
18001
|
+
color: 'default', size: 'normal',
|
|
18002
|
+
sourceType: 'entity',
|
|
18003
|
+
rtId: '', ckTypeId: '', attributePath: '',
|
|
18004
|
+
aggregation: 'count', aggAttribute: ''
|
|
18005
|
+
});
|
|
18006
|
+
}
|
|
18007
|
+
removeTile(index) {
|
|
18008
|
+
this.form.tiles.splice(index, 1);
|
|
18009
|
+
}
|
|
18010
|
+
onSave() {
|
|
18011
|
+
const tiles = this.form.tiles.map(t => {
|
|
18012
|
+
const tile = {
|
|
18013
|
+
id: t.id,
|
|
18014
|
+
label: t.label,
|
|
18015
|
+
prefix: t.prefix || undefined,
|
|
18016
|
+
suffix: t.suffix || undefined,
|
|
18017
|
+
color: t.color || undefined,
|
|
18018
|
+
size: t.size || undefined
|
|
18019
|
+
};
|
|
18020
|
+
if (t.sourceType === 'entity') {
|
|
18021
|
+
tile.entitySource = { rtId: t.rtId, ckTypeId: t.ckTypeId, attributePath: t.attributePath };
|
|
18022
|
+
}
|
|
18023
|
+
else {
|
|
18024
|
+
tile.aggregationSource = {
|
|
18025
|
+
ckTypeId: t.ckTypeId,
|
|
18026
|
+
aggregation: t.aggregation,
|
|
18027
|
+
attribute: t.aggAttribute || undefined
|
|
18028
|
+
};
|
|
18029
|
+
}
|
|
18030
|
+
return tile;
|
|
18031
|
+
});
|
|
18032
|
+
this.windowRef.close({
|
|
18033
|
+
ckTypeId: '',
|
|
18034
|
+
columns: this.form.columns,
|
|
18035
|
+
tiles
|
|
18036
|
+
});
|
|
18037
|
+
}
|
|
18038
|
+
onCancel() {
|
|
18039
|
+
this.windowRef.close();
|
|
18040
|
+
}
|
|
18041
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SummaryCardConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18042
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SummaryCardConfigDialogComponent, isStandalone: true, selector: "mm-summary-card-config-dialog", inputs: { initialColumns: "initialColumns", initialTiles: "initialTiles" }, ngImport: i0, template: `
|
|
18043
|
+
<div class="config-container">
|
|
18044
|
+
<div class="config-form">
|
|
18045
|
+
<div class="form-field">
|
|
18046
|
+
<label>Grid Columns</label>
|
|
18047
|
+
<kendo-numerictextbox [(ngModel)]="form.columns" [min]="1" [max]="6" [format]="'n0'" [spinners]="true"></kendo-numerictextbox>
|
|
18048
|
+
</div>
|
|
18049
|
+
|
|
18050
|
+
<h4>Tiles</h4>
|
|
18051
|
+
@for (tile of form.tiles; track $index) {
|
|
18052
|
+
<div class="tile-config">
|
|
18053
|
+
<div class="tile-header">
|
|
18054
|
+
<strong>Tile {{ $index + 1 }}</strong>
|
|
18055
|
+
<button kendoButton fillMode="flat" (click)="removeTile($index)">Remove</button>
|
|
18056
|
+
</div>
|
|
18057
|
+
<div class="tile-row">
|
|
18058
|
+
<kendo-textbox [(ngModel)]="tile.label" placeholder="Label" style="flex: 1;"></kendo-textbox>
|
|
18059
|
+
<kendo-textbox [(ngModel)]="tile.prefix" placeholder="Prefix" style="width: 60px;"></kendo-textbox>
|
|
18060
|
+
<kendo-textbox [(ngModel)]="tile.suffix" placeholder="Suffix" style="width: 80px;"></kendo-textbox>
|
|
18061
|
+
</div>
|
|
18062
|
+
<div class="tile-row">
|
|
18063
|
+
<kendo-dropdownlist [data]="colorOptions" [valuePrimitive]="true" [(ngModel)]="tile.color" style="width: 110px;"></kendo-dropdownlist>
|
|
18064
|
+
<kendo-dropdownlist [data]="sizeOptions" [valuePrimitive]="true" [(ngModel)]="tile.size" style="width: 110px;"></kendo-dropdownlist>
|
|
18065
|
+
<kendo-dropdownlist [data]="sourceTypeOptions" [valuePrimitive]="true" [(ngModel)]="tile.sourceType" style="width: 120px;"></kendo-dropdownlist>
|
|
18066
|
+
</div>
|
|
18067
|
+
@if (tile.sourceType === 'entity') {
|
|
18068
|
+
<div class="tile-row">
|
|
18069
|
+
<kendo-textbox [(ngModel)]="tile.ckTypeId" placeholder="CK Type ID" style="flex: 1;"></kendo-textbox>
|
|
18070
|
+
<kendo-textbox [(ngModel)]="tile.rtId" placeholder="Runtime ID" style="flex: 1;"></kendo-textbox>
|
|
18071
|
+
<kendo-textbox [(ngModel)]="tile.attributePath" placeholder="Attribute" style="width: 120px;"></kendo-textbox>
|
|
18072
|
+
</div>
|
|
18073
|
+
}
|
|
18074
|
+
@if (tile.sourceType === 'aggregation') {
|
|
18075
|
+
<div class="tile-row">
|
|
18076
|
+
<kendo-textbox [(ngModel)]="tile.ckTypeId" placeholder="CK Type ID" style="flex: 1;"></kendo-textbox>
|
|
18077
|
+
<kendo-dropdownlist [data]="aggregationOptions" [valuePrimitive]="true" [(ngModel)]="tile.aggregation" style="width: 100px;"></kendo-dropdownlist>
|
|
18078
|
+
<kendo-textbox [(ngModel)]="tile.aggAttribute" placeholder="Attribute (for sum/avg)" style="flex: 1;"></kendo-textbox>
|
|
18079
|
+
</div>
|
|
18080
|
+
}
|
|
18081
|
+
</div>
|
|
18082
|
+
}
|
|
18083
|
+
<button kendoButton fillMode="flat" (click)="addTile()">+ Add Tile</button>
|
|
18084
|
+
</div>
|
|
18085
|
+
|
|
18086
|
+
<div class="action-bar mm-dialog-actions">
|
|
18087
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18088
|
+
<button kendoButton themeColor="primary" [disabled]="!isValid" (click)="onSave()">Save</button>
|
|
18089
|
+
</div>
|
|
18090
|
+
</div>
|
|
18091
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.config-form{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.form-field{display:flex;flex-direction:column;gap:6px}.form-field label{font-weight:600;font-size:.9rem}h4{margin:8px 0 4px;font-size:.95rem}.tile-config{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;padding:10px;margin-bottom:8px;display:flex;flex-direction:column;gap:6px}.tile-header{display:flex;justify-content:space-between;align-items:center}.tile-row{display:flex;gap:6px;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "component", type: i4.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }] });
|
|
18092
|
+
}
|
|
18093
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SummaryCardConfigDialogComponent, decorators: [{
|
|
18094
|
+
type: Component,
|
|
18095
|
+
args: [{ selector: 'mm-summary-card-config-dialog', standalone: true, imports: [CommonModule, FormsModule, ButtonsModule, InputsModule, DropDownsModule], template: `
|
|
18096
|
+
<div class="config-container">
|
|
18097
|
+
<div class="config-form">
|
|
18098
|
+
<div class="form-field">
|
|
18099
|
+
<label>Grid Columns</label>
|
|
18100
|
+
<kendo-numerictextbox [(ngModel)]="form.columns" [min]="1" [max]="6" [format]="'n0'" [spinners]="true"></kendo-numerictextbox>
|
|
18101
|
+
</div>
|
|
18102
|
+
|
|
18103
|
+
<h4>Tiles</h4>
|
|
18104
|
+
@for (tile of form.tiles; track $index) {
|
|
18105
|
+
<div class="tile-config">
|
|
18106
|
+
<div class="tile-header">
|
|
18107
|
+
<strong>Tile {{ $index + 1 }}</strong>
|
|
18108
|
+
<button kendoButton fillMode="flat" (click)="removeTile($index)">Remove</button>
|
|
18109
|
+
</div>
|
|
18110
|
+
<div class="tile-row">
|
|
18111
|
+
<kendo-textbox [(ngModel)]="tile.label" placeholder="Label" style="flex: 1;"></kendo-textbox>
|
|
18112
|
+
<kendo-textbox [(ngModel)]="tile.prefix" placeholder="Prefix" style="width: 60px;"></kendo-textbox>
|
|
18113
|
+
<kendo-textbox [(ngModel)]="tile.suffix" placeholder="Suffix" style="width: 80px;"></kendo-textbox>
|
|
18114
|
+
</div>
|
|
18115
|
+
<div class="tile-row">
|
|
18116
|
+
<kendo-dropdownlist [data]="colorOptions" [valuePrimitive]="true" [(ngModel)]="tile.color" style="width: 110px;"></kendo-dropdownlist>
|
|
18117
|
+
<kendo-dropdownlist [data]="sizeOptions" [valuePrimitive]="true" [(ngModel)]="tile.size" style="width: 110px;"></kendo-dropdownlist>
|
|
18118
|
+
<kendo-dropdownlist [data]="sourceTypeOptions" [valuePrimitive]="true" [(ngModel)]="tile.sourceType" style="width: 120px;"></kendo-dropdownlist>
|
|
18119
|
+
</div>
|
|
18120
|
+
@if (tile.sourceType === 'entity') {
|
|
18121
|
+
<div class="tile-row">
|
|
18122
|
+
<kendo-textbox [(ngModel)]="tile.ckTypeId" placeholder="CK Type ID" style="flex: 1;"></kendo-textbox>
|
|
18123
|
+
<kendo-textbox [(ngModel)]="tile.rtId" placeholder="Runtime ID" style="flex: 1;"></kendo-textbox>
|
|
18124
|
+
<kendo-textbox [(ngModel)]="tile.attributePath" placeholder="Attribute" style="width: 120px;"></kendo-textbox>
|
|
18125
|
+
</div>
|
|
18126
|
+
}
|
|
18127
|
+
@if (tile.sourceType === 'aggregation') {
|
|
18128
|
+
<div class="tile-row">
|
|
18129
|
+
<kendo-textbox [(ngModel)]="tile.ckTypeId" placeholder="CK Type ID" style="flex: 1;"></kendo-textbox>
|
|
18130
|
+
<kendo-dropdownlist [data]="aggregationOptions" [valuePrimitive]="true" [(ngModel)]="tile.aggregation" style="width: 100px;"></kendo-dropdownlist>
|
|
18131
|
+
<kendo-textbox [(ngModel)]="tile.aggAttribute" placeholder="Attribute (for sum/avg)" style="flex: 1;"></kendo-textbox>
|
|
18132
|
+
</div>
|
|
18133
|
+
}
|
|
18134
|
+
</div>
|
|
18135
|
+
}
|
|
18136
|
+
<button kendoButton fillMode="flat" (click)="addTile()">+ Add Tile</button>
|
|
18137
|
+
</div>
|
|
18138
|
+
|
|
18139
|
+
<div class="action-bar mm-dialog-actions">
|
|
18140
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18141
|
+
<button kendoButton themeColor="primary" [disabled]="!isValid" (click)="onSave()">Save</button>
|
|
18142
|
+
</div>
|
|
18143
|
+
</div>
|
|
18144
|
+
`, styles: [":host{display:block;height:100%}.config-container{display:flex;flex-direction:column;height:100%}.config-form{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.action-bar{display:flex;justify-content:flex-end;gap:8px;padding:8px 16px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.form-field{display:flex;flex-direction:column;gap:6px}.form-field label{font-weight:600;font-size:.9rem}h4{margin:8px 0 4px;font-size:.95rem}.tile-config{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;padding:10px;margin-bottom:8px;display:flex;flex-direction:column;gap:6px}.tile-header{display:flex;justify-content:space-between;align-items:center}.tile-row{display:flex;gap:6px;align-items:center}\n"] }]
|
|
18145
|
+
}], propDecorators: { initialColumns: [{
|
|
18146
|
+
type: Input
|
|
18147
|
+
}], initialTiles: [{
|
|
18148
|
+
type: Input
|
|
18149
|
+
}] } });
|
|
18150
|
+
|
|
18151
|
+
function getAlertSeverityColor(level) {
|
|
18152
|
+
switch (level?.toUpperCase()) {
|
|
18153
|
+
case 'CRITICAL': return 'var(--mm-alert-critical, #dc2626)';
|
|
18154
|
+
case 'ERROR': return 'var(--mm-alert-error, #ef4444)';
|
|
18155
|
+
case 'WARNING': return 'var(--mm-alert-warning, #f59e0b)';
|
|
18156
|
+
case 'INFORMATION': return 'var(--mm-alert-info, #3b82f6)';
|
|
18157
|
+
case 'DEBUG': return 'var(--mm-alert-debug, #6b7280)';
|
|
18158
|
+
default: return 'var(--mm-alert-debug, #6b7280)';
|
|
18159
|
+
}
|
|
18160
|
+
}
|
|
18161
|
+
function getAlertSeverityIcon(level) {
|
|
18162
|
+
switch (level?.toUpperCase()) {
|
|
18163
|
+
case 'CRITICAL':
|
|
18164
|
+
case 'ERROR':
|
|
18165
|
+
return xCircleIcon;
|
|
18166
|
+
case 'WARNING':
|
|
18167
|
+
return exclamationCircleIcon;
|
|
18168
|
+
default:
|
|
18169
|
+
return infoCircleIcon;
|
|
18170
|
+
}
|
|
18171
|
+
}
|
|
18172
|
+
function getAlertSeverityOrder(level) {
|
|
18173
|
+
switch (level?.toUpperCase()) {
|
|
18174
|
+
case 'CRITICAL': return 4;
|
|
18175
|
+
case 'ERROR': return 3;
|
|
18176
|
+
case 'WARNING': return 2;
|
|
18177
|
+
case 'INFORMATION': return 1;
|
|
18178
|
+
case 'DEBUG': return 0;
|
|
18179
|
+
default: return -1;
|
|
18180
|
+
}
|
|
18181
|
+
}
|
|
18182
|
+
const DEFAULT_ALERT_CK_TYPE = 'System.Notification/StatefulEvent';
|
|
18183
|
+
|
|
18184
|
+
class AlertBannerWidgetComponent {
|
|
18185
|
+
getEntitiesByCkTypeGQL = inject(GetEntitiesByCkTypeDtoGQL);
|
|
18186
|
+
rotationTimer = null;
|
|
18187
|
+
config;
|
|
18188
|
+
_isLoading = signal(false, ...(ngDevMode ? [{ debugName: "_isLoading" }] : /* istanbul ignore next */ []));
|
|
18189
|
+
_error = signal(null, ...(ngDevMode ? [{ debugName: "_error" }] : /* istanbul ignore next */ []));
|
|
18190
|
+
_items = signal([], ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
|
|
18191
|
+
_currentIndex = signal(0, ...(ngDevMode ? [{ debugName: "_currentIndex" }] : /* istanbul ignore next */ []));
|
|
18192
|
+
isLoading = this._isLoading.asReadonly();
|
|
18193
|
+
error = this._error.asReadonly();
|
|
18194
|
+
data = this._items.asReadonly();
|
|
18195
|
+
items = this._items.asReadonly();
|
|
18196
|
+
currentIndex = this._currentIndex.asReadonly();
|
|
18197
|
+
currentAlert = computed(() => {
|
|
18198
|
+
const items = this._items();
|
|
18199
|
+
if (items.length === 0)
|
|
18200
|
+
return null;
|
|
18201
|
+
return items[this._currentIndex() % items.length];
|
|
18202
|
+
}, ...(ngDevMode ? [{ debugName: "currentAlert" }] : /* istanbul ignore next */ []));
|
|
18203
|
+
currentColor = computed(() => {
|
|
18204
|
+
const alert = this.currentAlert();
|
|
18205
|
+
return alert ? getAlertSeverityColor(alert.level) : '';
|
|
18206
|
+
}, ...(ngDevMode ? [{ debugName: "currentColor" }] : /* istanbul ignore next */ []));
|
|
18207
|
+
currentIcon = computed(() => {
|
|
18208
|
+
const alert = this.currentAlert();
|
|
18209
|
+
return alert ? getAlertSeverityIcon(alert.level) : getAlertSeverityIcon('DEBUG');
|
|
18210
|
+
}, ...(ngDevMode ? [{ debugName: "currentIcon" }] : /* istanbul ignore next */ []));
|
|
18211
|
+
isNotConfigured() {
|
|
18212
|
+
return false;
|
|
18213
|
+
}
|
|
18214
|
+
ngOnInit() {
|
|
18215
|
+
this.loadData();
|
|
18216
|
+
}
|
|
18217
|
+
ngOnChanges(changes) {
|
|
18218
|
+
if (changes['config'] && !changes['config'].firstChange) {
|
|
18219
|
+
this.loadData();
|
|
18220
|
+
}
|
|
18221
|
+
}
|
|
18222
|
+
ngOnDestroy() {
|
|
18223
|
+
this.stopRotation();
|
|
18224
|
+
}
|
|
18225
|
+
refresh() {
|
|
18226
|
+
this.loadData();
|
|
18227
|
+
}
|
|
18228
|
+
startRotation() {
|
|
18229
|
+
this.stopRotation();
|
|
18230
|
+
const interval = this.config?.rotationInterval ?? 5000;
|
|
18231
|
+
if (this._items().length > 1) {
|
|
18232
|
+
this.rotationTimer = setInterval(() => {
|
|
18233
|
+
this._currentIndex.update(i => (i + 1) % this._items().length);
|
|
18234
|
+
}, interval);
|
|
18235
|
+
}
|
|
18236
|
+
}
|
|
18237
|
+
stopRotation() {
|
|
18238
|
+
if (this.rotationTimer) {
|
|
18239
|
+
clearInterval(this.rotationTimer);
|
|
18240
|
+
this.rotationTimer = null;
|
|
18241
|
+
}
|
|
18242
|
+
}
|
|
18243
|
+
async loadData() {
|
|
18244
|
+
this._isLoading.set(true);
|
|
18245
|
+
this._error.set(null);
|
|
18246
|
+
try {
|
|
18247
|
+
const ckTypeId = this.config?.ckTypeId || DEFAULT_ALERT_CK_TYPE;
|
|
18248
|
+
const result = await firstValueFrom(this.getEntitiesByCkTypeGQL.fetch({
|
|
18249
|
+
variables: {
|
|
18250
|
+
ckTypeId,
|
|
18251
|
+
first: this.config?.maxAlerts ?? 20,
|
|
18252
|
+
fieldFilters: [
|
|
18253
|
+
{ attributePath: 'state', operator: FieldFilterOperatorsDto.EqualsDto, comparisonValue: '0' }
|
|
18254
|
+
],
|
|
18255
|
+
sort: [
|
|
18256
|
+
{ attributePath: 'level', sortOrder: SortOrdersDto.DescendingDto }
|
|
18257
|
+
]
|
|
18258
|
+
}
|
|
18259
|
+
}));
|
|
18260
|
+
const entities = result.data?.runtime?.runtimeEntities?.items ?? [];
|
|
18261
|
+
const items = [];
|
|
18262
|
+
for (const entity of entities) {
|
|
18263
|
+
if (!entity)
|
|
18264
|
+
continue;
|
|
18265
|
+
const attrs = (entity.attributes?.items ?? [])
|
|
18266
|
+
.filter((a) => a != null && a.attributeName != null);
|
|
18267
|
+
items.push({
|
|
18268
|
+
rtId: entity.rtId ?? '',
|
|
18269
|
+
message: this.getAttr(attrs, 'message') ?? '',
|
|
18270
|
+
level: this.getAttr(attrs, 'level') ?? 'INFORMATION',
|
|
18271
|
+
state: this.getAttr(attrs, 'state') ?? '',
|
|
18272
|
+
source: this.getAttr(attrs, 'source') ?? '',
|
|
18273
|
+
timestamp: entity.rtCreationDateTime ?? undefined
|
|
18274
|
+
});
|
|
18275
|
+
}
|
|
18276
|
+
items.sort((a, b) => getAlertSeverityOrder(b.level) - getAlertSeverityOrder(a.level));
|
|
18277
|
+
this._items.set(items);
|
|
18278
|
+
this._currentIndex.set(0);
|
|
18279
|
+
this.startRotation();
|
|
18280
|
+
}
|
|
18281
|
+
catch (err) {
|
|
18282
|
+
this._error.set(err instanceof Error ? err.message : 'Failed to load alerts');
|
|
18283
|
+
}
|
|
18284
|
+
finally {
|
|
18285
|
+
this._isLoading.set(false);
|
|
18286
|
+
}
|
|
18287
|
+
}
|
|
18288
|
+
getAttr(attrs, name) {
|
|
18289
|
+
const attr = attrs.find(a => a.attributeName === name);
|
|
18290
|
+
return attr?.value != null ? String(attr.value) : null;
|
|
18291
|
+
}
|
|
18292
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertBannerWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18293
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AlertBannerWidgetComponent, isStandalone: true, selector: "mm-alert-banner-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: `
|
|
18294
|
+
<div class="alert-banner-widget">
|
|
18295
|
+
@if (isNotConfigured()) {
|
|
18296
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
18297
|
+
} @else if (error()) {
|
|
18298
|
+
<div class="error-message">{{ error() }}</div>
|
|
18299
|
+
} @else if (currentAlert()) {
|
|
18300
|
+
<div class="alert-banner" [class.critical]="currentAlert()!.level === 'CRITICAL'"
|
|
18301
|
+
[style.--alert-color]="currentColor()">
|
|
18302
|
+
@if (config.showIcon !== false) {
|
|
18303
|
+
<kendo-svg-icon [icon]="currentIcon()" class="alert-icon"></kendo-svg-icon>
|
|
18304
|
+
}
|
|
18305
|
+
<span class="alert-severity-badge">{{ currentAlert()!.level }}</span>
|
|
18306
|
+
<span class="alert-message">{{ currentAlert()!.message }}</span>
|
|
18307
|
+
@if (items().length > 1) {
|
|
18308
|
+
<span class="alert-counter">{{ currentIndex() + 1 }}/{{ items().length }}</span>
|
|
18309
|
+
}
|
|
18310
|
+
</div>
|
|
18311
|
+
} @else if (!isLoading()) {
|
|
18312
|
+
<div class="alert-banner no-alerts">
|
|
18313
|
+
<span class="alert-message">No active alerts</span>
|
|
18314
|
+
</div>
|
|
18315
|
+
}
|
|
18316
|
+
</div>
|
|
18317
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.alert-banner-widget{height:100%;display:flex;align-items:center}.alert-banner{display:flex;align-items:center;gap:10px;width:100%;padding:10px 16px;border-left:4px solid var(--alert-color, #6b7280);background:color-mix(in srgb,var(--alert-color, #6b7280) 10%,transparent)}.alert-banner.critical{animation:pulse-bg 1.5s ease-in-out infinite}@keyframes pulse-bg{0%,to{background:color-mix(in srgb,var(--alert-color) 10%,transparent)}50%{background:color-mix(in srgb,var(--alert-color) 25%,transparent)}}.alert-icon{flex-shrink:0;color:var(--alert-color, #6b7280)}.alert-severity-badge{font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 8px;border-radius:3px;background:var(--alert-color, #6b7280);color:#fff;white-space:nowrap;flex-shrink:0}.alert-message{flex:1;font-size:.85rem;color:var(--kendo-color-on-app-surface, inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.alert-counter{font-size:.7rem;opacity:.5;white-space:nowrap;flex-shrink:0}.no-alerts{border-left-color:var(--mm-alert-debug, #6b7280);opacity:.5}.error-message{text-align:center;padding:16px;width:100%;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
18318
|
+
}
|
|
18319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertBannerWidgetComponent, decorators: [{
|
|
18320
|
+
type: Component,
|
|
18321
|
+
args: [{ selector: 'mm-alert-banner-widget', standalone: true, imports: [CommonModule, SVGIconModule, WidgetNotConfiguredComponent], template: `
|
|
18322
|
+
<div class="alert-banner-widget">
|
|
18323
|
+
@if (isNotConfigured()) {
|
|
18324
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
18325
|
+
} @else if (error()) {
|
|
18326
|
+
<div class="error-message">{{ error() }}</div>
|
|
18327
|
+
} @else if (currentAlert()) {
|
|
18328
|
+
<div class="alert-banner" [class.critical]="currentAlert()!.level === 'CRITICAL'"
|
|
18329
|
+
[style.--alert-color]="currentColor()">
|
|
18330
|
+
@if (config.showIcon !== false) {
|
|
18331
|
+
<kendo-svg-icon [icon]="currentIcon()" class="alert-icon"></kendo-svg-icon>
|
|
18332
|
+
}
|
|
18333
|
+
<span class="alert-severity-badge">{{ currentAlert()!.level }}</span>
|
|
18334
|
+
<span class="alert-message">{{ currentAlert()!.message }}</span>
|
|
18335
|
+
@if (items().length > 1) {
|
|
18336
|
+
<span class="alert-counter">{{ currentIndex() + 1 }}/{{ items().length }}</span>
|
|
18337
|
+
}
|
|
18338
|
+
</div>
|
|
18339
|
+
} @else if (!isLoading()) {
|
|
18340
|
+
<div class="alert-banner no-alerts">
|
|
18341
|
+
<span class="alert-message">No active alerts</span>
|
|
18342
|
+
</div>
|
|
18343
|
+
}
|
|
18344
|
+
</div>
|
|
18345
|
+
`, styles: [":host{display:block;width:100%;height:100%}.alert-banner-widget{height:100%;display:flex;align-items:center}.alert-banner{display:flex;align-items:center;gap:10px;width:100%;padding:10px 16px;border-left:4px solid var(--alert-color, #6b7280);background:color-mix(in srgb,var(--alert-color, #6b7280) 10%,transparent)}.alert-banner.critical{animation:pulse-bg 1.5s ease-in-out infinite}@keyframes pulse-bg{0%,to{background:color-mix(in srgb,var(--alert-color) 10%,transparent)}50%{background:color-mix(in srgb,var(--alert-color) 25%,transparent)}}.alert-icon{flex-shrink:0;color:var(--alert-color, #6b7280)}.alert-severity-badge{font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 8px;border-radius:3px;background:var(--alert-color, #6b7280);color:#fff;white-space:nowrap;flex-shrink:0}.alert-message{flex:1;font-size:.85rem;color:var(--kendo-color-on-app-surface, inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.alert-counter{font-size:.7rem;opacity:.5;white-space:nowrap;flex-shrink:0}.no-alerts{border-left-color:var(--mm-alert-debug, #6b7280);opacity:.5}.error-message{text-align:center;padding:16px;width:100%;color:var(--kendo-color-error, #dc3545)}\n"] }]
|
|
18346
|
+
}], propDecorators: { config: [{
|
|
18347
|
+
type: Input
|
|
18348
|
+
}] } });
|
|
18349
|
+
|
|
18350
|
+
class AlertBannerConfigDialogComponent {
|
|
18351
|
+
windowRef = inject(WindowRef);
|
|
18352
|
+
ckTypeId = 'System.Notification/StatefulEvent';
|
|
18353
|
+
rotationInterval = 5000;
|
|
18354
|
+
showIcon = true;
|
|
18355
|
+
maxAlerts = 20;
|
|
18356
|
+
onSave() {
|
|
18357
|
+
const result = {
|
|
18358
|
+
ckTypeId: this.ckTypeId,
|
|
18359
|
+
rotationInterval: this.rotationInterval,
|
|
18360
|
+
showIcon: this.showIcon,
|
|
18361
|
+
maxAlerts: this.maxAlerts
|
|
18362
|
+
};
|
|
18363
|
+
this.windowRef.close(result);
|
|
18364
|
+
}
|
|
18365
|
+
onCancel() {
|
|
18366
|
+
this.windowRef.close();
|
|
18367
|
+
}
|
|
18368
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertBannerConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18369
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: AlertBannerConfigDialogComponent, isStandalone: true, selector: "mm-alert-banner-config-dialog", ngImport: i0, template: `
|
|
18370
|
+
<div class="config-form">
|
|
18371
|
+
<div class="form-group">
|
|
18372
|
+
<kendo-label text="CK Type ID">
|
|
18373
|
+
<kendo-textbox [(ngModel)]="ckTypeId"></kendo-textbox>
|
|
18374
|
+
</kendo-label>
|
|
18375
|
+
</div>
|
|
18376
|
+
<div class="form-group">
|
|
18377
|
+
<kendo-label text="Rotation Interval (ms)">
|
|
18378
|
+
<kendo-numerictextbox [(ngModel)]="rotationInterval" [min]="1000" [step]="1000" [format]="'n0'"></kendo-numerictextbox>
|
|
18379
|
+
</kendo-label>
|
|
18380
|
+
</div>
|
|
18381
|
+
<div class="form-group">
|
|
18382
|
+
<kendo-label text="Max Alerts">
|
|
18383
|
+
<kendo-numerictextbox [(ngModel)]="maxAlerts" [min]="1" [max]="100" [format]="'n0'"></kendo-numerictextbox>
|
|
18384
|
+
</kendo-label>
|
|
18385
|
+
</div>
|
|
18386
|
+
<div class="mm-dialog-actions">
|
|
18387
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18388
|
+
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
18389
|
+
</div>
|
|
18390
|
+
</div>
|
|
18391
|
+
`, isInline: true, styles: [".config-form{display:flex;flex-direction:column;gap:12px;padding:16px}.form-group{display:flex;flex-direction:column;gap:4px}.mm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "ngmodule", type: LabelModule }, { kind: "component", type: i4$1.LabelComponent, selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }] });
|
|
18392
|
+
}
|
|
18393
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertBannerConfigDialogComponent, decorators: [{
|
|
18394
|
+
type: Component,
|
|
18395
|
+
args: [{ selector: 'mm-alert-banner-config-dialog', standalone: true, imports: [CommonModule, FormsModule, ButtonsModule, InputsModule, LabelModule], template: `
|
|
18396
|
+
<div class="config-form">
|
|
18397
|
+
<div class="form-group">
|
|
18398
|
+
<kendo-label text="CK Type ID">
|
|
18399
|
+
<kendo-textbox [(ngModel)]="ckTypeId"></kendo-textbox>
|
|
18400
|
+
</kendo-label>
|
|
18401
|
+
</div>
|
|
18402
|
+
<div class="form-group">
|
|
18403
|
+
<kendo-label text="Rotation Interval (ms)">
|
|
18404
|
+
<kendo-numerictextbox [(ngModel)]="rotationInterval" [min]="1000" [step]="1000" [format]="'n0'"></kendo-numerictextbox>
|
|
18405
|
+
</kendo-label>
|
|
18406
|
+
</div>
|
|
18407
|
+
<div class="form-group">
|
|
18408
|
+
<kendo-label text="Max Alerts">
|
|
18409
|
+
<kendo-numerictextbox [(ngModel)]="maxAlerts" [min]="1" [max]="100" [format]="'n0'"></kendo-numerictextbox>
|
|
18410
|
+
</kendo-label>
|
|
18411
|
+
</div>
|
|
18412
|
+
<div class="mm-dialog-actions">
|
|
18413
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18414
|
+
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
18415
|
+
</div>
|
|
18416
|
+
</div>
|
|
18417
|
+
`, styles: [".config-form{display:flex;flex-direction:column;gap:12px;padding:16px}.form-group{display:flex;flex-direction:column;gap:4px}.mm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\n"] }]
|
|
18418
|
+
}] });
|
|
18419
|
+
|
|
18420
|
+
class AlertListWidgetComponent {
|
|
18421
|
+
getEntitiesByCkTypeGQL = inject(GetEntitiesByCkTypeDtoGQL);
|
|
18422
|
+
config;
|
|
18423
|
+
_isLoading = signal(false, ...(ngDevMode ? [{ debugName: "_isLoading" }] : /* istanbul ignore next */ []));
|
|
18424
|
+
_error = signal(null, ...(ngDevMode ? [{ debugName: "_error" }] : /* istanbul ignore next */ []));
|
|
18425
|
+
_items = signal([], ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
|
|
18426
|
+
isLoading = this._isLoading.asReadonly();
|
|
18427
|
+
error = this._error.asReadonly();
|
|
18428
|
+
data = this._items.asReadonly();
|
|
18429
|
+
items = this._items.asReadonly();
|
|
18430
|
+
isNotConfigured() {
|
|
18431
|
+
return false;
|
|
18432
|
+
}
|
|
18433
|
+
ngOnInit() {
|
|
18434
|
+
this.loadData();
|
|
18435
|
+
}
|
|
18436
|
+
ngOnChanges(changes) {
|
|
18437
|
+
if (changes['config'] && !changes['config'].firstChange) {
|
|
18438
|
+
this.loadData();
|
|
18439
|
+
}
|
|
18440
|
+
}
|
|
18441
|
+
refresh() {
|
|
18442
|
+
this.loadData();
|
|
18443
|
+
}
|
|
18444
|
+
getColor(level) {
|
|
18445
|
+
return getAlertSeverityColor(level);
|
|
18446
|
+
}
|
|
18447
|
+
getIcon(level) {
|
|
18448
|
+
return getAlertSeverityIcon(level);
|
|
18449
|
+
}
|
|
18450
|
+
formatTime(timestamp) {
|
|
18451
|
+
try {
|
|
18452
|
+
const date = new Date(timestamp);
|
|
18453
|
+
return date.toLocaleString('de-AT', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
|
|
18454
|
+
}
|
|
18455
|
+
catch {
|
|
18456
|
+
return '';
|
|
18457
|
+
}
|
|
18458
|
+
}
|
|
18459
|
+
async loadData() {
|
|
18460
|
+
this._isLoading.set(true);
|
|
18461
|
+
this._error.set(null);
|
|
18462
|
+
try {
|
|
18463
|
+
const ckTypeId = this.config?.ckTypeId || DEFAULT_ALERT_CK_TYPE;
|
|
18464
|
+
const result = await firstValueFrom(this.getEntitiesByCkTypeGQL.fetch({
|
|
18465
|
+
variables: {
|
|
18466
|
+
ckTypeId,
|
|
18467
|
+
first: this.config?.maxAlerts ?? 50,
|
|
18468
|
+
fieldFilters: [
|
|
18469
|
+
{ attributePath: 'state', operator: FieldFilterOperatorsDto.EqualsDto, comparisonValue: '0' }
|
|
18470
|
+
],
|
|
18471
|
+
sort: [
|
|
18472
|
+
{ attributePath: 'level', sortOrder: SortOrdersDto.DescendingDto }
|
|
18473
|
+
]
|
|
18474
|
+
}
|
|
18475
|
+
}));
|
|
18476
|
+
const entities = result.data?.runtime?.runtimeEntities?.items ?? [];
|
|
18477
|
+
const items = [];
|
|
18478
|
+
for (const entity of entities) {
|
|
18479
|
+
if (!entity)
|
|
18480
|
+
continue;
|
|
18481
|
+
const attrs = (entity.attributes?.items ?? [])
|
|
18482
|
+
.filter((a) => a != null && a.attributeName != null);
|
|
18483
|
+
items.push({
|
|
18484
|
+
rtId: entity.rtId ?? '',
|
|
18485
|
+
message: this.getAttr(attrs, 'message') ?? '',
|
|
18486
|
+
level: this.getAttr(attrs, 'level') ?? 'INFORMATION',
|
|
18487
|
+
state: this.getAttr(attrs, 'state') ?? '',
|
|
18488
|
+
source: this.getAttr(attrs, 'source') ?? '',
|
|
18489
|
+
timestamp: entity.rtCreationDateTime ?? undefined
|
|
18490
|
+
});
|
|
18491
|
+
}
|
|
18492
|
+
if (this.config?.sortBySeverity !== false) {
|
|
18493
|
+
items.sort((a, b) => getAlertSeverityOrder(b.level) - getAlertSeverityOrder(a.level));
|
|
18494
|
+
}
|
|
18495
|
+
this._items.set(items);
|
|
18496
|
+
}
|
|
18497
|
+
catch (err) {
|
|
18498
|
+
this._error.set(err instanceof Error ? err.message : 'Failed to load alerts');
|
|
18499
|
+
}
|
|
18500
|
+
finally {
|
|
18501
|
+
this._isLoading.set(false);
|
|
18502
|
+
}
|
|
18503
|
+
}
|
|
18504
|
+
getAttr(attrs, name) {
|
|
18505
|
+
const attr = attrs.find(a => a.attributeName === name);
|
|
18506
|
+
return attr?.value != null ? String(attr.value) : null;
|
|
18507
|
+
}
|
|
18508
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertListWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18509
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AlertListWidgetComponent, isStandalone: true, selector: "mm-alert-list-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: `
|
|
18510
|
+
<div class="alert-list-widget">
|
|
18511
|
+
@if (isNotConfigured()) {
|
|
18512
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
18513
|
+
} @else if (error()) {
|
|
18514
|
+
<div class="error-message">{{ error() }}</div>
|
|
18515
|
+
} @else {
|
|
18516
|
+
<div class="alert-list">
|
|
18517
|
+
@for (item of items(); track item.rtId) {
|
|
18518
|
+
<div class="alert-item" [style.--alert-color]="getColor(item.level)">
|
|
18519
|
+
<kendo-svg-icon [icon]="getIcon(item.level)" class="alert-icon"></kendo-svg-icon>
|
|
18520
|
+
<span class="alert-badge" [style.background-color]="getColor(item.level)">
|
|
18521
|
+
{{ item.level }}
|
|
18522
|
+
</span>
|
|
18523
|
+
<span class="alert-message">{{ item.message }}</span>
|
|
18524
|
+
@if (config.showTimestamp !== false && item.timestamp) {
|
|
18525
|
+
<span class="alert-time">{{ formatTime(item.timestamp) }}</span>
|
|
18526
|
+
}
|
|
18527
|
+
</div>
|
|
18528
|
+
}
|
|
18529
|
+
@if (!isLoading() && items().length === 0) {
|
|
18530
|
+
<div class="empty-message">No active alerts</div>
|
|
18531
|
+
}
|
|
18532
|
+
</div>
|
|
18533
|
+
}
|
|
18534
|
+
</div>
|
|
18535
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.alert-list-widget{height:100%;display:flex;flex-direction:column;overflow-y:auto;padding:8px 0}.alert-list{display:flex;flex-direction:column;gap:4px;padding:0 12px}.alert-item{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:6px;border-left:3px solid var(--alert-color, #6b7280);background:var(--mm-alert-list-item-bg, rgba(255, 255, 255, .03))}.alert-icon{flex-shrink:0;color:var(--alert-color, #6b7280)}.alert-badge{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:3px;color:#fff;white-space:nowrap;flex-shrink:0}.alert-message{flex:1;font-size:.8rem;color:var(--kendo-color-on-app-surface, inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.alert-time{font-size:.7rem;opacity:.5;white-space:nowrap;flex-shrink:0}.empty-message{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.error-message{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: WidgetNotConfiguredComponent, selector: "mm-widget-not-configured" }] });
|
|
18536
|
+
}
|
|
18537
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertListWidgetComponent, decorators: [{
|
|
18538
|
+
type: Component,
|
|
18539
|
+
args: [{ selector: 'mm-alert-list-widget', standalone: true, imports: [CommonModule, SVGIconModule, WidgetNotConfiguredComponent], template: `
|
|
18540
|
+
<div class="alert-list-widget">
|
|
18541
|
+
@if (isNotConfigured()) {
|
|
18542
|
+
<mm-widget-not-configured></mm-widget-not-configured>
|
|
18543
|
+
} @else if (error()) {
|
|
18544
|
+
<div class="error-message">{{ error() }}</div>
|
|
18545
|
+
} @else {
|
|
18546
|
+
<div class="alert-list">
|
|
18547
|
+
@for (item of items(); track item.rtId) {
|
|
18548
|
+
<div class="alert-item" [style.--alert-color]="getColor(item.level)">
|
|
18549
|
+
<kendo-svg-icon [icon]="getIcon(item.level)" class="alert-icon"></kendo-svg-icon>
|
|
18550
|
+
<span class="alert-badge" [style.background-color]="getColor(item.level)">
|
|
18551
|
+
{{ item.level }}
|
|
18552
|
+
</span>
|
|
18553
|
+
<span class="alert-message">{{ item.message }}</span>
|
|
18554
|
+
@if (config.showTimestamp !== false && item.timestamp) {
|
|
18555
|
+
<span class="alert-time">{{ formatTime(item.timestamp) }}</span>
|
|
18556
|
+
}
|
|
18557
|
+
</div>
|
|
18558
|
+
}
|
|
18559
|
+
@if (!isLoading() && items().length === 0) {
|
|
18560
|
+
<div class="empty-message">No active alerts</div>
|
|
18561
|
+
}
|
|
18562
|
+
</div>
|
|
18563
|
+
}
|
|
18564
|
+
</div>
|
|
18565
|
+
`, styles: [":host{display:block;width:100%;height:100%}.alert-list-widget{height:100%;display:flex;flex-direction:column;overflow-y:auto;padding:8px 0}.alert-list{display:flex;flex-direction:column;gap:4px;padding:0 12px}.alert-item{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:6px;border-left:3px solid var(--alert-color, #6b7280);background:var(--mm-alert-list-item-bg, rgba(255, 255, 255, .03))}.alert-icon{flex-shrink:0;color:var(--alert-color, #6b7280)}.alert-badge{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:3px;color:#fff;white-space:nowrap;flex-shrink:0}.alert-message{flex:1;font-size:.8rem;color:var(--kendo-color-on-app-surface, inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.alert-time{font-size:.7rem;opacity:.5;white-space:nowrap;flex-shrink:0}.empty-message{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.error-message{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"] }]
|
|
18566
|
+
}], propDecorators: { config: [{
|
|
18567
|
+
type: Input
|
|
18568
|
+
}] } });
|
|
18569
|
+
|
|
18570
|
+
class AlertListConfigDialogComponent {
|
|
18571
|
+
windowRef = inject(WindowRef);
|
|
18572
|
+
ckTypeId = 'System.Notification/StatefulEvent';
|
|
18573
|
+
showTimestamp = true;
|
|
18574
|
+
sortBySeverity = true;
|
|
18575
|
+
maxAlerts = 50;
|
|
18576
|
+
onSave() {
|
|
18577
|
+
const result = {
|
|
18578
|
+
ckTypeId: this.ckTypeId,
|
|
18579
|
+
showTimestamp: this.showTimestamp,
|
|
18580
|
+
sortBySeverity: this.sortBySeverity,
|
|
18581
|
+
maxAlerts: this.maxAlerts
|
|
18582
|
+
};
|
|
18583
|
+
this.windowRef.close(result);
|
|
18584
|
+
}
|
|
18585
|
+
onCancel() {
|
|
18586
|
+
this.windowRef.close();
|
|
18587
|
+
}
|
|
18588
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertListConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18589
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: AlertListConfigDialogComponent, isStandalone: true, selector: "mm-alert-list-config-dialog", ngImport: i0, template: `
|
|
18590
|
+
<div class="config-form">
|
|
18591
|
+
<div class="form-group">
|
|
18592
|
+
<kendo-label text="CK Type ID">
|
|
18593
|
+
<kendo-textbox [(ngModel)]="ckTypeId"></kendo-textbox>
|
|
18594
|
+
</kendo-label>
|
|
18595
|
+
</div>
|
|
18596
|
+
<div class="form-group">
|
|
18597
|
+
<kendo-label text="Max Alerts">
|
|
18598
|
+
<kendo-numerictextbox [(ngModel)]="maxAlerts" [min]="1" [max]="200" [format]="'n0'"></kendo-numerictextbox>
|
|
18599
|
+
</kendo-label>
|
|
18600
|
+
</div>
|
|
18601
|
+
<div class="mm-dialog-actions">
|
|
18602
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18603
|
+
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
18604
|
+
</div>
|
|
18605
|
+
</div>
|
|
18606
|
+
`, isInline: true, styles: [".config-form{display:flex;flex-direction:column;gap:12px;padding:16px}.form-group{display:flex;flex-direction:column;gap:4px}.mm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "ngmodule", type: LabelModule }, { kind: "component", type: i4$1.LabelComponent, selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }] });
|
|
18607
|
+
}
|
|
18608
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AlertListConfigDialogComponent, decorators: [{
|
|
18609
|
+
type: Component,
|
|
18610
|
+
args: [{ selector: 'mm-alert-list-config-dialog', standalone: true, imports: [CommonModule, FormsModule, ButtonsModule, InputsModule, LabelModule], template: `
|
|
18611
|
+
<div class="config-form">
|
|
18612
|
+
<div class="form-group">
|
|
18613
|
+
<kendo-label text="CK Type ID">
|
|
18614
|
+
<kendo-textbox [(ngModel)]="ckTypeId"></kendo-textbox>
|
|
18615
|
+
</kendo-label>
|
|
18616
|
+
</div>
|
|
18617
|
+
<div class="form-group">
|
|
18618
|
+
<kendo-label text="Max Alerts">
|
|
18619
|
+
<kendo-numerictextbox [(ngModel)]="maxAlerts" [min]="1" [max]="200" [format]="'n0'"></kendo-numerictextbox>
|
|
18620
|
+
</kendo-label>
|
|
18621
|
+
</div>
|
|
18622
|
+
<div class="mm-dialog-actions">
|
|
18623
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18624
|
+
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
18625
|
+
</div>
|
|
18626
|
+
</div>
|
|
18627
|
+
`, styles: [".config-form{display:flex;flex-direction:column;gap:12px;padding:16px}.form-group{display:flex;flex-direction:column;gap:4px}.mm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\n"] }]
|
|
18628
|
+
}] });
|
|
18629
|
+
|
|
18630
|
+
class AiInsightsService {
|
|
18631
|
+
async generateInsights(context) {
|
|
18632
|
+
if (context.apiKey) {
|
|
18633
|
+
return this.callClaudeApi(context);
|
|
18634
|
+
}
|
|
18635
|
+
return this.getSimulatedInsights(context);
|
|
18636
|
+
}
|
|
18637
|
+
gatherWidgetContext(widgets) {
|
|
18638
|
+
return widgets
|
|
18639
|
+
.filter(w => w.type !== 'aiInsights')
|
|
18640
|
+
.map(w => this.extractWidgetSummary(w))
|
|
18641
|
+
.filter(s => s.dataPoints.length > 0 || s.type !== 'unknown');
|
|
18642
|
+
}
|
|
18643
|
+
extractWidgetSummary(widget) {
|
|
18644
|
+
const summary = {
|
|
18645
|
+
title: widget.title,
|
|
18646
|
+
type: widget.type,
|
|
18647
|
+
dataPoints: []
|
|
18648
|
+
};
|
|
18649
|
+
if (widget.type === 'kpi') {
|
|
18650
|
+
const kpi = widget;
|
|
18651
|
+
if (kpi.staticValue) {
|
|
18652
|
+
summary.dataPoints.push({ label: 'value', value: `${kpi.staticValue}${kpi.suffix ?? ''}` });
|
|
18653
|
+
}
|
|
18654
|
+
if (kpi.comparisonText) {
|
|
18655
|
+
summary.dataPoints.push({ label: 'comparison', value: kpi.comparisonText });
|
|
18656
|
+
}
|
|
18657
|
+
}
|
|
18658
|
+
if (widget.type === 'gauge') {
|
|
18659
|
+
const gauge = widget;
|
|
18660
|
+
if (gauge.valueAttribute) {
|
|
18661
|
+
summary.dataPoints.push({ label: 'attribute', value: gauge.valueAttribute });
|
|
18662
|
+
}
|
|
18663
|
+
}
|
|
18664
|
+
return summary;
|
|
18665
|
+
}
|
|
18666
|
+
async callClaudeApi(context) {
|
|
18667
|
+
const systemPrompt = context.systemPrompt ?? this.buildDefaultSystemPrompt(context);
|
|
18668
|
+
const userMessage = this.buildUserMessage(context);
|
|
18669
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
18670
|
+
method: 'POST',
|
|
18671
|
+
headers: {
|
|
18672
|
+
'Content-Type': 'application/json',
|
|
18673
|
+
'x-api-key': context.apiKey,
|
|
18674
|
+
'anthropic-version': '2023-06-01',
|
|
18675
|
+
'anthropic-dangerous-direct-browser-access': 'true'
|
|
18676
|
+
},
|
|
18677
|
+
body: JSON.stringify({
|
|
18678
|
+
model: context.model ?? 'claude-sonnet-4-20250514',
|
|
18679
|
+
max_tokens: 1024,
|
|
18680
|
+
system: systemPrompt,
|
|
18681
|
+
messages: [{ role: 'user', content: userMessage }]
|
|
18682
|
+
})
|
|
18683
|
+
});
|
|
18684
|
+
if (!response.ok) {
|
|
18685
|
+
throw new Error(`Claude API error: ${response.status}`);
|
|
18686
|
+
}
|
|
18687
|
+
const data = await response.json();
|
|
18688
|
+
const text = data.content?.[0]?.text ?? '';
|
|
18689
|
+
return this.parseInsightsFromResponse(text, context.maxInsights ?? 4);
|
|
18690
|
+
}
|
|
18691
|
+
buildDefaultSystemPrompt(context) {
|
|
18692
|
+
const domain = context.domainContext ?? 'energy management';
|
|
18693
|
+
return `You are an AI advisor for an industrial ${domain} dashboard.
|
|
18694
|
+
Analyze the provided dashboard data and generate actionable insights.
|
|
18695
|
+
Respond ONLY with a JSON array of insight objects. Each object has:
|
|
18696
|
+
- "title": short headline (max 8 words)
|
|
18697
|
+
- "description": actionable recommendation (1-2 sentences, German language)
|
|
18698
|
+
- "severity": one of "info", "warning", "success", "critical"
|
|
18699
|
+
|
|
18700
|
+
Focus on energy efficiency, cost savings, anomalies, and optimization opportunities.
|
|
18701
|
+
Return at most ${context.maxInsights ?? 4} insights. No markdown, no explanation, only the JSON array.`;
|
|
18702
|
+
}
|
|
18703
|
+
buildUserMessage(context) {
|
|
18704
|
+
const widgetData = context.widgetSummaries.map(w => ({
|
|
18705
|
+
widget: w.title,
|
|
18706
|
+
type: w.type,
|
|
18707
|
+
data: w.dataPoints
|
|
18708
|
+
}));
|
|
18709
|
+
return `Current dashboard state:\n${JSON.stringify(widgetData, null, 2)}`;
|
|
18710
|
+
}
|
|
18711
|
+
parseInsightsFromResponse(text, maxInsights) {
|
|
18712
|
+
try {
|
|
18713
|
+
const jsonMatch = text.match(/\[[\s\S]*\]/);
|
|
18714
|
+
if (!jsonMatch)
|
|
18715
|
+
return this.fallbackInsights();
|
|
18716
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
18717
|
+
return parsed.slice(0, maxInsights).map(i => ({
|
|
18718
|
+
title: i.title ?? 'Insight',
|
|
18719
|
+
description: i.description ?? '',
|
|
18720
|
+
severity: (['info', 'warning', 'success', 'critical'].includes(i.severity) ? i.severity : 'info')
|
|
18721
|
+
}));
|
|
18722
|
+
}
|
|
18723
|
+
catch {
|
|
18724
|
+
return this.fallbackInsights();
|
|
18725
|
+
}
|
|
18726
|
+
}
|
|
18727
|
+
getSimulatedInsights(_context) {
|
|
18728
|
+
const hour = new Date().getHours();
|
|
18729
|
+
const insights = [
|
|
18730
|
+
{
|
|
18731
|
+
title: 'Lastspitze prognostiziert',
|
|
18732
|
+
description: 'Basierend auf dem aktuellen Lastprofil wird die 3.000 kW Grenze voraussichtlich um 14:30 Uhr erreicht. Lastabwurf der HVAC-Anlage um 30% empfohlen.',
|
|
18733
|
+
severity: 'warning'
|
|
18734
|
+
},
|
|
18735
|
+
{
|
|
18736
|
+
title: 'PV-Optimierung möglich',
|
|
18737
|
+
description: hour < 14
|
|
18738
|
+
? 'Wettervorhersage: sonnig bis 16:00 Uhr. Energieintensive Prozesse jetzt starten — erwartete PV-Einspeisung von 810 kW nutzen.'
|
|
18739
|
+
: 'PV-Einspeisung sinkt ab 16:00 Uhr. Batteriespeicher auf 80% laden, solange Überschuss verfügbar ist.',
|
|
18740
|
+
severity: 'success'
|
|
18741
|
+
},
|
|
18742
|
+
{
|
|
18743
|
+
title: 'Kompressoranlage C3 auffällig',
|
|
18744
|
+
description: 'Verbrauch 18% über dem 30-Tage-Durchschnitt bei gleicher Auslastung. Mögliche Ursache: verschlissene Dichtungen oder Druckverlust. Wartung empfohlen.',
|
|
18745
|
+
severity: 'warning'
|
|
18746
|
+
},
|
|
18747
|
+
{
|
|
18748
|
+
title: 'CO2-Budget im Zeitplan',
|
|
18749
|
+
description: 'Mit 489 t von 680 t Budget (72%) und 9 Monaten verbleibend liegt der Verbrauch 4% unter Plan. Zertifikats-Beschaffung kann verschoben werden.',
|
|
18750
|
+
severity: 'success'
|
|
18751
|
+
}
|
|
18752
|
+
];
|
|
18753
|
+
return insights;
|
|
18754
|
+
}
|
|
18755
|
+
fallbackInsights() {
|
|
18756
|
+
return [{
|
|
18757
|
+
title: 'Analyse nicht verfügbar',
|
|
18758
|
+
description: 'Die KI-Analyse konnte nicht durchgeführt werden. Bitte prüfen Sie den API-Schlüssel in den Widget-Einstellungen.',
|
|
18759
|
+
severity: 'info'
|
|
18760
|
+
}];
|
|
18761
|
+
}
|
|
18762
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
18763
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsService, providedIn: 'root' });
|
|
18764
|
+
}
|
|
18765
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsService, decorators: [{
|
|
18766
|
+
type: Injectable,
|
|
18767
|
+
args: [{ providedIn: 'root' }]
|
|
18768
|
+
}] });
|
|
18769
|
+
|
|
18770
|
+
class AiInsightsWidgetComponent {
|
|
18771
|
+
aiService = inject(AiInsightsService);
|
|
18772
|
+
stateService = inject(MeshBoardStateService);
|
|
18773
|
+
refreshTimer = null;
|
|
18774
|
+
infoIcon = infoCircleIcon;
|
|
18775
|
+
warningIcon = exclamationCircleIcon;
|
|
18776
|
+
successIcon = checkCircleIcon;
|
|
18777
|
+
criticalIcon = xCircleIcon;
|
|
18778
|
+
config;
|
|
18779
|
+
_isLoading = signal(false, ...(ngDevMode ? [{ debugName: "_isLoading" }] : /* istanbul ignore next */ []));
|
|
18780
|
+
_error = signal(null, ...(ngDevMode ? [{ debugName: "_error" }] : /* istanbul ignore next */ []));
|
|
18781
|
+
_insights = signal(null, ...(ngDevMode ? [{ debugName: "_insights" }] : /* istanbul ignore next */ []));
|
|
18782
|
+
isLoading = this._isLoading.asReadonly();
|
|
18783
|
+
error = this._error.asReadonly();
|
|
18784
|
+
data = this._insights.asReadonly();
|
|
18785
|
+
insights = this._insights.asReadonly();
|
|
18786
|
+
isNotConfigured() {
|
|
18787
|
+
return false;
|
|
18788
|
+
}
|
|
18789
|
+
ngOnInit() {
|
|
18790
|
+
this.loadInsights();
|
|
18791
|
+
this.startAutoRefresh();
|
|
18792
|
+
}
|
|
18793
|
+
ngOnChanges(changes) {
|
|
18794
|
+
if (changes['config'] && !changes['config'].firstChange) {
|
|
18795
|
+
this.stopAutoRefresh();
|
|
18796
|
+
this.loadInsights();
|
|
18797
|
+
this.startAutoRefresh();
|
|
18798
|
+
}
|
|
18799
|
+
}
|
|
18800
|
+
ngOnDestroy() {
|
|
18801
|
+
this.stopAutoRefresh();
|
|
18802
|
+
}
|
|
18803
|
+
refresh() {
|
|
18804
|
+
this.loadInsights();
|
|
18805
|
+
}
|
|
18806
|
+
getIcon(severity) {
|
|
18807
|
+
switch (severity) {
|
|
18808
|
+
case 'warning': return this.warningIcon;
|
|
18809
|
+
case 'success': return this.successIcon;
|
|
18810
|
+
case 'critical': return this.criticalIcon;
|
|
18811
|
+
default: return this.infoIcon;
|
|
18812
|
+
}
|
|
18813
|
+
}
|
|
18814
|
+
async loadInsights() {
|
|
18815
|
+
this._isLoading.set(true);
|
|
18816
|
+
this._error.set(null);
|
|
18817
|
+
try {
|
|
18818
|
+
const widgets = this.stateService.widgets();
|
|
18819
|
+
const widgetSummaries = this.aiService.gatherWidgetContext(widgets);
|
|
18820
|
+
const context = {
|
|
18821
|
+
apiKey: this.config.apiKey,
|
|
18822
|
+
model: this.config.model,
|
|
18823
|
+
systemPrompt: this.config.systemPrompt,
|
|
18824
|
+
maxInsights: this.config.maxInsights ?? 4,
|
|
18825
|
+
domainContext: this.config.domainContext ?? 'energy management',
|
|
18826
|
+
widgetSummaries
|
|
18827
|
+
};
|
|
18828
|
+
const insights = await this.aiService.generateInsights(context);
|
|
18829
|
+
this._insights.set(insights);
|
|
18830
|
+
}
|
|
18831
|
+
catch (err) {
|
|
18832
|
+
this._error.set(err instanceof Error ? err.message : 'Failed to generate insights');
|
|
18833
|
+
}
|
|
18834
|
+
finally {
|
|
18835
|
+
this._isLoading.set(false);
|
|
18836
|
+
}
|
|
18837
|
+
}
|
|
18838
|
+
startAutoRefresh() {
|
|
18839
|
+
this.stopAutoRefresh();
|
|
18840
|
+
const interval = (this.config?.refreshInterval ?? 0) * 1000;
|
|
18841
|
+
if (interval > 0) {
|
|
18842
|
+
this.refreshTimer = setInterval(() => this.loadInsights(), interval);
|
|
18843
|
+
}
|
|
18844
|
+
}
|
|
18845
|
+
stopAutoRefresh() {
|
|
18846
|
+
if (this.refreshTimer) {
|
|
18847
|
+
clearInterval(this.refreshTimer);
|
|
18848
|
+
this.refreshTimer = null;
|
|
18849
|
+
}
|
|
18850
|
+
}
|
|
18851
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18852
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AiInsightsWidgetComponent, isStandalone: true, selector: "mm-ai-insights-widget", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: `
|
|
18853
|
+
<div class="ai-insights-widget">
|
|
18854
|
+
@if (isLoading() && !insights()) {
|
|
18855
|
+
<div class="loading-state">
|
|
18856
|
+
<div class="loading-dots">
|
|
18857
|
+
<span></span><span></span><span></span>
|
|
18858
|
+
</div>
|
|
18859
|
+
<span class="loading-text">Generating AI insights...</span>
|
|
18860
|
+
</div>
|
|
18861
|
+
} @else if (error()) {
|
|
18862
|
+
<div class="error-state">{{ error() }}</div>
|
|
18863
|
+
} @else if (insights(); as items) {
|
|
18864
|
+
<div class="insights-list">
|
|
18865
|
+
@for (insight of items; track insight.title) {
|
|
18866
|
+
<div class="insight-card" [class]="'severity-' + insight.severity">
|
|
18867
|
+
<div class="insight-icon">
|
|
18868
|
+
<kendo-svg-icon [icon]="getIcon(insight.severity)" size="medium"></kendo-svg-icon>
|
|
18869
|
+
</div>
|
|
18870
|
+
<div class="insight-content">
|
|
18871
|
+
<div class="insight-title">{{ insight.title }}</div>
|
|
18872
|
+
<div class="insight-description">{{ insight.description }}</div>
|
|
18873
|
+
</div>
|
|
18874
|
+
</div>
|
|
18875
|
+
}
|
|
18876
|
+
</div>
|
|
18877
|
+
@if (isLoading()) {
|
|
18878
|
+
<div class="refresh-indicator">Aktualisierung...</div>
|
|
18879
|
+
}
|
|
18880
|
+
}
|
|
18881
|
+
</div>
|
|
18882
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100%}.ai-insights-widget{height:100%;overflow-y:auto;padding:8px 12px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;opacity:.6}.loading-dots{display:flex;gap:6px}.loading-dots span{width:8px;height:8px;border-radius:50%;background:var(--kendo-color-primary, #06b6d4);animation:pulse-dot 1.4s ease-in-out infinite}.loading-dots span:nth-child(2){animation-delay:.2s}.loading-dots span:nth-child(3){animation-delay:.4s}@keyframes pulse-dot{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1.2)}}.loading-text{font-size:.8rem}.insights-list{display:flex;flex-direction:column;gap:8px}.insight-card{display:flex;gap:10px;padding:10px 12px;border-radius:6px;border-left:3px solid var(--mm-ai-border-color, #6b7280);background:var(--mm-ai-card-bg, rgba(255, 255, 255, .03))}.insight-icon{flex-shrink:0;padding-top:2px;color:var(--mm-ai-border-color, #6b7280)}.insight-content{flex:1;min-width:0}.insight-title{font-size:.85rem;font-weight:600;margin-bottom:4px;color:var(--kendo-color-on-app-surface, inherit)}.insight-description{font-size:.8rem;line-height:1.4;opacity:.8}.severity-info{--mm-ai-border-color: var(--mm-ai-info, #3b82f6)}.severity-warning{--mm-ai-border-color: var(--mm-ai-warning, #f59e0b)}.severity-success{--mm-ai-border-color: var(--mm-ai-success, #10b981)}.severity-critical{--mm-ai-border-color: var(--mm-ai-critical, #ef4444)}.refresh-indicator{text-align:center;padding:8px;font-size:.7rem;opacity:.5}.error-state{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }] });
|
|
18883
|
+
}
|
|
18884
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsWidgetComponent, decorators: [{
|
|
18885
|
+
type: Component,
|
|
18886
|
+
args: [{ selector: 'mm-ai-insights-widget', standalone: true, imports: [CommonModule, SVGIconModule, WidgetNotConfiguredComponent], template: `
|
|
18887
|
+
<div class="ai-insights-widget">
|
|
18888
|
+
@if (isLoading() && !insights()) {
|
|
18889
|
+
<div class="loading-state">
|
|
18890
|
+
<div class="loading-dots">
|
|
18891
|
+
<span></span><span></span><span></span>
|
|
18892
|
+
</div>
|
|
18893
|
+
<span class="loading-text">Generating AI insights...</span>
|
|
18894
|
+
</div>
|
|
18895
|
+
} @else if (error()) {
|
|
18896
|
+
<div class="error-state">{{ error() }}</div>
|
|
18897
|
+
} @else if (insights(); as items) {
|
|
18898
|
+
<div class="insights-list">
|
|
18899
|
+
@for (insight of items; track insight.title) {
|
|
18900
|
+
<div class="insight-card" [class]="'severity-' + insight.severity">
|
|
18901
|
+
<div class="insight-icon">
|
|
18902
|
+
<kendo-svg-icon [icon]="getIcon(insight.severity)" size="medium"></kendo-svg-icon>
|
|
18903
|
+
</div>
|
|
18904
|
+
<div class="insight-content">
|
|
18905
|
+
<div class="insight-title">{{ insight.title }}</div>
|
|
18906
|
+
<div class="insight-description">{{ insight.description }}</div>
|
|
18907
|
+
</div>
|
|
18908
|
+
</div>
|
|
18909
|
+
}
|
|
18910
|
+
</div>
|
|
18911
|
+
@if (isLoading()) {
|
|
18912
|
+
<div class="refresh-indicator">Aktualisierung...</div>
|
|
18913
|
+
}
|
|
18914
|
+
}
|
|
18915
|
+
</div>
|
|
18916
|
+
`, styles: [":host{display:block;width:100%;height:100%}.ai-insights-widget{height:100%;overflow-y:auto;padding:8px 12px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;opacity:.6}.loading-dots{display:flex;gap:6px}.loading-dots span{width:8px;height:8px;border-radius:50%;background:var(--kendo-color-primary, #06b6d4);animation:pulse-dot 1.4s ease-in-out infinite}.loading-dots span:nth-child(2){animation-delay:.2s}.loading-dots span:nth-child(3){animation-delay:.4s}@keyframes pulse-dot{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1.2)}}.loading-text{font-size:.8rem}.insights-list{display:flex;flex-direction:column;gap:8px}.insight-card{display:flex;gap:10px;padding:10px 12px;border-radius:6px;border-left:3px solid var(--mm-ai-border-color, #6b7280);background:var(--mm-ai-card-bg, rgba(255, 255, 255, .03))}.insight-icon{flex-shrink:0;padding-top:2px;color:var(--mm-ai-border-color, #6b7280)}.insight-content{flex:1;min-width:0}.insight-title{font-size:.85rem;font-weight:600;margin-bottom:4px;color:var(--kendo-color-on-app-surface, inherit)}.insight-description{font-size:.8rem;line-height:1.4;opacity:.8}.severity-info{--mm-ai-border-color: var(--mm-ai-info, #3b82f6)}.severity-warning{--mm-ai-border-color: var(--mm-ai-warning, #f59e0b)}.severity-success{--mm-ai-border-color: var(--mm-ai-success, #10b981)}.severity-critical{--mm-ai-border-color: var(--mm-ai-critical, #ef4444)}.refresh-indicator{text-align:center;padding:8px;font-size:.7rem;opacity:.5}.error-state{text-align:center;padding:16px;color:var(--kendo-color-error, #dc3545)}\n"] }]
|
|
18917
|
+
}], propDecorators: { config: [{
|
|
18918
|
+
type: Input
|
|
18919
|
+
}] } });
|
|
18920
|
+
|
|
18921
|
+
class AiInsightsConfigDialogComponent {
|
|
18922
|
+
windowRef = inject(WindowRef);
|
|
18923
|
+
apiKey = '';
|
|
18924
|
+
model = 'claude-sonnet-4-20250514';
|
|
18925
|
+
domainContext = 'energy management';
|
|
18926
|
+
refreshInterval = 0;
|
|
18927
|
+
maxInsights = 4;
|
|
18928
|
+
onSave() {
|
|
18929
|
+
const result = {
|
|
18930
|
+
ckTypeId: '',
|
|
18931
|
+
apiKey: this.apiKey || undefined,
|
|
18932
|
+
model: this.model,
|
|
18933
|
+
domainContext: this.domainContext,
|
|
18934
|
+
refreshInterval: this.refreshInterval,
|
|
18935
|
+
maxInsights: this.maxInsights
|
|
18936
|
+
};
|
|
18937
|
+
this.windowRef.close(result);
|
|
18938
|
+
}
|
|
18939
|
+
onCancel() {
|
|
18940
|
+
this.windowRef.close();
|
|
18941
|
+
}
|
|
18942
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsConfigDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18943
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: AiInsightsConfigDialogComponent, isStandalone: true, selector: "mm-ai-insights-config-dialog", ngImport: i0, template: `
|
|
18944
|
+
<div class="config-form">
|
|
18945
|
+
<div class="form-group">
|
|
18946
|
+
<kendo-label text="Anthropic API Key (optional for demo)">
|
|
18947
|
+
<kendo-textbox [(ngModel)]="apiKey" type="password" placeholder="sk-ant-..."></kendo-textbox>
|
|
18948
|
+
</kendo-label>
|
|
18949
|
+
<span class="hint">Without API key, simulated insights are shown.</span>
|
|
18950
|
+
</div>
|
|
18951
|
+
<div class="form-group">
|
|
18952
|
+
<kendo-label text="Model">
|
|
18953
|
+
<kendo-textbox [(ngModel)]="model"></kendo-textbox>
|
|
18954
|
+
</kendo-label>
|
|
18955
|
+
</div>
|
|
18956
|
+
<div class="form-group">
|
|
18957
|
+
<kendo-label text="Domain Context">
|
|
18958
|
+
<kendo-textbox [(ngModel)]="domainContext" placeholder="e.g. energy management"></kendo-textbox>
|
|
18959
|
+
</kendo-label>
|
|
18960
|
+
</div>
|
|
18961
|
+
<div class="form-row">
|
|
18962
|
+
<div class="form-group">
|
|
18963
|
+
<kendo-label text="Refresh Interval (seconds, 0=off)">
|
|
18964
|
+
<kendo-numerictextbox [(ngModel)]="refreshInterval" [min]="0" [step]="10" [format]="'n0'"></kendo-numerictextbox>
|
|
18965
|
+
</kendo-label>
|
|
18966
|
+
</div>
|
|
18967
|
+
<div class="form-group">
|
|
18968
|
+
<kendo-label text="Max Insights">
|
|
18969
|
+
<kendo-numerictextbox [(ngModel)]="maxInsights" [min]="1" [max]="8" [format]="'n0'"></kendo-numerictextbox>
|
|
18970
|
+
</kendo-label>
|
|
18971
|
+
</div>
|
|
18972
|
+
</div>
|
|
18973
|
+
<div class="mm-dialog-actions">
|
|
18974
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
18975
|
+
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
18976
|
+
</div>
|
|
18977
|
+
</div>
|
|
18978
|
+
`, isInline: true, styles: [".config-form{display:flex;flex-direction:column;gap:12px;padding:16px}.form-group{display:flex;flex-direction:column;gap:4px}.form-row{display:flex;gap:16px}.form-row .form-group{flex:1}.mm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.hint{font-size:.75rem;opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "ngmodule", type: LabelModule }, { kind: "component", type: i4$1.LabelComponent, selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }] });
|
|
18979
|
+
}
|
|
18980
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AiInsightsConfigDialogComponent, decorators: [{
|
|
18981
|
+
type: Component,
|
|
18982
|
+
args: [{ selector: 'mm-ai-insights-config-dialog', standalone: true, imports: [CommonModule, FormsModule, ButtonsModule, InputsModule, LabelModule], template: `
|
|
18983
|
+
<div class="config-form">
|
|
18984
|
+
<div class="form-group">
|
|
18985
|
+
<kendo-label text="Anthropic API Key (optional for demo)">
|
|
18986
|
+
<kendo-textbox [(ngModel)]="apiKey" type="password" placeholder="sk-ant-..."></kendo-textbox>
|
|
18987
|
+
</kendo-label>
|
|
18988
|
+
<span class="hint">Without API key, simulated insights are shown.</span>
|
|
18989
|
+
</div>
|
|
18990
|
+
<div class="form-group">
|
|
18991
|
+
<kendo-label text="Model">
|
|
18992
|
+
<kendo-textbox [(ngModel)]="model"></kendo-textbox>
|
|
18993
|
+
</kendo-label>
|
|
18994
|
+
</div>
|
|
18995
|
+
<div class="form-group">
|
|
18996
|
+
<kendo-label text="Domain Context">
|
|
18997
|
+
<kendo-textbox [(ngModel)]="domainContext" placeholder="e.g. energy management"></kendo-textbox>
|
|
18998
|
+
</kendo-label>
|
|
18999
|
+
</div>
|
|
19000
|
+
<div class="form-row">
|
|
19001
|
+
<div class="form-group">
|
|
19002
|
+
<kendo-label text="Refresh Interval (seconds, 0=off)">
|
|
19003
|
+
<kendo-numerictextbox [(ngModel)]="refreshInterval" [min]="0" [step]="10" [format]="'n0'"></kendo-numerictextbox>
|
|
19004
|
+
</kendo-label>
|
|
19005
|
+
</div>
|
|
19006
|
+
<div class="form-group">
|
|
19007
|
+
<kendo-label text="Max Insights">
|
|
19008
|
+
<kendo-numerictextbox [(ngModel)]="maxInsights" [min]="1" [max]="8" [format]="'n0'"></kendo-numerictextbox>
|
|
19009
|
+
</kendo-label>
|
|
19010
|
+
</div>
|
|
19011
|
+
</div>
|
|
19012
|
+
<div class="mm-dialog-actions">
|
|
19013
|
+
<button kendoButton fillMode="flat" (click)="onCancel()">Cancel</button>
|
|
19014
|
+
<button kendoButton themeColor="primary" (click)="onSave()">Save</button>
|
|
19015
|
+
</div>
|
|
19016
|
+
</div>
|
|
19017
|
+
`, styles: [".config-form{display:flex;flex-direction:column;gap:12px;padding:16px}.form-group{display:flex;flex-direction:column;gap:4px}.form-row{display:flex;gap:16px}.form-row .form-group{flex:1}.mm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.hint{font-size:.75rem;opacity:.6}\n"] }]
|
|
19018
|
+
}] });
|
|
19019
|
+
|
|
19020
|
+
class ProcessDataService {
|
|
19021
|
+
dataService = inject(MeshBoardDataService);
|
|
19022
|
+
variableService = inject(MeshBoardVariableService);
|
|
19023
|
+
stateService = inject(MeshBoardStateService);
|
|
19024
|
+
getProcessDiagramGQL = inject(GetProcessDiagramDtoGQL);
|
|
19025
|
+
getProcessDiagramsGQL = inject(GetProcessDiagramsDtoGQL);
|
|
19026
|
+
createProcessDiagramGQL = inject(CreateProcessDiagramDtoGQL);
|
|
19027
|
+
updateProcessDiagramGQL = inject(UpdateProcessDiagramDtoGQL);
|
|
19028
|
+
executeRuntimeQueryGQL = inject(ExecuteRuntimeQueryDtoGQL);
|
|
19029
|
+
/**
|
|
19030
|
+
* Loads a list of available process diagrams from the backend
|
|
19031
|
+
*
|
|
19032
|
+
* @param searchText - Optional search text to filter diagrams
|
|
19033
|
+
* @returns List of process diagram summaries
|
|
19034
|
+
*/
|
|
19035
|
+
async loadDiagramList(searchText) {
|
|
19036
|
+
try {
|
|
19037
|
+
const result = await firstValueFrom(this.getProcessDiagramsGQL.fetch({
|
|
19038
|
+
first: 100,
|
|
19039
|
+
searchFilter: searchText ? { searchTerm: searchText, language: 'de' } : undefined
|
|
19040
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Apollo fetch requires flexible variable typing
|
|
19041
|
+
}));
|
|
19042
|
+
const items = result.data?.runtime?.systemUIProcessDiagram?.items || [];
|
|
19043
|
+
return items
|
|
19044
|
+
.filter((item) => item !== null)
|
|
19045
|
+
.map(item => ({
|
|
19046
|
+
rtId: item.rtId,
|
|
19047
|
+
name: item.name,
|
|
19048
|
+
description: item.description,
|
|
19049
|
+
version: item.version,
|
|
19050
|
+
canvasWidth: item.canvasWidth,
|
|
19051
|
+
canvasHeight: item.canvasHeight
|
|
19052
|
+
}));
|
|
19053
|
+
}
|
|
19054
|
+
catch (error) {
|
|
19055
|
+
console.error('Error loading process diagrams:', error);
|
|
19056
|
+
return [];
|
|
19057
|
+
}
|
|
19058
|
+
}
|
|
19059
|
+
/**
|
|
19060
|
+
* Loads a process diagram configuration from the backend
|
|
19061
|
+
*
|
|
19062
|
+
* @param rtId - The runtime ID of the process diagram
|
|
19063
|
+
* @returns The process diagram configuration
|
|
19064
|
+
*/
|
|
19065
|
+
async loadDiagram(rtId) {
|
|
19066
|
+
const result = await firstValueFrom(this.getProcessDiagramGQL.fetch({ variables: { rtId } }));
|
|
19067
|
+
const item = result.data?.runtime?.systemUIProcessDiagram?.items?.[0];
|
|
19068
|
+
if (!item) {
|
|
19069
|
+
throw new Error(`Process diagram not found: ${rtId}`);
|
|
19070
|
+
}
|
|
19071
|
+
// Parse JSON fields
|
|
19072
|
+
const elements = this.parseJsonField(item.elements, []);
|
|
19073
|
+
const itemWithExtensions = item;
|
|
19074
|
+
const primitives = itemWithExtensions.primitives
|
|
19075
|
+
? this.parseJsonField(itemWithExtensions.primitives, [])
|
|
19076
|
+
: undefined;
|
|
19077
|
+
const symbolInstances = itemWithExtensions.symbolInstances
|
|
19078
|
+
? this.parseJsonField(itemWithExtensions.symbolInstances, [])
|
|
19079
|
+
: undefined;
|
|
19080
|
+
const connections = this.parseJsonField(item.connections, []);
|
|
19081
|
+
const variables = item.variables ? this.parseJsonField(item.variables, []) : undefined;
|
|
19082
|
+
// Parse diagram-level property fields
|
|
19083
|
+
const transformProperties = itemWithExtensions.transformProperties
|
|
19084
|
+
? this.parseJsonField(itemWithExtensions.transformProperties, [])
|
|
19085
|
+
: undefined;
|
|
19086
|
+
const propertyBindings = itemWithExtensions.propertyBindings
|
|
19087
|
+
? this.parseJsonField(itemWithExtensions.propertyBindings, [])
|
|
19088
|
+
: undefined;
|
|
19089
|
+
const animations = itemWithExtensions.animations
|
|
19090
|
+
? this.parseJsonField(itemWithExtensions.animations, [])
|
|
19091
|
+
: undefined;
|
|
19092
|
+
return {
|
|
19093
|
+
id: item.rtId,
|
|
19094
|
+
name: item.name,
|
|
19095
|
+
description: item.description ?? undefined,
|
|
19096
|
+
version: item.version,
|
|
19097
|
+
canvas: {
|
|
19098
|
+
width: item.canvasWidth,
|
|
19099
|
+
height: item.canvasHeight,
|
|
19100
|
+
backgroundColor: item.canvasBackgroundColor ?? undefined
|
|
19101
|
+
},
|
|
19102
|
+
elements,
|
|
19103
|
+
primitives,
|
|
19104
|
+
symbolInstances,
|
|
19105
|
+
connections,
|
|
19106
|
+
variables,
|
|
19107
|
+
transformProperties,
|
|
19108
|
+
propertyBindings,
|
|
19109
|
+
animations,
|
|
19110
|
+
refreshInterval: item.refreshInterval ?? undefined
|
|
19111
|
+
};
|
|
19112
|
+
}
|
|
19113
|
+
/**
|
|
19114
|
+
* Creates a new process diagram in the backend
|
|
19115
|
+
*
|
|
19116
|
+
* @param diagram - The process diagram configuration to create
|
|
19117
|
+
* @returns The created diagram with its new rtId
|
|
19118
|
+
*/
|
|
19119
|
+
async createDiagram(diagram) {
|
|
19120
|
+
const input = this.toInputDto(diagram);
|
|
19121
|
+
const result = await firstValueFrom(this.createProcessDiagramGQL.mutate({
|
|
19122
|
+
variables: { entities: [input] }
|
|
19123
|
+
}));
|
|
19124
|
+
const created = result.data?.runtime?.systemUIProcessDiagrams?.create?.[0];
|
|
19125
|
+
if (!created) {
|
|
19126
|
+
throw new Error('Failed to create process diagram');
|
|
19127
|
+
}
|
|
19128
|
+
return {
|
|
19129
|
+
...diagram,
|
|
19130
|
+
id: created.rtId
|
|
19131
|
+
};
|
|
19132
|
+
}
|
|
19133
|
+
/**
|
|
19134
|
+
* Updates an existing process diagram in the backend
|
|
19135
|
+
*
|
|
19136
|
+
* @param diagram - The process diagram configuration to update
|
|
19137
|
+
* @returns The updated diagram
|
|
19138
|
+
*/
|
|
19139
|
+
async updateDiagram(diagram) {
|
|
19140
|
+
if (!diagram.id) {
|
|
19141
|
+
throw new Error('Cannot update diagram without rtId');
|
|
19142
|
+
}
|
|
19143
|
+
const input = {
|
|
19144
|
+
rtId: diagram.id,
|
|
19145
|
+
item: this.toInputDto(diagram)
|
|
19146
|
+
};
|
|
19147
|
+
const result = await firstValueFrom(this.updateProcessDiagramGQL.mutate({
|
|
19148
|
+
variables: { entities: [input] }
|
|
19149
|
+
}));
|
|
19150
|
+
const updated = result.data?.runtime?.systemUIProcessDiagrams?.update?.[0];
|
|
19151
|
+
if (!updated) {
|
|
19152
|
+
throw new Error('Failed to update process diagram');
|
|
19153
|
+
}
|
|
19154
|
+
return diagram;
|
|
19155
|
+
}
|
|
19156
|
+
/**
|
|
19157
|
+
* Saves a process diagram (creates new or updates existing)
|
|
19158
|
+
*
|
|
19159
|
+
* @param diagram - The process diagram configuration to save
|
|
19160
|
+
* @param isNew - Whether this is a new diagram (default: false)
|
|
19161
|
+
* @returns The saved diagram
|
|
19162
|
+
*/
|
|
19163
|
+
async saveDiagram(diagram, isNew = false) {
|
|
17426
19164
|
if (isNew || !diagram.id) {
|
|
17427
19165
|
return this.createDiagram(diagram);
|
|
17428
19166
|
}
|
|
@@ -23011,6 +24749,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23011
24749
|
initialPrefix: kpiWidget.prefix,
|
|
23012
24750
|
initialSuffix: kpiWidget.suffix,
|
|
23013
24751
|
initialTrend: kpiWidget.trend,
|
|
24752
|
+
initialComparisonText: kpiWidget.comparisonText,
|
|
23014
24753
|
// Filters
|
|
23015
24754
|
initialFilters: kpiWidget.filters
|
|
23016
24755
|
};
|
|
@@ -23135,7 +24874,8 @@ function registerDefaultWidgets(registry) {
|
|
|
23135
24874
|
prefix: config['prefix'],
|
|
23136
24875
|
suffix: config['suffix'],
|
|
23137
24876
|
icon: config['icon'],
|
|
23138
|
-
trend: config['trend']
|
|
24877
|
+
trend: config['trend'],
|
|
24878
|
+
comparisonText: config['comparisonText']
|
|
23139
24879
|
};
|
|
23140
24880
|
}
|
|
23141
24881
|
if (dataSource.type === 'persistentQuery') {
|
|
@@ -23153,6 +24893,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23153
24893
|
suffix: config['suffix'],
|
|
23154
24894
|
icon: config['icon'],
|
|
23155
24895
|
trend: config['trend'],
|
|
24896
|
+
comparisonText: config['comparisonText'],
|
|
23156
24897
|
filters: config['filters']
|
|
23157
24898
|
};
|
|
23158
24899
|
}
|
|
@@ -23167,6 +24908,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23167
24908
|
suffix: config['suffix'],
|
|
23168
24909
|
icon: config['icon'],
|
|
23169
24910
|
trend: config['trend'],
|
|
24911
|
+
comparisonText: config['comparisonText'],
|
|
23170
24912
|
filters: config['filters']
|
|
23171
24913
|
};
|
|
23172
24914
|
}
|
|
@@ -23741,6 +25483,8 @@ function registerDefaultWidgets(registry) {
|
|
|
23741
25483
|
initialShowLegend: barWidget.showLegend,
|
|
23742
25484
|
initialLegendPosition: barWidget.legendPosition,
|
|
23743
25485
|
initialShowDataLabels: barWidget.showDataLabels,
|
|
25486
|
+
initialColorThresholds: barWidget.colorThresholds,
|
|
25487
|
+
initialDefaultBarColor: barWidget.defaultBarColor,
|
|
23744
25488
|
initialFilters: barWidget.filters
|
|
23745
25489
|
};
|
|
23746
25490
|
},
|
|
@@ -23767,6 +25511,8 @@ function registerDefaultWidgets(registry) {
|
|
|
23767
25511
|
showLegend: result.showLegend,
|
|
23768
25512
|
legendPosition: result.legendPosition,
|
|
23769
25513
|
showDataLabels: result.showDataLabels,
|
|
25514
|
+
colorThresholds: result.colorThresholds,
|
|
25515
|
+
defaultBarColor: result.defaultBarColor,
|
|
23770
25516
|
filters
|
|
23771
25517
|
};
|
|
23772
25518
|
},
|
|
@@ -23797,6 +25543,9 @@ function registerDefaultWidgets(registry) {
|
|
|
23797
25543
|
showLegend: widget.showLegend,
|
|
23798
25544
|
legendPosition: widget.legendPosition,
|
|
23799
25545
|
showDataLabels: widget.showDataLabels,
|
|
25546
|
+
dataLabelSuffix: widget.dataLabelSuffix,
|
|
25547
|
+
colorThresholds: widget.colorThresholds,
|
|
25548
|
+
defaultBarColor: widget.defaultBarColor,
|
|
23800
25549
|
queryName: widget.dataSource.queryName,
|
|
23801
25550
|
queryRtId: widget.dataSource.queryRtId,
|
|
23802
25551
|
filters: widget.filters
|
|
@@ -23819,6 +25568,9 @@ function registerDefaultWidgets(registry) {
|
|
|
23819
25568
|
showLegend: config['showLegend'] ?? true,
|
|
23820
25569
|
legendPosition: config['legendPosition'] ?? 'right',
|
|
23821
25570
|
showDataLabels: config['showDataLabels'] ?? false,
|
|
25571
|
+
dataLabelSuffix: config['dataLabelSuffix'],
|
|
25572
|
+
colorThresholds: config['colorThresholds'],
|
|
25573
|
+
defaultBarColor: config['defaultBarColor'],
|
|
23822
25574
|
filters: config['filters']
|
|
23823
25575
|
};
|
|
23824
25576
|
}
|
|
@@ -23848,6 +25600,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23848
25600
|
initialShowLegend: lineWidget.showLegend,
|
|
23849
25601
|
initialLegendPosition: lineWidget.legendPosition,
|
|
23850
25602
|
initialShowMarkers: lineWidget.showMarkers,
|
|
25603
|
+
initialReferenceLines: lineWidget.referenceLines,
|
|
23851
25604
|
initialFilters: lineWidget.filters
|
|
23852
25605
|
};
|
|
23853
25606
|
},
|
|
@@ -23873,6 +25626,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23873
25626
|
showLegend: result.showLegend,
|
|
23874
25627
|
legendPosition: result.legendPosition,
|
|
23875
25628
|
showMarkers: result.showMarkers,
|
|
25629
|
+
referenceLines: result.referenceLines,
|
|
23876
25630
|
filters
|
|
23877
25631
|
};
|
|
23878
25632
|
},
|
|
@@ -23902,6 +25656,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23902
25656
|
showLegend: widget.showLegend,
|
|
23903
25657
|
legendPosition: widget.legendPosition,
|
|
23904
25658
|
showMarkers: widget.showMarkers,
|
|
25659
|
+
referenceLines: widget.referenceLines,
|
|
23905
25660
|
queryName: widget.dataSource.queryName,
|
|
23906
25661
|
queryRtId: widget.dataSource.queryRtId,
|
|
23907
25662
|
filters: widget.filters
|
|
@@ -23923,6 +25678,7 @@ function registerDefaultWidgets(registry) {
|
|
|
23923
25678
|
showLegend: config['showLegend'] ?? true,
|
|
23924
25679
|
legendPosition: config['legendPosition'] ?? 'right',
|
|
23925
25680
|
showMarkers: config['showMarkers'] ?? false,
|
|
25681
|
+
referenceLines: config['referenceLines'],
|
|
23926
25682
|
filters: config['filters']
|
|
23927
25683
|
};
|
|
23928
25684
|
}
|
|
@@ -24464,6 +26220,300 @@ function registerDefaultWidgets(registry) {
|
|
|
24464
26220
|
};
|
|
24465
26221
|
}
|
|
24466
26222
|
});
|
|
26223
|
+
// Status List Widget
|
|
26224
|
+
registry.registerWidget({
|
|
26225
|
+
type: 'statusList',
|
|
26226
|
+
label: 'Status List',
|
|
26227
|
+
component: StatusListWidgetComponent,
|
|
26228
|
+
configDialogComponent: StatusListConfigDialogComponent,
|
|
26229
|
+
configDialogSize: { width: 650, height: 550, minWidth: 500, minHeight: 400 },
|
|
26230
|
+
configDialogTitle: 'Status List Configuration',
|
|
26231
|
+
defaultSize: { colSpan: 2, rowSpan: 2 },
|
|
26232
|
+
supportedDataSources: ['runtimeEntity'],
|
|
26233
|
+
getInitialConfig: (widget) => {
|
|
26234
|
+
const slWidget = widget;
|
|
26235
|
+
return {
|
|
26236
|
+
initialCkTypeId: slWidget.ckTypeId,
|
|
26237
|
+
initialLabelField: slWidget.labelField,
|
|
26238
|
+
initialStatusField: slWidget.statusField,
|
|
26239
|
+
initialStatusColors: slWidget.statusColors
|
|
26240
|
+
};
|
|
26241
|
+
},
|
|
26242
|
+
applyConfigResult: (widget, result) => ({
|
|
26243
|
+
...widget,
|
|
26244
|
+
ckTypeId: result.ckTypeId,
|
|
26245
|
+
labelField: result.labelField,
|
|
26246
|
+
statusField: result.statusField,
|
|
26247
|
+
statusColors: result.statusColors,
|
|
26248
|
+
dataSource: { type: 'runtimeEntity', ckTypeId: result.ckTypeId }
|
|
26249
|
+
}),
|
|
26250
|
+
createDefaultConfig: (base) => ({
|
|
26251
|
+
...base,
|
|
26252
|
+
type: 'statusList',
|
|
26253
|
+
colSpan: 3,
|
|
26254
|
+
rowSpan: 1,
|
|
26255
|
+
dataSource: { type: 'runtimeEntity' },
|
|
26256
|
+
ckTypeId: '',
|
|
26257
|
+
labelField: 'name',
|
|
26258
|
+
statusField: ''
|
|
26259
|
+
}),
|
|
26260
|
+
toPersistedConfig: (widget) => ({
|
|
26261
|
+
dataSourceType: 'runtimeEntity',
|
|
26262
|
+
dataSourceCkTypeId: widget.ckTypeId,
|
|
26263
|
+
config: {
|
|
26264
|
+
ckTypeId: widget.ckTypeId,
|
|
26265
|
+
labelField: widget.labelField,
|
|
26266
|
+
statusField: widget.statusField,
|
|
26267
|
+
statusColors: widget.statusColors
|
|
26268
|
+
}
|
|
26269
|
+
}),
|
|
26270
|
+
fromPersistedConfig: (data, base) => {
|
|
26271
|
+
const config = parseConfig(data);
|
|
26272
|
+
return {
|
|
26273
|
+
...base,
|
|
26274
|
+
rtId: data.rtId,
|
|
26275
|
+
type: 'statusList',
|
|
26276
|
+
dataSource: { type: 'runtimeEntity', ckTypeId: data.ckTypeId ?? config['ckTypeId'] },
|
|
26277
|
+
ckTypeId: config['ckTypeId'] ?? data.ckTypeId ?? '',
|
|
26278
|
+
labelField: config['labelField'] ?? 'name',
|
|
26279
|
+
statusField: config['statusField'] ?? '',
|
|
26280
|
+
statusColors: config['statusColors']
|
|
26281
|
+
};
|
|
26282
|
+
}
|
|
26283
|
+
});
|
|
26284
|
+
// Summary Card Widget
|
|
26285
|
+
registry.registerWidget({
|
|
26286
|
+
type: 'summaryCard',
|
|
26287
|
+
label: 'Summary Card',
|
|
26288
|
+
component: SummaryCardWidgetComponent,
|
|
26289
|
+
configDialogComponent: SummaryCardConfigDialogComponent,
|
|
26290
|
+
configDialogSize: { width: 750, height: 650, minWidth: 600, minHeight: 500 },
|
|
26291
|
+
configDialogTitle: 'Summary Card Configuration',
|
|
26292
|
+
defaultSize: { colSpan: 2, rowSpan: 2 },
|
|
26293
|
+
supportedDataSources: ['runtimeEntity'],
|
|
26294
|
+
getInitialConfig: (widget) => {
|
|
26295
|
+
const scWidget = widget;
|
|
26296
|
+
return {
|
|
26297
|
+
initialColumns: scWidget.columns,
|
|
26298
|
+
initialTiles: scWidget.tiles
|
|
26299
|
+
};
|
|
26300
|
+
},
|
|
26301
|
+
applyConfigResult: (widget, result) => ({
|
|
26302
|
+
...widget,
|
|
26303
|
+
columns: result.columns,
|
|
26304
|
+
tiles: result.tiles,
|
|
26305
|
+
dataSource: { type: 'runtimeEntity' }
|
|
26306
|
+
}),
|
|
26307
|
+
createDefaultConfig: (base) => ({
|
|
26308
|
+
...base,
|
|
26309
|
+
type: 'summaryCard',
|
|
26310
|
+
colSpan: 2,
|
|
26311
|
+
rowSpan: 2,
|
|
26312
|
+
dataSource: { type: 'runtimeEntity' },
|
|
26313
|
+
columns: 2,
|
|
26314
|
+
tiles: []
|
|
26315
|
+
}),
|
|
26316
|
+
toPersistedConfig: (widget) => ({
|
|
26317
|
+
dataSourceType: 'runtimeEntity',
|
|
26318
|
+
config: {
|
|
26319
|
+
columns: widget.columns,
|
|
26320
|
+
tiles: widget.tiles
|
|
26321
|
+
}
|
|
26322
|
+
}),
|
|
26323
|
+
fromPersistedConfig: (data, base) => {
|
|
26324
|
+
const config = parseConfig(data);
|
|
26325
|
+
return {
|
|
26326
|
+
...base,
|
|
26327
|
+
rtId: data.rtId,
|
|
26328
|
+
type: 'summaryCard',
|
|
26329
|
+
dataSource: { type: 'runtimeEntity', ckTypeId: data.ckTypeId ?? 'configured' },
|
|
26330
|
+
columns: config['columns'] ?? 2,
|
|
26331
|
+
tiles: config['tiles'] ?? []
|
|
26332
|
+
};
|
|
26333
|
+
}
|
|
26334
|
+
});
|
|
26335
|
+
// Alert Banner Widget
|
|
26336
|
+
registry.registerWidget({
|
|
26337
|
+
type: 'alertBanner',
|
|
26338
|
+
label: 'Alert Banner',
|
|
26339
|
+
component: AlertBannerWidgetComponent,
|
|
26340
|
+
configDialogComponent: AlertBannerConfigDialogComponent,
|
|
26341
|
+
configDialogSize: { width: 500, height: 400, minWidth: 400, minHeight: 300 },
|
|
26342
|
+
configDialogTitle: 'Alert Banner Configuration',
|
|
26343
|
+
defaultSize: { colSpan: 4, rowSpan: 1 },
|
|
26344
|
+
supportedDataSources: ['runtimeEntity'],
|
|
26345
|
+
getInitialConfig: (widget) => {
|
|
26346
|
+
const abWidget = widget;
|
|
26347
|
+
return {
|
|
26348
|
+
ckTypeId: abWidget.ckTypeId ?? 'System.Notification/StatefulEvent',
|
|
26349
|
+
rotationInterval: abWidget.rotationInterval ?? 5000,
|
|
26350
|
+
showIcon: abWidget.showIcon ?? true,
|
|
26351
|
+
maxAlerts: abWidget.maxAlerts ?? 20
|
|
26352
|
+
};
|
|
26353
|
+
},
|
|
26354
|
+
applyConfigResult: (widget, result) => ({
|
|
26355
|
+
...widget,
|
|
26356
|
+
ckTypeId: result.ckTypeId,
|
|
26357
|
+
rotationInterval: result.rotationInterval,
|
|
26358
|
+
showIcon: result.showIcon,
|
|
26359
|
+
maxAlerts: result.maxAlerts
|
|
26360
|
+
}),
|
|
26361
|
+
createDefaultConfig: (base) => ({
|
|
26362
|
+
...base,
|
|
26363
|
+
type: 'alertBanner',
|
|
26364
|
+
colSpan: 4,
|
|
26365
|
+
rowSpan: 1,
|
|
26366
|
+
dataSource: { type: 'runtimeEntity' },
|
|
26367
|
+
ckTypeId: 'System.Notification/StatefulEvent'
|
|
26368
|
+
}),
|
|
26369
|
+
toPersistedConfig: (widget) => ({
|
|
26370
|
+
dataSourceType: 'runtimeEntity',
|
|
26371
|
+
dataSourceCkTypeId: widget.ckTypeId ?? 'System.Notification/StatefulEvent',
|
|
26372
|
+
config: {
|
|
26373
|
+
ckTypeId: widget.ckTypeId,
|
|
26374
|
+
rotationInterval: widget.rotationInterval,
|
|
26375
|
+
showIcon: widget.showIcon,
|
|
26376
|
+
maxAlerts: widget.maxAlerts
|
|
26377
|
+
}
|
|
26378
|
+
}),
|
|
26379
|
+
fromPersistedConfig: (data, base) => {
|
|
26380
|
+
const config = parseConfig(data);
|
|
26381
|
+
return {
|
|
26382
|
+
...base,
|
|
26383
|
+
rtId: data.rtId,
|
|
26384
|
+
type: 'alertBanner',
|
|
26385
|
+
dataSource: { type: 'runtimeEntity', ckTypeId: data.ckTypeId ?? 'System.Notification/StatefulEvent' },
|
|
26386
|
+
ckTypeId: config['ckTypeId'] ?? data.ckTypeId ?? 'System.Notification/StatefulEvent',
|
|
26387
|
+
rotationInterval: config['rotationInterval'],
|
|
26388
|
+
showIcon: config['showIcon'],
|
|
26389
|
+
maxAlerts: config['maxAlerts']
|
|
26390
|
+
};
|
|
26391
|
+
}
|
|
26392
|
+
});
|
|
26393
|
+
// Alert List Widget
|
|
26394
|
+
registry.registerWidget({
|
|
26395
|
+
type: 'alertList',
|
|
26396
|
+
label: 'Alert List',
|
|
26397
|
+
component: AlertListWidgetComponent,
|
|
26398
|
+
configDialogComponent: AlertListConfigDialogComponent,
|
|
26399
|
+
configDialogSize: { width: 500, height: 400, minWidth: 400, minHeight: 300 },
|
|
26400
|
+
configDialogTitle: 'Alert List Configuration',
|
|
26401
|
+
defaultSize: { colSpan: 3, rowSpan: 3 },
|
|
26402
|
+
supportedDataSources: ['runtimeEntity'],
|
|
26403
|
+
getInitialConfig: (widget) => {
|
|
26404
|
+
const alWidget = widget;
|
|
26405
|
+
return {
|
|
26406
|
+
ckTypeId: alWidget.ckTypeId ?? 'System.Notification/StatefulEvent',
|
|
26407
|
+
showTimestamp: alWidget.showTimestamp ?? true,
|
|
26408
|
+
sortBySeverity: alWidget.sortBySeverity ?? true,
|
|
26409
|
+
maxAlerts: alWidget.maxAlerts ?? 50
|
|
26410
|
+
};
|
|
26411
|
+
},
|
|
26412
|
+
applyConfigResult: (widget, result) => ({
|
|
26413
|
+
...widget,
|
|
26414
|
+
ckTypeId: result.ckTypeId,
|
|
26415
|
+
showTimestamp: result.showTimestamp,
|
|
26416
|
+
sortBySeverity: result.sortBySeverity,
|
|
26417
|
+
maxAlerts: result.maxAlerts
|
|
26418
|
+
}),
|
|
26419
|
+
createDefaultConfig: (base) => ({
|
|
26420
|
+
...base,
|
|
26421
|
+
type: 'alertList',
|
|
26422
|
+
colSpan: 3,
|
|
26423
|
+
rowSpan: 3,
|
|
26424
|
+
dataSource: { type: 'runtimeEntity' },
|
|
26425
|
+
ckTypeId: 'System.Notification/StatefulEvent'
|
|
26426
|
+
}),
|
|
26427
|
+
toPersistedConfig: (widget) => ({
|
|
26428
|
+
dataSourceType: 'runtimeEntity',
|
|
26429
|
+
dataSourceCkTypeId: widget.ckTypeId ?? 'System.Notification/StatefulEvent',
|
|
26430
|
+
config: {
|
|
26431
|
+
ckTypeId: widget.ckTypeId,
|
|
26432
|
+
showTimestamp: widget.showTimestamp,
|
|
26433
|
+
sortBySeverity: widget.sortBySeverity,
|
|
26434
|
+
maxAlerts: widget.maxAlerts
|
|
26435
|
+
}
|
|
26436
|
+
}),
|
|
26437
|
+
fromPersistedConfig: (data, base) => {
|
|
26438
|
+
const config = parseConfig(data);
|
|
26439
|
+
return {
|
|
26440
|
+
...base,
|
|
26441
|
+
rtId: data.rtId,
|
|
26442
|
+
type: 'alertList',
|
|
26443
|
+
dataSource: { type: 'runtimeEntity', ckTypeId: data.ckTypeId ?? 'System.Notification/StatefulEvent' },
|
|
26444
|
+
ckTypeId: config['ckTypeId'] ?? data.ckTypeId ?? 'System.Notification/StatefulEvent',
|
|
26445
|
+
showTimestamp: config['showTimestamp'],
|
|
26446
|
+
sortBySeverity: config['sortBySeverity'],
|
|
26447
|
+
maxAlerts: config['maxAlerts']
|
|
26448
|
+
};
|
|
26449
|
+
}
|
|
26450
|
+
});
|
|
26451
|
+
// AI Insights Widget
|
|
26452
|
+
registry.registerWidget({
|
|
26453
|
+
type: 'aiInsights',
|
|
26454
|
+
label: 'AI Insights',
|
|
26455
|
+
component: AiInsightsWidgetComponent,
|
|
26456
|
+
configDialogComponent: AiInsightsConfigDialogComponent,
|
|
26457
|
+
configDialogSize: { width: 600, height: 500, minWidth: 450, minHeight: 400 },
|
|
26458
|
+
configDialogTitle: 'AI Insights Configuration',
|
|
26459
|
+
defaultSize: { colSpan: 3, rowSpan: 2 },
|
|
26460
|
+
supportedDataSources: ['static'],
|
|
26461
|
+
getInitialConfig: (widget) => {
|
|
26462
|
+
const aiWidget = widget;
|
|
26463
|
+
return {
|
|
26464
|
+
apiKey: aiWidget.apiKey,
|
|
26465
|
+
model: aiWidget.model ?? 'claude-sonnet-4-20250514',
|
|
26466
|
+
domainContext: aiWidget.domainContext ?? 'energy management',
|
|
26467
|
+
refreshInterval: aiWidget.refreshInterval ?? 0,
|
|
26468
|
+
maxInsights: aiWidget.maxInsights ?? 4
|
|
26469
|
+
};
|
|
26470
|
+
},
|
|
26471
|
+
applyConfigResult: (widget, result) => ({
|
|
26472
|
+
...widget,
|
|
26473
|
+
apiKey: result.apiKey,
|
|
26474
|
+
model: result.model,
|
|
26475
|
+
domainContext: result.domainContext,
|
|
26476
|
+
refreshInterval: result.refreshInterval,
|
|
26477
|
+
maxInsights: result.maxInsights,
|
|
26478
|
+
dataSource: { type: 'static' }
|
|
26479
|
+
}),
|
|
26480
|
+
createDefaultConfig: (base) => ({
|
|
26481
|
+
...base,
|
|
26482
|
+
type: 'aiInsights',
|
|
26483
|
+
colSpan: 3,
|
|
26484
|
+
rowSpan: 2,
|
|
26485
|
+
dataSource: { type: 'static' },
|
|
26486
|
+
refreshInterval: 0,
|
|
26487
|
+
maxInsights: 4,
|
|
26488
|
+
domainContext: 'energy management'
|
|
26489
|
+
}),
|
|
26490
|
+
toPersistedConfig: (widget) => ({
|
|
26491
|
+
dataSourceType: 'static',
|
|
26492
|
+
config: {
|
|
26493
|
+
apiKey: widget.apiKey,
|
|
26494
|
+
model: widget.model,
|
|
26495
|
+
systemPrompt: widget.systemPrompt,
|
|
26496
|
+
refreshInterval: widget.refreshInterval,
|
|
26497
|
+
maxInsights: widget.maxInsights,
|
|
26498
|
+
domainContext: widget.domainContext
|
|
26499
|
+
}
|
|
26500
|
+
}),
|
|
26501
|
+
fromPersistedConfig: (data, base) => {
|
|
26502
|
+
const config = parseConfig(data);
|
|
26503
|
+
return {
|
|
26504
|
+
...base,
|
|
26505
|
+
rtId: data.rtId,
|
|
26506
|
+
type: 'aiInsights',
|
|
26507
|
+
dataSource: { type: 'static' },
|
|
26508
|
+
apiKey: config['apiKey'],
|
|
26509
|
+
model: config['model'],
|
|
26510
|
+
systemPrompt: config['systemPrompt'],
|
|
26511
|
+
refreshInterval: config['refreshInterval'] ?? 0,
|
|
26512
|
+
maxInsights: config['maxInsights'] ?? 4,
|
|
26513
|
+
domainContext: config['domainContext'] ?? 'energy management'
|
|
26514
|
+
};
|
|
26515
|
+
}
|
|
26516
|
+
});
|
|
24467
26517
|
// Note: Process Widget registration moved to process-widget-registration.ts
|
|
24468
26518
|
// Use provideProcessWidget() or registerProcessWidget() to enable it
|
|
24469
26519
|
}
|
|
@@ -25355,7 +27405,7 @@ class AddWidgetDialogComponent {
|
|
|
25355
27405
|
this.dialogRef.close();
|
|
25356
27406
|
}
|
|
25357
27407
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AddWidgetDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
25358
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AddWidgetDialogComponent, isStandalone: true, selector: "mm-add-widget-dialog", ngImport: i0, template: "<div class=\"add-widget-dialog\">\n <div class=\"dialog-content\">\n <p class=\"dialog-description\">\n Select a widget type to add to your MeshBoard:\n </p>\n\n <div class=\"widget-types-list\">\n <div class=\"list-header\">Available Widgets</div>\n\n @for (item of widgetTypes(); track item.type) {\n <div\n class=\"widget-type-item\"\n [class.selected]=\"isSelected(item.type)\"\n (click)=\"selectType(item.type)\">\n <div class=\"widget-icon\">\n <kendo-svg-icon [icon]=\"item.icon\" size=\"large\"></kendo-svg-icon>\n </div>\n <div class=\"widget-info\">\n <h4 class=\"widget-label\">{{ item.label }}</h4>\n <p class=\"widget-description\">{{ item.description }}</p>\n </div>\n @if (isSelected(item.type)) {\n <div class=\"selected-indicator\">\n <kendo-svg-icon [icon]=\"checkCircleIcon\" size=\"medium\"></kendo-svg-icon>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Dialog Actions -->\n <div class=\"dialog-actions mm-dialog-actions\">\n <button kendoButton (click)=\"cancel()\" fillMode=\"flat\">\n Cancel\n </button>\n <button\n kendoButton\n (click)=\"add()\"\n [disabled]=\"!selectedType()\"\n themeColor=\"primary\">\n Add Widget\n </button>\n </div>\n</div>\n", styles: [".add-widget-dialog{display:flex;flex-direction:column;gap:.75rem;padding:.75rem;max-height:60vh;overflow:hidden}.add-widget-dialog .dialog-content{display:flex;flex-direction:column;gap:1rem;flex:1;min-height:0;overflow:hidden}.add-widget-dialog .dialog-content .dialog-description{margin:0;color:var(--kendo-color-subtle, #757575);font-size:.875rem}.add-widget-dialog .dialog-content .widget-types-list{flex:1;overflow-y:auto;border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:4px}.add-widget-dialog .dialog-content .widget-types-list .list-header{font-weight:600;font-size:.75rem;color:var(--kendo-color-on-app-surface, #424242);padding:.5rem .75rem;background-color:var(--kendo-color-surface-alt, #fafafa);border-bottom:1px solid var(--kendo-color-border, #e0e0e0);text-transform:uppercase;letter-spacing:.5px}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item{display:flex;align-items:center;gap:.5rem;padding:.375rem .5rem;cursor:pointer;border-bottom:1px solid var(--kendo-color-border, #e0e0e0);transition:background-color .2s,box-shadow .2s}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item:last-child{border-bottom:none}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item:hover{background-color:var(--kendo-color-base-hover, #f5f5f5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item.selected{background-color:var(--kendo-color-primary-subtle, #e8eaf6);box-shadow:inset 3px 0 0 var(--kendo-color-primary, #3f51b5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:4px;background-color:var(--kendo-color-surface-alt, #f5f5f5);color:var(--kendo-color-primary, #3f51b5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-icon kendo-svg-icon{color:inherit}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-info{flex:1;min-width:0}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-info .widget-label{margin:0 0 .125rem;font-size:.875rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-info .widget-description{margin:0;font-size:.75rem;color:var(--kendo-color-subtle, #757575);line-height:1.3}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .selected-indicator{flex-shrink:0;color:var(--kendo-color-primary, #3f51b5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .selected-indicator kendo-svg-icon{color:inherit}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item.selected .widget-icon{background-color:var(--kendo-color-primary, #3f51b5);color:var(--kendo-color-on-primary, #ffffff)}.add-widget-dialog .dialog-actions{display:flex;justify-content:flex-end;gap:.5rem;padding-top:.5rem;border-top:1px solid var(--kendo-color-border, #e0e0e0);flex-shrink:0}.widget-types-list::-webkit-scrollbar{width:8px}.widget-types-list::-webkit-scrollbar-track{background:var(--kendo-color-surface-alt, #f5f5f5)}.widget-types-list::-webkit-scrollbar-thumb{background:var(--kendo-color-border, #e0e0e0);border-radius:4px}.widget-types-list::-webkit-scrollbar-thumb:hover{background:var(--kendo-color-subtle, #9e9e9e)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type:
|
|
27408
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AddWidgetDialogComponent, isStandalone: true, selector: "mm-add-widget-dialog", ngImport: i0, template: "<div class=\"add-widget-dialog\">\n <div class=\"dialog-content\">\n <p class=\"dialog-description\">\n Select a widget type to add to your MeshBoard:\n </p>\n\n <div class=\"widget-types-list\">\n <div class=\"list-header\">Available Widgets</div>\n\n @for (item of widgetTypes(); track item.type) {\n <div\n class=\"widget-type-item\"\n [class.selected]=\"isSelected(item.type)\"\n (click)=\"selectType(item.type)\">\n <div class=\"widget-icon\">\n <kendo-svg-icon [icon]=\"item.icon\" size=\"large\"></kendo-svg-icon>\n </div>\n <div class=\"widget-info\">\n <h4 class=\"widget-label\">{{ item.label }}</h4>\n <p class=\"widget-description\">{{ item.description }}</p>\n </div>\n @if (isSelected(item.type)) {\n <div class=\"selected-indicator\">\n <kendo-svg-icon [icon]=\"checkCircleIcon\" size=\"medium\"></kendo-svg-icon>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Dialog Actions -->\n <div class=\"dialog-actions mm-dialog-actions\">\n <button kendoButton (click)=\"cancel()\" fillMode=\"flat\">\n Cancel\n </button>\n <button\n kendoButton\n (click)=\"add()\"\n [disabled]=\"!selectedType()\"\n themeColor=\"primary\">\n Add Widget\n </button>\n </div>\n</div>\n", styles: [".add-widget-dialog{display:flex;flex-direction:column;gap:.75rem;padding:.75rem;max-height:60vh;overflow:hidden}.add-widget-dialog .dialog-content{display:flex;flex-direction:column;gap:1rem;flex:1;min-height:0;overflow:hidden}.add-widget-dialog .dialog-content .dialog-description{margin:0;color:var(--kendo-color-subtle, #757575);font-size:.875rem}.add-widget-dialog .dialog-content .widget-types-list{flex:1;overflow-y:auto;border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:4px}.add-widget-dialog .dialog-content .widget-types-list .list-header{font-weight:600;font-size:.75rem;color:var(--kendo-color-on-app-surface, #424242);padding:.5rem .75rem;background-color:var(--kendo-color-surface-alt, #fafafa);border-bottom:1px solid var(--kendo-color-border, #e0e0e0);text-transform:uppercase;letter-spacing:.5px}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item{display:flex;align-items:center;gap:.5rem;padding:.375rem .5rem;cursor:pointer;border-bottom:1px solid var(--kendo-color-border, #e0e0e0);transition:background-color .2s,box-shadow .2s}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item:last-child{border-bottom:none}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item:hover{background-color:var(--kendo-color-base-hover, #f5f5f5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item.selected{background-color:var(--kendo-color-primary-subtle, #e8eaf6);box-shadow:inset 3px 0 0 var(--kendo-color-primary, #3f51b5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:4px;background-color:var(--kendo-color-surface-alt, #f5f5f5);color:var(--kendo-color-primary, #3f51b5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-icon kendo-svg-icon{color:inherit}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-info{flex:1;min-width:0}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-info .widget-label{margin:0 0 .125rem;font-size:.875rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .widget-info .widget-description{margin:0;font-size:.75rem;color:var(--kendo-color-subtle, #757575);line-height:1.3}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .selected-indicator{flex-shrink:0;color:var(--kendo-color-primary, #3f51b5)}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item .selected-indicator kendo-svg-icon{color:inherit}.add-widget-dialog .dialog-content .widget-types-list .widget-type-item.selected .widget-icon{background-color:var(--kendo-color-primary, #3f51b5);color:var(--kendo-color-on-primary, #ffffff)}.add-widget-dialog .dialog-actions{display:flex;justify-content:flex-end;gap:.5rem;padding-top:.5rem;border-top:1px solid var(--kendo-color-border, #e0e0e0);flex-shrink:0}.widget-types-list::-webkit-scrollbar{width:8px}.widget-types-list::-webkit-scrollbar-track{background:var(--kendo-color-surface-alt, #f5f5f5)}.widget-types-list::-webkit-scrollbar-thumb{background:var(--kendo-color-border, #e0e0e0);border-radius:4px}.widget-types-list::-webkit-scrollbar-thumb:hover{background:var(--kendo-color-subtle, #9e9e9e)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }] });
|
|
25359
27409
|
}
|
|
25360
27410
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AddWidgetDialogComponent, decorators: [{
|
|
25361
27411
|
type: Component,
|
|
@@ -25735,7 +27785,7 @@ class MeshBoardManagerDialogComponent {
|
|
|
25735
27785
|
}
|
|
25736
27786
|
}
|
|
25737
27787
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MeshBoardManagerDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
25738
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MeshBoardManagerDialogComponent, isStandalone: true, selector: "mm-meshboard-manager-dialog", ngImport: i0, template: "<div class=\"meshboard-manager-dialog\">\n <!-- Header with Create/Import Buttons -->\n <div class=\"dialog-header\">\n <p class=\"dialog-description\">Manage your MeshBoards</p>\n <div class=\"header-actions\">\n @if (canExport) {\n <button\n kendoButton\n [svgIcon]=\"uploadIcon\"\n (click)=\"triggerImport()\"\n [disabled]=\"isCreating() || isLoading() || isImporting()\"\n fillMode=\"outline\">\n Import\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"startCreate()\"\n [disabled]=\"isCreating() || isLoading()\"\n themeColor=\"primary\">\n New MeshBoard\n </button>\n </div>\n </div>\n\n <!-- Create New MeshBoard Form -->\n @if (isCreating()) {\n <div class=\"create-form\">\n <h4 class=\"form-title\">Create New MeshBoard</h4>\n <div class=\"form-fields\">\n <kendo-textbox\n [(ngModel)]=\"newName\"\n placeholder=\"MeshBoard name\"\n [disabled]=\"isLoading()\">\n </kendo-textbox>\n <kendo-textarea\n [(ngModel)]=\"newDescription\"\n placeholder=\"Description (optional)\"\n [rows]=\"2\"\n [disabled]=\"isLoading()\">\n </kendo-textarea>\n </div>\n <div class=\"form-actions\">\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelCreate()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\">\n Cancel\n </button>\n <button\n kendoButton\n [svgIcon]=\"checkIcon\"\n (click)=\"create()\"\n [disabled]=\"newName().trim().length === 0 || isLoading()\"\n themeColor=\"primary\"\n size=\"small\">\n Create\n </button>\n </div>\n </div>\n }\n\n <!-- MeshBoards List -->\n <div class=\"meshboards-list\">\n @if (isLoading()) {\n <div class=\"loading-state\">\n <span class=\"k-loading-text\">Loading...</span>\n </div>\n } @else if (hasMeshBoards()) {\n @for (item of meshBoards(); track item.rtId) {\n <div\n class=\"meshboard-item\"\n [class.active]=\"isActive(item)\"\n [class.editing]=\"isEditing(item)\">\n\n @if (!isEditing(item)) {\n <!-- Display Mode -->\n <div class=\"item-content\" (click)=\"switchTo(item)\">\n <div class=\"item-icon\">\n <kendo-svg-icon [icon]=\"gridLayoutIcon\" size=\"large\"></kendo-svg-icon>\n </div>\n <div class=\"item-info\">\n <h4 class=\"item-name\">\n {{ item.name }}\n @if (isActive(item)) {\n <span class=\"active-badge\">Active</span>\n }\n </h4>\n @if (getDisplayDescription(item)) {\n <p class=\"item-description\">{{ getDisplayDescription(item) }}</p>\n }\n </div>\n <div class=\"item-actions\">\n @if (canExport) {\n <button\n kendoButton\n [svgIcon]=\"downloadIcon\"\n (click)=\"exportMeshBoard(item, $event)\"\n [disabled]=\"isLoading() || isExporting()\"\n fillMode=\"flat\"\n size=\"small\"\n title=\"Export\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"copyIcon\"\n (click)=\"duplicate(item); $event.stopPropagation()\"\n [disabled]=\"isLoading() || isDuplicating()\"\n fillMode=\"flat\"\n size=\"small\"\n title=\"Duplicate\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"pencilIcon\"\n (click)=\"startEdit(item); $event.stopPropagation()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\"\n title=\"Edit\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"delete(item); $event.stopPropagation()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\"\n themeColor=\"error\"\n title=\"Delete\">\n </button>\n </div>\n </div>\n } @else {\n <!-- Edit Mode -->\n <div class=\"item-edit\">\n <div class=\"edit-fields\">\n <kendo-textbox\n [(ngModel)]=\"editingName\"\n placeholder=\"MeshBoard name\"\n [disabled]=\"isLoading()\">\n </kendo-textbox>\n <kendo-textarea\n [(ngModel)]=\"editingDescription\"\n placeholder=\"Description (optional)\"\n [rows]=\"2\"\n [disabled]=\"isLoading()\">\n </kendo-textarea>\n </div>\n <div class=\"edit-actions mm-dialog-actions\">\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelEdit()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\">\n Cancel\n </button>\n <button\n kendoButton\n [svgIcon]=\"checkIcon\"\n (click)=\"saveEdit()\"\n [disabled]=\"editingName().trim().length === 0 || isLoading()\"\n themeColor=\"primary\"\n size=\"small\">\n Save\n </button>\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <div class=\"empty-state\">\n <kendo-svg-icon [icon]=\"gridLayoutIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h3>No MeshBoards</h3>\n <p>Create your first MeshBoard to get started.</p>\n </div>\n }\n </div>\n\n <!-- Dialog Actions -->\n <div class=\"dialog-actions mm-dialog-actions\">\n <button kendoButton (click)=\"close()\" fillMode=\"flat\">\n Close\n </button>\n </div>\n</div>\n", styles: [".meshboard-manager-dialog{display:flex;flex-direction:column;gap:.75rem;padding:.75rem .75rem 1.5rem;overflow:hidden}.meshboard-manager-dialog .dialog-header{display:flex;justify-content:space-between;align-items:center;gap:1rem}.meshboard-manager-dialog .dialog-header .dialog-description{margin:0;color:var(--kendo-color-subtle, #757575);font-size:.875rem;flex:1}.meshboard-manager-dialog .dialog-header .header-actions{display:flex;gap:.5rem}.meshboard-manager-dialog .create-form{padding:1rem;background-color:var(--kendo-color-surface-alt, #fafafa);border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:4px}.meshboard-manager-dialog .create-form .form-title{margin:0 0 1rem;font-size:1rem;font-weight:600;color:var(--kendo-color-on-app-surface, #424242)}.meshboard-manager-dialog .create-form .form-fields{display:flex;flex-direction:column;gap:.75rem;margin-bottom:1rem}.meshboard-manager-dialog .create-form .form-fields kendo-textbox,.meshboard-manager-dialog .create-form .form-fields kendo-textarea{width:100%}.meshboard-manager-dialog .create-form .form-actions{display:flex;justify-content:flex-end;gap:.5rem}.meshboard-manager-dialog .meshboards-list{flex:1;min-height:250px;overflow-y:auto;border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:4px;background-color:var(--kendo-color-surface, #ffffff)}.meshboard-manager-dialog .meshboards-list .loading-state{display:flex;align-items:center;justify-content:center;padding:2rem;color:var(--kendo-color-subtle, #757575)}.meshboard-manager-dialog .meshboards-list .empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 2rem;text-align:center}.meshboard-manager-dialog .meshboards-list .empty-state kendo-svg-icon{color:var(--kendo-color-subtle, #9e9e9e);margin-bottom:1rem}.meshboard-manager-dialog .meshboards-list .empty-state h3{margin:.5rem 0;color:var(--kendo-color-on-app-surface, #424242);font-size:1.125rem;font-weight:500}.meshboard-manager-dialog .meshboards-list .empty-state p{margin:0;color:var(--kendo-color-subtle, #757575);font-size:.875rem}.meshboard-manager-dialog .meshboards-list .meshboard-item{border-bottom:1px solid var(--kendo-color-border, #e0e0e0);transition:background-color .2s,box-shadow .2s}.meshboard-manager-dialog .meshboards-list .meshboard-item:last-child{border-bottom:none}.meshboard-manager-dialog .meshboards-list .meshboard-item:not(.active):not(.editing):hover{background-color:var(--kendo-color-base-hover, #f5f5f5)}.meshboard-manager-dialog .meshboards-list .meshboard-item.active{background-color:var(--kendo-color-primary-subtle, #e8eaf6);box-shadow:inset 4px 0 0 var(--kendo-color-primary, #3f51b5)}.meshboard-manager-dialog .meshboards-list .meshboard-item.editing{background-color:var(--kendo-color-surface-alt, #fafafa)}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content{display:flex;align-items:center;gap:1rem;padding:1rem;cursor:pointer}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:8px;background-color:var(--kendo-color-surface-alt, #f5f5f5);color:var(--kendo-color-primary, #3f51b5)}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-icon kendo-svg-icon{color:inherit}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info{flex:1;min-width:0}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info .item-name{margin:0 0 .25rem;font-size:1rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121);display:flex;align-items:center;gap:.5rem}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info .item-name .active-badge{display:inline-block;padding:.125rem .5rem;font-size:.75rem;font-weight:600;color:var(--kendo-color-on-primary, #ffffff);background-color:var(--kendo-color-primary, #3f51b5);border-radius:12px}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info .item-description{margin:0;font-size:.875rem;color:var(--kendo-color-subtle, #757575);line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-actions{flex-shrink:0;display:flex;gap:.25rem;opacity:.5;transition:opacity .2s}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content:hover .item-actions{opacity:1}.meshboard-manager-dialog .meshboards-list .meshboard-item.active .item-content .item-icon{background-color:var(--kendo-color-primary, #3f51b5);color:var(--kendo-color-on-primary, #ffffff)}.meshboard-manager-dialog .meshboards-list .meshboard-item:not(.active) .item-content:after{content:\"Click to switch\";font-size:.75rem;color:var(--kendo-color-subtle, #9e9e9e);opacity:0;transition:opacity .2s;white-space:nowrap}.meshboard-manager-dialog .meshboards-list .meshboard-item:not(.active):hover .item-content:after{opacity:1}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit{padding:1rem}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-fields{display:flex;flex-direction:column;gap:.75rem;margin-bottom:.75rem}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-fields kendo-textbox,.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-fields kendo-textarea{width:100%}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-actions{display:flex;justify-content:flex-end;gap:.5rem}.meshboard-manager-dialog .dialog-actions{display:flex;justify-content:flex-end;gap:.5rem;padding-top:.75rem;border-top:1px solid var(--kendo-color-border, #e0e0e0);flex-shrink:0;margin-bottom:.5rem}.meshboards-list::-webkit-scrollbar{width:8px}.meshboards-list::-webkit-scrollbar-track{background:var(--kendo-color-surface-alt, #f5f5f5)}.meshboards-list::-webkit-scrollbar-thumb{background:var(--kendo-color-border, #e0e0e0);border-radius:4px}.meshboards-list::-webkit-scrollbar-thumb:hover{background:var(--kendo-color-subtle, #9e9e9e)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i2$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }] });
|
|
27788
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MeshBoardManagerDialogComponent, isStandalone: true, selector: "mm-meshboard-manager-dialog", ngImport: i0, template: "<div class=\"meshboard-manager-dialog\">\n <!-- Header with Create/Import Buttons -->\n <div class=\"dialog-header\">\n <p class=\"dialog-description\">Manage your MeshBoards</p>\n <div class=\"header-actions\">\n @if (canExport) {\n <button\n kendoButton\n [svgIcon]=\"uploadIcon\"\n (click)=\"triggerImport()\"\n [disabled]=\"isCreating() || isLoading() || isImporting()\"\n fillMode=\"outline\">\n Import\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"startCreate()\"\n [disabled]=\"isCreating() || isLoading()\"\n themeColor=\"primary\">\n New MeshBoard\n </button>\n </div>\n </div>\n\n <!-- Create New MeshBoard Form -->\n @if (isCreating()) {\n <div class=\"create-form\">\n <h4 class=\"form-title\">Create New MeshBoard</h4>\n <div class=\"form-fields\">\n <kendo-textbox\n [(ngModel)]=\"newName\"\n placeholder=\"MeshBoard name\"\n [disabled]=\"isLoading()\">\n </kendo-textbox>\n <kendo-textarea\n [(ngModel)]=\"newDescription\"\n placeholder=\"Description (optional)\"\n [rows]=\"2\"\n [disabled]=\"isLoading()\">\n </kendo-textarea>\n </div>\n <div class=\"form-actions\">\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelCreate()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\">\n Cancel\n </button>\n <button\n kendoButton\n [svgIcon]=\"checkIcon\"\n (click)=\"create()\"\n [disabled]=\"newName().trim().length === 0 || isLoading()\"\n themeColor=\"primary\"\n size=\"small\">\n Create\n </button>\n </div>\n </div>\n }\n\n <!-- MeshBoards List -->\n <div class=\"meshboards-list\">\n @if (isLoading()) {\n <div class=\"loading-state\">\n <span class=\"k-loading-text\">Loading...</span>\n </div>\n } @else if (hasMeshBoards()) {\n @for (item of meshBoards(); track item.rtId) {\n <div\n class=\"meshboard-item\"\n [class.active]=\"isActive(item)\"\n [class.editing]=\"isEditing(item)\">\n\n @if (!isEditing(item)) {\n <!-- Display Mode -->\n <div class=\"item-content\" (click)=\"switchTo(item)\">\n <div class=\"item-icon\">\n <kendo-svg-icon [icon]=\"gridLayoutIcon\" size=\"large\"></kendo-svg-icon>\n </div>\n <div class=\"item-info\">\n <h4 class=\"item-name\">\n {{ item.name }}\n @if (isActive(item)) {\n <span class=\"active-badge\">Active</span>\n }\n </h4>\n @if (getDisplayDescription(item)) {\n <p class=\"item-description\">{{ getDisplayDescription(item) }}</p>\n }\n </div>\n <div class=\"item-actions\">\n @if (canExport) {\n <button\n kendoButton\n [svgIcon]=\"downloadIcon\"\n (click)=\"exportMeshBoard(item, $event)\"\n [disabled]=\"isLoading() || isExporting()\"\n fillMode=\"flat\"\n size=\"small\"\n title=\"Export\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"copyIcon\"\n (click)=\"duplicate(item); $event.stopPropagation()\"\n [disabled]=\"isLoading() || isDuplicating()\"\n fillMode=\"flat\"\n size=\"small\"\n title=\"Duplicate\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"pencilIcon\"\n (click)=\"startEdit(item); $event.stopPropagation()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\"\n title=\"Edit\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"delete(item); $event.stopPropagation()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\"\n themeColor=\"error\"\n title=\"Delete\">\n </button>\n </div>\n </div>\n } @else {\n <!-- Edit Mode -->\n <div class=\"item-edit\">\n <div class=\"edit-fields\">\n <kendo-textbox\n [(ngModel)]=\"editingName\"\n placeholder=\"MeshBoard name\"\n [disabled]=\"isLoading()\">\n </kendo-textbox>\n <kendo-textarea\n [(ngModel)]=\"editingDescription\"\n placeholder=\"Description (optional)\"\n [rows]=\"2\"\n [disabled]=\"isLoading()\">\n </kendo-textarea>\n </div>\n <div class=\"edit-actions mm-dialog-actions\">\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelEdit()\"\n [disabled]=\"isLoading()\"\n fillMode=\"flat\"\n size=\"small\">\n Cancel\n </button>\n <button\n kendoButton\n [svgIcon]=\"checkIcon\"\n (click)=\"saveEdit()\"\n [disabled]=\"editingName().trim().length === 0 || isLoading()\"\n themeColor=\"primary\"\n size=\"small\">\n Save\n </button>\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <div class=\"empty-state\">\n <kendo-svg-icon [icon]=\"gridLayoutIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h3>No MeshBoards</h3>\n <p>Create your first MeshBoard to get started.</p>\n </div>\n }\n </div>\n\n <!-- Dialog Actions -->\n <div class=\"dialog-actions mm-dialog-actions\">\n <button kendoButton (click)=\"close()\" fillMode=\"flat\">\n Close\n </button>\n </div>\n</div>\n", styles: [".meshboard-manager-dialog{display:flex;flex-direction:column;gap:.75rem;padding:.75rem .75rem 1.5rem;overflow:hidden}.meshboard-manager-dialog .dialog-header{display:flex;justify-content:space-between;align-items:center;gap:1rem}.meshboard-manager-dialog .dialog-header .dialog-description{margin:0;color:var(--kendo-color-subtle, #757575);font-size:.875rem;flex:1}.meshboard-manager-dialog .dialog-header .header-actions{display:flex;gap:.5rem}.meshboard-manager-dialog .create-form{padding:1rem;background-color:var(--kendo-color-surface-alt, #fafafa);border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:4px}.meshboard-manager-dialog .create-form .form-title{margin:0 0 1rem;font-size:1rem;font-weight:600;color:var(--kendo-color-on-app-surface, #424242)}.meshboard-manager-dialog .create-form .form-fields{display:flex;flex-direction:column;gap:.75rem;margin-bottom:1rem}.meshboard-manager-dialog .create-form .form-fields kendo-textbox,.meshboard-manager-dialog .create-form .form-fields kendo-textarea{width:100%}.meshboard-manager-dialog .create-form .form-actions{display:flex;justify-content:flex-end;gap:.5rem}.meshboard-manager-dialog .meshboards-list{flex:1;min-height:250px;overflow-y:auto;border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:4px;background-color:var(--kendo-color-surface, #ffffff)}.meshboard-manager-dialog .meshboards-list .loading-state{display:flex;align-items:center;justify-content:center;padding:2rem;color:var(--kendo-color-subtle, #757575)}.meshboard-manager-dialog .meshboards-list .empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 2rem;text-align:center}.meshboard-manager-dialog .meshboards-list .empty-state kendo-svg-icon{color:var(--kendo-color-subtle, #9e9e9e);margin-bottom:1rem}.meshboard-manager-dialog .meshboards-list .empty-state h3{margin:.5rem 0;color:var(--kendo-color-on-app-surface, #424242);font-size:1.125rem;font-weight:500}.meshboard-manager-dialog .meshboards-list .empty-state p{margin:0;color:var(--kendo-color-subtle, #757575);font-size:.875rem}.meshboard-manager-dialog .meshboards-list .meshboard-item{border-bottom:1px solid var(--kendo-color-border, #e0e0e0);transition:background-color .2s,box-shadow .2s}.meshboard-manager-dialog .meshboards-list .meshboard-item:last-child{border-bottom:none}.meshboard-manager-dialog .meshboards-list .meshboard-item:not(.active):not(.editing):hover{background-color:var(--kendo-color-base-hover, #f5f5f5)}.meshboard-manager-dialog .meshboards-list .meshboard-item.active{background-color:var(--kendo-color-primary-subtle, #e8eaf6);box-shadow:inset 4px 0 0 var(--kendo-color-primary, #3f51b5)}.meshboard-manager-dialog .meshboards-list .meshboard-item.editing{background-color:var(--kendo-color-surface-alt, #fafafa)}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content{display:flex;align-items:center;gap:1rem;padding:1rem;cursor:pointer}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:8px;background-color:var(--kendo-color-surface-alt, #f5f5f5);color:var(--kendo-color-primary, #3f51b5)}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-icon kendo-svg-icon{color:inherit}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info{flex:1;min-width:0}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info .item-name{margin:0 0 .25rem;font-size:1rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121);display:flex;align-items:center;gap:.5rem}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info .item-name .active-badge{display:inline-block;padding:.125rem .5rem;font-size:.75rem;font-weight:600;color:var(--kendo-color-on-primary, #ffffff);background-color:var(--kendo-color-primary, #3f51b5);border-radius:12px}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-info .item-description{margin:0;font-size:.875rem;color:var(--kendo-color-subtle, #757575);line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content .item-actions{flex-shrink:0;display:flex;gap:.25rem;opacity:.5;transition:opacity .2s}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-content:hover .item-actions{opacity:1}.meshboard-manager-dialog .meshboards-list .meshboard-item.active .item-content .item-icon{background-color:var(--kendo-color-primary, #3f51b5);color:var(--kendo-color-on-primary, #ffffff)}.meshboard-manager-dialog .meshboards-list .meshboard-item:not(.active) .item-content:after{content:\"Click to switch\";font-size:.75rem;color:var(--kendo-color-subtle, #9e9e9e);opacity:0;transition:opacity .2s;white-space:nowrap}.meshboard-manager-dialog .meshboards-list .meshboard-item:not(.active):hover .item-content:after{opacity:1}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit{padding:1rem}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-fields{display:flex;flex-direction:column;gap:.75rem;margin-bottom:.75rem}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-fields kendo-textbox,.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-fields kendo-textarea{width:100%}.meshboard-manager-dialog .meshboards-list .meshboard-item .item-edit .edit-actions{display:flex;justify-content:flex-end;gap:.5rem}.meshboard-manager-dialog .dialog-actions{display:flex;justify-content:flex-end;gap:.5rem;padding-top:.75rem;border-top:1px solid var(--kendo-color-border, #e0e0e0);flex-shrink:0;margin-bottom:.5rem}.meshboards-list::-webkit-scrollbar{width:8px}.meshboards-list::-webkit-scrollbar-track{background:var(--kendo-color-surface-alt, #f5f5f5)}.meshboards-list::-webkit-scrollbar-thumb{background:var(--kendo-color-border, #e0e0e0);border-radius:4px}.meshboards-list::-webkit-scrollbar-thumb:hover{background:var(--kendo-color-subtle, #9e9e9e)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }] });
|
|
25739
27789
|
}
|
|
25740
27790
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MeshBoardManagerDialogComponent, decorators: [{
|
|
25741
27791
|
type: Component,
|
|
@@ -25773,7 +27823,8 @@ class EditWidgetDialogComponent {
|
|
|
25773
27823
|
col: this.widget.col,
|
|
25774
27824
|
row: this.widget.row,
|
|
25775
27825
|
colSpan: this.widget.colSpan,
|
|
25776
|
-
rowSpan: this.widget.rowSpan
|
|
27826
|
+
rowSpan: this.widget.rowSpan,
|
|
27827
|
+
chromeless: this.widget.chromeless ?? false
|
|
25777
27828
|
};
|
|
25778
27829
|
}
|
|
25779
27830
|
onSave() {
|
|
@@ -25859,6 +27910,11 @@ class EditWidgetDialogComponent {
|
|
|
25859
27910
|
</div>
|
|
25860
27911
|
</div>
|
|
25861
27912
|
|
|
27913
|
+
<div class="form-field form-field-checkbox">
|
|
27914
|
+
<input type="checkbox" id="editWidgetChromeless" [(ngModel)]="form.chromeless" />
|
|
27915
|
+
<label for="editWidgetChromeless">Chromeless (hide title bar and border in view mode)</label>
|
|
27916
|
+
</div>
|
|
27917
|
+
|
|
25862
27918
|
@if (error) {
|
|
25863
27919
|
<div class="form-error">{{ error }}</div>
|
|
25864
27920
|
}
|
|
@@ -25875,7 +27931,7 @@ class EditWidgetDialogComponent {
|
|
|
25875
27931
|
</kendo-dialog-actions>
|
|
25876
27932
|
|
|
25877
27933
|
</kendo-dialog>
|
|
25878
|
-
`, isInline: true, styles: [".edit-widget-form{display:flex;flex-direction:column;gap:16px;padding:8px 0}.form-field{display:flex;flex-direction:column;gap:4px}.form-field label{font-weight:500;font-size:.875rem;color:var(--kendo-color-on-app-surface, #212529)}.form-row{display:flex;gap:16px}.form-row .form-field{flex:1}.form-error{color:var(--kendo-color-error, #dc3545);font-size:.875rem;padding:8px;background:var(--kendo-color-error-subtle, rgba(220, 53, 69, .1));border-radius:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1$
|
|
27934
|
+
`, isInline: true, styles: [".edit-widget-form{display:flex;flex-direction:column;gap:16px;padding:8px 0}.form-field{display:flex;flex-direction:column;gap:4px}.form-field label{font-weight:500;font-size:.875rem;color:var(--kendo-color-on-app-surface, #212529)}.form-row{display:flex;gap:16px}.form-row .form-field{flex:1}.form-field-checkbox{flex-direction:row;align-items:center;gap:8px}.form-field-checkbox label{font-weight:400}.form-error{color:var(--kendo-color-error, #dc3545);font-size:.875rem;padding:8px;background:var(--kendo-color-error-subtle, rgba(220, 53, 69, .1));border-radius:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1$5.DialogComponent, selector: "kendo-dialog", inputs: ["actions", "actionsLayout", "autoFocusedElement", "title", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "animation", "themeColor"], outputs: ["action", "close"], exportAs: ["kendoDialog"] }, { kind: "component", type: i1$5.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i3.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i3.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
|
|
25879
27935
|
}
|
|
25880
27936
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EditWidgetDialogComponent, decorators: [{
|
|
25881
27937
|
type: Component,
|
|
@@ -25950,6 +28006,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
25950
28006
|
</div>
|
|
25951
28007
|
</div>
|
|
25952
28008
|
|
|
28009
|
+
<div class="form-field form-field-checkbox">
|
|
28010
|
+
<input type="checkbox" id="editWidgetChromeless" [(ngModel)]="form.chromeless" />
|
|
28011
|
+
<label for="editWidgetChromeless">Chromeless (hide title bar and border in view mode)</label>
|
|
28012
|
+
</div>
|
|
28013
|
+
|
|
25953
28014
|
@if (error) {
|
|
25954
28015
|
<div class="form-error">{{ error }}</div>
|
|
25955
28016
|
}
|
|
@@ -25966,7 +28027,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
25966
28027
|
</kendo-dialog-actions>
|
|
25967
28028
|
|
|
25968
28029
|
</kendo-dialog>
|
|
25969
|
-
`, styles: [".edit-widget-form{display:flex;flex-direction:column;gap:16px;padding:8px 0}.form-field{display:flex;flex-direction:column;gap:4px}.form-field label{font-weight:500;font-size:.875rem;color:var(--kendo-color-on-app-surface, #212529)}.form-row{display:flex;gap:16px}.form-row .form-field{flex:1}.form-error{color:var(--kendo-color-error, #dc3545);font-size:.875rem;padding:8px;background:var(--kendo-color-error-subtle, rgba(220, 53, 69, .1));border-radius:4px}\n"] }]
|
|
28030
|
+
`, styles: [".edit-widget-form{display:flex;flex-direction:column;gap:16px;padding:8px 0}.form-field{display:flex;flex-direction:column;gap:4px}.form-field label{font-weight:500;font-size:.875rem;color:var(--kendo-color-on-app-surface, #212529)}.form-row{display:flex;gap:16px}.form-row .form-field{flex:1}.form-field-checkbox{flex-direction:row;align-items:center;gap:8px}.form-field-checkbox label{font-weight:400}.form-error{color:var(--kendo-color-error, #dc3545);font-size:.875rem;padding:8px;background:var(--kendo-color-error-subtle, rgba(220, 53, 69, .1));border-radius:4px}\n"] }]
|
|
25970
28031
|
}], propDecorators: { widget: [{
|
|
25971
28032
|
type: Input
|
|
25972
28033
|
}], widgets: [{
|
|
@@ -26049,6 +28110,9 @@ class MeshBoardViewComponent {
|
|
|
26049
28110
|
}, ...(ngDevMode ? [{ debugName: "meshBoardPageLink" }] : /* istanbul ignore next */ []));
|
|
26050
28111
|
// Computed
|
|
26051
28112
|
hasWidgets = computed(() => this.config().widgets.length > 0, ...(ngDevMode ? [{ debugName: "hasWidgets" }] : /* istanbul ignore next */ []));
|
|
28113
|
+
bannerWidgets = computed(() => this.config().widgets.filter(w => w.chromeless), ...(ngDevMode ? [{ debugName: "bannerWidgets" }] : /* istanbul ignore next */ []));
|
|
28114
|
+
gridWidgets = computed(() => this.config().widgets.filter(w => !w.chromeless), ...(ngDevMode ? [{ debugName: "gridWidgets" }] : /* istanbul ignore next */ []));
|
|
28115
|
+
hasGridWidgets = computed(() => this.gridWidgets().length > 0, ...(ngDevMode ? [{ debugName: "hasGridWidgets" }] : /* istanbul ignore next */ []));
|
|
26052
28116
|
canSave = computed(() => this.isEditMode() && !this.isSaving(), ...(ngDevMode ? [{ debugName: "canSave" }] : /* istanbul ignore next */ []));
|
|
26053
28117
|
// Time Filter computed signals
|
|
26054
28118
|
isTimeFilterEnabled = computed(() => this.stateService.isTimeFilterEnabled(), ...(ngDevMode ? [{ debugName: "isTimeFilterEnabled" }] : /* istanbul ignore next */ []));
|
|
@@ -26833,7 +28897,8 @@ class MeshBoardViewComponent {
|
|
|
26833
28897
|
col: update.col,
|
|
26834
28898
|
row: update.row,
|
|
26835
28899
|
colSpan: update.colSpan,
|
|
26836
|
-
rowSpan: update.rowSpan
|
|
28900
|
+
rowSpan: update.rowSpan,
|
|
28901
|
+
chromeless: update.chromeless
|
|
26837
28902
|
}));
|
|
26838
28903
|
this.closeEditWidgetDialog();
|
|
26839
28904
|
// Enter edit mode if not already in it
|
|
@@ -26995,7 +29060,7 @@ class MeshBoardViewComponent {
|
|
|
26995
29060
|
}
|
|
26996
29061
|
}
|
|
26997
29062
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MeshBoardViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
26998
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MeshBoardViewComponent, isStandalone: true, selector: "mm-meshboard-view", providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: MeshBoardViewComponent }], hostDirectives: [{ directive: i1$7.UnsavedChangesDirective }], ngImport: i0, template: "<div class=\"meshboard-view\">\n @if (isLoading()) {\n <div class=\"loading-container\">\n <div class=\"k-loading-mask\">\n <span class=\"k-loading-text\">Loading MeshBoard...</span>\n <div class=\"k-loading-image\"></div>\n <div class=\"k-loading-color\"></div>\n </div>\n </div>\n } @else if (isModelAvailable() === false) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Available</h2>\n <p>The MeshBoard feature requires the CK model 'System.UI' version 1.0.1 or higher.</p>\n <p>Please install the required model in your tenant to use this feature.</p>\n </div>\n </div>\n } @else if (notFoundError()) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Found</h2>\n <p>{{ notFoundError() }}</p>\n <p>To create a MeshBoard with a Well-Known Name:</p>\n <ol>\n <li>Go to the <a [routerLink]=\"meshBoardPageLink()\">MeshBoard</a> page</li>\n <li>Open Settings</li>\n <li>Set the \"Well-Known Name\" field</li>\n <li>Save the MeshBoard</li>\n </ol>\n </div>\n </div>\n } @else if (isInitialized()) {\n <!-- Toolbar -->\n <div class=\"meshboard-toolbar\">\n <div class=\"toolbar-left\">\n <h2 class=\"meshboard-title\">{{ config().name }}</h2>\n @if (config().description) {\n <span class=\"meshboard-description\">{{ config().description }}</span>\n }\n </div>\n\n <!-- Time Filter (center) -->\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-center\">\n <mm-time-range-picker\n [config]=\"timeFilterConfig()?.pickerConfig ?? {}\"\n [labels]=\"timeRangeLabels()\"\n [initialSelection]=\"initialTimeSelection()\"\n (rangeChange)=\"onTimeRangeChange($event)\"\n (selectionChange)=\"onTimeSelectionChange($event)\">\n </mm-time-range-picker>\n @if (canResetTimeFilter()) {\n <button\n kendoButton\n [svgIcon]=\"undoIcon\"\n (click)=\"resetTimeFilterToDefault()\"\n title=\"Reset to default time filter\"\n fillMode=\"flat\"\n size=\"small\">\n </button>\n }\n </div>\n }\n\n <!-- Entity Selectors -->\n @if (hasEntitySelectors()) {\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-entity-selectors\">\n <mm-entity-selector-toolbar\n [entitySelectors]=\"entitySelectorsConfig()\"\n (entitySelected)=\"onEntitySelectorSelected($event)\"\n (entityCleared)=\"onEntitySelectorCleared($event)\">\n </mm-entity-selector-toolbar>\n </div>\n }\n\n @if (isTimeFilterEnabled() || hasEntitySelectors()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-right mm-toolbar-actions\">\n @if (!isReadonly()) {\n <!-- Manager Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gridLayoutIcon\"\n (click)=\"openManager()\"\n title=\"Manage MeshBoards\"\n fillMode=\"flat\">\n </button>\n\n <!-- Settings Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openSettings()\"\n title=\"MeshBoard Settings\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Refresh Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"arrowRotateCwIcon\"\n (click)=\"refresh()\"\n title=\"Refresh All Widgets\"\n fillMode=\"flat\">\n </button>\n\n @if (!isReadonly()) {\n <!-- Edit Mode Toggle (icon only) -->\n @if (!isEditMode()) {\n <button\n kendoButton\n [svgIcon]=\"pencilIcon\"\n (click)=\"toggleEditMode()\"\n title=\"Enter Edit Mode\"\n fillMode=\"flat\">\n </button>\n } @else {\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelEdit()\"\n title=\"Cancel Edit Mode\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Add Widget Button (with text) -->\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n title=\"Add Widget\"\n themeColor=\"primary\">\n Add Widget\n </button>\n\n <!-- Save Button (with text) -->\n @if (canSave()) {\n <button\n kendoButton\n [svgIcon]=\"saveIcon\"\n (click)=\"save()\"\n [disabled]=\"isSaving()\"\n title=\"Save MeshBoard\"\n themeColor=\"primary\">\n {{ isSaving() ? 'Saving...' : 'Save' }}\n </button>\n }\n }\n </div>\n </div>\n\n <!-- Entity Selector Hint -->\n @if (unselectedToolbarSelectors().length > 0) {\n <div class=\"entity-selector-hint\">\n <kendo-svg-icon [icon]=\"infoCircleIcon\" size=\"medium\"></kendo-svg-icon>\n <span>\n Please select\n @for (selector of unselectedToolbarSelectors(); track selector.id; let last = $last) {\n <strong>{{ selector.label }}</strong>@if (!last) {, }\n }\n to display dashboard data.\n </span>\n </div>\n }\n\n <!-- Variable Resolution Errors -->\n @if (variableResolutionErrors().length > 0) {\n <div class=\"variable-resolution-errors\">\n <strong>Variable resolution errors:</strong>\n @for (error of variableResolutionErrors(); track error.variableName) {\n <span class=\"error-item\">{{ error.variableName }}: {{ error.message }}</span>\n }\n </div>\n }\n\n <!-- MeshBoard Grid -->\n @if (hasWidgets()) {\n <kendo-tilelayout\n [columns]=\"config().columns\"\n [rowHeight]=\"config().rowHeight\"\n [gap]=\"config().gap\"\n [resizable]=\"isEditMode()\"\n [reorderable]=\"isEditMode()\"\n (reorder)=\"onReorder($event)\"\n (resize)=\"onResize($event)\">\n @for (widget of config().widgets; track trackByWidgetId($index, widget)) {\n <kendo-tilelayout-item\n [col]=\"widget.col\"\n [row]=\"widget.row\"\n [colSpan]=\"widget.colSpan\"\n [rowSpan]=\"widget.rowSpan\">\n <kendo-tilelayout-item-header>\n <div class=\"widget-header\" [class.unconfigured]=\"isWidgetUnconfigured(widget)\">\n <span class=\"widget-title\">{{ widget.title }}</span>\n @if (isWidgetUnconfigured(widget) && !isEditMode()) {\n <span class=\"unconfigured-badge\" title=\"Widget needs configuration\">!</span>\n }\n @if (isEditMode()) {\n <div class=\"widget-actions\" (pointerdown)=\"$event.stopPropagation()\">\n @if (supportsConfiguration(widget)) {\n <button\n kendoButton\n [svgIcon]=\"linkIcon\"\n (click)=\"openWidgetConfig(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"config-widget-btn\"\n [class.needs-config]=\"isWidgetUnconfigured(widget)\"\n [title]=\"isWidgetUnconfigured(widget) ? 'Configure data source (required)' : 'Configure data source'\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openEditWidgetDialog(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"edit-widget-btn\"\n title=\"Edit position\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"copyIcon\"\n (click)=\"duplicateWidget(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"duplicate-widget-btn\"\n title=\"Duplicate widget\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"removeWidget(widget.id)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"remove-widget-btn\"\n title=\"Delete widget\">\n </button>\n </div>\n }\n </div>\n </kendo-tilelayout-item-header>\n <kendo-tilelayout-item-body>\n @if (getWidgetComponentType(widget.type); as componentType) {\n <ng-container *ngComponentOutlet=\"componentType; inputs: { config: widget }\"></ng-container>\n } @else {\n <div class=\"widget-error\">\n <p>Unknown widget type: {{ widget.type }}</p>\n </div>\n }\n </kendo-tilelayout-item-body>\n </kendo-tilelayout-item>\n }\n </kendo-tilelayout>\n } @else {\n <div class=\"empty-state\">\n <div class=\"empty-state-content\">\n <kendo-svg-icon [icon]=\"plusIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h3>No Widgets</h3>\n <p>Get started by adding widgets to your MeshBoard.</p>\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n themeColor=\"primary\">\n Add Your First Widget\n </button>\n </div>\n </div>\n }\n\n <!-- Edit Widget Dialog -->\n @if (showEditWidgetDialog && editingWidget) {\n <mm-edit-widget-dialog\n [widget]=\"editingWidget\"\n [widgets]=\"config().widgets\"\n [maxColumns]=\"config().columns\"\n [gridService]=\"gridService\"\n (save)=\"onEditWidgetSave($event)\"\n (cancelled)=\"closeEditWidgetDialog()\">\n </mm-edit-widget-dialog>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;height:100%;width:100%}.meshboard-view{display:flex;flex-direction:column;flex:1;min-height:0;width:100%;background-color:var(--kendo-color-surface, #f5f5f5)}.loading-container{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.entity-selector-hint{display:flex;align-items:center;gap:8px;padding:10px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-info, #2196f3) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid color-mix(in srgb,var(--kendo-color-info, #2196f3) 40%,transparent);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.entity-selector-hint strong{color:var(--kendo-color-info, #2196f3)}.variable-resolution-errors{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid var(--kendo-color-error, #f44336);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.variable-resolution-errors strong{color:var(--kendo-color-error, #f44336)}.variable-resolution-errors .error-item{padding:2px 8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 8%,transparent);border-radius:3px;font-family:Consolas,Monaco,monospace;font-size:12px}.model-unavailable{display:flex;align-items:center;justify-content:center;height:100%;width:100%;padding:2rem;overflow:hidden;box-sizing:border-box}.model-unavailable .message-card{text-align:center;max-width:500px;padding:2rem;background:var(--kendo-color-surface-alt, #fafafa);border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:8px;overflow:hidden}.model-unavailable .message-card kendo-svg-icon{color:var(--kendo-color-warning, #ff9800);margin-bottom:1rem}.model-unavailable .message-card h2{margin:1rem 0;color:var(--kendo-color-on-app-surface, #424242)}.model-unavailable .message-card p{margin:.5rem 0;color:var(--kendo-color-subtle, #757575);line-height:1.5}.model-unavailable .message-card ol{text-align:left;margin:1rem 0;padding-left:1.5rem;color:var(--kendo-color-subtle, #757575);line-height:1.8}.model-unavailable .message-card ol li{margin:.25rem 0}.model-unavailable .message-card ol a{color:var(--kendo-color-primary, #3f51b5);text-decoration:none}.model-unavailable .message-card ol a:hover{text-decoration:underline}.meshboard-toolbar{display:flex;justify-content:space-between;align-items:flex-end;padding:1rem 1.5rem;background-color:var(--kendo-color-surface-alt, white);border-bottom:1px solid var(--kendo-color-border, #e0e0e0);gap:1rem;flex-shrink:0}.meshboard-toolbar .toolbar-left{display:flex;align-items:baseline;gap:1rem;flex:1;min-width:0;align-self:center}.meshboard-toolbar .toolbar-left .meshboard-title{margin:0;font-size:1.5rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-left .meshboard-description{color:var(--kendo-color-subtle, #757575);font-size:.875rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-center{display:flex;justify-content:center;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-center mm-time-range-picker ::ng-deep .time-range-picker{gap:.5rem}.meshboard-toolbar .toolbar-separator{width:1px;align-self:stretch;background-color:var(--kendo-color-border, #e0e0e0);flex-shrink:0}.meshboard-toolbar .toolbar-entity-selectors{display:flex;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-right{display:flex;gap:.5rem;align-items:center;flex-shrink:0}.empty-state{display:flex;align-items:flex-start;justify-content:center;height:calc(100% - 80px);width:100%;padding-top:4rem}.empty-state .empty-state-content{text-align:center;padding:2rem}.empty-state .empty-state-content kendo-svg-icon{color:var(--kendo-color-subtle, #9e9e9e);margin-bottom:1rem}.empty-state .empty-state-content h3{margin:1rem 0 .5rem;color:var(--kendo-color-on-app-surface, #424242);font-size:1.25rem;font-weight:500}.empty-state .empty-state-content p{margin:0 0 1.5rem;color:var(--kendo-color-subtle, #757575)}kendo-tilelayout{padding:1.5rem;overflow:auto;flex:1;min-height:0}.widget-header{display:flex;justify-content:space-between;align-items:center;width:100%;gap:.5rem}.widget-header.unconfigured{background-color:#ff98001a}.widget-header .widget-title{flex:1;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.widget-header .unconfigured-badge{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background-color:var(--kendo-color-warning, #ff9800);color:#fff;font-size:12px;font-weight:700;flex-shrink:0}.widget-header .widget-actions{display:flex;align-items:center;gap:.25rem;flex-shrink:0}.widget-header .config-widget-btn,.widget-header .edit-widget-btn,.widget-header .remove-widget-btn{opacity:.6;transition:opacity .2s}.widget-header .config-widget-btn:hover,.widget-header .edit-widget-btn:hover,.widget-header .remove-widget-btn:hover{opacity:1}.widget-header .config-widget-btn.needs-config{color:var(--kendo-color-warning, #ff9800);opacity:1}.widget-header .remove-widget-btn{color:var(--kendo-color-error, #f44336)}.widget-error{display:flex;align-items:center;justify-content:center;height:100%;padding:1rem;color:var(--kendo-color-error, #f44336);text-align:center}.meshboard-view.edit-mode kendo-tilelayout-item:hover{box-shadow:0 0 0 2px var(--kendo-color-primary, #3f51b5)}@media(max-width:768px){.meshboard-toolbar{flex-direction:column;align-items:stretch;gap:.75rem}.meshboard-toolbar .toolbar-left{flex-direction:column;align-items:flex-start;gap:.25rem}.meshboard-toolbar .toolbar-right{flex-wrap:wrap;justify-content:flex-end}kendo-tilelayout{padding:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: TileLayoutModule }, { kind: "component", type: i5.TileLayoutComponent, selector: "kendo-tilelayout", inputs: ["columns", "columnWidth", "gap", "reorderable", "resizable", "rowHeight", "autoFlow", "navigable"], outputs: ["reorder", "resize"] }, { kind: "component", type: i5.TileLayoutItemBodyComponent, selector: "kendo-tilelayout-item-body" }, { kind: "component", type: i5.TileLayoutItemComponent, selector: "kendo-tilelayout-item", inputs: ["title", "rowSpan", "colSpan", "order", "col", "row", "reorderable", "resizable"] }, { kind: "component", type: i5.TileLayoutItemHeaderComponent, selector: "kendo-tilelayout-item-header" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i2$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: EditWidgetDialogComponent, selector: "mm-edit-widget-dialog", inputs: ["widget", "widgets", "maxColumns", "gridService"], outputs: ["save", "cancelled"] }, { kind: "component", type: TimeRangePickerComponent, selector: "mm-time-range-picker", inputs: ["config", "labels", "initialSelection"], outputs: ["rangeChange", "rangeChangeISO", "selectionChange"] }, { kind: "component", type: EntitySelectorToolbarComponent, selector: "mm-entity-selector-toolbar", inputs: ["entitySelectors"], outputs: ["entitySelected", "entityCleared"] }] });
|
|
29063
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MeshBoardViewComponent, isStandalone: true, selector: "mm-meshboard-view", providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: MeshBoardViewComponent }], hostDirectives: [{ directive: i1$8.UnsavedChangesDirective }], ngImport: i0, template: "<div class=\"meshboard-view\">\n @if (isLoading()) {\n <div class=\"loading-container\">\n <div class=\"k-loading-mask\">\n <span class=\"k-loading-text\">Loading MeshBoard...</span>\n <div class=\"k-loading-image\"></div>\n <div class=\"k-loading-color\"></div>\n </div>\n </div>\n } @else if (isModelAvailable() === false) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Available</h2>\n <p>The MeshBoard feature requires the CK model 'System.UI' version 1.0.1 or higher.</p>\n <p>Please install the required model in your tenant to use this feature.</p>\n </div>\n </div>\n } @else if (notFoundError()) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Found</h2>\n <p>{{ notFoundError() }}</p>\n <p>To create a MeshBoard with a Well-Known Name:</p>\n <ol>\n <li>Go to the <a [routerLink]=\"meshBoardPageLink()\">MeshBoard</a> page</li>\n <li>Open Settings</li>\n <li>Set the \"Well-Known Name\" field</li>\n <li>Save the MeshBoard</li>\n </ol>\n </div>\n </div>\n } @else if (isInitialized()) {\n <!-- Toolbar -->\n <div class=\"meshboard-toolbar\">\n <div class=\"toolbar-left\">\n <h2 class=\"meshboard-title\">{{ config().name }}</h2>\n @if (config().description) {\n <span class=\"meshboard-description\">{{ config().description }}</span>\n }\n </div>\n\n <!-- Time Filter (center) -->\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-center\">\n <mm-time-range-picker\n [config]=\"timeFilterConfig()?.pickerConfig ?? {}\"\n [labels]=\"timeRangeLabels()\"\n [initialSelection]=\"initialTimeSelection()\"\n (rangeChange)=\"onTimeRangeChange($event)\"\n (selectionChange)=\"onTimeSelectionChange($event)\">\n </mm-time-range-picker>\n @if (canResetTimeFilter()) {\n <button\n kendoButton\n [svgIcon]=\"undoIcon\"\n (click)=\"resetTimeFilterToDefault()\"\n title=\"Reset to default time filter\"\n fillMode=\"flat\"\n size=\"small\">\n </button>\n }\n </div>\n }\n\n <!-- Entity Selectors -->\n @if (hasEntitySelectors()) {\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-entity-selectors\">\n <mm-entity-selector-toolbar\n [entitySelectors]=\"entitySelectorsConfig()\"\n (entitySelected)=\"onEntitySelectorSelected($event)\"\n (entityCleared)=\"onEntitySelectorCleared($event)\">\n </mm-entity-selector-toolbar>\n </div>\n }\n\n @if (isTimeFilterEnabled() || hasEntitySelectors()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-right mm-toolbar-actions\">\n @if (!isReadonly()) {\n <!-- Manager Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gridLayoutIcon\"\n (click)=\"openManager()\"\n title=\"Manage MeshBoards\"\n fillMode=\"flat\">\n </button>\n\n <!-- Settings Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openSettings()\"\n title=\"MeshBoard Settings\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Refresh Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"arrowRotateCwIcon\"\n (click)=\"refresh()\"\n title=\"Refresh All Widgets\"\n fillMode=\"flat\">\n </button>\n\n @if (!isReadonly()) {\n <!-- Edit Mode Toggle (icon only) -->\n @if (!isEditMode()) {\n <button\n kendoButton\n [svgIcon]=\"pencilIcon\"\n (click)=\"toggleEditMode()\"\n title=\"Enter Edit Mode\"\n fillMode=\"flat\">\n </button>\n } @else {\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelEdit()\"\n title=\"Cancel Edit Mode\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Add Widget Button (with text) -->\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n title=\"Add Widget\"\n themeColor=\"primary\">\n Add Widget\n </button>\n\n <!-- Save Button (with text) -->\n @if (canSave()) {\n <button\n kendoButton\n [svgIcon]=\"saveIcon\"\n (click)=\"save()\"\n [disabled]=\"isSaving()\"\n title=\"Save MeshBoard\"\n themeColor=\"primary\">\n {{ isSaving() ? 'Saving...' : 'Save' }}\n </button>\n }\n }\n </div>\n </div>\n\n <!-- Entity Selector Hint -->\n @if (unselectedToolbarSelectors().length > 0) {\n <div class=\"entity-selector-hint\">\n <kendo-svg-icon [icon]=\"infoCircleIcon\" size=\"medium\"></kendo-svg-icon>\n <span>\n Please select\n @for (selector of unselectedToolbarSelectors(); track selector.id; let last = $last) {\n <strong>{{ selector.label }}</strong>@if (!last) {, }\n }\n to display dashboard data.\n </span>\n </div>\n }\n\n <!-- Variable Resolution Errors -->\n @if (variableResolutionErrors().length > 0) {\n <div class=\"variable-resolution-errors\">\n <strong>Variable resolution errors:</strong>\n @for (error of variableResolutionErrors(); track error.variableName) {\n <span class=\"error-item\">{{ error.variableName }}: {{ error.message }}</span>\n }\n </div>\n }\n\n <!-- Banner Zone: chromeless widgets rendered outside the grid -->\n @for (widget of bannerWidgets(); track trackByWidgetId($index, widget)) {\n <div class=\"banner-zone-item\" [class.banner-edit]=\"isEditMode()\">\n @if (isEditMode()) {\n <div class=\"banner-edit-header\">\n <span class=\"widget-title\">{{ widget.title }}</span>\n <div class=\"widget-actions\">\n @if (supportsConfiguration(widget)) {\n <button\n kendoButton\n [svgIcon]=\"linkIcon\"\n (click)=\"openWidgetConfig(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"config-widget-btn\"\n [class.needs-config]=\"isWidgetUnconfigured(widget)\"\n [title]=\"isWidgetUnconfigured(widget) ? 'Configure data source (required)' : 'Configure data source'\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openEditWidgetDialog(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"edit-widget-btn\"\n title=\"Edit position\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"removeWidget(widget.id)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"remove-widget-btn\"\n title=\"Delete widget\">\n </button>\n </div>\n </div>\n }\n @if (getWidgetComponentType(widget.type); as componentType) {\n <ng-container *ngComponentOutlet=\"componentType; inputs: { config: widget }\"></ng-container>\n }\n </div>\n }\n\n <!-- MeshBoard Grid -->\n @if (hasGridWidgets()) {\n <kendo-tilelayout\n [columns]=\"config().columns\"\n [rowHeight]=\"config().rowHeight\"\n [gap]=\"config().gap\"\n [class.has-banners]=\"bannerWidgets().length > 0 && !isEditMode()\"\n [resizable]=\"isEditMode()\"\n [reorderable]=\"isEditMode()\"\n (reorder)=\"onReorder($event)\"\n (resize)=\"onResize($event)\">\n @for (widget of gridWidgets(); track trackByWidgetId($index, widget)) {\n <kendo-tilelayout-item\n [col]=\"widget.col\"\n [row]=\"widget.row\"\n [colSpan]=\"widget.colSpan\"\n [rowSpan]=\"widget.rowSpan\">\n <kendo-tilelayout-item-header>\n <div class=\"widget-header\" [class.unconfigured]=\"isWidgetUnconfigured(widget)\">\n <span class=\"widget-title\">{{ widget.title }}</span>\n @if (isWidgetUnconfigured(widget) && !isEditMode()) {\n <span class=\"unconfigured-badge\" title=\"Widget needs configuration\">!</span>\n }\n @if (isEditMode()) {\n <div class=\"widget-actions\" (pointerdown)=\"$event.stopPropagation()\">\n @if (supportsConfiguration(widget)) {\n <button\n kendoButton\n [svgIcon]=\"linkIcon\"\n (click)=\"openWidgetConfig(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"config-widget-btn\"\n [class.needs-config]=\"isWidgetUnconfigured(widget)\"\n [title]=\"isWidgetUnconfigured(widget) ? 'Configure data source (required)' : 'Configure data source'\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openEditWidgetDialog(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"edit-widget-btn\"\n title=\"Edit position\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"copyIcon\"\n (click)=\"duplicateWidget(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"duplicate-widget-btn\"\n title=\"Duplicate widget\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"removeWidget(widget.id)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"remove-widget-btn\"\n title=\"Delete widget\">\n </button>\n </div>\n }\n </div>\n </kendo-tilelayout-item-header>\n <kendo-tilelayout-item-body>\n @if (getWidgetComponentType(widget.type); as componentType) {\n <ng-container *ngComponentOutlet=\"componentType; inputs: { config: widget }\"></ng-container>\n } @else {\n <div class=\"widget-error\">\n <p>Unknown widget type: {{ widget.type }}</p>\n </div>\n }\n </kendo-tilelayout-item-body>\n </kendo-tilelayout-item>\n }\n </kendo-tilelayout>\n } @else {\n <div class=\"empty-state\">\n <div class=\"empty-state-content\">\n <kendo-svg-icon [icon]=\"plusIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h3>No Widgets</h3>\n <p>Get started by adding widgets to your MeshBoard.</p>\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n themeColor=\"primary\">\n Add Your First Widget\n </button>\n </div>\n </div>\n }\n\n <!-- Edit Widget Dialog -->\n @if (showEditWidgetDialog && editingWidget) {\n <mm-edit-widget-dialog\n [widget]=\"editingWidget\"\n [widgets]=\"config().widgets\"\n [maxColumns]=\"config().columns\"\n [gridService]=\"gridService\"\n (save)=\"onEditWidgetSave($event)\"\n (cancelled)=\"closeEditWidgetDialog()\">\n </mm-edit-widget-dialog>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;height:100%;width:100%}.meshboard-view{display:flex;flex-direction:column;flex:1;min-height:0;width:100%;background-color:var(--kendo-color-surface, #f5f5f5)}.loading-container{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.entity-selector-hint{display:flex;align-items:center;gap:8px;padding:10px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-info, #2196f3) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid color-mix(in srgb,var(--kendo-color-info, #2196f3) 40%,transparent);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.entity-selector-hint strong{color:var(--kendo-color-info, #2196f3)}.variable-resolution-errors{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid var(--kendo-color-error, #f44336);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.variable-resolution-errors strong{color:var(--kendo-color-error, #f44336)}.variable-resolution-errors .error-item{padding:2px 8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 8%,transparent);border-radius:3px;font-family:Consolas,Monaco,monospace;font-size:12px}.model-unavailable{display:flex;align-items:center;justify-content:center;height:100%;width:100%;padding:2rem;overflow:hidden;box-sizing:border-box}.model-unavailable .message-card{text-align:center;max-width:500px;padding:2rem;background:var(--kendo-color-surface-alt, #fafafa);border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:8px;overflow:hidden}.model-unavailable .message-card kendo-svg-icon{color:var(--kendo-color-warning, #ff9800);margin-bottom:1rem}.model-unavailable .message-card h2{margin:1rem 0;color:var(--kendo-color-on-app-surface, #424242)}.model-unavailable .message-card p{margin:.5rem 0;color:var(--kendo-color-subtle, #757575);line-height:1.5}.model-unavailable .message-card ol{text-align:left;margin:1rem 0;padding-left:1.5rem;color:var(--kendo-color-subtle, #757575);line-height:1.8}.model-unavailable .message-card ol li{margin:.25rem 0}.model-unavailable .message-card ol a{color:var(--kendo-color-primary, #3f51b5);text-decoration:none}.model-unavailable .message-card ol a:hover{text-decoration:underline}.meshboard-toolbar{display:flex;justify-content:space-between;align-items:flex-end;padding:1rem 1.5rem;background-color:var(--kendo-color-surface-alt, white);border-bottom:1px solid var(--kendo-color-border, #e0e0e0);gap:1rem;flex-shrink:0}.meshboard-toolbar .toolbar-left{display:flex;align-items:baseline;gap:1rem;flex:1;min-width:0;align-self:center}.meshboard-toolbar .toolbar-left .meshboard-title{margin:0;font-size:1.5rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-left .meshboard-description{color:var(--kendo-color-subtle, #757575);font-size:.875rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-center{display:flex;justify-content:center;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-center mm-time-range-picker ::ng-deep .time-range-picker{gap:.5rem}.meshboard-toolbar .toolbar-separator{width:1px;align-self:stretch;background-color:var(--kendo-color-border, #e0e0e0);flex-shrink:0}.meshboard-toolbar .toolbar-entity-selectors{display:flex;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-right{display:flex;gap:.5rem;align-items:center;flex-shrink:0}.empty-state{display:flex;align-items:flex-start;justify-content:center;height:calc(100% - 80px);width:100%;padding-top:4rem}.empty-state .empty-state-content{text-align:center;padding:2rem}.empty-state .empty-state-content kendo-svg-icon{color:var(--kendo-color-subtle, #9e9e9e);margin-bottom:1rem}.empty-state .empty-state-content h3{margin:1rem 0 .5rem;color:var(--kendo-color-on-app-surface, #424242);font-size:1.25rem;font-weight:500}.empty-state .empty-state-content p{margin:0 0 1.5rem;color:var(--kendo-color-subtle, #757575)}kendo-tilelayout{padding:1.5rem;overflow:auto;flex:1;min-height:0}.widget-header{display:flex;justify-content:space-between;align-items:center;width:100%;gap:.5rem}.widget-header.unconfigured{background-color:#ff98001a}.widget-header .widget-title{flex:1;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.widget-header .unconfigured-badge{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background-color:var(--kendo-color-warning, #ff9800);color:#fff;font-size:12px;font-weight:700;flex-shrink:0}.widget-header .widget-actions{display:flex;align-items:center;gap:.25rem;flex-shrink:0}.widget-header .config-widget-btn,.widget-header .edit-widget-btn,.widget-header .remove-widget-btn{opacity:.6;transition:opacity .2s}.widget-header .config-widget-btn:hover,.widget-header .edit-widget-btn:hover,.widget-header .remove-widget-btn:hover{opacity:1}.widget-header .config-widget-btn.needs-config{color:var(--kendo-color-warning, #ff9800);opacity:1}.widget-header .remove-widget-btn{color:var(--kendo-color-error, #f44336)}.widget-error{display:flex;align-items:center;justify-content:center;height:100%;padding:1rem;color:var(--kendo-color-error, #f44336);text-align:center}.meshboard-view.edit-mode kendo-tilelayout-item:hover{box-shadow:0 0 0 2px var(--kendo-color-primary, #3f51b5)}@media(max-width:768px){.meshboard-toolbar{flex-direction:column;align-items:stretch;gap:.75rem}.meshboard-toolbar .toolbar-left{flex-direction:column;align-items:flex-start;gap:.25rem}.meshboard-toolbar .toolbar-right{flex-wrap:wrap;justify-content:flex-end}kendo-tilelayout{padding:1rem}}:host ::ng-deep kendo-tilelayout.has-banners{padding-top:0!important}:host ::ng-deep kendo-tilelayout{padding-bottom:1.5rem!important}.banner-zone-item{margin:0;padding:8px 1rem}.banner-zone-item.banner-edit{border:1px dashed var(--kendo-color-border, rgba(255, 255, 255, .2));border-radius:4px;margin:0 1rem 12px;padding:4px 0}.banner-edit-header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;opacity:.7}.banner-edit-header .widget-title{font-size:.75rem;text-transform:uppercase;letter-spacing:.5px}.banner-edit-header .widget-actions{display:flex;gap:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: TileLayoutModule }, { kind: "component", type: i5.TileLayoutComponent, selector: "kendo-tilelayout", inputs: ["columns", "columnWidth", "gap", "reorderable", "resizable", "rowHeight", "autoFlow", "navigable"], outputs: ["reorder", "resize"] }, { kind: "component", type: i5.TileLayoutItemBodyComponent, selector: "kendo-tilelayout-item-body" }, { kind: "component", type: i5.TileLayoutItemComponent, selector: "kendo-tilelayout-item", inputs: ["title", "rowSpan", "colSpan", "order", "col", "row", "reorderable", "resizable"] }, { kind: "component", type: i5.TileLayoutItemHeaderComponent, selector: "kendo-tilelayout-item-header" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i1$4.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: EditWidgetDialogComponent, selector: "mm-edit-widget-dialog", inputs: ["widget", "widgets", "maxColumns", "gridService"], outputs: ["save", "cancelled"] }, { kind: "component", type: TimeRangePickerComponent, selector: "mm-time-range-picker", inputs: ["config", "labels", "initialSelection"], outputs: ["rangeChange", "rangeChangeISO", "selectionChange"] }, { kind: "component", type: EntitySelectorToolbarComponent, selector: "mm-entity-selector-toolbar", inputs: ["entitySelectors"], outputs: ["entitySelected", "entityCleared"] }] });
|
|
26999
29064
|
}
|
|
27000
29065
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MeshBoardViewComponent, decorators: [{
|
|
27001
29066
|
type: Component,
|
|
@@ -27009,7 +29074,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
27009
29074
|
EditWidgetDialogComponent,
|
|
27010
29075
|
TimeRangePickerComponent,
|
|
27011
29076
|
EntitySelectorToolbarComponent
|
|
27012
|
-
], hostDirectives: [UnsavedChangesDirective], providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: MeshBoardViewComponent }], template: "<div class=\"meshboard-view\">\n @if (isLoading()) {\n <div class=\"loading-container\">\n <div class=\"k-loading-mask\">\n <span class=\"k-loading-text\">Loading MeshBoard...</span>\n <div class=\"k-loading-image\"></div>\n <div class=\"k-loading-color\"></div>\n </div>\n </div>\n } @else if (isModelAvailable() === false) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Available</h2>\n <p>The MeshBoard feature requires the CK model 'System.UI' version 1.0.1 or higher.</p>\n <p>Please install the required model in your tenant to use this feature.</p>\n </div>\n </div>\n } @else if (notFoundError()) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Found</h2>\n <p>{{ notFoundError() }}</p>\n <p>To create a MeshBoard with a Well-Known Name:</p>\n <ol>\n <li>Go to the <a [routerLink]=\"meshBoardPageLink()\">MeshBoard</a> page</li>\n <li>Open Settings</li>\n <li>Set the \"Well-Known Name\" field</li>\n <li>Save the MeshBoard</li>\n </ol>\n </div>\n </div>\n } @else if (isInitialized()) {\n <!-- Toolbar -->\n <div class=\"meshboard-toolbar\">\n <div class=\"toolbar-left\">\n <h2 class=\"meshboard-title\">{{ config().name }}</h2>\n @if (config().description) {\n <span class=\"meshboard-description\">{{ config().description }}</span>\n }\n </div>\n\n <!-- Time Filter (center) -->\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-center\">\n <mm-time-range-picker\n [config]=\"timeFilterConfig()?.pickerConfig ?? {}\"\n [labels]=\"timeRangeLabels()\"\n [initialSelection]=\"initialTimeSelection()\"\n (rangeChange)=\"onTimeRangeChange($event)\"\n (selectionChange)=\"onTimeSelectionChange($event)\">\n </mm-time-range-picker>\n @if (canResetTimeFilter()) {\n <button\n kendoButton\n [svgIcon]=\"undoIcon\"\n (click)=\"resetTimeFilterToDefault()\"\n title=\"Reset to default time filter\"\n fillMode=\"flat\"\n size=\"small\">\n </button>\n }\n </div>\n }\n\n <!-- Entity Selectors -->\n @if (hasEntitySelectors()) {\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-entity-selectors\">\n <mm-entity-selector-toolbar\n [entitySelectors]=\"entitySelectorsConfig()\"\n (entitySelected)=\"onEntitySelectorSelected($event)\"\n (entityCleared)=\"onEntitySelectorCleared($event)\">\n </mm-entity-selector-toolbar>\n </div>\n }\n\n @if (isTimeFilterEnabled() || hasEntitySelectors()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-right mm-toolbar-actions\">\n @if (!isReadonly()) {\n <!-- Manager Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gridLayoutIcon\"\n (click)=\"openManager()\"\n title=\"Manage MeshBoards\"\n fillMode=\"flat\">\n </button>\n\n <!-- Settings Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openSettings()\"\n title=\"MeshBoard Settings\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Refresh Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"arrowRotateCwIcon\"\n (click)=\"refresh()\"\n title=\"Refresh All Widgets\"\n fillMode=\"flat\">\n </button>\n\n @if (!isReadonly()) {\n <!-- Edit Mode Toggle (icon only) -->\n @if (!isEditMode()) {\n <button\n kendoButton\n [svgIcon]=\"pencilIcon\"\n (click)=\"toggleEditMode()\"\n title=\"Enter Edit Mode\"\n fillMode=\"flat\">\n </button>\n } @else {\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelEdit()\"\n title=\"Cancel Edit Mode\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Add Widget Button (with text) -->\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n title=\"Add Widget\"\n themeColor=\"primary\">\n Add Widget\n </button>\n\n <!-- Save Button (with text) -->\n @if (canSave()) {\n <button\n kendoButton\n [svgIcon]=\"saveIcon\"\n (click)=\"save()\"\n [disabled]=\"isSaving()\"\n title=\"Save MeshBoard\"\n themeColor=\"primary\">\n {{ isSaving() ? 'Saving...' : 'Save' }}\n </button>\n }\n }\n </div>\n </div>\n\n <!-- Entity Selector Hint -->\n @if (unselectedToolbarSelectors().length > 0) {\n <div class=\"entity-selector-hint\">\n <kendo-svg-icon [icon]=\"infoCircleIcon\" size=\"medium\"></kendo-svg-icon>\n <span>\n Please select\n @for (selector of unselectedToolbarSelectors(); track selector.id; let last = $last) {\n <strong>{{ selector.label }}</strong>@if (!last) {, }\n }\n to display dashboard data.\n </span>\n </div>\n }\n\n <!-- Variable Resolution Errors -->\n @if (variableResolutionErrors().length > 0) {\n <div class=\"variable-resolution-errors\">\n <strong>Variable resolution errors:</strong>\n @for (error of variableResolutionErrors(); track error.variableName) {\n <span class=\"error-item\">{{ error.variableName }}: {{ error.message }}</span>\n }\n </div>\n }\n\n <!-- MeshBoard Grid -->\n @if (hasWidgets()) {\n <kendo-tilelayout\n [columns]=\"config().columns\"\n [rowHeight]=\"config().rowHeight\"\n [gap]=\"config().gap\"\n [resizable]=\"isEditMode()\"\n [reorderable]=\"isEditMode()\"\n (reorder)=\"onReorder($event)\"\n (resize)=\"onResize($event)\">\n @for (widget of config().widgets; track trackByWidgetId($index, widget)) {\n <kendo-tilelayout-item\n [col]=\"widget.col\"\n [row]=\"widget.row\"\n [colSpan]=\"widget.colSpan\"\n [rowSpan]=\"widget.rowSpan\">\n <kendo-tilelayout-item-header>\n <div class=\"widget-header\" [class.unconfigured]=\"isWidgetUnconfigured(widget)\">\n <span class=\"widget-title\">{{ widget.title }}</span>\n @if (isWidgetUnconfigured(widget) && !isEditMode()) {\n <span class=\"unconfigured-badge\" title=\"Widget needs configuration\">!</span>\n }\n @if (isEditMode()) {\n <div class=\"widget-actions\" (pointerdown)=\"$event.stopPropagation()\">\n @if (supportsConfiguration(widget)) {\n <button\n kendoButton\n [svgIcon]=\"linkIcon\"\n (click)=\"openWidgetConfig(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"config-widget-btn\"\n [class.needs-config]=\"isWidgetUnconfigured(widget)\"\n [title]=\"isWidgetUnconfigured(widget) ? 'Configure data source (required)' : 'Configure data source'\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openEditWidgetDialog(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"edit-widget-btn\"\n title=\"Edit position\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"copyIcon\"\n (click)=\"duplicateWidget(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"duplicate-widget-btn\"\n title=\"Duplicate widget\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"removeWidget(widget.id)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"remove-widget-btn\"\n title=\"Delete widget\">\n </button>\n </div>\n }\n </div>\n </kendo-tilelayout-item-header>\n <kendo-tilelayout-item-body>\n @if (getWidgetComponentType(widget.type); as componentType) {\n <ng-container *ngComponentOutlet=\"componentType; inputs: { config: widget }\"></ng-container>\n } @else {\n <div class=\"widget-error\">\n <p>Unknown widget type: {{ widget.type }}</p>\n </div>\n }\n </kendo-tilelayout-item-body>\n </kendo-tilelayout-item>\n }\n </kendo-tilelayout>\n } @else {\n <div class=\"empty-state\">\n <div class=\"empty-state-content\">\n <kendo-svg-icon [icon]=\"plusIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h3>No Widgets</h3>\n <p>Get started by adding widgets to your MeshBoard.</p>\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n themeColor=\"primary\">\n Add Your First Widget\n </button>\n </div>\n </div>\n }\n\n <!-- Edit Widget Dialog -->\n @if (showEditWidgetDialog && editingWidget) {\n <mm-edit-widget-dialog\n [widget]=\"editingWidget\"\n [widgets]=\"config().widgets\"\n [maxColumns]=\"config().columns\"\n [gridService]=\"gridService\"\n (save)=\"onEditWidgetSave($event)\"\n (cancelled)=\"closeEditWidgetDialog()\">\n </mm-edit-widget-dialog>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;height:100%;width:100%}.meshboard-view{display:flex;flex-direction:column;flex:1;min-height:0;width:100%;background-color:var(--kendo-color-surface, #f5f5f5)}.loading-container{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.entity-selector-hint{display:flex;align-items:center;gap:8px;padding:10px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-info, #2196f3) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid color-mix(in srgb,var(--kendo-color-info, #2196f3) 40%,transparent);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.entity-selector-hint strong{color:var(--kendo-color-info, #2196f3)}.variable-resolution-errors{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid var(--kendo-color-error, #f44336);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.variable-resolution-errors strong{color:var(--kendo-color-error, #f44336)}.variable-resolution-errors .error-item{padding:2px 8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 8%,transparent);border-radius:3px;font-family:Consolas,Monaco,monospace;font-size:12px}.model-unavailable{display:flex;align-items:center;justify-content:center;height:100%;width:100%;padding:2rem;overflow:hidden;box-sizing:border-box}.model-unavailable .message-card{text-align:center;max-width:500px;padding:2rem;background:var(--kendo-color-surface-alt, #fafafa);border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:8px;overflow:hidden}.model-unavailable .message-card kendo-svg-icon{color:var(--kendo-color-warning, #ff9800);margin-bottom:1rem}.model-unavailable .message-card h2{margin:1rem 0;color:var(--kendo-color-on-app-surface, #424242)}.model-unavailable .message-card p{margin:.5rem 0;color:var(--kendo-color-subtle, #757575);line-height:1.5}.model-unavailable .message-card ol{text-align:left;margin:1rem 0;padding-left:1.5rem;color:var(--kendo-color-subtle, #757575);line-height:1.8}.model-unavailable .message-card ol li{margin:.25rem 0}.model-unavailable .message-card ol a{color:var(--kendo-color-primary, #3f51b5);text-decoration:none}.model-unavailable .message-card ol a:hover{text-decoration:underline}.meshboard-toolbar{display:flex;justify-content:space-between;align-items:flex-end;padding:1rem 1.5rem;background-color:var(--kendo-color-surface-alt, white);border-bottom:1px solid var(--kendo-color-border, #e0e0e0);gap:1rem;flex-shrink:0}.meshboard-toolbar .toolbar-left{display:flex;align-items:baseline;gap:1rem;flex:1;min-width:0;align-self:center}.meshboard-toolbar .toolbar-left .meshboard-title{margin:0;font-size:1.5rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-left .meshboard-description{color:var(--kendo-color-subtle, #757575);font-size:.875rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-center{display:flex;justify-content:center;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-center mm-time-range-picker ::ng-deep .time-range-picker{gap:.5rem}.meshboard-toolbar .toolbar-separator{width:1px;align-self:stretch;background-color:var(--kendo-color-border, #e0e0e0);flex-shrink:0}.meshboard-toolbar .toolbar-entity-selectors{display:flex;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-right{display:flex;gap:.5rem;align-items:center;flex-shrink:0}.empty-state{display:flex;align-items:flex-start;justify-content:center;height:calc(100% - 80px);width:100%;padding-top:4rem}.empty-state .empty-state-content{text-align:center;padding:2rem}.empty-state .empty-state-content kendo-svg-icon{color:var(--kendo-color-subtle, #9e9e9e);margin-bottom:1rem}.empty-state .empty-state-content h3{margin:1rem 0 .5rem;color:var(--kendo-color-on-app-surface, #424242);font-size:1.25rem;font-weight:500}.empty-state .empty-state-content p{margin:0 0 1.5rem;color:var(--kendo-color-subtle, #757575)}kendo-tilelayout{padding:1.5rem;overflow:auto;flex:1;min-height:0}.widget-header{display:flex;justify-content:space-between;align-items:center;width:100%;gap:.5rem}.widget-header.unconfigured{background-color:#ff98001a}.widget-header .widget-title{flex:1;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.widget-header .unconfigured-badge{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background-color:var(--kendo-color-warning, #ff9800);color:#fff;font-size:12px;font-weight:700;flex-shrink:0}.widget-header .widget-actions{display:flex;align-items:center;gap:.25rem;flex-shrink:0}.widget-header .config-widget-btn,.widget-header .edit-widget-btn,.widget-header .remove-widget-btn{opacity:.6;transition:opacity .2s}.widget-header .config-widget-btn:hover,.widget-header .edit-widget-btn:hover,.widget-header .remove-widget-btn:hover{opacity:1}.widget-header .config-widget-btn.needs-config{color:var(--kendo-color-warning, #ff9800);opacity:1}.widget-header .remove-widget-btn{color:var(--kendo-color-error, #f44336)}.widget-error{display:flex;align-items:center;justify-content:center;height:100%;padding:1rem;color:var(--kendo-color-error, #f44336);text-align:center}.meshboard-view.edit-mode kendo-tilelayout-item:hover{box-shadow:0 0 0 2px var(--kendo-color-primary, #3f51b5)}@media(max-width:768px){.meshboard-toolbar{flex-direction:column;align-items:stretch;gap:.75rem}.meshboard-toolbar .toolbar-left{flex-direction:column;align-items:flex-start;gap:.25rem}.meshboard-toolbar .toolbar-right{flex-wrap:wrap;justify-content:flex-end}kendo-tilelayout{padding:1rem}}\n"] }]
|
|
29077
|
+
], hostDirectives: [UnsavedChangesDirective], providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: MeshBoardViewComponent }], template: "<div class=\"meshboard-view\">\n @if (isLoading()) {\n <div class=\"loading-container\">\n <div class=\"k-loading-mask\">\n <span class=\"k-loading-text\">Loading MeshBoard...</span>\n <div class=\"k-loading-image\"></div>\n <div class=\"k-loading-color\"></div>\n </div>\n </div>\n } @else if (isModelAvailable() === false) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Available</h2>\n <p>The MeshBoard feature requires the CK model 'System.UI' version 1.0.1 or higher.</p>\n <p>Please install the required model in your tenant to use this feature.</p>\n </div>\n </div>\n } @else if (notFoundError()) {\n <div class=\"model-unavailable\">\n <div class=\"message-card\">\n <kendo-svg-icon [icon]=\"xIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h2>MeshBoard Not Found</h2>\n <p>{{ notFoundError() }}</p>\n <p>To create a MeshBoard with a Well-Known Name:</p>\n <ol>\n <li>Go to the <a [routerLink]=\"meshBoardPageLink()\">MeshBoard</a> page</li>\n <li>Open Settings</li>\n <li>Set the \"Well-Known Name\" field</li>\n <li>Save the MeshBoard</li>\n </ol>\n </div>\n </div>\n } @else if (isInitialized()) {\n <!-- Toolbar -->\n <div class=\"meshboard-toolbar\">\n <div class=\"toolbar-left\">\n <h2 class=\"meshboard-title\">{{ config().name }}</h2>\n @if (config().description) {\n <span class=\"meshboard-description\">{{ config().description }}</span>\n }\n </div>\n\n <!-- Time Filter (center) -->\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-center\">\n <mm-time-range-picker\n [config]=\"timeFilterConfig()?.pickerConfig ?? {}\"\n [labels]=\"timeRangeLabels()\"\n [initialSelection]=\"initialTimeSelection()\"\n (rangeChange)=\"onTimeRangeChange($event)\"\n (selectionChange)=\"onTimeSelectionChange($event)\">\n </mm-time-range-picker>\n @if (canResetTimeFilter()) {\n <button\n kendoButton\n [svgIcon]=\"undoIcon\"\n (click)=\"resetTimeFilterToDefault()\"\n title=\"Reset to default time filter\"\n fillMode=\"flat\"\n size=\"small\">\n </button>\n }\n </div>\n }\n\n <!-- Entity Selectors -->\n @if (hasEntitySelectors()) {\n @if (isTimeFilterEnabled()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-entity-selectors\">\n <mm-entity-selector-toolbar\n [entitySelectors]=\"entitySelectorsConfig()\"\n (entitySelected)=\"onEntitySelectorSelected($event)\"\n (entityCleared)=\"onEntitySelectorCleared($event)\">\n </mm-entity-selector-toolbar>\n </div>\n }\n\n @if (isTimeFilterEnabled() || hasEntitySelectors()) {\n <div class=\"toolbar-separator\"></div>\n }\n <div class=\"toolbar-right mm-toolbar-actions\">\n @if (!isReadonly()) {\n <!-- Manager Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gridLayoutIcon\"\n (click)=\"openManager()\"\n title=\"Manage MeshBoards\"\n fillMode=\"flat\">\n </button>\n\n <!-- Settings Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openSettings()\"\n title=\"MeshBoard Settings\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Refresh Button (icon only) -->\n <button\n kendoButton\n [svgIcon]=\"arrowRotateCwIcon\"\n (click)=\"refresh()\"\n title=\"Refresh All Widgets\"\n fillMode=\"flat\">\n </button>\n\n @if (!isReadonly()) {\n <!-- Edit Mode Toggle (icon only) -->\n @if (!isEditMode()) {\n <button\n kendoButton\n [svgIcon]=\"pencilIcon\"\n (click)=\"toggleEditMode()\"\n title=\"Enter Edit Mode\"\n fillMode=\"flat\">\n </button>\n } @else {\n <button\n kendoButton\n [svgIcon]=\"xIcon\"\n (click)=\"cancelEdit()\"\n title=\"Cancel Edit Mode\"\n fillMode=\"flat\">\n </button>\n }\n\n <!-- Add Widget Button (with text) -->\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n title=\"Add Widget\"\n themeColor=\"primary\">\n Add Widget\n </button>\n\n <!-- Save Button (with text) -->\n @if (canSave()) {\n <button\n kendoButton\n [svgIcon]=\"saveIcon\"\n (click)=\"save()\"\n [disabled]=\"isSaving()\"\n title=\"Save MeshBoard\"\n themeColor=\"primary\">\n {{ isSaving() ? 'Saving...' : 'Save' }}\n </button>\n }\n }\n </div>\n </div>\n\n <!-- Entity Selector Hint -->\n @if (unselectedToolbarSelectors().length > 0) {\n <div class=\"entity-selector-hint\">\n <kendo-svg-icon [icon]=\"infoCircleIcon\" size=\"medium\"></kendo-svg-icon>\n <span>\n Please select\n @for (selector of unselectedToolbarSelectors(); track selector.id; let last = $last) {\n <strong>{{ selector.label }}</strong>@if (!last) {, }\n }\n to display dashboard data.\n </span>\n </div>\n }\n\n <!-- Variable Resolution Errors -->\n @if (variableResolutionErrors().length > 0) {\n <div class=\"variable-resolution-errors\">\n <strong>Variable resolution errors:</strong>\n @for (error of variableResolutionErrors(); track error.variableName) {\n <span class=\"error-item\">{{ error.variableName }}: {{ error.message }}</span>\n }\n </div>\n }\n\n <!-- Banner Zone: chromeless widgets rendered outside the grid -->\n @for (widget of bannerWidgets(); track trackByWidgetId($index, widget)) {\n <div class=\"banner-zone-item\" [class.banner-edit]=\"isEditMode()\">\n @if (isEditMode()) {\n <div class=\"banner-edit-header\">\n <span class=\"widget-title\">{{ widget.title }}</span>\n <div class=\"widget-actions\">\n @if (supportsConfiguration(widget)) {\n <button\n kendoButton\n [svgIcon]=\"linkIcon\"\n (click)=\"openWidgetConfig(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"config-widget-btn\"\n [class.needs-config]=\"isWidgetUnconfigured(widget)\"\n [title]=\"isWidgetUnconfigured(widget) ? 'Configure data source (required)' : 'Configure data source'\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openEditWidgetDialog(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"edit-widget-btn\"\n title=\"Edit position\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"removeWidget(widget.id)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"remove-widget-btn\"\n title=\"Delete widget\">\n </button>\n </div>\n </div>\n }\n @if (getWidgetComponentType(widget.type); as componentType) {\n <ng-container *ngComponentOutlet=\"componentType; inputs: { config: widget }\"></ng-container>\n }\n </div>\n }\n\n <!-- MeshBoard Grid -->\n @if (hasGridWidgets()) {\n <kendo-tilelayout\n [columns]=\"config().columns\"\n [rowHeight]=\"config().rowHeight\"\n [gap]=\"config().gap\"\n [class.has-banners]=\"bannerWidgets().length > 0 && !isEditMode()\"\n [resizable]=\"isEditMode()\"\n [reorderable]=\"isEditMode()\"\n (reorder)=\"onReorder($event)\"\n (resize)=\"onResize($event)\">\n @for (widget of gridWidgets(); track trackByWidgetId($index, widget)) {\n <kendo-tilelayout-item\n [col]=\"widget.col\"\n [row]=\"widget.row\"\n [colSpan]=\"widget.colSpan\"\n [rowSpan]=\"widget.rowSpan\">\n <kendo-tilelayout-item-header>\n <div class=\"widget-header\" [class.unconfigured]=\"isWidgetUnconfigured(widget)\">\n <span class=\"widget-title\">{{ widget.title }}</span>\n @if (isWidgetUnconfigured(widget) && !isEditMode()) {\n <span class=\"unconfigured-badge\" title=\"Widget needs configuration\">!</span>\n }\n @if (isEditMode()) {\n <div class=\"widget-actions\" (pointerdown)=\"$event.stopPropagation()\">\n @if (supportsConfiguration(widget)) {\n <button\n kendoButton\n [svgIcon]=\"linkIcon\"\n (click)=\"openWidgetConfig(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"config-widget-btn\"\n [class.needs-config]=\"isWidgetUnconfigured(widget)\"\n [title]=\"isWidgetUnconfigured(widget) ? 'Configure data source (required)' : 'Configure data source'\">\n </button>\n }\n <button\n kendoButton\n [svgIcon]=\"gearIcon\"\n (click)=\"openEditWidgetDialog(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"edit-widget-btn\"\n title=\"Edit position\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"copyIcon\"\n (click)=\"duplicateWidget(widget)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"duplicate-widget-btn\"\n title=\"Duplicate widget\">\n </button>\n <button\n kendoButton\n [svgIcon]=\"trashIcon\"\n (click)=\"removeWidget(widget.id)\"\n fillMode=\"flat\"\n size=\"small\"\n class=\"remove-widget-btn\"\n title=\"Delete widget\">\n </button>\n </div>\n }\n </div>\n </kendo-tilelayout-item-header>\n <kendo-tilelayout-item-body>\n @if (getWidgetComponentType(widget.type); as componentType) {\n <ng-container *ngComponentOutlet=\"componentType; inputs: { config: widget }\"></ng-container>\n } @else {\n <div class=\"widget-error\">\n <p>Unknown widget type: {{ widget.type }}</p>\n </div>\n }\n </kendo-tilelayout-item-body>\n </kendo-tilelayout-item>\n }\n </kendo-tilelayout>\n } @else {\n <div class=\"empty-state\">\n <div class=\"empty-state-content\">\n <kendo-svg-icon [icon]=\"plusIcon\" size=\"xlarge\"></kendo-svg-icon>\n <h3>No Widgets</h3>\n <p>Get started by adding widgets to your MeshBoard.</p>\n <button\n kendoButton\n [svgIcon]=\"plusIcon\"\n (click)=\"openAddWidget()\"\n themeColor=\"primary\">\n Add Your First Widget\n </button>\n </div>\n </div>\n }\n\n <!-- Edit Widget Dialog -->\n @if (showEditWidgetDialog && editingWidget) {\n <mm-edit-widget-dialog\n [widget]=\"editingWidget\"\n [widgets]=\"config().widgets\"\n [maxColumns]=\"config().columns\"\n [gridService]=\"gridService\"\n (save)=\"onEditWidgetSave($event)\"\n (cancelled)=\"closeEditWidgetDialog()\">\n </mm-edit-widget-dialog>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;height:100%;width:100%}.meshboard-view{display:flex;flex-direction:column;flex:1;min-height:0;width:100%;background-color:var(--kendo-color-surface, #f5f5f5)}.loading-container{display:flex;align-items:center;justify-content:center;height:100%;width:100%}.entity-selector-hint{display:flex;align-items:center;gap:8px;padding:10px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-info, #2196f3) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid color-mix(in srgb,var(--kendo-color-info, #2196f3) 40%,transparent);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.entity-selector-hint strong{color:var(--kendo-color-info, #2196f3)}.variable-resolution-errors{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 16px;margin-bottom:8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 10%,var(--kendo-color-surface-alt, #fafafa));border:1px solid var(--kendo-color-error, #f44336);border-radius:4px;font-size:13px;color:var(--kendo-color-on-app-surface, #424242)}.variable-resolution-errors strong{color:var(--kendo-color-error, #f44336)}.variable-resolution-errors .error-item{padding:2px 8px;background:color-mix(in srgb,var(--kendo-color-error, #f44336) 8%,transparent);border-radius:3px;font-family:Consolas,Monaco,monospace;font-size:12px}.model-unavailable{display:flex;align-items:center;justify-content:center;height:100%;width:100%;padding:2rem;overflow:hidden;box-sizing:border-box}.model-unavailable .message-card{text-align:center;max-width:500px;padding:2rem;background:var(--kendo-color-surface-alt, #fafafa);border:1px solid var(--kendo-color-border, #e0e0e0);border-radius:8px;overflow:hidden}.model-unavailable .message-card kendo-svg-icon{color:var(--kendo-color-warning, #ff9800);margin-bottom:1rem}.model-unavailable .message-card h2{margin:1rem 0;color:var(--kendo-color-on-app-surface, #424242)}.model-unavailable .message-card p{margin:.5rem 0;color:var(--kendo-color-subtle, #757575);line-height:1.5}.model-unavailable .message-card ol{text-align:left;margin:1rem 0;padding-left:1.5rem;color:var(--kendo-color-subtle, #757575);line-height:1.8}.model-unavailable .message-card ol li{margin:.25rem 0}.model-unavailable .message-card ol a{color:var(--kendo-color-primary, #3f51b5);text-decoration:none}.model-unavailable .message-card ol a:hover{text-decoration:underline}.meshboard-toolbar{display:flex;justify-content:space-between;align-items:flex-end;padding:1rem 1.5rem;background-color:var(--kendo-color-surface-alt, white);border-bottom:1px solid var(--kendo-color-border, #e0e0e0);gap:1rem;flex-shrink:0}.meshboard-toolbar .toolbar-left{display:flex;align-items:baseline;gap:1rem;flex:1;min-width:0;align-self:center}.meshboard-toolbar .toolbar-left .meshboard-title{margin:0;font-size:1.5rem;font-weight:500;color:var(--kendo-color-on-app-surface, #212121);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-left .meshboard-description{color:var(--kendo-color-subtle, #757575);font-size:.875rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meshboard-toolbar .toolbar-center{display:flex;justify-content:center;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-center mm-time-range-picker ::ng-deep .time-range-picker{gap:.5rem}.meshboard-toolbar .toolbar-separator{width:1px;align-self:stretch;background-color:var(--kendo-color-border, #e0e0e0);flex-shrink:0}.meshboard-toolbar .toolbar-entity-selectors{display:flex;align-items:flex-end;flex-shrink:0}.meshboard-toolbar .toolbar-right{display:flex;gap:.5rem;align-items:center;flex-shrink:0}.empty-state{display:flex;align-items:flex-start;justify-content:center;height:calc(100% - 80px);width:100%;padding-top:4rem}.empty-state .empty-state-content{text-align:center;padding:2rem}.empty-state .empty-state-content kendo-svg-icon{color:var(--kendo-color-subtle, #9e9e9e);margin-bottom:1rem}.empty-state .empty-state-content h3{margin:1rem 0 .5rem;color:var(--kendo-color-on-app-surface, #424242);font-size:1.25rem;font-weight:500}.empty-state .empty-state-content p{margin:0 0 1.5rem;color:var(--kendo-color-subtle, #757575)}kendo-tilelayout{padding:1.5rem;overflow:auto;flex:1;min-height:0}.widget-header{display:flex;justify-content:space-between;align-items:center;width:100%;gap:.5rem}.widget-header.unconfigured{background-color:#ff98001a}.widget-header .widget-title{flex:1;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.widget-header .unconfigured-badge{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background-color:var(--kendo-color-warning, #ff9800);color:#fff;font-size:12px;font-weight:700;flex-shrink:0}.widget-header .widget-actions{display:flex;align-items:center;gap:.25rem;flex-shrink:0}.widget-header .config-widget-btn,.widget-header .edit-widget-btn,.widget-header .remove-widget-btn{opacity:.6;transition:opacity .2s}.widget-header .config-widget-btn:hover,.widget-header .edit-widget-btn:hover,.widget-header .remove-widget-btn:hover{opacity:1}.widget-header .config-widget-btn.needs-config{color:var(--kendo-color-warning, #ff9800);opacity:1}.widget-header .remove-widget-btn{color:var(--kendo-color-error, #f44336)}.widget-error{display:flex;align-items:center;justify-content:center;height:100%;padding:1rem;color:var(--kendo-color-error, #f44336);text-align:center}.meshboard-view.edit-mode kendo-tilelayout-item:hover{box-shadow:0 0 0 2px var(--kendo-color-primary, #3f51b5)}@media(max-width:768px){.meshboard-toolbar{flex-direction:column;align-items:stretch;gap:.75rem}.meshboard-toolbar .toolbar-left{flex-direction:column;align-items:flex-start;gap:.25rem}.meshboard-toolbar .toolbar-right{flex-wrap:wrap;justify-content:flex-end}kendo-tilelayout{padding:1rem}}:host ::ng-deep kendo-tilelayout.has-banners{padding-top:0!important}:host ::ng-deep kendo-tilelayout{padding-bottom:1.5rem!important}.banner-zone-item{margin:0;padding:8px 1rem}.banner-zone-item.banner-edit{border:1px dashed var(--kendo-color-border, rgba(255, 255, 255, .2));border-radius:4px;margin:0 1rem 12px;padding:4px 0}.banner-edit-header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;opacity:.7}.banner-edit-header .widget-title{font-size:.75rem;text-transform:uppercase;letter-spacing:.5px}.banner-edit-header .widget-actions{display:flex;gap:2px}\n"] }]
|
|
27013
29078
|
}], ctorParameters: () => [] });
|
|
27014
29079
|
|
|
27015
29080
|
/*
|
|
@@ -27021,5 +29086,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
27021
29086
|
* Generated bundle index. Do not edit.
|
|
27022
29087
|
*/
|
|
27023
29088
|
|
|
27024
|
-
export { AddWidgetDialogComponent, AssociationsConfigDialogComponent, BarChartConfigDialogComponent, BarChartWidgetComponent, DashboardDataService, DashboardGridService, EditModeStateService, EditWidgetDialogComponent, EntityAssociationsWidgetComponent, EntityCardConfigDialogComponent, EntityCardWidgetComponent, EntityDetailDialogComponent, EntitySelectorEditorComponent, EntitySelectorToolbarComponent, GaugeConfigDialogComponent, GaugeWidgetComponent, HeatmapConfigDialogComponent, HeatmapWidgetComponent, KpiConfigDialogComponent, KpiWidgetComponent, LineChartConfigDialogComponent, LineChartWidgetComponent, MESHBOARD_OPTIONS, MESHBOARD_TENANT_ID_PROVIDER, MarkdownConfigDialogComponent, MarkdownWidgetComponent, MeshBoardDataService, MeshBoardGridService, MeshBoardManagerDialogComponent, MeshBoardPersistenceService, MeshBoardSettingsDialogComponent, MeshBoardSettingsResult, MeshBoardStateService, MeshBoardViewComponent, PieChartConfigDialogComponent, PieChartWidgetComponent, QuerySelectorComponent, RuntimeEntitySelectorComponent, ServiceHealthConfigDialogComponent, ServiceHealthWidgetComponent, StatsGridConfigDialogComponent, StatsGridWidgetComponent, StatusIndicatorConfigDialogComponent, StatusIndicatorWidgetComponent, TableConfigDialogComponent, TableWidgetComponent, TableWidgetDataSourceDirective, WidgetFactoryService, WidgetGroupComponent, WidgetGroupConfigDialogComponent, WidgetNotConfiguredComponent, WidgetRegistryService, provideDefaultWidgets, provideMeshBoard, provideProcessWidget, provideWidgetRegistrations, registerDefaultWidgets, registerProcessWidget };
|
|
29089
|
+
export { AddWidgetDialogComponent, AiInsightsConfigDialogComponent, AiInsightsService, AiInsightsWidgetComponent, AlertBannerConfigDialogComponent, AlertBannerWidgetComponent, AlertListConfigDialogComponent, AlertListWidgetComponent, AssociationsConfigDialogComponent, BarChartConfigDialogComponent, BarChartWidgetComponent, DashboardDataService, DashboardGridService, EditModeStateService, EditWidgetDialogComponent, EntityAssociationsWidgetComponent, EntityCardConfigDialogComponent, EntityCardWidgetComponent, EntityDetailDialogComponent, EntitySelectorEditorComponent, EntitySelectorToolbarComponent, GaugeConfigDialogComponent, GaugeWidgetComponent, HeatmapConfigDialogComponent, HeatmapWidgetComponent, KpiConfigDialogComponent, KpiWidgetComponent, LineChartConfigDialogComponent, LineChartWidgetComponent, MESHBOARD_OPTIONS, MESHBOARD_TENANT_ID_PROVIDER, MarkdownConfigDialogComponent, MarkdownWidgetComponent, MeshBoardDataService, MeshBoardGridService, MeshBoardManagerDialogComponent, MeshBoardPersistenceService, MeshBoardSettingsDialogComponent, MeshBoardSettingsResult, MeshBoardStateService, MeshBoardViewComponent, PieChartConfigDialogComponent, PieChartWidgetComponent, QuerySelectorComponent, RuntimeEntitySelectorComponent, ServiceHealthConfigDialogComponent, ServiceHealthWidgetComponent, StatsGridConfigDialogComponent, StatsGridWidgetComponent, StatusIndicatorConfigDialogComponent, StatusIndicatorWidgetComponent, StatusListConfigDialogComponent, StatusListWidgetComponent, SummaryCardConfigDialogComponent, SummaryCardWidgetComponent, TableConfigDialogComponent, TableWidgetComponent, TableWidgetDataSourceDirective, WidgetFactoryService, WidgetGroupComponent, WidgetGroupConfigDialogComponent, WidgetNotConfiguredComponent, WidgetRegistryService, provideDefaultWidgets, provideMeshBoard, provideProcessWidget, provideWidgetRegistrations, registerDefaultWidgets, registerProcessWidget };
|
|
27025
29090
|
//# sourceMappingURL=meshmakers-octo-meshboard.mjs.map
|