@c8y/ngx-components 1024.16.19 → 1024.18.0

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.
Files changed (29) hide show
  1. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +14 -4
  2. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
  3. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +1 -1
  4. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  5. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +1 -1
  6. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  7. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +77 -20
  8. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-widgets-definitions-linear-gauge.mjs +4 -3
  10. package/fesm2022/c8y-ngx-components-widgets-definitions-linear-gauge.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-notes.mjs +29 -7
  12. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-notes.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +24 -24
  14. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1 -1
  16. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components.mjs +159 -75
  18. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  19. package/locales/locales.pot +31 -17
  20. package/package.json +1 -1
  21. package/types/c8y-ngx-components-ai-agent-chat.d.ts +8 -1
  22. package/types/c8y-ngx-components-ai-agent-chat.d.ts.map +1 -1
  23. package/types/c8y-ngx-components-repository-configuration.d.ts +20 -4
  24. package/types/c8y-ngx-components-repository-configuration.d.ts.map +1 -1
  25. package/types/c8y-ngx-components-widgets-definitions-linear-gauge.d.ts.map +1 -1
  26. package/types/c8y-ngx-components-widgets-implementations-asset-notes.d.ts +7 -0
  27. package/types/c8y-ngx-components-widgets-implementations-asset-notes.d.ts.map +1 -1
  28. package/types/c8y-ngx-components.d.ts +80 -23
  29. package/types/c8y-ngx-components.d.ts.map +1 -1
@@ -76,11 +76,12 @@ const siloWidgetDefinition = {
76
76
  }
77
77
  }
78
78
  };
