@c8y/ngx-components 1024.16.21 → 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.
- package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +14 -4
- package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-repository-configuration.mjs +77 -20
- package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-notes.mjs +29 -7
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-notes.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +24 -24
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +159 -75
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/locales/locales.pot +31 -17
- package/package.json +1 -1
- package/types/c8y-ngx-components-ai-agent-chat.d.ts +8 -1
- package/types/c8y-ngx-components-ai-agent-chat.d.ts.map +1 -1
- package/types/c8y-ngx-components-repository-configuration.d.ts +20 -4
- package/types/c8y-ngx-components-repository-configuration.d.ts.map +1 -1
- package/types/c8y-ngx-components-widgets-implementations-asset-notes.d.ts +7 -0
- package/types/c8y-ngx-components-widgets-implementations-asset-notes.d.ts.map +1 -1
- package/types/c8y-ngx-components.d.ts +80 -23
- package/types/c8y-ngx-components.d.ts.map +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
290
|
+
@let displayValue = value | stringifyObject;
|
|
291
|
+
<span class="text-truncate" [title]="displayValue">{{ displayValue }}</span>
|
|
295
292
|
}
|
|
296
293
|
} @else {
|
|
297
|
-
|
|
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
|
-
|
|
342
|
+
@let displayValue = value | stringifyObject;
|
|
343
|
+
<span class="text-truncate" [title]="displayValue">{{ displayValue }}</span>
|
|
345
344
|
}
|
|
346
345
|
} @else {
|
|
347
|
-
|
|
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)
|
|
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.
|
|
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
|
|
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)
|