@c8y/ngx-components 1023.70.0 → 1023.75.1
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/asset-properties/index.d.ts +19 -1
- package/asset-properties/index.d.ts.map +1 -1
- package/cockpit-config/index.d.ts +4 -3
- package/cockpit-config/index.d.ts.map +1 -1
- package/context-dashboard/index.d.ts +202 -4
- package/context-dashboard/index.d.ts.map +1 -1
- package/datapoints-export-selector/index.d.ts +8 -1
- package/datapoints-export-selector/index.d.ts.map +1 -1
- package/device-profile/index.d.ts +8 -1
- package/device-profile/index.d.ts.map +1 -1
- package/events/cockpit/index.d.ts +6 -0
- package/events/cockpit/index.d.ts.map +1 -0
- package/events/devicemanagement/index.d.ts +6 -0
- package/events/devicemanagement/index.d.ts.map +1 -0
- package/events/events-timeline/index.d.ts +11 -10
- package/events/events-timeline/index.d.ts.map +1 -1
- package/events/index.d.ts +363 -5
- package/events/index.d.ts.map +1 -1
- package/fesm2022/c8y-ngx-components-alarm-event-selector.mjs +1 -1
- package/fesm2022/c8y-ngx-components-alarm-event-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-alarms.mjs +1 -1
- package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-asset-properties.mjs +2 -2
- package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-auth-configuration.mjs +1 -1
- package/fesm2022/c8y-ngx-components-auth-configuration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs +2 -2
- package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-cockpit-config.mjs +8 -11
- package/fesm2022/c8y-ngx-components-cockpit-config.mjs.map +1 -1
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-alarm-count-config.component-CPLDClTp.mjs → c8y-ngx-components-computed-asset-properties-alarm-count-config.component-DX9Rgjgl.mjs} +2 -2
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-alarm-count-config.component-CPLDClTp.mjs.map → c8y-ngx-components-computed-asset-properties-alarm-count-config.component-DX9Rgjgl.mjs.map} +1 -1
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-9be_iMQg.mjs → c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-CRpLJ5H7.mjs} +8 -8
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-9be_iMQg.mjs.map → c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-CRpLJ5H7.mjs.map} +1 -1
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-B2em01_W.mjs → c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-2rDsrxcs.mjs} +2 -2
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-B2em01_W.mjs.map → c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-2rDsrxcs.mjs.map} +1 -1
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-event-count-config.component-CQuGa1RI.mjs → c8y-ngx-components-computed-asset-properties-event-count-config.component-BJNoqWZf.mjs} +2 -2
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-event-count-config.component-CQuGa1RI.mjs.map → c8y-ngx-components-computed-asset-properties-event-count-config.component-BJNoqWZf.mjs.map} +1 -1
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-CkmurxJv.mjs → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-DYac6foX.mjs} +3 -3
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-CkmurxJv.mjs.map → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-DYac6foX.mjs.map} +1 -1
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-last-measurement-config.component-CTK9zNUh.mjs → c8y-ngx-components-computed-asset-properties-last-measurement-config.component-3yTe6lIr.mjs} +3 -3
- package/fesm2022/{c8y-ngx-components-computed-asset-properties-last-measurement-config.component-CTK9zNUh.mjs.map → c8y-ngx-components-computed-asset-properties-last-measurement-config.component-3yTe6lIr.mjs.map} +1 -1
- package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs +1 -1
- package/fesm2022/{c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-DsCDppJx.mjs → c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-C7yXSDYC.mjs} +3 -3
- package/fesm2022/{c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-DsCDppJx.mjs.map → c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-C7yXSDYC.mjs.map} +1 -1
- package/fesm2022/{c8y-ngx-components-context-dashboard-dashboard-general-settings.component-RdLW5nde.mjs → c8y-ngx-components-context-dashboard-dashboard-general-settings.component-w8N16Z3t.mjs} +4 -4
- package/fesm2022/{c8y-ngx-components-context-dashboard-dashboard-general-settings.component-RdLW5nde.mjs.map → c8y-ngx-components-context-dashboard-dashboard-general-settings.component-w8N16Z3t.mjs.map} +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs +561 -21
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +2 -2
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-library-details.mjs +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-library-details.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +41 -8
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-device-profile.mjs +38 -12
- package/fesm2022/c8y-ngx-components-device-profile.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-device-shell.mjs +1 -1
- package/fesm2022/c8y-ngx-components-device-shell.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-license-confirm.mjs +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-license-confirm.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem.mjs +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-events-cockpit.mjs +54 -0
- package/fesm2022/c8y-ngx-components-events-cockpit.mjs.map +1 -0
- package/fesm2022/c8y-ngx-components-events-devicemanagement.mjs +79 -0
- package/fesm2022/c8y-ngx-components-events-devicemanagement.mjs.map +1 -0
- package/fesm2022/c8y-ngx-components-events-events-timeline.mjs +30 -20
- package/fesm2022/c8y-ngx-components-events-events-timeline.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-events.mjs +1080 -4
- package/fesm2022/c8y-ngx-components-events.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-file-preview.mjs +48 -41
- package/fesm2022/c8y-ngx-components-file-preview.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-files-repository.mjs +1 -1
- package/fesm2022/c8y-ngx-components-files-repository.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-global-context.mjs +68 -34
- package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-interval-picker.mjs +3 -3
- package/fesm2022/c8y-ngx-components-interval-picker.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-location.mjs +1 -1
- package/fesm2022/c8y-ngx-components-location.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operation-picker.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operation-picker.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-bulk-operation-scheduler.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-bulk-operation-scheduler.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs +5 -2
- package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs +5 -5
- package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +2 -2
- package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-shared.mjs +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-shared.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-repository-firmware.mjs +1 -1
- package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-static-assets-modal.mjs +1 -1
- package/fesm2022/c8y-ngx-components-static-assets-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-time-context.mjs +1 -1
- package/fesm2022/c8y-ngx-components-time-context.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs +1 -1
- package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-event-list.mjs +39 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-event-list.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs +76 -4
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-events.mjs +236 -0
- package/fesm2022/c8y-ngx-components-widgets-implementations-events.mjs.map +1 -0
- package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +271 -31
- package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-image.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-image.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-info-gauge.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-info-gauge.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-linear-gauge.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-linear-gauge.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +257 -31
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/file-preview/index.d.ts +7 -6
- package/file-preview/index.d.ts.map +1 -1
- package/global-context/index.d.ts +3 -0
- package/global-context/index.d.ts.map +1 -1
- package/index.d.ts +108 -12
- package/index.d.ts.map +1 -1
- package/locales/de.po +205 -38
- package/locales/es.po +204 -37
- package/locales/fr.po +204 -37
- package/locales/ja_JP.po +204 -38
- package/locales/ko.po +205 -38
- package/locales/locales.pot +117 -3
- package/locales/nl.po +205 -38
- package/locales/pl.po +205 -38
- package/locales/pt_BR.po +204 -37
- package/locales/zh_CN.po +205 -38
- package/locales/zh_TW.po +205 -38
- package/operations/operations-timeline/index.d.ts +3 -2
- package/operations/operations-timeline/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/widgets/definitions/event-list/index.d.ts +44 -1
- package/widgets/definitions/event-list/index.d.ts.map +1 -1
- package/widgets/implementations/alarms/index.d.ts +2 -0
- package/widgets/implementations/alarms/index.d.ts.map +1 -1
- package/widgets/implementations/events/index.d.ts +89 -0
- package/widgets/implementations/events/index.d.ts.map +1 -0
- package/widgets/implementations/html-widget/index.d.ts +69 -9
- package/widgets/implementations/html-widget/index.d.ts.map +1 -1
|
@@ -1,41 +1,61 @@
|
|
|
1
1
|
import { NgIf, NgClass, AsyncPipe } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { inject, Injectable, Input, Component, input, computed, ChangeDetectionStrategy, viewChild, SecurityContext, ViewChild } from '@angular/core';
|
|
3
|
+
import { inject, Injectable, Input, Component, input, computed, ChangeDetectionStrategy, viewChild, SecurityContext, ViewChild, DestroyRef, signal } from '@angular/core';
|
|
4
4
|
import * as i2 from '@angular/forms';
|
|
5
5
|
import { FormsModule } from '@angular/forms';
|
|
6
6
|
import { Router, RouterModule } from '@angular/router';
|
|
7
7
|
import { gettext } from '@c8y/ngx-components/gettext';
|
|
8
8
|
import * as i2$1 from '@c8y/ngx-components';
|
|
9
|
-
import { AppStateService, Permissions, IconDirective, C8yTranslatePipe, TabsModule, LoadingComponent, OptionsService, ClipboardService } from '@c8y/ngx-components';
|
|
10
|
-
import { WidgetConfigService, WidgetConfigFeedbackComponent } from '@c8y/ngx-components/context-dashboard';
|
|
9
|
+
import { AppStateService, Permissions, IconDirective, C8yTranslatePipe, ManagedObjectRealtimeService, TabsModule, LoadingComponent, AlertService, OptionsService, ClipboardService, DashboardChildComponent } from '@c8y/ngx-components';
|
|
10
|
+
import { WidgetConfigService, quoteAndEscape, WidgetConfigFeedbackComponent, AssetPropertyMappingsService, renamePropertyKeyInCode } from '@c8y/ngx-components/context-dashboard';
|
|
11
11
|
import * as i1 from 'ngx-bootstrap/popover';
|
|
12
12
|
import { PopoverModule } from 'ngx-bootstrap/popover';
|
|
13
13
|
import * as i3 from 'ngx-bootstrap/tooltip';
|
|
14
14
|
import { TooltipModule, TooltipDirective } from 'ngx-bootstrap/tooltip';
|
|
15
15
|
import { isEmpty } from 'lodash';
|
|
16
|
-
import { Subject, first, map, filter, withLatestFrom, switchMap, shareReplay, takeUntil, startWith, combineLatest, distinctUntilChanged, debounceTime, of, merge, from, isEmpty as isEmpty$1, catchError,
|
|
16
|
+
import { Subject, first, map, filter, withLatestFrom, switchMap, shareReplay, takeUntil, startWith, combineLatest, distinctUntilChanged, debounceTime, of, EMPTY, merge, from, isEmpty as isEmpty$1, catchError, fromEvent, BehaviorSubject } from 'rxjs';
|
|
17
17
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
18
18
|
import { InventoryService } from '@c8y/client';
|
|
19
19
|
import { kebabCase } from 'lodash-es';
|
|
20
20
|
import { TranslateService } from '@ngx-translate/core';
|
|
21
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
22
|
+
import { PRESET_NAME, REFRESH_OPTION, LocalControlsComponent, GLOBAL_CONTEXT_DISPLAY_MODE, GlobalContextConnectorComponent } from '@c8y/ngx-components/global-context';
|
|
23
|
+
import * as i4 from 'ngx-bootstrap/dropdown';
|
|
24
|
+
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
|
21
25
|
import { EditorComponent } from '@c8y/ngx-components/editor';
|
|
26
|
+
import { map as map$1, distinctUntilChanged as distinctUntilChanged$1, switchMap as switchMap$1, filter as filter$1 } from 'rxjs/operators';
|
|
22
27
|
import { AssetPropertyListComponent, AssetPropertyActionDirective } from '@c8y/ngx-components/asset-properties';
|
|
23
28
|
|
|
24
29
|
const INITIAL_HTML_FORMATTED = `<div>
|
|
25
30
|
<h2>Hello from <span class="branded">HTML widget</span></h2>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
|
|
32
|
+
<p class="m-t-16">
|
|
33
|
+
\$\{this.c8yTranslate('You can use HTML and JavaScript template literals:')\}
|
|
29
34
|
</p>
|
|
30
35
|
|
|
31
|
-
<
|
|
36
|
+
<p class="m-t-16">
|
|
37
|
+
<b>Context properties:</b> Access the assigned asset's properties via <code>c8yContext</code>: <br>
|
|
38
|
+
<tt>\$\{this.c8yContext ? this.c8yTranslate('Selected asset: {{ assetName }}', { assetName: this.c8yContext.name }) : this.c8yTranslate('No asset selected')\}</tt>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<p class="m-t-16">
|
|
42
|
+
<b>Asset properties:</b> Use "Asset properties" to select other properties (incl. computed ones) and access their values via <code>c8yProperties</code>: <br>
|
|
43
|
+
<i>Last updated:</i> <tt>\${this.c8yProperties?.lastUpdated || '-'}</tt> <br>
|
|
44
|
+
<i>Last device message:</i> <tt>\${this.c8yProperties?.lastDeviceMessage || '-'}</tt>
|
|
45
|
+
</p>
|
|
32
46
|
|
|
33
|
-
<p>
|
|
34
|
-
Use the CSS editor to customize
|
|
47
|
+
<p class="m-t-16">
|
|
48
|
+
<b>Styles:</b> Use the CSS editor to customize styles. You can use <span class="text-bold">any design-token CSS variable</span> in there.
|
|
35
49
|
</p>
|
|
36
50
|
|
|
37
|
-
<p>
|
|
38
|
-
|
|
51
|
+
<p class="m-t-16">
|
|
52
|
+
<b>Translations:</b> Use the <code>c8yTranslate('text {{ var }}', { var: value })</code> function to translate strings.
|
|
53
|
+
<i>Note: texts must be written in English and their translations must be available in the loaded standard or custom translation resources.</i>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p class="m-t-16">
|
|
57
|
+
<b>Buttons:</b> Use other HTML elements like buttons: <br>
|
|
58
|
+
<a class="btn btn-primary m-t-8" href="#/group">\$\{this.c8yTranslate('Go to groups')\}</a>
|
|
39
59
|
</p>
|
|
40
60
|
</div>`;
|
|
41
61
|
const INITIAL_CSS_FORMATTED = `
|
|
@@ -60,6 +80,10 @@ export default class ${name} extends LitElement {
|
|
|
60
80
|
static properties = {
|
|
61
81
|
// The managed object this widget is assigned to. Can be null.
|
|
62
82
|
c8yContext: { type: Object },
|
|
83
|
+
// The object with realtime values of configured properties. Can be null.
|
|
84
|
+
c8yProperties: { type: Object },
|
|
85
|
+
// The instant translation function.
|
|
86
|
+
c8yTranslate: { type: Function },
|
|
63
87
|
};
|
|
64
88
|
|
|
65
89
|
constructor() {
|
|
@@ -143,6 +167,7 @@ class HtmlWidgetConfigService {
|
|
|
143
167
|
this.widgetConfigService = inject(WidgetConfigService);
|
|
144
168
|
this.appState = inject(AppStateService);
|
|
145
169
|
this.destroy$ = new Subject();
|
|
170
|
+
this.notify$ = this.widgetConfigService.notify$;
|
|
146
171
|
this.init$ = this.widgetConfigService.currentConfig$.pipe(first(), map(current => {
|
|
147
172
|
if (current.html) {
|
|
148
173
|
current.config = this.mapLegacyConfig(current);
|
|
@@ -338,6 +363,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
338
363
|
|
|
339
364
|
class HtmlFrameComponent {
|
|
340
365
|
constructor() {
|
|
366
|
+
this.propertyValues$ = EMPTY;
|
|
341
367
|
/**
|
|
342
368
|
* If set to true, it will be ensured that a unique hash is generated
|
|
343
369
|
* for every webcomponent. This is useful if configured as otherwise it might
|
|
@@ -348,6 +374,7 @@ class HtmlFrameComponent {
|
|
|
348
374
|
this.alerts = [];
|
|
349
375
|
this.sanitizer = inject(DomSanitizer);
|
|
350
376
|
this.translateService = inject(TranslateService);
|
|
377
|
+
this.moRealtime = inject(ManagedObjectRealtimeService);
|
|
351
378
|
this.destroy$ = new Subject();
|
|
352
379
|
this.hostElement = viewChild('hostElement', ...(ngDevMode ? [{ debugName: "hostElement" }] : []));
|
|
353
380
|
this.reload$ = new Subject();
|
|
@@ -447,9 +474,21 @@ class HtmlFrameComponent {
|
|
|
447
474
|
}
|
|
448
475
|
createWebComponent(webComponentName, divHostElement, context) {
|
|
449
476
|
const webComponent = document.createElement(webComponentName);
|
|
450
|
-
webComponent.c8yContext = context;
|
|
451
477
|
const instantTranslate = this.translateService.instant.bind(this.translateService);
|
|
452
478
|
webComponent.c8yTranslate = instantTranslate;
|
|
479
|
+
// TODO: should c8yContext be updated in realtime and also connected under global time controls?
|
|
480
|
+
webComponent.c8yContext = context;
|
|
481
|
+
if (context?.id) {
|
|
482
|
+
this.moRealtime
|
|
483
|
+
.onAll$(context.id)
|
|
484
|
+
.pipe(takeUntil(merge(this.reload$, this.destroy$)))
|
|
485
|
+
.subscribe(res => {
|
|
486
|
+
webComponent.c8yContext = res.data;
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
this.propertyValues$.pipe(takeUntil(merge(this.reload$, this.destroy$))).subscribe(values => {
|
|
490
|
+
webComponent.c8yProperties = values;
|
|
491
|
+
});
|
|
453
492
|
divHostElement.appendChild(webComponent);
|
|
454
493
|
return webComponent;
|
|
455
494
|
}
|
|
@@ -491,7 +530,7 @@ class HtmlFrameComponent {
|
|
|
491
530
|
return webComponentScript;
|
|
492
531
|
}
|
|
493
532
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: HtmlFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
494
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: HtmlFrameComponent, isStandalone: true, selector: "c8y-html-frame", inputs: { config: "config", device: "device", useSalt: "useSalt" }, host: { classAttribute: "d-contents" }, viewQueries: [{ propertyName: "hostElement", first: true, predicate: ["hostElement"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "@for (alert of alerts; track alert) {\n <div\n class=\"alert m-8\"\n role=\"alert\"\n [ngClass]=\"{\n 'alert-danger': alert.type === 'danger',\n 'alert-warning': alert.type === 'warning',\n 'alert-info': alert.type === 'info',\n 'alert-success': alert.type === 'success'\n }\"\n >\n <p><strong translate>There was an issue in the HTML widget:</strong></p>\n <pre>{{ alert.text }}</pre>\n </div>\n}\n<div\n class=\"fit-w fit-h\"\n #hostElement\n></div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
|
|
533
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: HtmlFrameComponent, isStandalone: true, selector: "c8y-html-frame", inputs: { config: "config", device: "device", propertyValues$: "propertyValues$", useSalt: "useSalt" }, host: { classAttribute: "d-contents" }, viewQueries: [{ propertyName: "hostElement", first: true, predicate: ["hostElement"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "@for (alert of alerts; track alert) {\n <div\n class=\"alert m-8\"\n role=\"alert\"\n [ngClass]=\"{\n 'alert-danger': alert.type === 'danger',\n 'alert-warning': alert.type === 'warning',\n 'alert-info': alert.type === 'info',\n 'alert-success': alert.type === 'success'\n }\"\n >\n <p><strong translate>There was an issue in the HTML widget:</strong></p>\n <pre>{{ alert.text }}</pre>\n </div>\n}\n<div\n class=\"fit-w fit-h\"\n #hostElement\n></div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
|
|
495
534
|
}
|
|
496
535
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: HtmlFrameComponent, decorators: [{
|
|
497
536
|
type: Component,
|
|
@@ -500,6 +539,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
500
539
|
type: Input
|
|
501
540
|
}], device: [{
|
|
502
541
|
type: Input
|
|
542
|
+
}], propertyValues$: [{
|
|
543
|
+
type: Input
|
|
503
544
|
}], useSalt: [{
|
|
504
545
|
type: Input
|
|
505
546
|
}], hostElement: [{ type: i0.ViewChild, args: ['hostElement', { isSignal: true }] }] } });
|
|
@@ -508,6 +549,9 @@ class WidgetCodeEditorComponent {
|
|
|
508
549
|
constructor() {
|
|
509
550
|
this.mode = 'code';
|
|
510
551
|
this.configService = inject(HtmlWidgetConfigService);
|
|
552
|
+
this.translate = inject(TranslateService);
|
|
553
|
+
this.widgetConfigService = inject(WidgetConfigService);
|
|
554
|
+
this.propertyKeys$ = this.widgetConfigService.currentConfig$.pipe(map(config => Object.keys(config?.properties || {}).sort((a, b) => a.localeCompare(b))));
|
|
511
555
|
this.isAutoSaveEnabled = true;
|
|
512
556
|
this.language = 'html';
|
|
513
557
|
this.isLoading = false;
|
|
@@ -518,8 +562,10 @@ class WidgetCodeEditorComponent {
|
|
|
518
562
|
this.BUTTON_ENABLE_AUTOSAVE_LABEL = gettext('Enable auto save`An action you can do on the html widget editor`');
|
|
519
563
|
this.TAB_OUTLET_NAME = 'html-widget-tab-outlet';
|
|
520
564
|
this.destroy$ = new Subject();
|
|
565
|
+
this.suggestionProviders = [];
|
|
521
566
|
}
|
|
522
567
|
ngOnDestroy() {
|
|
568
|
+
this.suggestionProviders.forEach(a => a.dispose());
|
|
523
569
|
this.destroy$.next();
|
|
524
570
|
this.destroy$.complete();
|
|
525
571
|
}
|
|
@@ -557,6 +603,9 @@ class WidgetCodeEditorComponent {
|
|
|
557
603
|
this.editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
|
|
558
604
|
this.saveCode();
|
|
559
605
|
});
|
|
606
|
+
this.propertyKeys$.pipe(takeUntil(this.destroy$)).subscribe(keys => {
|
|
607
|
+
this.registerPropertySuggestions(keys);
|
|
608
|
+
});
|
|
560
609
|
}
|
|
561
610
|
formatCode() {
|
|
562
611
|
this.editor.getAction('editor.action.formatDocument').run();
|
|
@@ -580,12 +629,122 @@ class WidgetCodeEditorComponent {
|
|
|
580
629
|
}
|
|
581
630
|
this.configService.changeCss(code);
|
|
582
631
|
}
|
|
632
|
+
insertPropertyAtCursor(key) {
|
|
633
|
+
if (!this.editor) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const text = this.getFormattedPropertyExpression(key);
|
|
637
|
+
const monaco = this.editorComponent.monaco;
|
|
638
|
+
const position = this.editor.getPosition();
|
|
639
|
+
const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column);
|
|
640
|
+
this.editor.executeEdits('insert-property', [{ range, text, forceMoveMarkers: true }]);
|
|
641
|
+
this.editor.focus();
|
|
642
|
+
}
|
|
643
|
+
registerPropertySuggestions(keys) {
|
|
644
|
+
this.suggestionProviders.forEach(a => a.dispose());
|
|
645
|
+
this.suggestionProviders = [];
|
|
646
|
+
if (!keys.length)
|
|
647
|
+
return;
|
|
648
|
+
const monaco = this.editorComponent.monaco;
|
|
649
|
+
const providerOptions = {
|
|
650
|
+
triggerCharacters: ['$', '.', '[', "'"],
|
|
651
|
+
provideCompletionItems: (model, position) => {
|
|
652
|
+
const lineText = model.getValueInRange({
|
|
653
|
+
startLineNumber: position.lineNumber,
|
|
654
|
+
startColumn: 1,
|
|
655
|
+
endLineNumber: position.lineNumber,
|
|
656
|
+
endColumn: position.column
|
|
657
|
+
});
|
|
658
|
+
const makeRange = (startColumn) => ({
|
|
659
|
+
startLineNumber: position.lineNumber,
|
|
660
|
+
endLineNumber: position.lineNumber,
|
|
661
|
+
startColumn,
|
|
662
|
+
endColumn: position.column
|
|
663
|
+
});
|
|
664
|
+
// Case 1: after dot access – this.c8yProperties?. or this.c8yProperties.
|
|
665
|
+
const dotMatch = /this\.c8yProperties\??\.(\w*)$/.exec(lineText);
|
|
666
|
+
if (dotMatch) {
|
|
667
|
+
const typed = dotMatch[1];
|
|
668
|
+
const startColumn = position.column - typed.length;
|
|
669
|
+
const suggestions = keys
|
|
670
|
+
.filter(key => !/[^a-zA-Z0-9_]/.test(key) && key.startsWith(typed))
|
|
671
|
+
.map(key => ({
|
|
672
|
+
label: key,
|
|
673
|
+
kind: monaco.languages.CompletionItemKind.Property,
|
|
674
|
+
insertText: key,
|
|
675
|
+
range: makeRange(startColumn),
|
|
676
|
+
sortText: key
|
|
677
|
+
}));
|
|
678
|
+
return { suggestions };
|
|
679
|
+
}
|
|
680
|
+
// Case 2: after bracket access – this.c8yProperties?.[ or this.c8yProperties[
|
|
681
|
+
const bracketMatch = /this\.c8yProperties(?:\?\.)?\[([^\]]*)$/.exec(lineText);
|
|
682
|
+
if (bracketMatch) {
|
|
683
|
+
const typed = bracketMatch[1];
|
|
684
|
+
const charAfterCursor = model.getValueInRange({
|
|
685
|
+
startLineNumber: position.lineNumber,
|
|
686
|
+
startColumn: position.column,
|
|
687
|
+
endLineNumber: position.lineNumber,
|
|
688
|
+
endColumn: position.column + 1
|
|
689
|
+
});
|
|
690
|
+
const closingBracketAlreadyPresent = charAfterCursor === ']';
|
|
691
|
+
const startColumn = position.column - typed.length;
|
|
692
|
+
const endColumn = closingBracketAlreadyPresent ? position.column + 1 : position.column;
|
|
693
|
+
const suggestions = keys.map(key => ({
|
|
694
|
+
label: key,
|
|
695
|
+
kind: monaco.languages.CompletionItemKind.Property,
|
|
696
|
+
insertText: `${quoteAndEscape(key)}]`,
|
|
697
|
+
range: {
|
|
698
|
+
startLineNumber: position.lineNumber,
|
|
699
|
+
endLineNumber: position.lineNumber,
|
|
700
|
+
startColumn,
|
|
701
|
+
endColumn
|
|
702
|
+
},
|
|
703
|
+
sortText: key
|
|
704
|
+
}));
|
|
705
|
+
return { suggestions };
|
|
706
|
+
}
|
|
707
|
+
// Case 3: fresh new expression – cursor is at a word boundary and the user
|
|
708
|
+
// has started typing a key name.
|
|
709
|
+
const freshMatch = /(?:^|[\s=(<>,;{}\[\]"'`])(\w*)$/.exec(lineText);
|
|
710
|
+
if (freshMatch) {
|
|
711
|
+
const typed = freshMatch[1];
|
|
712
|
+
if (!typed)
|
|
713
|
+
return { suggestions: [] };
|
|
714
|
+
const startColumn = position.column - typed.length;
|
|
715
|
+
const suggestions = keys
|
|
716
|
+
.filter(key => key.startsWith(typed))
|
|
717
|
+
.map(key => {
|
|
718
|
+
const insertText = this.getFormattedPropertyExpression(key);
|
|
719
|
+
return {
|
|
720
|
+
label: key,
|
|
721
|
+
kind: monaco.languages.CompletionItemKind.Property,
|
|
722
|
+
insertText,
|
|
723
|
+
range: makeRange(startColumn),
|
|
724
|
+
detail: insertText,
|
|
725
|
+
filterText: key,
|
|
726
|
+
sortText: key
|
|
727
|
+
};
|
|
728
|
+
});
|
|
729
|
+
return { suggestions };
|
|
730
|
+
}
|
|
731
|
+
return { suggestions: [] };
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
this.suggestionProviders.push(monaco.languages.registerCompletionItemProvider('html', providerOptions), monaco.languages.registerCompletionItemProvider('javascript', providerOptions));
|
|
735
|
+
}
|
|
736
|
+
getFormattedPropertyExpression(key) {
|
|
737
|
+
const nonAlphanumericRegex = /[^a-zA-Z0-9]/;
|
|
738
|
+
const formattedKey = nonAlphanumericRegex.test(key) ? `[${quoteAndEscape(key)}]` : `${key}`;
|
|
739
|
+
return '${this.c8yProperties?.' + formattedKey + '}';
|
|
740
|
+
}
|
|
583
741
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: WidgetCodeEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
584
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: WidgetCodeEditorComponent, isStandalone: true, selector: "c8y-widget-code-editor", inputs: { mode: "mode", config: "config" }, viewQueries: [{ propertyName: "editorComponent", first: true, predicate: EditorComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<c8y-widget-config-feedback>\n <div class=\"d-flex\">\n @if (config?.devMode && !config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n translate\n >\n Advanced developer mode\n </span>\n }\n </div>\n <div class=\"d-flex\">\n @if (config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n [title]=\"\n 'This widget is in legacy mode. Consider to upgrade this to a new HTML widget. Read our documentation on details to transform your widget'\n | translate\n \"\n translate\n >\n Legacy mode\n </span>\n }\n </div>\n</c8y-widget-config-feedback>\n\n<div class=\"d-flex d-col fit-h fit-w\">\n <c8y-html-widget-advanced-settings\n [devMode]=\"config?.devMode\"\n [cssEncapsulation]=\"config?.options?.cssEncapsulation\"\n ></c8y-html-widget-advanced-settings>\n\n <fieldset class=\"c8y-fieldset p-0 overflow-hidden\">\n <legend class=\"m-l-16 p-l-0\">{{ 'Code' | translate }}</legend>\n\n <div class=\"btn-group btn-group-sm m-l-0 p-t-8 p-b-8 p-l-16 p-r-16 fit-w d-flex\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"'Undo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"undo()\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"'Redo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"redo()\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Format code' | translate\"\n [tooltip]=\"'Format code' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"formatCode()\"\n >\n <i [c8yIcon]=\"'format-align-left'\"></i>\n </button>\n\n <label class=\"c8y-switch m-l-auto\">\n <input\n type=\"checkbox\"\n [checked]=\"isAutoSaveEnabled\"\n (change)=\"isAutoSaveEnabled = !isAutoSaveEnabled\"\n />\n <span></span>\n <span translate>Auto save</span>\n </label>\n </div>\n\n <div\n class=\"btn-toolbar m-0 p-relative\"\n role=\"toolbar\"\n >\n <c8y-tabs-outlet\n class=\"elevation-none\"\n [outletName]=\"TAB_OUTLET_NAME\"\n [orientation]=\"'horizontal'\"\n [openFirstTab]=\"false\"\n ></c8y-tabs-outlet>\n <c8y-tab\n [icon]=\"'code'\"\n [label]=\"(config?.devMode ? TAB_WEBCOMPONENT_LABEL : TAB_HTML_LABEL) | translate\"\n [priority]=\"100\"\n [showAlways]=\"true\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'code'\"\n (onSelect)=\"switchMode('code')\"\n ></c8y-tab>\n @if (!config?.devMode && !config?.legacy) {\n <c8y-tab\n [icon]=\"'c8y-css'\"\n [label]=\"TAB_CSS_LABEL | translate\"\n [priority]=\"0\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'css'\"\n (onSelect)=\"switchMode('css')\"\n ></c8y-tab>\n }\n </div>\n\n @if (!isLoading) {\n @if (!(mode === 'css' && config?.devMode)) {\n <c8y-editor\n class=\"flex-grow d-block\"\n style=\"height: 450px\"\n [ngModel]=\"value\"\n (ngModelChange)=\"changeCode($event)\"\n [editorOptions]=\"{\n language,\n tabSize: 2,\n insertSpaces: true,\n minimap: { enabled: false }\n }\"\n (editorInit)=\"editorLoaded($event)\"\n ></c8y-editor>\n }\n } @else {\n <c8y-loading></c8y-loading>\n }\n </fieldset>\n</div>\n", dependencies: [{ kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "ngmodule", type: FormsModule }, { 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: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: WidgetConfigFeedbackComponent, selector: "c8y-widget-config-feedback" }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i2$1.TabsOutletComponent, selector: "c8y-tabs-outlet,c8y-ui-tabs", inputs: ["tabs", "orientation", "navigatorOpen", "outletName", "context", "openFirstTab", "hasHeader"] }, { kind: "component", type: i2$1.TabComponent, selector: "c8y-tab", inputs: ["path", "label", "icon", "priority", "orientation", "injector", "tabsOutlet", "isActive", "text", "showAlways"], outputs: ["onSelect"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: AdvancedSettingsComponent, selector: "c8y-html-widget-advanced-settings", inputs: ["devMode", "cssEncapsulation"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
|
|
742
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: WidgetCodeEditorComponent, isStandalone: true, selector: "c8y-widget-code-editor", inputs: { mode: "mode", config: "config" }, viewQueries: [{ propertyName: "editorComponent", first: true, predicate: EditorComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<c8y-widget-config-feedback>\n <div class=\"d-flex\">\n @if (config?.devMode && !config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n translate\n >\n Advanced developer mode\n </span>\n }\n </div>\n <div class=\"d-flex\">\n @if (config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n [title]=\"\n 'This widget is in legacy mode. Consider to upgrade this to a new HTML widget. Read our documentation on details to transform your widget'\n | translate\n \"\n translate\n >\n Legacy mode\n </span>\n }\n </div>\n</c8y-widget-config-feedback>\n\n<div class=\"d-flex d-col fit-h fit-w\">\n <c8y-html-widget-advanced-settings\n [devMode]=\"config?.devMode\"\n [cssEncapsulation]=\"config?.options?.cssEncapsulation\"\n ></c8y-html-widget-advanced-settings>\n\n <fieldset class=\"c8y-fieldset p-0 overflow-hidden\">\n <legend class=\"m-l-16 p-l-0\">{{ 'Code' | translate }}</legend>\n\n <div class=\"btn-group btn-group-sm m-l-0 p-t-8 p-b-8 p-l-16 p-r-16 fit-w d-flex\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"'Undo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"undo()\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"'Redo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"redo()\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Format code' | translate\"\n [tooltip]=\"'Format code' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"formatCode()\"\n >\n <i [c8yIcon]=\"'format-align-left'\"></i>\n </button>\n\n @let propertyKeys = propertyKeys$ | async;\n @if (mode !== 'css' && propertyKeys?.length) {\n <div\n class=\"btn-group btn-group-sm m-l-4\"\n container=\"body\"\n dropdown\n >\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Insert property' | translate\"\n [tooltip]=\"'Insert property' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n </button>\n <ul\n class=\"dropdown-menu\"\n *dropdownMenu\n >\n @for (key of propertyKeys; track key) {\n <li>\n <button\n class=\"dropdown-item\"\n type=\"button\"\n (click)=\"insertPropertyAtCursor(key)\"\n >\n {{ key }}\n </button>\n </li>\n }\n </ul>\n </div>\n }\n\n <label class=\"c8y-switch m-l-auto\">\n <input\n type=\"checkbox\"\n [checked]=\"isAutoSaveEnabled\"\n (change)=\"isAutoSaveEnabled = !isAutoSaveEnabled\"\n />\n <span></span>\n <span translate>Auto save</span>\n </label>\n </div>\n\n <div\n class=\"btn-toolbar m-0 p-relative\"\n role=\"toolbar\"\n >\n <c8y-tabs-outlet\n class=\"elevation-none\"\n [outletName]=\"TAB_OUTLET_NAME\"\n [orientation]=\"'horizontal'\"\n [openFirstTab]=\"false\"\n ></c8y-tabs-outlet>\n <c8y-tab\n [icon]=\"'code'\"\n [label]=\"(config?.devMode ? TAB_WEBCOMPONENT_LABEL : TAB_HTML_LABEL) | translate\"\n [priority]=\"100\"\n [showAlways]=\"true\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'code'\"\n (onSelect)=\"switchMode('code')\"\n ></c8y-tab>\n @if (!config?.devMode && !config?.legacy) {\n <c8y-tab\n [icon]=\"'c8y-css'\"\n [label]=\"TAB_CSS_LABEL | translate\"\n [priority]=\"0\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'css'\"\n (onSelect)=\"switchMode('css')\"\n ></c8y-tab>\n }\n </div>\n\n @if (!isLoading) {\n @if (!(mode === 'css' && config?.devMode)) {\n <c8y-editor\n class=\"flex-grow d-block\"\n style=\"height: 450px\"\n [ngModel]=\"value\"\n (ngModelChange)=\"changeCode($event)\"\n [editorOptions]=\"{\n language,\n tabSize: 2,\n insertSpaces: true,\n minimap: { enabled: false }\n }\"\n (editorInit)=\"editorLoaded($event)\"\n ></c8y-editor>\n }\n } @else {\n <c8y-loading></c8y-loading>\n }\n </fieldset>\n</div>\n", dependencies: [{ kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "ngmodule", type: FormsModule }, { 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: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: WidgetConfigFeedbackComponent, selector: "c8y-widget-config-feedback" }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i2$1.TabsOutletComponent, selector: "c8y-tabs-outlet,c8y-ui-tabs", inputs: ["tabs", "orientation", "navigatorOpen", "outletName", "context", "openFirstTab", "hasHeader"] }, { kind: "component", type: i2$1.TabComponent, selector: "c8y-tab", inputs: ["path", "label", "icon", "priority", "orientation", "injector", "tabsOutlet", "isActive", "text", "showAlways"], outputs: ["onSelect"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i4.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i4.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i4.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: AdvancedSettingsComponent, selector: "c8y-html-widget-advanced-settings", inputs: ["devMode", "cssEncapsulation"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
|
|
585
743
|
}
|
|
586
744
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: WidgetCodeEditorComponent, decorators: [{
|
|
587
745
|
type: Component,
|
|
588
746
|
args: [{ standalone: true, imports: [
|
|
747
|
+
AsyncPipe,
|
|
589
748
|
EditorComponent,
|
|
590
749
|
FormsModule,
|
|
591
750
|
IconDirective,
|
|
@@ -594,9 +753,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
594
753
|
TabsModule,
|
|
595
754
|
TooltipModule,
|
|
596
755
|
PopoverModule,
|
|
756
|
+
BsDropdownModule,
|
|
597
757
|
LoadingComponent,
|
|
598
758
|
AdvancedSettingsComponent
|
|
599
|
-
], selector: 'c8y-widget-code-editor', template: "<c8y-widget-config-feedback>\n <div class=\"d-flex\">\n @if (config?.devMode && !config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n translate\n >\n Advanced developer mode\n </span>\n }\n </div>\n <div class=\"d-flex\">\n @if (config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n [title]=\"\n 'This widget is in legacy mode. Consider to upgrade this to a new HTML widget. Read our documentation on details to transform your widget'\n | translate\n \"\n translate\n >\n Legacy mode\n </span>\n }\n </div>\n</c8y-widget-config-feedback>\n\n<div class=\"d-flex d-col fit-h fit-w\">\n <c8y-html-widget-advanced-settings\n [devMode]=\"config?.devMode\"\n [cssEncapsulation]=\"config?.options?.cssEncapsulation\"\n ></c8y-html-widget-advanced-settings>\n\n <fieldset class=\"c8y-fieldset p-0 overflow-hidden\">\n <legend class=\"m-l-16 p-l-0\">{{ 'Code' | translate }}</legend>\n\n <div class=\"btn-group btn-group-sm m-l-0 p-t-8 p-b-8 p-l-16 p-r-16 fit-w d-flex\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"'Undo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"undo()\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"'Redo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"redo()\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Format code' | translate\"\n [tooltip]=\"'Format code' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"formatCode()\"\n >\n <i [c8yIcon]=\"'format-align-left'\"></i>\n </button>\n\n <label class=\"c8y-switch m-l-auto\">\n <input\n type=\"checkbox\"\n [checked]=\"isAutoSaveEnabled\"\n (change)=\"isAutoSaveEnabled = !isAutoSaveEnabled\"\n />\n <span></span>\n <span translate>Auto save</span>\n </label>\n </div>\n\n <div\n class=\"btn-toolbar m-0 p-relative\"\n role=\"toolbar\"\n >\n <c8y-tabs-outlet\n class=\"elevation-none\"\n [outletName]=\"TAB_OUTLET_NAME\"\n [orientation]=\"'horizontal'\"\n [openFirstTab]=\"false\"\n ></c8y-tabs-outlet>\n <c8y-tab\n [icon]=\"'code'\"\n [label]=\"(config?.devMode ? TAB_WEBCOMPONENT_LABEL : TAB_HTML_LABEL) | translate\"\n [priority]=\"100\"\n [showAlways]=\"true\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'code'\"\n (onSelect)=\"switchMode('code')\"\n ></c8y-tab>\n @if (!config?.devMode && !config?.legacy) {\n <c8y-tab\n [icon]=\"'c8y-css'\"\n [label]=\"TAB_CSS_LABEL | translate\"\n [priority]=\"0\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'css'\"\n (onSelect)=\"switchMode('css')\"\n ></c8y-tab>\n }\n </div>\n\n @if (!isLoading) {\n @if (!(mode === 'css' && config?.devMode)) {\n <c8y-editor\n class=\"flex-grow d-block\"\n style=\"height: 450px\"\n [ngModel]=\"value\"\n (ngModelChange)=\"changeCode($event)\"\n [editorOptions]=\"{\n language,\n tabSize: 2,\n insertSpaces: true,\n minimap: { enabled: false }\n }\"\n (editorInit)=\"editorLoaded($event)\"\n ></c8y-editor>\n }\n } @else {\n <c8y-loading></c8y-loading>\n }\n </fieldset>\n</div>\n" }]
|
|
759
|
+
], selector: 'c8y-widget-code-editor', template: "<c8y-widget-config-feedback>\n <div class=\"d-flex\">\n @if (config?.devMode && !config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n translate\n >\n Advanced developer mode\n </span>\n }\n </div>\n <div class=\"d-flex\">\n @if (config?.legacy) {\n <span\n class=\"tag tag--warning text-12\"\n [title]=\"\n 'This widget is in legacy mode. Consider to upgrade this to a new HTML widget. Read our documentation on details to transform your widget'\n | translate\n \"\n translate\n >\n Legacy mode\n </span>\n }\n </div>\n</c8y-widget-config-feedback>\n\n<div class=\"d-flex d-col fit-h fit-w\">\n <c8y-html-widget-advanced-settings\n [devMode]=\"config?.devMode\"\n [cssEncapsulation]=\"config?.options?.cssEncapsulation\"\n ></c8y-html-widget-advanced-settings>\n\n <fieldset class=\"c8y-fieldset p-0 overflow-hidden\">\n <legend class=\"m-l-16 p-l-0\">{{ 'Code' | translate }}</legend>\n\n <div class=\"btn-group btn-group-sm m-l-0 p-t-8 p-b-8 p-l-16 p-r-16 fit-w d-flex\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Undo' | translate\"\n [tooltip]=\"'Undo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"undo()\"\n >\n <i [c8yIcon]=\"'undo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Redo' | translate\"\n [tooltip]=\"'Redo' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"redo()\"\n >\n <i [c8yIcon]=\"'redo'\"></i>\n </button>\n\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Format code' | translate\"\n [tooltip]=\"'Format code' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"formatCode()\"\n >\n <i [c8yIcon]=\"'format-align-left'\"></i>\n </button>\n\n @let propertyKeys = propertyKeys$ | async;\n @if (mode !== 'css' && propertyKeys?.length) {\n <div\n class=\"btn-group btn-group-sm m-l-4\"\n container=\"body\"\n dropdown\n >\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Insert property' | translate\"\n [tooltip]=\"'Insert property' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n </button>\n <ul\n class=\"dropdown-menu\"\n *dropdownMenu\n >\n @for (key of propertyKeys; track key) {\n <li>\n <button\n class=\"dropdown-item\"\n type=\"button\"\n (click)=\"insertPropertyAtCursor(key)\"\n >\n {{ key }}\n </button>\n </li>\n }\n </ul>\n </div>\n }\n\n <label class=\"c8y-switch m-l-auto\">\n <input\n type=\"checkbox\"\n [checked]=\"isAutoSaveEnabled\"\n (change)=\"isAutoSaveEnabled = !isAutoSaveEnabled\"\n />\n <span></span>\n <span translate>Auto save</span>\n </label>\n </div>\n\n <div\n class=\"btn-toolbar m-0 p-relative\"\n role=\"toolbar\"\n >\n <c8y-tabs-outlet\n class=\"elevation-none\"\n [outletName]=\"TAB_OUTLET_NAME\"\n [orientation]=\"'horizontal'\"\n [openFirstTab]=\"false\"\n ></c8y-tabs-outlet>\n <c8y-tab\n [icon]=\"'code'\"\n [label]=\"(config?.devMode ? TAB_WEBCOMPONENT_LABEL : TAB_HTML_LABEL) | translate\"\n [priority]=\"100\"\n [showAlways]=\"true\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'code'\"\n (onSelect)=\"switchMode('code')\"\n ></c8y-tab>\n @if (!config?.devMode && !config?.legacy) {\n <c8y-tab\n [icon]=\"'c8y-css'\"\n [label]=\"TAB_CSS_LABEL | translate\"\n [priority]=\"0\"\n [tabsOutlet]=\"TAB_OUTLET_NAME\"\n [isActive]=\"mode === 'css'\"\n (onSelect)=\"switchMode('css')\"\n ></c8y-tab>\n }\n </div>\n\n @if (!isLoading) {\n @if (!(mode === 'css' && config?.devMode)) {\n <c8y-editor\n class=\"flex-grow d-block\"\n style=\"height: 450px\"\n [ngModel]=\"value\"\n (ngModelChange)=\"changeCode($event)\"\n [editorOptions]=\"{\n language,\n tabSize: 2,\n insertSpaces: true,\n minimap: { enabled: false }\n }\"\n (editorInit)=\"editorLoaded($event)\"\n ></c8y-editor>\n }\n } @else {\n <c8y-loading></c8y-loading>\n }\n </fieldset>\n</div>\n" }]
|
|
600
760
|
}], propDecorators: { mode: [{
|
|
601
761
|
type: Input
|
|
602
762
|
}], config: [{
|
|
@@ -607,11 +767,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
607
767
|
}] } });
|
|
608
768
|
|
|
609
769
|
class HtmlWidgetConfigComponent {
|
|
610
|
-
constructor() {
|
|
611
|
-
this.options = inject(OptionsService);
|
|
612
|
-
this.htmlWidgetConfigService = inject(HtmlWidgetConfigService);
|
|
613
|
-
this.widgetConfigService = inject(WidgetConfigService);
|
|
614
|
-
}
|
|
615
770
|
set htmlPreviewTemplate(template) {
|
|
616
771
|
if (template) {
|
|
617
772
|
this.widgetConfigService.setPreview(template);
|
|
@@ -620,19 +775,56 @@ class HtmlWidgetConfigComponent {
|
|
|
620
775
|
this.widgetConfigService.setPreview(null);
|
|
621
776
|
}
|
|
622
777
|
}
|
|
778
|
+
constructor() {
|
|
779
|
+
this.alert = inject(AlertService);
|
|
780
|
+
this.options = inject(OptionsService);
|
|
781
|
+
this.htmlWidgetConfigService = inject(HtmlWidgetConfigService);
|
|
782
|
+
this.widgetConfigService = inject(WidgetConfigService);
|
|
783
|
+
this.assetPropertyMappings = inject(AssetPropertyMappingsService);
|
|
784
|
+
this.controls = PRESET_NAME.AUTO_REFRESH_ONLY;
|
|
785
|
+
this.destroyRef = inject(DestroyRef);
|
|
786
|
+
this.realtimeControl$ = this.widgetConfigService.currentConfig$.pipe(map$1(config => config?.refreshOption === REFRESH_OPTION.LIVE && config?.isAutoRefreshEnabled === true), distinctUntilChanged$1());
|
|
787
|
+
this.propertyValues$ = this.widgetConfigService.currentConfig$.pipe(switchMap$1(config => this.assetPropertyMappings.getValues$(config?.properties, this.realtimeControl$)));
|
|
788
|
+
this.globalContextState$ = this.widgetConfigService.currentConfig$.pipe(map$1(config => config));
|
|
789
|
+
this.htmlWidgetConfigService.notify$
|
|
790
|
+
.pipe(takeUntilDestroyed(this.destroyRef), filter$1((n) => n.type === 'asset-property-mapping-key-renamed'))
|
|
791
|
+
.subscribe(notification => this.handleRename(notification));
|
|
792
|
+
}
|
|
623
793
|
ngOnDestroy() {
|
|
624
794
|
// sadly the service is component scoped
|
|
625
795
|
// but still not recycled correctly. That is why we do
|
|
626
796
|
// it here.
|
|
627
797
|
this.htmlWidgetConfigService.destroy();
|
|
628
798
|
}
|
|
799
|
+
handleRename(notification) {
|
|
800
|
+
const { oldKey, newKey } = notification;
|
|
801
|
+
const htmlWidgetConfig = this.widgetConfigService.currentConfig;
|
|
802
|
+
if (!htmlWidgetConfig?.config) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const newCode = renamePropertyKeyInCode(htmlWidgetConfig.config.code, oldKey, newKey);
|
|
806
|
+
if (newCode === htmlWidgetConfig.config.code) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const updated = { ...htmlWidgetConfig.config, code: newCode };
|
|
810
|
+
this.htmlWidgetConfigService.save(updated);
|
|
811
|
+
this.htmlWidgetConfigService.configChanged$.next(updated);
|
|
812
|
+
this.alert.success(gettext('Renamed asset property and updated references in HTML code.'));
|
|
813
|
+
}
|
|
629
814
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: HtmlWidgetConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
630
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
815
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: HtmlWidgetConfigComponent, isStandalone: true, selector: "c8y-html-widget-config", viewQueries: [{ propertyName: "htmlPreviewTemplate", first: true, predicate: ["htmlPreview"], descendants: true }], ngImport: i0, template: "<c8y-widget-code-editor\n [config]=\"htmlWidgetConfigService.config$ | async\"\n [mode]=\"'code'\"\n></c8y-widget-code-editor>\n\n<ng-template #htmlPreview>\n @if ((widgetConfigService.currentConfig$ | async)?.displayMode !== 'dashboard') {\n <c8y-local-controls\n [controls]=\"controls\"\n [displayMode]=\"(widgetConfigService.currentConfig$ | async)?.displayMode\"\n [config]=\"globalContextState$ | async\"\n [disabled]=\"true\"\n ></c8y-local-controls>\n }\n <c8y-html-frame\n [config]=\"htmlWidgetConfigService.codeEditorChangeConfig$ | async\"\n [device]=\"(widgetConfigService.currentConfig$ | async).device\"\n [propertyValues$]=\"propertyValues$\"\n [useSalt]=\"true\"\n ></c8y-html-frame>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: HtmlFrameComponent, selector: "c8y-html-frame", inputs: ["config", "device", "propertyValues$", "useSalt"] }, { kind: "component", type: WidgetCodeEditorComponent, selector: "c8y-widget-code-editor", inputs: ["mode", "config"] }, { kind: "component", type: LocalControlsComponent, selector: "c8y-local-controls", inputs: ["controls", "displayMode", "config", "isLoading", "disabled", "emitRefresh"], outputs: ["configChange", "refresh"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
631
816
|
}
|
|
632
817
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: HtmlWidgetConfigComponent, decorators: [{
|
|
633
818
|
type: Component,
|
|
634
|
-
args: [{ selector: 'c8y-html-widget-config', standalone: true, imports: [
|
|
635
|
-
|
|
819
|
+
args: [{ selector: 'c8y-html-widget-config', standalone: true, imports: [
|
|
820
|
+
RouterModule,
|
|
821
|
+
FormsModule,
|
|
822
|
+
AsyncPipe,
|
|
823
|
+
HtmlFrameComponent,
|
|
824
|
+
WidgetCodeEditorComponent,
|
|
825
|
+
LocalControlsComponent
|
|
826
|
+
], template: "<c8y-widget-code-editor\n [config]=\"htmlWidgetConfigService.config$ | async\"\n [mode]=\"'code'\"\n></c8y-widget-code-editor>\n\n<ng-template #htmlPreview>\n @if ((widgetConfigService.currentConfig$ | async)?.displayMode !== 'dashboard') {\n <c8y-local-controls\n [controls]=\"controls\"\n [displayMode]=\"(widgetConfigService.currentConfig$ | async)?.displayMode\"\n [config]=\"globalContextState$ | async\"\n [disabled]=\"true\"\n ></c8y-local-controls>\n }\n <c8y-html-frame\n [config]=\"htmlWidgetConfigService.codeEditorChangeConfig$ | async\"\n [device]=\"(widgetConfigService.currentConfig$ | async).device\"\n [propertyValues$]=\"propertyValues$\"\n [useSalt]=\"true\"\n ></c8y-html-frame>\n</ng-template>\n" }]
|
|
827
|
+
}], ctorParameters: () => [], propDecorators: { htmlPreviewTemplate: [{
|
|
636
828
|
type: ViewChild,
|
|
637
829
|
args: ['htmlPreview']
|
|
638
830
|
}] } });
|
|
@@ -679,10 +871,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
679
871
|
}] });
|
|
680
872
|
|
|
681
873
|
class HtmlWidgetComponent {
|
|
874
|
+
constructor() {
|
|
875
|
+
this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
|
|
876
|
+
this.realtimeControl$ = new BehaviorSubject(false);
|
|
877
|
+
this.propertyValues$ = computed(() => this.assetPropertiesMappings.getValues$(this.config()?.properties, this.realtimeControl$.asObservable()), ...(ngDevMode ? [{ debugName: "propertyValues$" }] : []));
|
|
878
|
+
this.dashboardChild = inject(DashboardChildComponent);
|
|
879
|
+
this.displayMode = signal(GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD, ...(ngDevMode ? [{ debugName: "displayMode" }] : []));
|
|
880
|
+
this.contextConfig = signal({}, ...(ngDevMode ? [{ debugName: "contextConfig" }] : []));
|
|
881
|
+
this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
882
|
+
/**
|
|
883
|
+
* Controls link state to global context:
|
|
884
|
+
* - true/undefined: Widget follows global time context
|
|
885
|
+
* - false: Widget uses local state, ignores global changes
|
|
886
|
+
* Set to false when user is interacting (scrolling, zooming) to prevent interruption
|
|
887
|
+
*/
|
|
888
|
+
this.isLinkedToGlobal = signal(undefined, ...(ngDevMode ? [{ debugName: "isLinkedToGlobal" }] : []));
|
|
889
|
+
this.GLOBAL_CONTEXT_DISPLAY_MODE = GLOBAL_CONTEXT_DISPLAY_MODE;
|
|
890
|
+
this.PRESET_NAME = PRESET_NAME;
|
|
891
|
+
this.assetPropertiesMappings = inject(AssetPropertyMappingsService);
|
|
892
|
+
}
|
|
682
893
|
ngOnInit() {
|
|
683
|
-
|
|
684
|
-
|
|
894
|
+
const config = this.config();
|
|
895
|
+
if (config?.html && !config.config) {
|
|
896
|
+
config.config = this.mapLegacyConfig(config);
|
|
685
897
|
}
|
|
898
|
+
const { displayMode = GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD, dateTimeContext, aggregation, isAutoRefreshEnabled, refreshInterval, refreshOption } = config;
|
|
899
|
+
this.displayMode.set(displayMode);
|
|
900
|
+
this.contextConfig.set({
|
|
901
|
+
dateTimeContext,
|
|
902
|
+
aggregation,
|
|
903
|
+
isAutoRefreshEnabled,
|
|
904
|
+
refreshInterval,
|
|
905
|
+
refreshOption
|
|
906
|
+
});
|
|
907
|
+
// Initialize realtime from persisted config — controls may be hidden in
|
|
908
|
+
// config display mode (AUTO_REFRESH_ONLY.config = []), in which case
|
|
909
|
+
// onContextChange never fires and realtimeControl$ would stay false.
|
|
910
|
+
this.realtimeControl$.next(this.shouldEnableRealtime());
|
|
911
|
+
}
|
|
912
|
+
onContextChange(event) {
|
|
913
|
+
const { context } = event;
|
|
914
|
+
this.contextConfig.set(context);
|
|
915
|
+
this.realtimeControl$.next(this.shouldEnableRealtime());
|
|
916
|
+
}
|
|
917
|
+
getDashboardChild() {
|
|
918
|
+
return this.dashboardChild;
|
|
919
|
+
}
|
|
920
|
+
shouldEnableRealtime() {
|
|
921
|
+
const ctx = this.contextConfig();
|
|
922
|
+
return ctx.refreshOption === REFRESH_OPTION.LIVE && ctx.isAutoRefreshEnabled === true;
|
|
686
923
|
}
|
|
687
924
|
mapLegacyConfig(current) {
|
|
688
925
|
const isAlreadyInAdvancedMode = current?.config?.devMode === true;
|
|
@@ -701,14 +938,17 @@ class HtmlWidgetComponent {
|
|
|
701
938
|
};
|
|
702
939
|
}
|
|
703
940
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: HtmlWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
704
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
941
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: HtmlWidgetComponent, isStandalone: true, selector: "c8y-html-widget", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (displayMode() === GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD) {\n <c8y-global-context-connector\n [controls]=\"PRESET_NAME.AUTO_REFRESH_ONLY\"\n [config]=\"contextConfig()\"\n [isLoading]=\"isLoading()\"\n [dashboardChild]=\"getDashboardChild()\"\n [linked]=\"isLinkedToGlobal()\"\n [emitRefresh]=\"false\"\n (configChange)=\"onContextChange($event)\"\n >\n </c8y-global-context-connector>\n} @else {\n <c8y-local-controls\n [controls]=\"PRESET_NAME.AUTO_REFRESH_ONLY\"\n [displayMode]=\"displayMode()\"\n [config]=\"contextConfig()\"\n [isLoading]=\"isLoading()\"\n [emitRefresh]=\"false\"\n (configChange)=\"onContextChange($event)\"\n >\n </c8y-local-controls>\n}\n\n<div class=\"p-16\">\n <c8y-html-frame\n [config]=\"config().config\"\n [device]=\"config().device\"\n [propertyValues$]=\"propertyValues$()\"\n ></c8y-html-frame>\n</div>\n", dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "component", type: HtmlFrameComponent, selector: "c8y-html-frame", inputs: ["config", "device", "propertyValues$", "useSalt"] }, { kind: "component", type: GlobalContextConnectorComponent, selector: "c8y-global-context-connector", inputs: ["controls", "config", "isLoading", "dashboardChild", "linked", "emitRefresh"], outputs: ["configChange", "refresh", "linkedChange"] }, { kind: "component", type: LocalControlsComponent, selector: "c8y-local-controls", inputs: ["controls", "displayMode", "config", "isLoading", "disabled", "emitRefresh"], outputs: ["configChange", "refresh"] }] }); }
|
|
705
942
|
}
|
|
706
943
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: HtmlWidgetComponent, decorators: [{
|
|
707
944
|
type: Component,
|
|
708
|
-
args: [{ selector: 'c8y-html-widget', standalone: true, imports: [
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
945
|
+
args: [{ selector: 'c8y-html-widget', standalone: true, imports: [
|
|
946
|
+
RouterModule,
|
|
947
|
+
HtmlFrameComponent,
|
|
948
|
+
GlobalContextConnectorComponent,
|
|
949
|
+
LocalControlsComponent
|
|
950
|
+
], template: "@if (displayMode() === GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD) {\n <c8y-global-context-connector\n [controls]=\"PRESET_NAME.AUTO_REFRESH_ONLY\"\n [config]=\"contextConfig()\"\n [isLoading]=\"isLoading()\"\n [dashboardChild]=\"getDashboardChild()\"\n [linked]=\"isLinkedToGlobal()\"\n [emitRefresh]=\"false\"\n (configChange)=\"onContextChange($event)\"\n >\n </c8y-global-context-connector>\n} @else {\n <c8y-local-controls\n [controls]=\"PRESET_NAME.AUTO_REFRESH_ONLY\"\n [displayMode]=\"displayMode()\"\n [config]=\"contextConfig()\"\n [isLoading]=\"isLoading()\"\n [emitRefresh]=\"false\"\n (configChange)=\"onContextChange($event)\"\n >\n </c8y-local-controls>\n}\n\n<div class=\"p-16\">\n <c8y-html-frame\n [config]=\"config().config\"\n [device]=\"config().device\"\n [propertyValues$]=\"propertyValues$()\"\n ></c8y-html-frame>\n</div>\n" }]
|
|
951
|
+
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
|
|
712
952
|
|
|
713
953
|
/**
|
|
714
954
|
* Generated bundle index. Do not edit.
|