79
+ const LINEAR_GAUGE_WIDGET_IDS = [defaultWidgetIds.LINEAR_GAUGE, defaultWidgetIds.SILO];
79
80
  const linearGaugeWidgetProviders = [
80
81
  hookWidget(linearGaugeWidgetDefinition),
81
82
  hookWidget(siloWidgetDefinition),
82
- hookWidgetConfig({
83
- widgetId: defaultWidgetIds.LINEAR_GAUGE,
83
+ ...LINEAR_GAUGE_WIDGET_IDS.map(widgetId => hookWidgetConfig({
84
+ widgetId,
84
85
  label: gettext('Data point selection'),
85
86
  loadComponent: () => import('@c8y/ngx-components/datapoint-selector').then(m => m.WidgetDatapointsSelectorComponent),
86
87
  initialState: {
@@ -90,7 +91,7 @@ const linearGaugeWidgetProviders = [
90
91
  },
91
92
  expanded: true,
92
93
  priority: 80
93
- })
94
+ }))
94
95
  ];
95
96
 
96
97
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-widgets-definitions-linear-gauge.mjs","sources":["../../widgets/definitions/linear-gauge/linear-gauge.constants.ts","../../widgets/definitions/linear-gauge/index.ts","../../widgets/definitions/linear-gauge/c8y-ngx-components-widgets-definitions-linear-gauge.ts"],"sourcesContent":["import { DatapointAttributesFormConfig } from '@c8y/ngx-components/datapoint-selector';\n\nexport const LINEAR_GAUGE_OPTIONS: Partial<DatapointAttributesFormConfig> = {\n showRedRange: true,\n showYellowRange: true,\n showRange: true,\n showTarget: true\n};\n","import type { DynamicWidgetDefinition } from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport {\n DynamicComponentErrorStrategy,\n DynamicDatapointsResolver,\n hookWidget\n} from '@c8y/ngx-components';\nimport { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';\nimport {\n exportConfigWithTargets,\n importConfigWithTargets\n} from '@c8y/ngx-components/widgets/import-export-config';\nimport { hookWidgetConfig } from '@c8y/ngx-components/context-dashboard';\nimport { LINEAR_GAUGE_OPTIONS } from './linear-gauge.constants';\n\nexport const linearGaugeWidgetDefinition = {\n id: defaultWidgetIds.LINEAR_GAUGE,\n label: gettext('Linear Gauge'),\n description: gettext('A linear gauge graph displaying current values for selected measurements'),\n loadComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetViewComponent\n ),\n loadConfigComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetConfigComponent\n ),\n previewImage: 'c8y-style-assets/linear-gauge-widget-pr.png',\n resolve: {\n datapoints: DynamicDatapointsResolver\n },\n errorStrategy: DynamicComponentErrorStrategy.OVERLAY_ERROR,\n data: {\n schema: () =>\n import(\n 'c8y-schema-loader?interfaceName=LinearGaugeWidgetConfig&type=widget-config!@c8y/ngx-components/widgets/implementations/linear-gauge'\n ),\n export: exportConfigWithTargets,\n import: importConfigWithTargets,\n settings: {\n noNewWidgets: false,\n widgetDefaults: {\n _width: 6,\n _height: 4\n },\n ng1: {\n options: {\n noDeviceTarget: true,\n groupsSelectable: false\n }\n }\n }\n }\n} satisfies DynamicWidgetDefinition;\n\n/**\n * Backwards-compat definition for the legacy silo gauge widget (id: 'KPI Silo').\n * Existing dashboards are rendered as a linear gauge with the 'vertical' option selected.\n * No new widgets of this type can be created.\n */\nexport const siloWidgetDefinition = {\n id: defaultWidgetIds.SILO,\n label: gettext('Silo'),\n description: gettext('A silo displaying current values for selected measurements'),\n loadComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetViewComponent\n ),\n loadConfigComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetConfigComponent\n ),\n previewImage: 'c8y-style-assets/silo-widget-pr.png',\n resolve: {\n datapoints: DynamicDatapointsResolver\n },\n errorStrategy: DynamicComponentErrorStrategy.OVERLAY_ERROR,\n data: {\n schema: () =>\n import(\n 'c8y-schema-loader?interfaceName=LinearGaugeWidgetConfig&type=widget-config!@c8y/ngx-components/widgets/implementations/linear-gauge'\n ),\n export: exportConfigWithTargets,\n import: importConfigWithTargets,\n settings: {\n noNewWidgets: true,\n widgetDefaults: {\n _width: 4,\n _height: 4\n },\n ng1: {\n options: {\n noDeviceTarget: true,\n groupsSelectable: false\n }\n }\n }\n }\n} satisfies DynamicWidgetDefinition;\n\nexport const linearGaugeWidgetProviders = [\n hookWidget(linearGaugeWidgetDefinition),\n hookWidget(siloWidgetDefinition),\n hookWidgetConfig({\n widgetId: defaultWidgetIds.LINEAR_GAUGE,\n label: gettext('Data point selection'),\n loadComponent: () =>\n import('@c8y/ngx-components/datapoint-selector').then(\n m => m.WidgetDatapointsSelectorComponent\n ),\n initialState: {\n minActiveCount: 1,\n maxActiveCount: 1,\n defaultFormOptions: LINEAR_GAUGE_OPTIONS\n },\n expanded: true,\n priority: 80\n })\n];\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-widgets-definitions-linear-gauge.mjs","sources":["../../widgets/definitions/linear-gauge/linear-gauge.constants.ts","../../widgets/definitions/linear-gauge/index.ts","../../widgets/definitions/linear-gauge/c8y-ngx-components-widgets-definitions-linear-gauge.ts"],"sourcesContent":["import { DatapointAttributesFormConfig } from '@c8y/ngx-components/datapoint-selector';\n\nexport const LINEAR_GAUGE_OPTIONS: Partial<DatapointAttributesFormConfig> = {\n showRedRange: true,\n showYellowRange: true,\n showRange: true,\n showTarget: true\n};\n","import type { DynamicWidgetDefinition } from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport {\n DynamicComponentErrorStrategy,\n DynamicDatapointsResolver,\n hookWidget\n} from '@c8y/ngx-components';\nimport { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';\nimport {\n exportConfigWithTargets,\n importConfigWithTargets\n} from '@c8y/ngx-components/widgets/import-export-config';\nimport { hookWidgetConfig } from '@c8y/ngx-components/context-dashboard';\nimport { LINEAR_GAUGE_OPTIONS } from './linear-gauge.constants';\n\nexport const linearGaugeWidgetDefinition = {\n id: defaultWidgetIds.LINEAR_GAUGE,\n label: gettext('Linear Gauge'),\n description: gettext('A linear gauge graph displaying current values for selected measurements'),\n loadComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetViewComponent\n ),\n loadConfigComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetConfigComponent\n ),\n previewImage: 'c8y-style-assets/linear-gauge-widget-pr.png',\n resolve: {\n datapoints: DynamicDatapointsResolver\n },\n errorStrategy: DynamicComponentErrorStrategy.OVERLAY_ERROR,\n data: {\n schema: () =>\n import(\n 'c8y-schema-loader?interfaceName=LinearGaugeWidgetConfig&type=widget-config!@c8y/ngx-components/widgets/implementations/linear-gauge'\n ),\n export: exportConfigWithTargets,\n import: importConfigWithTargets,\n settings: {\n noNewWidgets: false,\n widgetDefaults: {\n _width: 6,\n _height: 4\n },\n ng1: {\n options: {\n noDeviceTarget: true,\n groupsSelectable: false\n }\n }\n }\n }\n} satisfies DynamicWidgetDefinition;\n\n/**\n * Backwards-compat definition for the legacy silo gauge widget (id: 'KPI Silo').\n * Existing dashboards are rendered as a linear gauge with the 'vertical' option selected.\n * No new widgets of this type can be created.\n */\nexport const siloWidgetDefinition = {\n id: defaultWidgetIds.SILO,\n label: gettext('Silo'),\n description: gettext('A silo displaying current values for selected measurements'),\n loadComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetViewComponent\n ),\n loadConfigComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/linear-gauge').then(\n m => m.LinearGaugeWidgetConfigComponent\n ),\n previewImage: 'c8y-style-assets/silo-widget-pr.png',\n resolve: {\n datapoints: DynamicDatapointsResolver\n },\n errorStrategy: DynamicComponentErrorStrategy.OVERLAY_ERROR,\n data: {\n schema: () =>\n import(\n 'c8y-schema-loader?interfaceName=LinearGaugeWidgetConfig&type=widget-config!@c8y/ngx-components/widgets/implementations/linear-gauge'\n ),\n export: exportConfigWithTargets,\n import: importConfigWithTargets,\n settings: {\n noNewWidgets: true,\n widgetDefaults: {\n _width: 4,\n _height: 4\n },\n ng1: {\n options: {\n noDeviceTarget: true,\n groupsSelectable: false\n }\n }\n }\n }\n} satisfies DynamicWidgetDefinition;\n\nconst LINEAR_GAUGE_WIDGET_IDS = [defaultWidgetIds.LINEAR_GAUGE, defaultWidgetIds.SILO];\n\nexport const linearGaugeWidgetProviders = [\n hookWidget(linearGaugeWidgetDefinition),\n hookWidget(siloWidgetDefinition),\n ...LINEAR_GAUGE_WIDGET_IDS.map(widgetId =>\n hookWidgetConfig({\n widgetId,\n label: gettext('Data point selection'),\n loadComponent: () =>\n import('@c8y/ngx-components/datapoint-selector').then(\n m => m.WidgetDatapointsSelectorComponent\n ),\n initialState: {\n minActiveCount: 1,\n maxActiveCount: 1,\n defaultFormOptions: LINEAR_GAUGE_OPTIONS\n },\n expanded: true,\n priority: 80\n })\n )\n];\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,13 +1,13 @@
1
- import * as i2 from '@angular/common';
1
+ import * as i3 from '@angular/common';
2
2
  import { CommonModule as CommonModule$1 } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { inject, input, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
5
- import * as i3 from '@angular/forms';
5
+ import * as i2 from '@angular/forms';
6
6
  import { FormsModule } from '@angular/forms';
7
7
  import { InventoryService } from '@c8y/client';
8
8
  import { gettext } from '@c8y/ngx-components/gettext';
9
9
  import * as i1 from '@c8y/ngx-components';
10
- import { AppStateService, AlertService, DatePipe, CommonModule, CoreModule, FormsModule as FormsModule$1 } from '@c8y/ngx-components';
10
+ import { AppStateService, AlertService, DatePipe, ContextRouteService, CommonModule, CoreModule, FormsModule as FormsModule$1 } from '@c8y/ngx-components';
11
11
 
12
12
  class AssetNotesWidgetComponent {
13
13
  constructor() {
@@ -15,6 +15,7 @@ class AssetNotesWidgetComponent {
15
15
  this.appState = inject(AppStateService);
16
16
  this.alertService = inject(AlertService);
17
17
  this.datePipe = inject(DatePipe);
18
+ this.contextRoute = inject(ContextRouteService);
18
19
  this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
19
20
  this.notes = signal(null, ...(ngDevMode ? [{ debugName: "notes" }] : /* istanbul ignore next */ []));
20
21
  this.editable = signal(false, ...(ngDevMode ? [{ debugName: "editable" }] : /* istanbul ignore next */ []));
@@ -32,6 +33,10 @@ class AssetNotesWidgetComponent {
32
33
  this.editable.set(!this.editable());
33
34
  }
34
35
  async save() {
36
+ const id = this.deviceId();
37
+ if (!id) {
38
+ return;
39
+ }
35
40
  try {
36
41
  const updatedNotes = {
37
42
  ...this.notes(),
@@ -39,7 +44,7 @@ class AssetNotesWidgetComponent {
39
44
  lastUpdated: new Date().toISOString()
40
45
  };
41
46
  await this.inventory.update({
42
- id: this.config().device.id,
47
+ id,
43
48
  [this.FRAGMENT]: updatedNotes
44
49
  });
45
50
  this.notes.set(updatedNotes);
@@ -51,20 +56,37 @@ class AssetNotesWidgetComponent {
51
56
  }
52
57
  }
53
58
  async loadNotes() {
59
+ const id = this.deviceId();
60
+ if (!id) {
61
+ // No device resolved — stay read-only (Edit is hidden while loading) instead of
62
+ // presenting an editable empty state.
63
+ return;
64
+ }
54
65
  try {
55
- const device = await this.inventory.detail(this.config().device.id);
66
+ const device = await this.inventory.detail(id);
56
67
  this.notes.set(device.data[this.FRAGMENT] || { htmlContent: '' });
57
68
  }
58
69
  catch (error) {
70
+ // Leave the widget read-only on failure: a transient error must not let the user save
71
+ // over notes that are still on the device.
59
72
  this.alertService.addServerFailure(error);
60
73
  }
61
74
  }
75
+ /**
76
+ * Id of the device whose notes are shown. Prefers the widget's own `config.device`, and
77
+ * falls back to the dashboard context device — pre-migration (AngularJS) Asset Notes
78
+ * dashboards saved no `config.device` and relied on the surrounding dashboard context.
79
+ */
80
+ deviceId() {
81
+ const id = this.config()?.device?.id ?? this.contextRoute.activatedContextData?.contextData?.id;
82
+ return id == null ? undefined : `${id}`;
83
+ }
62
84
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AssetNotesWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
63
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: AssetNotesWidgetComponent, isStandalone: true, selector: "c8y-asset-notes", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"fit-h d-flex flex-wrap a-i-stretch\">\n <i\n class=\"c8y-icon c8y-icon-duocolor asset-notes-icon\"\n [c8yIcon]=\"'c8y-notification'\"\n ></i>\n\n @if (!editable()) {\n <div class=\"asset-notes-content\">\n <c8y-loading *ngIf=\"isLoading()\"></c8y-loading>\n <div class=\"text-break-word asset-notes-body\">\n @if (notes()?.htmlContent && !isLoading()) {\n <span\n class=\"markdown-content d-inline-block\"\n [innerHTML]=\"notes()?.htmlContent | markdownToHtml | async\"\n ></span>\n } @else if (!notes()?.htmlContent) {\n <span>\n {{ 'No notes yet.' | translate }}\n </span>\n }\n\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"pencil\"></i>\n {{ 'Edit' | translate }}\n </button>\n </div>\n </div>\n <div class=\"asset-notes-footer m-t-8\">\n <small class=\"text-muted\">\n <em\n *ngIf=\"notes()?.lastUpdated\"\n ngNonBindable\n translate\n [translateParams]=\"ngNonBindableTranslate()\"\n >\n {{ lastUpdated }} by {{ user }}\n </em>\n </small>\n </div>\n } @else {\n <div class=\"fit-h flex-grow\">\n <div class=\"d-flex a-i-stretch fit-h\">\n <textarea\n class=\"form-control fit-h text-monospace\"\n [attr.aria-label]=\"'Notes' | translate\"\n rows=\"5\"\n [(ngModel)]=\"notes().htmlContent\"\n c8y-code-editor\n ></textarea>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n (click)=\"save()\"\n >\n <i c8yIcon=\"check\"></i>\n </button>\n </div>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "progressLabel", "message"] }, { kind: "ngmodule", type: CommonModule$1 }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.MarkdownToHtmlPipe, name: "markdownToHtml" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
85
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: AssetNotesWidgetComponent, isStandalone: true, selector: "c8y-asset-notes", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"fit-h d-flex flex-wrap a-i-stretch\">\n <i\n class=\"c8y-icon c8y-icon-duocolor asset-notes-icon\"\n [c8yIcon]=\"'c8y-notification'\"\n ></i>\n\n @if (!editable()) {\n <div class=\"asset-notes-content\">\n @if (isLoading()) {\n <c8y-loading></c8y-loading>\n }\n <div class=\"text-break-word asset-notes-body\">\n @if (notes()?.htmlContent && !isLoading()) {\n <span\n class=\"markdown-content d-inline-block\"\n [innerHTML]=\"notes()?.htmlContent | markdownToHtml | async\"\n ></span>\n } @else if (!notes()?.htmlContent) {\n <span>\n {{ 'No notes yet.' | translate }}\n </span>\n }\n\n @if (!isLoading()) {\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"pencil\"></i>\n {{ 'Edit' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"asset-notes-footer m-t-8\">\n <small class=\"text-muted\">\n @if (notes()?.lastUpdated) {\n <em\n ngNonBindable\n translate\n [translateParams]=\"ngNonBindableTranslate()\"\n >\n {{ lastUpdated }} by {{ user }}\n </em>\n }\n </small>\n </div>\n } @else {\n <div class=\"fit-h flex-grow\">\n <div class=\"d-flex a-i-stretch fit-h\">\n <textarea\n class=\"form-control fit-h text-monospace\"\n [attr.aria-label]=\"'Notes' | translate\"\n rows=\"5\"\n [(ngModel)]=\"notes().htmlContent\"\n c8y-code-editor\n ></textarea>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n (click)=\"save()\"\n >\n <i c8yIcon=\"check\"></i>\n </button>\n </div>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "progressLabel", "message"] }, { kind: "ngmodule", type: CommonModule$1 }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.MarkdownToHtmlPipe, name: "markdownToHtml" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
64
86
  }
65
87
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AssetNotesWidgetComponent, decorators: [{
66
88
  type: Component,
67
- args: [{ selector: 'c8y-asset-notes', standalone: true, imports: [CommonModule, CommonModule$1, CoreModule, FormsModule, FormsModule$1, DatePipe], changeDetection: ChangeDetectionStrategy.Eager, template: "<div class=\"fit-h d-flex flex-wrap a-i-stretch\">\n <i\n class=\"c8y-icon c8y-icon-duocolor asset-notes-icon\"\n [c8yIcon]=\"'c8y-notification'\"\n ></i>\n\n @if (!editable()) {\n <div class=\"asset-notes-content\">\n <c8y-loading *ngIf=\"isLoading()\"></c8y-loading>\n <div class=\"text-break-word asset-notes-body\">\n @if (notes()?.htmlContent && !isLoading()) {\n <span\n class=\"markdown-content d-inline-block\"\n [innerHTML]=\"notes()?.htmlContent | markdownToHtml | async\"\n ></span>\n } @else if (!notes()?.htmlContent) {\n <span>\n {{ 'No notes yet.' | translate }}\n </span>\n }\n\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"pencil\"></i>\n {{ 'Edit' | translate }}\n </button>\n </div>\n </div>\n <div class=\"asset-notes-footer m-t-8\">\n <small class=\"text-muted\">\n <em\n *ngIf=\"notes()?.lastUpdated\"\n ngNonBindable\n translate\n [translateParams]=\"ngNonBindableTranslate()\"\n >\n {{ lastUpdated }} by {{ user }}\n </em>\n </small>\n </div>\n } @else {\n <div class=\"fit-h flex-grow\">\n <div class=\"d-flex a-i-stretch fit-h\">\n <textarea\n class=\"form-control fit-h text-monospace\"\n [attr.aria-label]=\"'Notes' | translate\"\n rows=\"5\"\n [(ngModel)]=\"notes().htmlContent\"\n c8y-code-editor\n ></textarea>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n (click)=\"save()\"\n >\n <i c8yIcon=\"check\"></i>\n </button>\n </div>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n" }]
89
+ args: [{ selector: 'c8y-asset-notes', standalone: true, imports: [CommonModule, CommonModule$1, CoreModule, FormsModule, FormsModule$1, DatePipe], changeDetection: ChangeDetectionStrategy.Eager, template: "<div class=\"fit-h d-flex flex-wrap a-i-stretch\">\n <i\n class=\"c8y-icon c8y-icon-duocolor asset-notes-icon\"\n [c8yIcon]=\"'c8y-notification'\"\n ></i>\n\n @if (!editable()) {\n <div class=\"asset-notes-content\">\n @if (isLoading()) {\n <c8y-loading></c8y-loading>\n }\n <div class=\"text-break-word asset-notes-body\">\n @if (notes()?.htmlContent && !isLoading()) {\n <span\n class=\"markdown-content d-inline-block\"\n [innerHTML]=\"notes()?.htmlContent | markdownToHtml | async\"\n ></span>\n } @else if (!notes()?.htmlContent) {\n <span>\n {{ 'No notes yet.' | translate }}\n </span>\n }\n\n @if (!isLoading()) {\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"pencil\"></i>\n {{ 'Edit' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"asset-notes-footer m-t-8\">\n <small class=\"text-muted\">\n @if (notes()?.lastUpdated) {\n <em\n ngNonBindable\n translate\n [translateParams]=\"ngNonBindableTranslate()\"\n >\n {{ lastUpdated }} by {{ user }}\n </em>\n }\n </small>\n </div>\n } @else {\n <div class=\"fit-h flex-grow\">\n <div class=\"d-flex a-i-stretch fit-h\">\n <textarea\n class=\"form-control fit-h text-monospace\"\n [attr.aria-label]=\"'Notes' | translate\"\n rows=\"5\"\n [(ngModel)]=\"notes().htmlContent\"\n c8y-code-editor\n ></textarea>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n (click)=\"save()\"\n >\n <i c8yIcon=\"check\"></i>\n </button>\n </div>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n" }]
68
90
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
69
91
 
70
92
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-widgets-implementations-asset-notes.mjs","sources":["../../widgets/implementations/asset-notes/asset-notes-widget.component.ts","../../widgets/implementations/asset-notes/asset-notes-widget.component.html","../../widgets/implementations/asset-notes/c8y-ngx-components-widgets-implementations-asset-notes.ts"],"sourcesContent":["import { CommonModule as NgCommonModule } from '@angular/common';\nimport { Component, computed, inject, input, InputSignal, OnInit, signal, ChangeDetectionStrategy } from '@angular/core';\nimport { FormsModule as NgFormsModule } from '@angular/forms';\nimport { IManagedObject, InventoryService } from '@c8y/client';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport {\n AlertService,\n AppStateService,\n CommonModule,\n CoreModule,\n DatePipe,\n FormsModule\n} from '@c8y/ngx-components';\n\ninterface AssetNotes {\n user: string;\n lastUpdated: string;\n htmlContent: string;\n}\n\nexport type AssetNotesConfig = { device: Partial<IManagedObject> };\n\n@Component({\n selector: 'c8y-asset-notes',\n templateUrl: './asset-notes-widget.component.html',\n standalone: true,\n imports: [CommonModule, NgCommonModule, CoreModule, NgFormsModule, FormsModule, DatePipe],\n changeDetection: ChangeDetectionStrategy.Eager\n})\nexport class AssetNotesWidgetComponent implements OnInit {\n private inventory = inject(InventoryService);\n private appState = inject(AppStateService);\n private alertService = inject(AlertService);\n private datePipe = inject(DatePipe);\n\n config: InputSignal<AssetNotesConfig> = input();\n\n notes = signal<AssetNotes | null>(null);\n editable = signal(false);\n isLoading = computed(() => this.notes()?.htmlContent === undefined);\n\n private readonly FRAGMENT = 'c8y_ComponentConfig!assetNotes';\n ngNonBindableTranslate = computed(() => ({\n lastUpdated: this.datePipe.transform(this.notes()?.lastUpdated),\n user: this.notes()?.user\n }));\n\n async ngOnInit() {\n await this.loadNotes();\n }\n\n toggleEdit() {\n this.editable.set(!this.editable());\n }\n\n async save() {\n try {\n const updatedNotes = {\n ...this.notes(),\n user: this.appState.currentUser.value.id,\n lastUpdated: new Date().toISOString()\n };\n\n await this.inventory.update({\n id: this.config().device.id,\n [this.FRAGMENT]: updatedNotes\n });\n\n this.notes.set(updatedNotes);\n this.editable.set(false);\n this.alertService.success(gettext('Notes saved.'));\n } catch (error) {\n this.alertService.addServerFailure(error);\n }\n }\n\n private async loadNotes() {\n try {\n const device = await this.inventory.detail(this.config().device.id);\n this.notes.set(device.data[this.FRAGMENT] || { htmlContent: '' });\n } catch (error) {\n this.alertService.addServerFailure(error);\n }\n }\n}\n","<div class=\"fit-h d-flex flex-wrap a-i-stretch\">\n <i\n class=\"c8y-icon c8y-icon-duocolor asset-notes-icon\"\n [c8yIcon]=\"'c8y-notification'\"\n ></i>\n\n @if (!editable()) {\n <div class=\"asset-notes-content\">\n <c8y-loading *ngIf=\"isLoading()\"></c8y-loading>\n <div class=\"text-break-word asset-notes-body\">\n @if (notes()?.htmlContent && !isLoading()) {\n <span\n class=\"markdown-content d-inline-block\"\n [innerHTML]=\"notes()?.htmlContent | markdownToHtml | async\"\n ></span>\n } @else if (!notes()?.htmlContent) {\n <span>\n {{ 'No notes yet.' | translate }}\n </span>\n }\n\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"pencil\"></i>\n {{ 'Edit' | translate }}\n </button>\n </div>\n </div>\n <div class=\"asset-notes-footer m-t-8\">\n <small class=\"text-muted\">\n <em\n *ngIf=\"notes()?.lastUpdated\"\n ngNonBindable\n translate\n [translateParams]=\"ngNonBindableTranslate()\"\n >\n {{ lastUpdated }} by {{ user }}\n </em>\n </small>\n </div>\n } @else {\n <div class=\"fit-h flex-grow\">\n <div class=\"d-flex a-i-stretch fit-h\">\n <textarea\n class=\"form-control fit-h text-monospace\"\n [attr.aria-label]=\"'Notes' | translate\"\n rows=\"5\"\n [(ngModel)]=\"notes().htmlContent\"\n c8y-code-editor\n ></textarea>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n (click)=\"save()\"\n >\n <i c8yIcon=\"check\"></i>\n </button>\n </div>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["NgCommonModule","NgFormsModule","FormsModule"],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-widgets-implementations-asset-notes.mjs","sources":["../../widgets/implementations/asset-notes/asset-notes-widget.component.ts","../../widgets/implementations/asset-notes/asset-notes-widget.component.html","../../widgets/implementations/asset-notes/c8y-ngx-components-widgets-implementations-asset-notes.ts"],"sourcesContent":["import { CommonModule as NgCommonModule } from '@angular/common';\nimport {\n Component,\n computed,\n inject,\n input,\n InputSignal,\n OnInit,\n signal,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { FormsModule as NgFormsModule } from '@angular/forms';\nimport { IManagedObject, InventoryService } from '@c8y/client';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport {\n AlertService,\n AppStateService,\n CommonModule,\n ContextRouteService,\n CoreModule,\n DatePipe,\n FormsModule\n} from '@c8y/ngx-components';\n\ninterface AssetNotes {\n user: string;\n lastUpdated: string;\n htmlContent: string;\n}\n\nexport type AssetNotesConfig = { device: Partial<IManagedObject> };\n\n@Component({\n selector: 'c8y-asset-notes',\n templateUrl: './asset-notes-widget.component.html',\n standalone: true,\n imports: [CommonModule, NgCommonModule, CoreModule, NgFormsModule, FormsModule, DatePipe],\n changeDetection: ChangeDetectionStrategy.Eager\n})\nexport class AssetNotesWidgetComponent implements OnInit {\n private inventory = inject(InventoryService);\n private appState = inject(AppStateService);\n private alertService = inject(AlertService);\n private datePipe = inject(DatePipe);\n private contextRoute = inject(ContextRouteService);\n\n config: InputSignal<AssetNotesConfig> = input();\n\n notes = signal<AssetNotes | null>(null);\n editable = signal(false);\n isLoading = computed(() => this.notes()?.htmlContent === undefined);\n\n private readonly FRAGMENT = 'c8y_ComponentConfig!assetNotes';\n ngNonBindableTranslate = computed(() => ({\n lastUpdated: this.datePipe.transform(this.notes()?.lastUpdated),\n user: this.notes()?.user\n }));\n\n async ngOnInit() {\n await this.loadNotes();\n }\n\n toggleEdit() {\n this.editable.set(!this.editable());\n }\n\n async save() {\n const id = this.deviceId();\n if (!id) {\n return;\n }\n try {\n const updatedNotes = {\n ...this.notes(),\n user: this.appState.currentUser.value.id,\n lastUpdated: new Date().toISOString()\n };\n\n await this.inventory.update({\n id,\n [this.FRAGMENT]: updatedNotes\n });\n\n this.notes.set(updatedNotes);\n this.editable.set(false);\n this.alertService.success(gettext('Notes saved.'));\n } catch (error) {\n this.alertService.addServerFailure(error);\n }\n }\n\n private async loadNotes() {\n const id = this.deviceId();\n if (!id) {\n // No device resolved — stay read-only (Edit is hidden while loading) instead of\n // presenting an editable empty state.\n return;\n }\n try {\n const device = await this.inventory.detail(id);\n this.notes.set(device.data[this.FRAGMENT] || { htmlContent: '' });\n } catch (error) {\n // Leave the widget read-only on failure: a transient error must not let the user save\n // over notes that are still on the device.\n this.alertService.addServerFailure(error);\n }\n }\n\n /**\n * Id of the device whose notes are shown. Prefers the widget's own `config.device`, and\n * falls back to the dashboard context device — pre-migration (AngularJS) Asset Notes\n * dashboards saved no `config.device` and relied on the surrounding dashboard context.\n */\n private deviceId(): string | undefined {\n const id = this.config()?.device?.id ?? this.contextRoute.activatedContextData?.contextData?.id;\n return id == null ? undefined : `${id}`;\n }\n}\n","<div class=\"fit-h d-flex flex-wrap a-i-stretch\">\n <i\n class=\"c8y-icon c8y-icon-duocolor asset-notes-icon\"\n [c8yIcon]=\"'c8y-notification'\"\n ></i>\n\n @if (!editable()) {\n <div class=\"asset-notes-content\">\n @if (isLoading()) {\n <c8y-loading></c8y-loading>\n }\n <div class=\"text-break-word asset-notes-body\">\n @if (notes()?.htmlContent && !isLoading()) {\n <span\n class=\"markdown-content d-inline-block\"\n [innerHTML]=\"notes()?.htmlContent | markdownToHtml | async\"\n ></span>\n } @else if (!notes()?.htmlContent) {\n <span>\n {{ 'No notes yet.' | translate }}\n </span>\n }\n\n @if (!isLoading()) {\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"pencil\"></i>\n {{ 'Edit' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"asset-notes-footer m-t-8\">\n <small class=\"text-muted\">\n @if (notes()?.lastUpdated) {\n <em\n ngNonBindable\n translate\n [translateParams]=\"ngNonBindableTranslate()\"\n >\n {{ lastUpdated }} by {{ user }}\n </em>\n }\n </small>\n </div>\n } @else {\n <div class=\"fit-h flex-grow\">\n <div class=\"d-flex a-i-stretch fit-h\">\n <textarea\n class=\"form-control fit-h text-monospace\"\n [attr.aria-label]=\"'Notes' | translate\"\n rows=\"5\"\n [(ngModel)]=\"notes().htmlContent\"\n c8y-code-editor\n ></textarea>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n (click)=\"save()\"\n >\n <i c8yIcon=\"check\"></i>\n </button>\n </div>\n <div class=\"input-group-btn a-s-center\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["NgCommonModule","NgFormsModule","FormsModule"],"mappings":"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"}
@@ -6,21 +6,21 @@ import { FormGroup, FormBuilder, FormControl, Validators, FormsModule, ReactiveF
6
6
  import * as i1$1 from '@c8y/client';
7
7
  import { OperationService, InventoryService, QueriesUtil } from '@c8y/client';
8
8
  import * as i1 from '@c8y/ngx-components';
9
- import { DatePipe, BaseColumn, CustomColumn, IconDirective, AlertService, CellRendererContext, CommonModule, IntervalBasedReload, DEFAULT_INTERVAL_VALUES, WIDGET_TYPE_VALUES, CoreModule, CountdownIntervalComponent, ManagedObjectRealtimeService, WidgetGlobalAutoRefreshService, globalAutoRefreshLoading, WidgetActionWrapperComponent, ModalModule, SelectModule, DateTimePickerModule, C8yTranslateModule, BottomDrawerService, InputGroupEditableComponent, DropdownFocusTrapDirective, EmptyStateComponent, ListGroupModule, C8yTranslatePipe, HumanizePipe } from '@c8y/ngx-components';
9
+ import { DatePipe, BaseColumn, CustomColumn, IconDirective, StringifyObjectPipe, AlertService, CellRendererContext, CommonModule, IntervalBasedReload, DEFAULT_INTERVAL_VALUES, WIDGET_TYPE_VALUES, CoreModule, CountdownIntervalComponent, ManagedObjectRealtimeService, WidgetGlobalAutoRefreshService, globalAutoRefreshLoading, WidgetActionWrapperComponent, ModalModule, SelectModule, DateTimePickerModule, C8yTranslateModule, BottomDrawerService, InputGroupEditableComponent, DropdownFocusTrapDirective, EmptyStateComponent, ListGroupModule, C8yTranslatePipe, HumanizePipe } from '@c8y/ngx-components';
10
10
  import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
11
11
  import { WidgetConfigService, ContextDashboardService } from '@c8y/ngx-components/context-dashboard';
12
- import { from, switchMap, isObservable, of, map, firstValueFrom, tap, BehaviorSubject, Subject, merge, startWith, scan, distinctUntilChanged, takeUntil, shareReplay, skip } from 'rxjs';
12
+ import { from, switchMap, isObservable, of, firstValueFrom, tap, BehaviorSubject, Subject, merge, startWith, scan, distinctUntilChanged, takeUntil, shareReplay, skip } from 'rxjs';
13
13
  import * as i2$1 from '@c8y/ngx-components/asset-properties';
14
14
  import { AssetPropertySelectorDrawerComponent } from '@c8y/ngx-components/asset-properties';
15
- import { transform, identity, get, assign } from 'lodash';
15
+ import { transform, identity, get as get$1, assign } from 'lodash';
16
16
  import * as i2 from '@c8y/ngx-components/device-grid';
17
17
  import { AlarmsDeviceGridColumn, StatusDeviceGridColumn } from '@c8y/ngx-components/device-grid';
18
18
  import { gettext } from '@c8y/ngx-components/gettext';
19
+ import { get, isEqual } from 'lodash-es';
19
20
  import * as i1$2 from '@ngx-translate/core';
20
21
  import { TranslateService } from '@ngx-translate/core';
21
22
  import * as i3 from 'ngx-bootstrap/tooltip';
22
23
  import { TooltipModule } from 'ngx-bootstrap/tooltip';
23
- import { isEqual } from 'lodash-es';
24
24
  import * as i3$1 from 'ngx-bootstrap/popover';
25
25
  import { PopoverModule } from 'ngx-bootstrap/popover';
26
26
  import { RouterModule } from '@angular/router';
@@ -239,11 +239,7 @@ class IconCellRendererComponent {
239
239
  if (!item || !property) {
240
240
  return undefined;
241
241
  }
242
- const path = property.path;
243
- if (Array.isArray(path)) {
244
- return path.reduce((acc, key) => acc?.[key], item);
245
- }
246
- return item[path];
242
+ return get(item, property.path);
247
243
  }
248
244
  /**
249
245
  * Whether `cellValue`/`value` may be compared as numbers instead of their native types.
@@ -291,10 +287,12 @@ class IconCellRendererComponent {
291
287
  @if (matchedCondition(value); as match) {
292
288
  <i class="m-r-4" [c8yIcon]="match.icon" [style.color]="match.color"></i>
293
289
  @if (context.property.showIconAndValue) {
294
- <span class="text-truncate" [title]="value">{{ value }}</span>
290
+ @let displayValue = value | stringifyObject;
291
+ <span class="text-truncate" [title]="displayValue">{{ displayValue }}</span>
295
292
  }
296
293
  } @else {
297
- <span class="text-truncate" [title]="value">{{ value }}</span>
294
+ @let displayValue = value | stringifyObject;
295
+ <span class="text-truncate" [title]="displayValue">{{ displayValue }}</span>
298
296
  }
299
297
  </ng-template>
300
298
 
@@ -332,7 +330,7 @@ class IconCellRendererComponent {
332
330
  ></ng-container>
333
331
  }
334
332
  </div>
335
- }`, isInline: true, dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
333
+ }`, isInline: true, dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: StringifyObjectPipe, name: "stringifyObject" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
336
334
  }
337
335
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: IconCellRendererComponent, decorators: [{
338
336
  type: Component,
@@ -341,10 +339,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
341
339
  @if (matchedCondition(value); as match) {
342
340
  <i class="m-r-4" [c8yIcon]="match.icon" [style.color]="match.color"></i>
343
341
  @if (context.property.showIconAndValue) {
344
- <span class="text-truncate" [title]="value">{{ value }}</span>
342
+ @let displayValue = value | stringifyObject;
343
+ <span class="text-truncate" [title]="displayValue">{{ displayValue }}</span>
345
344
  }
346
345
  } @else {
347
- <span class="text-truncate" [title]="value">{{ value }}</span>
346
+ @let displayValue = value | stringifyObject;
347
+ <span class="text-truncate" [title]="displayValue">{{ displayValue }}</span>
348
348
  }
349
349
  </ng-template>
350
350
 
@@ -384,7 +384,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
384
384
  </div>
385
385
  }`,
386
386
  selector: 'c8y-icon-cell-renderer',
387
- imports: [AsyncPipe, IconDirective, NgTemplateOutlet],
387
+ imports: [AsyncPipe, IconDirective, NgTemplateOutlet, StringifyObjectPipe],
388
388
  changeDetection: ChangeDetectionStrategy.Eager
389
389
  }]
390
390
  }], ctorParameters: () => [{ type: i1.CellRendererContext }, { type: i2$1.ComputedPropertiesService }, { type: i2.ColumnUtilService }] });
@@ -514,7 +514,7 @@ class ComputedCellRendererComponent {
514
514
  this.computedPropertyService = computedPropertyService;
515
515
  }
516
516
  ngOnInit() {
517
- this.computedValue = this.getCallbackComputedPropertyValue(this.context.property, this.context.item).pipe(map(value => (typeof value === 'object' && value !== null ? JSON.stringify(value) : value)));
517
+ this.computedValue = this.getCallbackComputedPropertyValue(this.context.property, this.context.item);
518
518
  }
519
519
  getCallbackComputedPropertyValue(property, context) {
520
520
  const propertyName = property.computedConfig?.__propertyName || property.name;
@@ -539,14 +539,14 @@ class ComputedCellRendererComponent {
539
539
  }));
540
540
  }
541
541
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ComputedCellRendererComponent, deps: [{ token: i1.CellRendererContext }, { token: i2$1.ComputedPropertiesService }], target: i0.ɵɵFactoryTarget.Component }); }
542
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: ComputedCellRendererComponent, isStandalone: true, selector: "c8y-computed-cell-renderer", ngImport: i0, template: `{{ computedValue | async }}`, isInline: true, dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
542
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: ComputedCellRendererComponent, isStandalone: true, selector: "c8y-computed-cell-renderer", ngImport: i0, template: `{{ computedValue | async | stringifyObject }}`, isInline: true, dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: StringifyObjectPipe, name: "stringifyObject" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
543
543
  }
544
544
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ComputedCellRendererComponent, decorators: [{
545
545
  type: Component,
546
546
  args: [{
547
- template: `{{ computedValue | async }}`,
547
+ template: `{{ computedValue | async | stringifyObject }}`,
548
548
  selector: 'c8y-computed-cell-renderer',
549
- imports: [AsyncPipe],
549
+ imports: [AsyncPipe, StringifyObjectPipe],
550
550
  changeDetection: ChangeDetectionStrategy.Eager
551
551
  }]
552
552
  }], ctorParameters: () => [{ type: i1.CellRendererContext }, { type: i2$1.ComputedPropertiesService }] });
@@ -986,7 +986,7 @@ class AssetTableService {
986
986
  name: prop.name || prop.title,
987
987
  header: prop.columnLabel || prop.displayedLabel || prop.label || prop.title,
988
988
  visible: prop.visible ?? true,
989
- path: this.normalizePath(prop.name || prop.keyPath),
989
+ path: this.normalizePath(prop.keyPath || prop.name),
990
990
  sortOrder: prop.sortOrder ?? null
991
991
  });
992
992
  case 'icon':
@@ -995,7 +995,7 @@ class AssetTableService {
995
995
  path: this.normalizePath(prop.keyPath || prop.name),
996
996
  header: prop.columnLabel || prop.displayedLabel || prop.label || prop.title,
997
997
  iconConfig: prop.iconConfig || {},
998
- computedConfig: prop.computed && prop.config ? prop.config : null,
998
+ computedConfig: prop.computed ? prop.config || {} : null,
999
999
  showIconAndValue: config?.showIconAndValue,
1000
1000
  visible: prop.visible ?? true
1001
1001
  });
@@ -1139,7 +1139,7 @@ class AssetTableService {
1139
1139
  query.__filter.__and = query.__filter.__and || [];
1140
1140
  query.__filter.__and.push(queryObj);
1141
1141
  }
1142
- else if (queryObj.__and && get(query, '__filter.__and')) {
1142
+ else if (queryObj.__and && get$1(query, '__filter.__and')) {
1143
1143
  queryObj.__and.map(obj => query.__filter.__and.push(obj));
1144
1144
  }
1145
1145
  else {
@@ -1235,8 +1235,8 @@ class AssetTableService {
1235
1235
  return [...data].sort((a, b) => {
1236
1236
  for (const col of columns) {
1237
1237
  const isComputed = col.type === 'computed';
1238
- const valA = isComputed ? (valueCache.get(a)?.[col.name] ?? '') : get(a, col.path, '');
1239
- const valB = isComputed ? (valueCache.get(b)?.[col.name] ?? '') : get(b, col.path, '');
1238
+ const valA = isComputed ? (valueCache.get(a)?.[col.name] ?? '') : get$1(a, col.path, '');
1239
+ const valB = isComputed ? (valueCache.get(b)?.[col.name] ?? '') : get$1(b, col.path, '');
1240
1240
  const emptyA = valA === '' || valA === '-' || valA == null;
1241
1241
  const emptyB = valB === '' || valB === '-' || valB == null;
1242
1242
  if (emptyA && emptyB)