@c8y/ngx-components 1023.71.1 → 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.
Files changed (163) hide show
  1. package/asset-properties/index.d.ts +19 -1
  2. package/asset-properties/index.d.ts.map +1 -1
  3. package/cockpit-config/index.d.ts +4 -3
  4. package/cockpit-config/index.d.ts.map +1 -1
  5. package/context-dashboard/index.d.ts +202 -4
  6. package/context-dashboard/index.d.ts.map +1 -1
  7. package/datapoints-export-selector/index.d.ts +8 -1
  8. package/datapoints-export-selector/index.d.ts.map +1 -1
  9. package/device-profile/index.d.ts +8 -1
  10. package/device-profile/index.d.ts.map +1 -1
  11. package/events/cockpit/index.d.ts +6 -0
  12. package/events/cockpit/index.d.ts.map +1 -0
  13. package/events/devicemanagement/index.d.ts +6 -0
  14. package/events/devicemanagement/index.d.ts.map +1 -0
  15. package/events/events-timeline/index.d.ts +10 -10
  16. package/events/events-timeline/index.d.ts.map +1 -1
  17. package/events/index.d.ts +363 -5
  18. package/events/index.d.ts.map +1 -1
  19. package/fesm2022/c8y-ngx-components-alarm-event-selector.mjs +1 -1
  20. package/fesm2022/c8y-ngx-components-alarm-event-selector.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-alarms.mjs +1 -1
  22. package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
  23. package/fesm2022/c8y-ngx-components-asset-properties.mjs +2 -2
  24. package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
  25. package/fesm2022/c8y-ngx-components-auth-configuration.mjs +1 -1
  26. package/fesm2022/c8y-ngx-components-auth-configuration.mjs.map +1 -1
  27. package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs +1 -1
  28. package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs.map +1 -1
  29. package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs +2 -2
  30. package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs.map +1 -1
  31. package/fesm2022/c8y-ngx-components-cockpit-config.mjs +8 -11
  32. package/fesm2022/c8y-ngx-components-cockpit-config.mjs.map +1 -1
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs +1 -1
  46. 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
  47. 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
  48. 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
  49. 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
  50. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +561 -21
  51. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  52. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +2 -2
  53. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  54. package/fesm2022/c8y-ngx-components-datapoint-library-details.mjs +1 -1
  55. package/fesm2022/c8y-ngx-components-datapoint-library-details.mjs.map +1 -1
  56. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +1 -1
  57. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
  58. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +41 -8
  59. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  60. package/fesm2022/c8y-ngx-components-device-profile.mjs +38 -12
  61. package/fesm2022/c8y-ngx-components-device-profile.mjs.map +1 -1
  62. package/fesm2022/c8y-ngx-components-ecosystem-license-confirm.mjs +1 -1
  63. package/fesm2022/c8y-ngx-components-ecosystem-license-confirm.mjs.map +1 -1
  64. package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs +1 -1
  65. package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
  66. package/fesm2022/c8y-ngx-components-ecosystem.mjs +1 -1
  67. package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
  68. package/fesm2022/c8y-ngx-components-events-cockpit.mjs +54 -0
  69. package/fesm2022/c8y-ngx-components-events-cockpit.mjs.map +1 -0
  70. package/fesm2022/c8y-ngx-components-events-devicemanagement.mjs +79 -0
  71. package/fesm2022/c8y-ngx-components-events-devicemanagement.mjs.map +1 -0
  72. package/fesm2022/c8y-ngx-components-events-events-timeline.mjs +30 -23
  73. package/fesm2022/c8y-ngx-components-events-events-timeline.mjs.map +1 -1
  74. package/fesm2022/c8y-ngx-components-events.mjs +1080 -4
  75. package/fesm2022/c8y-ngx-components-events.mjs.map +1 -1
  76. package/fesm2022/c8y-ngx-components-file-preview.mjs +48 -41
  77. package/fesm2022/c8y-ngx-components-file-preview.mjs.map +1 -1
  78. package/fesm2022/c8y-ngx-components-files-repository.mjs +1 -1
  79. package/fesm2022/c8y-ngx-components-files-repository.mjs.map +1 -1
  80. package/fesm2022/c8y-ngx-components-global-context.mjs +68 -34
  81. package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
  82. package/fesm2022/c8y-ngx-components-interval-picker.mjs +3 -3
  83. package/fesm2022/c8y-ngx-components-interval-picker.mjs.map +1 -1
  84. package/fesm2022/c8y-ngx-components-location.mjs +1 -1
  85. package/fesm2022/c8y-ngx-components-location.mjs.map +1 -1
  86. package/fesm2022/c8y-ngx-components-operation-picker.mjs +1 -1
  87. package/fesm2022/c8y-ngx-components-operation-picker.mjs.map +1 -1
  88. package/fesm2022/c8y-ngx-components-operations-bulk-operation-scheduler.mjs +1 -1
  89. package/fesm2022/c8y-ngx-components-operations-bulk-operation-scheduler.mjs.map +1 -1
  90. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs +1 -1
  91. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs.map +1 -1
  92. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs +1 -1
  93. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs.map +1 -1
  94. package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs +5 -5
  95. package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs.map +1 -1
  96. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +2 -2
  97. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
  98. package/fesm2022/c8y-ngx-components-remote-access-shared.mjs +1 -1
  99. package/fesm2022/c8y-ngx-components-remote-access-shared.mjs.map +1 -1
  100. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +1 -1
  101. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs.map +1 -1
  102. package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs +1 -1
  103. package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs.map +1 -1
  104. package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs +1 -1
  105. package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs.map +1 -1
  106. package/fesm2022/c8y-ngx-components-repository-firmware.mjs +1 -1
  107. package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
  108. package/fesm2022/c8y-ngx-components-static-assets-modal.mjs +1 -1
  109. package/fesm2022/c8y-ngx-components-static-assets-modal.mjs.map +1 -1
  110. package/fesm2022/c8y-ngx-components-time-context.mjs +1 -1
  111. package/fesm2022/c8y-ngx-components-time-context.mjs.map +1 -1
  112. package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs +1 -1
  113. package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs.map +1 -1
  114. package/fesm2022/c8y-ngx-components-widgets-definitions-event-list.mjs +39 -1
  115. package/fesm2022/c8y-ngx-components-widgets-definitions-event-list.mjs.map +1 -1
  116. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs +76 -4
  117. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs.map +1 -1
  118. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs +1 -1
  119. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs.map +1 -1
  120. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +1 -1
  121. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  122. package/fesm2022/c8y-ngx-components-widgets-implementations-events.mjs +236 -0
  123. package/fesm2022/c8y-ngx-components-widgets-implementations-events.mjs.map +1 -0
  124. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +271 -31
  125. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
  126. package/fesm2022/c8y-ngx-components-widgets-implementations-image.mjs +1 -1
  127. package/fesm2022/c8y-ngx-components-widgets-implementations-image.mjs.map +1 -1
  128. package/fesm2022/c8y-ngx-components-widgets-implementations-info-gauge.mjs +1 -1
  129. package/fesm2022/c8y-ngx-components-widgets-implementations-info-gauge.mjs.map +1 -1
  130. package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs +1 -1
  131. package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs.map +1 -1
  132. package/fesm2022/c8y-ngx-components-widgets-implementations-linear-gauge.mjs +1 -1
  133. package/fesm2022/c8y-ngx-components-widgets-implementations-linear-gauge.mjs.map +1 -1
  134. package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs +1 -1
  135. package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs.map +1 -1
  136. package/fesm2022/c8y-ngx-components.mjs +248 -26
  137. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  138. package/file-preview/index.d.ts +7 -6
  139. package/file-preview/index.d.ts.map +1 -1
  140. package/global-context/index.d.ts +3 -0
  141. package/global-context/index.d.ts.map +1 -1
  142. package/index.d.ts +106 -11
  143. package/index.d.ts.map +1 -1
  144. package/locales/de.po +117 -3
  145. package/locales/es.po +117 -3
  146. package/locales/fr.po +117 -3
  147. package/locales/ja_JP.po +117 -3
  148. package/locales/ko.po +117 -3
  149. package/locales/locales.pot +117 -3
  150. package/locales/nl.po +117 -3
  151. package/locales/pl.po +117 -3
  152. package/locales/pt_BR.po +117 -3
  153. package/locales/zh_CN.po +117 -3
  154. package/locales/zh_TW.po +117 -3
  155. package/package.json +1 -1
  156. package/widgets/definitions/event-list/index.d.ts +44 -1
  157. package/widgets/definitions/event-list/index.d.ts.map +1 -1
  158. package/widgets/implementations/alarms/index.d.ts +2 -0
  159. package/widgets/implementations/alarms/index.d.ts.map +1 -1
  160. package/widgets/implementations/events/index.d.ts +89 -0
  161. package/widgets/implementations/events/index.d.ts.map +1 -0
  162. package/widgets/implementations/html-widget/index.d.ts +69 -9
  163. package/widgets/implementations/html-widget/index.d.ts.map +1 -1
@@ -1,35 +1,37 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Component, inject, InjectionToken, EventEmitter, Output, Input, signal, DestroyRef, TemplateRef, ViewChild, Optional, Inject, HostListener, input, HostBinding, NgModule } from '@angular/core';
2
+ import { Injectable, Component, inject, InjectionToken, EventEmitter, Output, Input, signal, DestroyRef, TemplateRef, ViewChild, Optional, Inject, HostListener, input, HostBinding, NgModule, Injector, runInInjectionContext, ChangeDetectionStrategy } from '@angular/core';
3
3
  import * as i2 from '@c8y/ngx-components';
4
- import { IconDirective, C8yTranslatePipe, Permissions, ContextRouteService, Status, NavigatorNode, NEW_DASHBOARD_ROUTER_STATE_PROP, getActivatedRoute, ViewContext, TabsOutletComponent, memoize, hookGeneric, ExtensionPointForPlugins, fromTriggerOnce, getInjectedHooks, stateToFactory, ListGroupModule, C8yComponentOutlet, AlertService, C8yTranslateDirective, DynamicComponentModule, DynamicComponentComponent, sortByPriority, isPromise, CoreModule, WIDGET_CONFIGURATION_GRID_SIZE, HighlightComponent, EmptyStateComponent, FormGroupComponent, RequiredInputPlaceholderDirective, ProductExperienceDirective, ResizableGridComponent, DashboardChildChange, CopyDashboardDisabledReason, TitleComponent, ActionBarItemComponent, HelpComponent, WidgetsDashboardComponent, DatePipe, hookRoute, hookTab, PreviewService, hookNavigator } from '@c8y/ngx-components';
4
+ import { IconDirective, C8yTranslatePipe, Permissions, ContextRouteService, Status, NavigatorNode, NEW_DASHBOARD_ROUTER_STATE_PROP, getActivatedRoute, ViewContext, TabsOutletComponent, memoize, hookGeneric, ExtensionPointForPlugins, fromTriggerOnce, getInjectedHooks, stateToFactory, ListGroupModule, C8yComponentOutlet, AlertService, C8yTranslateDirective, DynamicComponentModule, DynamicComponentComponent, sortByPriority, isPromise, CoreModule, WIDGET_CONFIGURATION_GRID_SIZE, HighlightComponent, EmptyStateComponent, FormGroupComponent, RequiredInputPlaceholderDirective, ProductExperienceDirective, ResizableGridComponent, DashboardChildChange, CopyDashboardDisabledReason, TitleComponent, ActionBarItemComponent, HelpComponent, WidgetsDashboardComponent, DatePipe, hookRoute, hookTab, PreviewService, hookNavigator, ManagedObjectRealtimeService, BottomDrawerService, ClipboardService, InputGroupEditableComponent, MessageDirective } from '@c8y/ngx-components';
5
5
  import * as i1 from '@angular/router';
6
6
  import { RouterOutlet, ActivatedRoute, RouterModule } from '@angular/router';
7
- import { of, Subject, from, combineLatest, map as map$1, merge, BehaviorSubject, tap as tap$1, withLatestFrom, mergeMap as mergeMap$1, shareReplay as shareReplay$1, scan, debounceTime, isObservable, iif, timer, filter as filter$1, switchMap as switchMap$1, take } from 'rxjs';
7
+ import { of, Subject, from, combineLatest, map as map$1, merge, BehaviorSubject, tap as tap$1, withLatestFrom, mergeMap as mergeMap$1, shareReplay as shareReplay$1, scan, debounceTime, isObservable, iif, timer, filter as filter$1, switchMap as switchMap$1, take, forkJoin, firstValueFrom } from 'rxjs';
8
8
  import { gettext } from '@c8y/ngx-components/gettext';
9
9
  import { __decorate, __metadata } from 'tslib';
10
10
  import * as i3 from '@angular/common';
11
11
  import { NgTemplateOutlet, CommonModule, NgClass, AsyncPipe, NgIf, NgForOf, NgFor } from '@angular/common';
12
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
12
+ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
13
13
  import * as i6 from '@c8y/ngx-components/context-dashboard-state';
14
14
  import * as i2$1 from '@ngx-translate/core';
15
- import { assign, pick, isEmpty, cloneDeep, some, keys, keyBy, has, set, reduce, forEach, get, isEqual, clone, merge as merge$1, omit, sortBy, isNull, escapeRegExp, findIndex, kebabCase, every } from 'lodash-es';
15
+ import { assign, pick, isEmpty, cloneDeep, some, keys, keyBy, has, set, reduce, forEach, get, isEqual, clone, merge as merge$1, omit, sortBy, isNull, escapeRegExp, findIndex, kebabCase, every, words, camelCase } from 'lodash-es';
16
16
  import * as i2$2 from 'ngx-bootstrap/popover';
17
17
  import { PopoverModule, PopoverDirective } from 'ngx-bootstrap/popover';
18
18
  import * as i1$1 from '@c8y/client';
19
19
  import { QueriesUtil, InventoryService } from '@c8y/client';
20
- import { tap, map, catchError, throwIfEmpty, filter, mergeMap, toArray, first, distinctUntilChanged, shareReplay, switchMap } from 'rxjs/operators';
21
- import * as i5 from '@angular/forms';
20
+ import { tap, map, catchError, throwIfEmpty, filter, mergeMap, toArray, first, distinctUntilChanged, shareReplay, switchMap, startWith, take as take$1 } from 'rxjs/operators';
21
+ import * as i1$2 from '@angular/forms';
22
22
  import { Validators, NgForm, ControlContainer, FormsModule } from '@angular/forms';
23
23
  import * as i2$3 from 'ngx-bootstrap/collapse';
24
24
  import { CollapseDirective, CollapseModule } from 'ngx-bootstrap/collapse';
25
- import * as i1$2 from '@c8y/ngx-components/assets-navigator';
25
+ import * as i1$3 from '@c8y/ngx-components/assets-navigator';
26
26
  import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
27
+ import * as i2$4 from 'ngx-bootstrap/tooltip';
27
28
  import { TooltipDirective, TooltipModule } from 'ngx-bootstrap/tooltip';
28
29
  import { IconSelectorModule } from '@c8y/ngx-components/icon-selector';
29
- import * as i1$3 from 'ngx-bootstrap/dropdown';
30
+ import * as i1$4 from 'ngx-bootstrap/dropdown';
30
31
  import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
31
32
  import { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';
32
33
  import { GlobalContextWidgetWrapperComponent, ConfigModeControlsComponent } from '@c8y/ngx-components/global-context';
34
+ import { AssetPropertiesService, ComputedPropertiesService, AssetPropertySelectorDrawerComponent, AssetPropertyValuePipe } from '@c8y/ngx-components/asset-properties';
33
35
 
34
36
  const newDashboardTab = {
35
37
  featureId: 'newDashboard',
@@ -1170,12 +1172,12 @@ class DashboardDetailService {
1170
1172
  children: dashboard?.children || {}
1171
1173
  });
1172
1174
  }
1173
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DashboardDetailService, deps: [{ token: i5.FormBuilder }, { token: i2$1.TranslateService }, { token: i2.TabsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1175
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DashboardDetailService, deps: [{ token: i1$2.FormBuilder }, { token: i2$1.TranslateService }, { token: i2.TabsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1174
1176
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DashboardDetailService }); }
1175
1177
  }
1176
1178
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DashboardDetailService, decorators: [{
1177
1179
  type: Injectable
1178
- }], ctorParameters: () => [{ type: i5.FormBuilder }, { type: i2$1.TranslateService }, { type: i2.TabsService }] });
1180
+ }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$1.TranslateService }, { type: i2.TabsService }] });
1179
1181
 
1180
1182
  class DashboardDetailComponent {
1181
1183
  constructor(contextDashboardService, translateService, contextRoute, activatedRoute, tabsService, router, inventory, route, dashboardDetailService, appState, groupService, modal, gainsightService) {
@@ -2004,7 +2006,7 @@ class WidgetAssetSelectorComponent {
2004
2006
  this.widgetConfigService.updateConfig({ device });
2005
2007
  }
2006
2008
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: WidgetAssetSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2007
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: WidgetAssetSelectorComponent, isStandalone: true, selector: "c8y-widget-asset-selector", inputs: { isRequired: "isRequired", showUnassigned: "showUnassigned", groupsSelectable: "groupsSelectable", assetSelectorConfig: "assetSelectorConfig", selectedDevice: "selectedDevice" }, host: { classAttribute: "bg-level-1" }, ngImport: i0, template: "<div class=\"card borderless\">\n <div\n class=\"card-block p-0 bg-inherit\"\n style=\"height: 315px\"\n >\n @if (widgetConfigService.isDeviceTypeDashboard$ | async) {\n <div class=\"alert alert-info m-4\">\n <span translate>\n This widget is used within a dashboard template, so the asset selector is unavailable. The\n widget automatically inherits the asset from the context in which the dashboard is\n displayed.\n </span>\n\n @if (!isRequired) {\n <div class=\"p-t-8\">\n <p translate>Asset selection is optional for this widget.</p>\n @if (!selectedDevice) {\n <button\n class=\"btn btn-primary btn-sm m-t-8 text-truncate\"\n (click)=\"selectCurrentContext()\"\n ngNonBindable\n translate\n [translateParams]=\"{\n deviceName:\n (widgetConfigService.currentConfig$ | async)?.settings?.context?.name ||\n (deviceWithIdTpl\n | translate\n : {\n id: (widgetConfigService.currentConfig$ | async)?.settings?.context?.id\n })\n }\"\n >\n Use context asset \"{{ deviceName }}\"\n </button>\n }\n @if (selectedDevice) {\n <button\n class=\"btn btn-default btn-sm m-t-8 text-truncate\"\n (click)=\"selectedDevice = null; updateConfig(null)\"\n ngNonBindable\n translate\n [translateParams]=\"{\n deviceName:\n selectedDevice.name || (deviceWithIdTpl | translate: { id: selectedDevice.id })\n }\"\n >\n Use without asset \"{{ deviceName }}\"\n </button>\n }\n </div>\n }\n </div>\n }\n @if (!(widgetConfigService.isDeviceTypeDashboard$ | async) && assetSelectorConfig) {\n <c8y-asset-selector-miller\n class=\"d-block bg-inherit p-relative\"\n name=\"configAsset\"\n (onSelected)=\"selectionChanged($event)\"\n [config]=\"assetSelectorConfig\"\n [asset]=\"(widgetConfigService.currentConfig$ | async).settings?.context\"\n [(ngModel)]=\"selectedDevice\"\n [required]=\"isRequired\"\n ></c8y-asset-selector-miller>\n }\n\n <c8y-widget-config-feedback>\n <span\n class=\"tag chip text-12 m-4\"\n [ngClass]=\"{\n 'tag--info': selectedDevice || !isRequired,\n 'tag--danger': !selectedDevice && isRequired\n }\"\n >\n @if (\n selectedDevice &&\n (!(widgetConfigService.isDeviceTypeDashboard$ | async) ||\n (!isRequired && (widgetConfigService.isDeviceTypeDashboard$ | async)))\n ) {\n <button\n class=\"btn-clean text-12 m-r-4\"\n title=\"{{ 'Deselect' | translate }}\"\n type=\"button\"\n (click)=\"selectedDevice = null; updateConfig(null)\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n }\n @if (selectedDevice) {\n <span\n class=\"text-truncate\"\n title=\"{{\n selectedDevice.name || (deviceWithIdTpl | translate: { id: selectedDevice.id })\n }}\"\n >\n {{ selectedDevice.name || (deviceWithIdTpl | translate: { id: selectedDevice.id }) }}\n </span>\n }\n @if (!selectedDevice) {\n <span translate>No asset selected</span>\n }\n </span>\n </c8y-widget-config-feedback>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: AssetSelectorModule }, { kind: "component", type: i1$2.MillerViewComponent, selector: "c8y-asset-selector-miller", inputs: ["config", "asset", "selectedDevice", "rootNode", "container"], outputs: ["onSelected", "onClearSelected"] }, { kind: "component", type: WidgetConfigFeedbackComponent, selector: "c8y-widget-config-feedback" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
2009
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: WidgetAssetSelectorComponent, isStandalone: true, selector: "c8y-widget-asset-selector", inputs: { isRequired: "isRequired", showUnassigned: "showUnassigned", groupsSelectable: "groupsSelectable", assetSelectorConfig: "assetSelectorConfig", selectedDevice: "selectedDevice" }, host: { classAttribute: "bg-level-1" }, ngImport: i0, template: "<div class=\"card borderless\">\n <div\n class=\"card-block p-0 bg-inherit\"\n style=\"height: 315px\"\n >\n @if (widgetConfigService.isDeviceTypeDashboard$ | async) {\n <div class=\"alert alert-info m-4\">\n <span translate>\n This widget is used within a dashboard template, so the asset selector is unavailable. The\n widget automatically inherits the asset from the context in which the dashboard is\n displayed.\n </span>\n\n @if (!isRequired) {\n <div class=\"p-t-8\">\n <p translate>Asset selection is optional for this widget.</p>\n @if (!selectedDevice) {\n <button\n class=\"btn btn-primary btn-sm m-t-8 text-truncate\"\n (click)=\"selectCurrentContext()\"\n ngNonBindable\n translate\n [translateParams]=\"{\n deviceName:\n (widgetConfigService.currentConfig$ | async)?.settings?.context?.name ||\n (deviceWithIdTpl\n | translate\n : {\n id: (widgetConfigService.currentConfig$ | async)?.settings?.context?.id\n })\n }\"\n >\n Use context asset \"{{ deviceName }}\"\n </button>\n }\n @if (selectedDevice) {\n <button\n class=\"btn btn-default btn-sm m-t-8 text-truncate\"\n (click)=\"selectedDevice = null; updateConfig(null)\"\n ngNonBindable\n translate\n [translateParams]=\"{\n deviceName:\n selectedDevice.name || (deviceWithIdTpl | translate: { id: selectedDevice.id })\n }\"\n >\n Use without asset \"{{ deviceName }}\"\n </button>\n }\n </div>\n }\n </div>\n }\n @if (!(widgetConfigService.isDeviceTypeDashboard$ | async) && assetSelectorConfig) {\n <c8y-asset-selector-miller\n class=\"d-block bg-inherit p-relative\"\n name=\"configAsset\"\n (onSelected)=\"selectionChanged($event)\"\n [config]=\"assetSelectorConfig\"\n [asset]=\"(widgetConfigService.currentConfig$ | async).settings?.context\"\n [(ngModel)]=\"selectedDevice\"\n [required]=\"isRequired\"\n ></c8y-asset-selector-miller>\n }\n\n <c8y-widget-config-feedback>\n <span\n class=\"tag chip text-12 m-4\"\n [ngClass]=\"{\n 'tag--info': selectedDevice || !isRequired,\n 'tag--danger': !selectedDevice && isRequired\n }\"\n >\n @if (\n selectedDevice &&\n (!(widgetConfigService.isDeviceTypeDashboard$ | async) ||\n (!isRequired && (widgetConfigService.isDeviceTypeDashboard$ | async)))\n ) {\n <button\n class=\"btn-clean text-12 m-r-4\"\n title=\"{{ 'Deselect' | translate }}\"\n type=\"button\"\n (click)=\"selectedDevice = null; updateConfig(null)\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n }\n @if (selectedDevice) {\n <span\n class=\"text-truncate\"\n title=\"{{\n selectedDevice.name || (deviceWithIdTpl | translate: { id: selectedDevice.id })\n }}\"\n >\n {{ selectedDevice.name || (deviceWithIdTpl | translate: { id: selectedDevice.id }) }}\n </span>\n }\n @if (!selectedDevice) {\n <span translate>No asset selected</span>\n }\n </span>\n </c8y-widget-config-feedback>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: AssetSelectorModule }, { kind: "component", type: i1$3.MillerViewComponent, selector: "c8y-asset-selector-miller", inputs: ["config", "asset", "selectedDevice", "rootNode", "container"], outputs: ["onSelected", "onClearSelected"] }, { kind: "component", type: WidgetConfigFeedbackComponent, selector: "c8y-widget-config-feedback" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
2008
2010
  }
2009
2011
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: WidgetAssetSelectorComponent, decorators: [{
2010
2012
  type: Component,
@@ -2091,6 +2093,41 @@ class WidgetConfigService {
2091
2093
  * Indicates if the selected widget is placed on a device type dashboard.
2092
2094
  */
2093
2095
  this.isDeviceTypeDashboard$ = this._isDeviceTypeDashboard$.asObservable();
2096
+ /**
2097
+ * A bus for broadcasting {@link WidgetConfigNotification} events between independent
2098
+ * widget config sections during an active configuration session.
2099
+ *
2100
+ * **Who emits:** Any config section component (or its service) that needs to
2101
+ * inform other sections about a state change — for example,
2102
+ * `AssetPropertyMappingsComponent` emits an
2103
+ * `AssetPropertyMappingKeyRenamedNotification` whenever a mapping key is renamed
2104
+ * so that referencing sections can update their stored keys.
2105
+ *
2106
+ * **Who subscribes:** Config section components that hold references to data owned
2107
+ * by other sections. Subscribers should filter by `type` and silently ignore
2108
+ * unknown variants to stay forward-compatible:
2109
+ *
2110
+ * ```ts
2111
+ * this.widgetConfigService.notify$
2112
+ * .pipe(takeUntil(this.destroy$))
2113
+ * .subscribe(notification => {
2114
+ * if (notification.type === 'asset-property-mapping-key-renamed') {
2115
+ * // handle rename
2116
+ * }
2117
+ * // ignore other types
2118
+ * });
2119
+ * ```
2120
+ *
2121
+ * **Subscription management:** Each subscriber is responsible for unsubscribing
2122
+ * (e.g. via `takeUntil(destroy$)` or `DestroyRef`). The subject itself is never
2123
+ * completed by the service — it lives for the lifetime of the service instance.
2124
+ *
2125
+ * **Unknown notification types:** Because `WidgetConfigNotification` is a
2126
+ * discriminated union that may grow over time, always guard with an `if`/`switch`
2127
+ * on `type` rather than exhaustive checks, so that future additions do not break
2128
+ * existing subscribers.
2129
+ */
2130
+ this.notify$ = new Subject();
2094
2131
  /**
2095
2132
  * The current configuration of the selected widget as observable.
2096
2133
  * Only to read the value. Use `updateConfig` to update the configuration.
@@ -2379,7 +2416,7 @@ class AppearanceSettingsComponent {
2379
2416
  return value;
2380
2417
  }
2381
2418
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AppearanceSettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2382
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: AppearanceSettingsComponent, isStandalone: true, selector: "c8y-appearance-settings", inputs: { themeClass: "themeClass", headerClass: "headerClass", defaultThemeClass: "defaultThemeClass", defaultHeaderClass: "defaultHeaderClass", dashboardSettings: "dashboardSettings", possibleStylingTheme: "possibleStylingTheme", possibleStylingHeader: "possibleStylingHeader", columns: "columns" }, outputs: { themeClassChange: "themeClassChange", headerClassChange: "headerClassChange", onChange: "onChange" }, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-lg-{{ 12 / columns }} col-xs-12\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend *ngIf=\"dashboardSettings\">{{ 'Default theme' | translate }}</legend>\n <legend *ngIf=\"!dashboardSettings\">{{ 'Theme' | translate }}</legend>\n <ul class=\"list-group\">\n <li\n class=\"list-group-item d-flex a-i-center p-l-0 p-r-0 fit-w\"\n *ngFor=\"let themeClassItem of possibleStylingTheme; let i = index\"\n >\n <div\n class=\"list-item-checkbox\"\n style=\"max-width: calc(100% - 24px)\"\n >\n <label class=\"c8y-radio\">\n <input\n name=\"content\"\n type=\"radio\"\n [id]=\"'groupradiocontentclass' + i\"\n [value]=\"themeClassItem.class\"\n [ngModel]=\"themeClass\"\n (click)=\"themeClassClick(themeClassItem.class)\"\n />\n <span></span>\n <span\n class=\"text-truncate\"\n title=\"{{ themeClassItem.label | translate }}{{\n themeClassItem.class === defaultThemeClass\n ? ' | ' + (dashboardDefaultLabel | translate)\n : ''\n }}\"\n >\n <span>{{ themeClassItem.label | translate }}</span>\n <br />\n <small\n class=\"text-muted\"\n *ngIf=\"themeClassItem.class === defaultThemeClass\"\n >\n {{ dashboardDefaultLabel | translate }}\n </small>\n </span>\n </label>\n </div>\n\n <button\n class=\"btn-help btn-help--sm m-l-auto\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ themeClassItem.description | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </li>\n </ul>\n </fieldset>\n </div>\n <div class=\"col-lg-{{ 12 / columns }} col-xs-12\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend *ngIf=\"dashboardSettings\">\n {{ 'Default widget header style' | translate }}\n </legend>\n <legend *ngIf=\"!dashboardSettings\">\n {{ 'Widget header style' | translate }}\n </legend>\n <ul class=\"list-group\">\n <li\n class=\"list-group-item d-flex a-i-center p-l-0 p-r-0\"\n *ngFor=\"let headerClassItem of possibleStylingHeader; let i = index\"\n >\n <div\n class=\"list-item-checkbox\"\n style=\"max-width: calc(100% - 24px)\"\n >\n <label class=\"c8y-radio\">\n <input\n name=\"header\"\n type=\"radio\"\n [id]=\"'groupradioheaderclass' + i\"\n [value]=\"headerClassItem.class\"\n [ngModel]=\"headerClass\"\n (click)=\"headerClassClick(headerClassItem.class)\"\n />\n <span></span>\n <span\n class=\"text-truncate\"\n title=\"{{ headerClassItem.label | translate }}{{\n headerClassItem.class === defaultHeaderClass\n ? ' | ' + (dashboardDefaultLabel | translate)\n : ''\n }}\"\n >\n <span>{{ headerClassItem.label | translate }}</span>\n <br />\n <small\n class=\"text-muted\"\n *ngIf=\"headerClassItem.class === defaultHeaderClass\"\n >\n {{ dashboardDefaultLabel | translate }}\n </small>\n </span>\n </label>\n </div>\n <button\n class=\"btn-help btn-help--sm m-l-auto\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ headerClassItem.description | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </li>\n </ul>\n </fieldset>\n </div>\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.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: i5.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
2419
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: AppearanceSettingsComponent, isStandalone: true, selector: "c8y-appearance-settings", inputs: { themeClass: "themeClass", headerClass: "headerClass", defaultThemeClass: "defaultThemeClass", defaultHeaderClass: "defaultHeaderClass", dashboardSettings: "dashboardSettings", possibleStylingTheme: "possibleStylingTheme", possibleStylingHeader: "possibleStylingHeader", columns: "columns" }, outputs: { themeClassChange: "themeClassChange", headerClassChange: "headerClassChange", onChange: "onChange" }, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-lg-{{ 12 / columns }} col-xs-12\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend *ngIf=\"dashboardSettings\">{{ 'Default theme' | translate }}</legend>\n <legend *ngIf=\"!dashboardSettings\">{{ 'Theme' | translate }}</legend>\n <ul class=\"list-group\">\n <li\n class=\"list-group-item d-flex a-i-center p-l-0 p-r-0 fit-w\"\n *ngFor=\"let themeClassItem of possibleStylingTheme; let i = index\"\n >\n <div\n class=\"list-item-checkbox\"\n style=\"max-width: calc(100% - 24px)\"\n >\n <label class=\"c8y-radio\">\n <input\n name=\"content\"\n type=\"radio\"\n [id]=\"'groupradiocontentclass' + i\"\n [value]=\"themeClassItem.class\"\n [ngModel]=\"themeClass\"\n (click)=\"themeClassClick(themeClassItem.class)\"\n />\n <span></span>\n <span\n class=\"text-truncate\"\n title=\"{{ themeClassItem.label | translate }}{{\n themeClassItem.class === defaultThemeClass\n ? ' | ' + (dashboardDefaultLabel | translate)\n : ''\n }}\"\n >\n <span>{{ themeClassItem.label | translate }}</span>\n <br />\n <small\n class=\"text-muted\"\n *ngIf=\"themeClassItem.class === defaultThemeClass\"\n >\n {{ dashboardDefaultLabel | translate }}\n </small>\n </span>\n </label>\n </div>\n\n <button\n class=\"btn-help btn-help--sm m-l-auto\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ themeClassItem.description | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </li>\n </ul>\n </fieldset>\n </div>\n <div class=\"col-lg-{{ 12 / columns }} col-xs-12\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend *ngIf=\"dashboardSettings\">\n {{ 'Default widget header style' | translate }}\n </legend>\n <legend *ngIf=\"!dashboardSettings\">\n {{ 'Widget header style' | translate }}\n </legend>\n <ul class=\"list-group\">\n <li\n class=\"list-group-item d-flex a-i-center p-l-0 p-r-0\"\n *ngFor=\"let headerClassItem of possibleStylingHeader; let i = index\"\n >\n <div\n class=\"list-item-checkbox\"\n style=\"max-width: calc(100% - 24px)\"\n >\n <label class=\"c8y-radio\">\n <input\n name=\"header\"\n type=\"radio\"\n [id]=\"'groupradioheaderclass' + i\"\n [value]=\"headerClassItem.class\"\n [ngModel]=\"headerClass\"\n (click)=\"headerClassClick(headerClassItem.class)\"\n />\n <span></span>\n <span\n class=\"text-truncate\"\n title=\"{{ headerClassItem.label | translate }}{{\n headerClassItem.class === defaultHeaderClass\n ? ' | ' + (dashboardDefaultLabel | translate)\n : ''\n }}\"\n >\n <span>{{ headerClassItem.label | translate }}</span>\n <br />\n <small\n class=\"text-muted\"\n *ngIf=\"headerClassItem.class === defaultHeaderClass\"\n >\n {{ dashboardDefaultLabel | translate }}\n </small>\n </span>\n </label>\n </div>\n <button\n class=\"btn-help btn-help--sm m-l-auto\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ headerClassItem.description | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </li>\n </ul>\n </fieldset>\n </div>\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
2383
2420
  }
2384
2421
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AppearanceSettingsComponent, decorators: [{
2385
2422
  type: Component,
@@ -2749,7 +2786,7 @@ class WidgetConfigComponent {
2749
2786
  return widgetConfig;
2750
2787
  }
2751
2788
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: WidgetConfigComponent, deps: [{ token: WidgetService }, { token: i2.BottomDrawerRef }, { token: ContextDashboardService }, { token: WidgetConfigService }, { token: i2.BottomDrawerService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2752
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: WidgetConfigComponent, isStandalone: true, selector: "c8y-widget-config", host: { listeners: { "document:keydown.escape": "onEscapePress($event)" }, classAttribute: "d-contents" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "configForm", first: true, predicate: ["configForm"], descendants: true }], ngImport: i0, template: "<!-- select widget -->\n@if (!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header j-c-center separator\">\n <div\n class=\"h4 text-center\"\n id=\"drawerTitle\"\n >\n {{ 'Select widget' | translate }}\n </div>\n </div>\n <div class=\"card-inner-scroll fit-h bg-level-2\">\n <div\n class=\"bg-level-0 p-l-24 p-r-24 p-t-8 p-b-8 sticky-header-top-0 elevation-md\"\n style=\"z-index: 2\"\n >\n <div class=\"row\">\n <div class=\"col-sm-6 col-sm-offset-3\">\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Search' | translate\"\n placeholder=\"{{ 'Search\u2026' | translate }}\"\n type=\"text\"\n #searchInput\n data-cy=\"widget-config--Search\"\n [(ngModel)]=\"searchTerm\"\n [ngModelOptions]=\"{ standalone: true }\"\n (keydown)=\"searchChange$.next($event)\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n <i [c8yIcon]=\"searchTerm.length === 0 ? 'search' : 'close'\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"card-block\">\n <div class=\"card-group p-l-24 p-r-24 d-grid grid__col--auto-300 gap-24 card-select m-b-0\">\n @for (cmp of searchResult || components; track cmp) {\n <button\n class=\"btn-clean d-col card m-b-0\"\n [title]=\"cmp.description || cmp.label | translate\"\n type=\"button\"\n data-cy=\"widget-config--widget-list\"\n (click)=\"select(cmp)\"\n >\n <div\n class=\"border-bottom\"\n role=\"presentation\"\n >\n @if (!cmp.previewImage) {\n <div class=\"h1\"><i c8yIcon=\"file-image-o\"></i></div>\n <small translate>Preview not available</small>\n } @else {\n <img\n class=\"widget-thumbnail\"\n alt=\"{{ cmp.label | translate }}\"\n [src]=\"cmp.previewImage\"\n />\n }\n </div>\n <div class=\"card-block\">\n <p class=\"card-title text-truncate text-medium\">\n <c8y-highlight\n text=\"{{ cmp.label | translate }}\"\n [pattern]=\"searchTerm\"\n ></c8y-highlight>\n </p>\n <p\n class=\"small text-default\"\n style=\"white-space: wrap\"\n >\n {{ cmp.description | translate }}\n </p>\n </div>\n </button>\n }\n @if (searchResult && searchResult.length === 0) {\n <c8y-ui-empty-state\n class=\"p-24 grid__col--fullspan\"\n [icon]=\"'search'\"\n [title]=\"'No widgets found.' | translate\"\n [subtitle]=\"'Rephrase your search term.' | translate\"\n >\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n {{ 'Reset search' | translate }}\n </button>\n </c8y-ui-empty-state>\n }\n </div>\n </div>\n </div>\n <div class=\"card-footer text-center separator flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n </div>\n}\n\n<!-- widget configuration -->\n@if (!!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header d-block separator-bottom flex-no-shrink\">\n <div\n class=\"h3 p-t-16\"\n title=\"{{ selected?.label | translate }}\"\n >\n <span>{{ selected?.label | translate }}</span>\n <button\n class=\"btn btn-default btn-sm m-l-8\"\n [title]=\"'Change widget' | translate\"\n (click)=\"backToWidgetSelection(); (false)\"\n >\n <i c8yIcon=\"replace\"></i>\n {{ 'Change widget' | translate }}\n </button>\n </div>\n @if (selected) {\n <div class=\"p-t-8\">\n <p>\n {{ selected.description | translate }}\n </p>\n </div>\n }\n </div>\n\n <c8y-resizable-grid\n class=\"min-height-0 flex-grow\"\n [collapsible]=\"false\"\n [trackId]=\"'c8y-widget-resizable-grid-size-' + (widgetConfigService.instanceId$ | async)\"\n [leftColumnWidth]=\"\n (widgetConfigService.currentConfig$ | async)?.settings?.configurationViewGridSize ||\n WIDGET_CONFIGURATION_GRID_SIZE.HALF\n \"\n >\n <div\n class=\"bg-level-1 inner-scroll\"\n left-pane\n >\n <div class=\"p-16 flex-no-shrink separator-bottom bg-level-1\">\n <c8y-form-group>\n <label\n for=\"widgetTitle\"\n translate\n >\n Widget title\n </label>\n <input\n class=\"form-control\"\n id=\"widgetTitle\"\n placeholder=\"{{ 'e.g.' | translate }} {{ componentLabel | translate }}\"\n name=\"widgetTitle\"\n type=\"text\"\n required\n [(ngModel)]=\"widgetTitle\"\n (ngModelChange)=\"onWidgetTitleChange($event)\"\n />\n </c8y-form-group>\n </div>\n\n @if (!(widgetConfigService.hasConfig$ | async)) {\n <c8y-ui-empty-state\n class=\"p-24\"\n [icon]=\"'settings'\"\n [title]=\"'No configuration needed.' | translate\"\n [subtitle]=\"'This widget does not need any specific configuration.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <div>\n <form\n name=\"form\"\n #configForm=\"ngForm\"\n >\n @if (widgetConfigService.hasConfig$ | async) {\n @if (widgetConfigService.providers$ | async; as providers) {\n <ng-container\n *c8yComponentOutlet=\"widgetConfigRoot; providers: providers\"\n ></ng-container>\n }\n }\n </form>\n </div>\n </div>\n\n <div\n class=\"inner-scroll p-32 p-t-0\"\n right-pane\n >\n <c8y-widget-preview [previewClasses]=\"getStyle(true)\"></c8y-widget-preview>\n\n <c8y-appearance-settings\n [(themeClass)]=\"styling.contentClass\"\n [(headerClass)]=\"styling.headerClass\"\n [possibleStylingTheme]=\"possibleStyling.WIDGET_CONTENT_CLASSES\"\n [possibleStylingHeader]=\"possibleStyling.WIDGET_HEADER_CLASSES\"\n [defaultThemeClass]=\"defaultStyling.contentClass\"\n [defaultHeaderClass]=\"defaultStyling.headerClass\"\n [columns]=\"2\"\n ></c8y-appearance-settings>\n </div>\n </c8y-resizable-grid>\n\n <div class=\"card-footer separator text-center\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n data-cy=\"widget-config--save-widget\"\n (click)=\"save()\"\n [disabled]=\"(contextDashboardService.formDisabled$ | async) || isSaveDisabled()\"\n c8yProductExperience\n [actionName]=\"current ? 'editWidget' : 'createWidget'\"\n [actionData]=\"{ widgetName: selected && selected.id }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: C8yComponentOutlet, selector: "[c8yComponentOutlet]", inputs: ["c8yComponentOutlet", "c8yComponentOutletInjector", "c8yComponentOutletEnvironmentInjector", "c8yComponentOutletProviders", "c8yComponentOutletInitialState"] }, { kind: "component", type: WidgetPreviewComponent, selector: "c8y-widget-preview", inputs: ["previewClasses"] }, { kind: "component", type: AppearanceSettingsComponent, selector: "c8y-appearance-settings", inputs: ["themeClass", "headerClass", "defaultThemeClass", "defaultHeaderClass", "dashboardSettings", "possibleStylingTheme", "possibleStylingHeader", "columns"], outputs: ["themeClassChange", "headerClassChange", "onChange"] }, { kind: "directive", type: ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: ResizableGridComponent, selector: "c8y-resizable-grid", inputs: ["leftColumnWidth", "trackId", "collapseThreshold", "collapsible"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
2789
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: WidgetConfigComponent, isStandalone: true, selector: "c8y-widget-config", host: { listeners: { "document:keydown.escape": "onEscapePress($event)" }, classAttribute: "d-contents" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "configForm", first: true, predicate: ["configForm"], descendants: true }], ngImport: i0, template: "<!-- select widget -->\n@if (!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header j-c-center separator\">\n <div\n class=\"h4 text-center\"\n id=\"drawerTitle\"\n >\n {{ 'Select widget' | translate }}\n </div>\n </div>\n <div class=\"card-inner-scroll fit-h bg-level-2\">\n <div\n class=\"bg-level-0 p-l-24 p-r-24 p-t-8 p-b-8 sticky-header-top-0 elevation-md\"\n style=\"z-index: 2\"\n >\n <div class=\"row\">\n <div class=\"col-sm-6 col-sm-offset-3\">\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Search' | translate\"\n placeholder=\"{{ 'Search\u2026' | translate }}\"\n type=\"text\"\n #searchInput\n data-cy=\"widget-config--Search\"\n [(ngModel)]=\"searchTerm\"\n [ngModelOptions]=\"{ standalone: true }\"\n (keydown)=\"searchChange$.next($event)\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n <i [c8yIcon]=\"searchTerm.length === 0 ? 'search' : 'close'\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"card-block\">\n <div class=\"card-group p-l-24 p-r-24 d-grid grid__col--auto-300 gap-24 card-select m-b-0\">\n @for (cmp of searchResult || components; track cmp) {\n <button\n class=\"btn-clean d-col card m-b-0\"\n [title]=\"cmp.description || cmp.label | translate\"\n type=\"button\"\n data-cy=\"widget-config--widget-list\"\n (click)=\"select(cmp)\"\n >\n <div\n class=\"border-bottom\"\n role=\"presentation\"\n >\n @if (!cmp.previewImage) {\n <div class=\"h1\"><i c8yIcon=\"file-image-o\"></i></div>\n <small translate>Preview not available</small>\n } @else {\n <img\n class=\"widget-thumbnail\"\n alt=\"{{ cmp.label | translate }}\"\n [src]=\"cmp.previewImage\"\n />\n }\n </div>\n <div class=\"card-block\">\n <p class=\"card-title text-truncate text-medium\">\n <c8y-highlight\n text=\"{{ cmp.label | translate }}\"\n [pattern]=\"searchTerm\"\n ></c8y-highlight>\n </p>\n <p\n class=\"small text-default\"\n style=\"white-space: wrap\"\n >\n {{ cmp.description | translate }}\n </p>\n </div>\n </button>\n }\n @if (searchResult && searchResult.length === 0) {\n <c8y-ui-empty-state\n class=\"p-24 grid__col--fullspan\"\n [icon]=\"'search'\"\n [title]=\"'No widgets found.' | translate\"\n [subtitle]=\"'Rephrase your search term.' | translate\"\n >\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n {{ 'Reset search' | translate }}\n </button>\n </c8y-ui-empty-state>\n }\n </div>\n </div>\n </div>\n <div class=\"card-footer text-center separator flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n </div>\n}\n\n<!-- widget configuration -->\n@if (!!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header d-block separator-bottom flex-no-shrink\">\n <div\n class=\"h3 p-t-16\"\n title=\"{{ selected?.label | translate }}\"\n >\n <span>{{ selected?.label | translate }}</span>\n <button\n class=\"btn btn-default btn-sm m-l-8\"\n [title]=\"'Change widget' | translate\"\n (click)=\"backToWidgetSelection(); (false)\"\n >\n <i c8yIcon=\"replace\"></i>\n {{ 'Change widget' | translate }}\n </button>\n </div>\n @if (selected) {\n <div class=\"p-t-8\">\n <p>\n {{ selected.description | translate }}\n </p>\n </div>\n }\n </div>\n\n <c8y-resizable-grid\n class=\"min-height-0 flex-grow\"\n [collapsible]=\"false\"\n [trackId]=\"'c8y-widget-resizable-grid-size-' + (widgetConfigService.instanceId$ | async)\"\n [leftColumnWidth]=\"\n (widgetConfigService.currentConfig$ | async)?.settings?.configurationViewGridSize ||\n WIDGET_CONFIGURATION_GRID_SIZE.DEFAULT\n \"\n >\n <div\n class=\"bg-level-1 inner-scroll\"\n left-pane\n >\n <div class=\"p-16 flex-no-shrink separator-bottom bg-level-1\">\n <c8y-form-group>\n <label\n for=\"widgetTitle\"\n translate\n >\n Widget title\n </label>\n <input\n class=\"form-control\"\n id=\"widgetTitle\"\n placeholder=\"{{ 'e.g.' | translate }} {{ componentLabel | translate }}\"\n name=\"widgetTitle\"\n type=\"text\"\n required\n [(ngModel)]=\"widgetTitle\"\n (ngModelChange)=\"onWidgetTitleChange($event)\"\n />\n </c8y-form-group>\n </div>\n\n @if (!(widgetConfigService.hasConfig$ | async)) {\n <c8y-ui-empty-state\n class=\"p-24\"\n [icon]=\"'settings'\"\n [title]=\"'No configuration needed.' | translate\"\n [subtitle]=\"'This widget does not need any specific configuration.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <div>\n <form\n name=\"form\"\n #configForm=\"ngForm\"\n >\n @if (widgetConfigService.hasConfig$ | async) {\n @if (widgetConfigService.providers$ | async; as providers) {\n <ng-container\n *c8yComponentOutlet=\"widgetConfigRoot; providers: providers\"\n ></ng-container>\n }\n }\n </form>\n </div>\n </div>\n\n <div\n class=\"inner-scroll p-32 p-t-0\"\n right-pane\n >\n <c8y-widget-preview [previewClasses]=\"getStyle(true)\"></c8y-widget-preview>\n\n <c8y-appearance-settings\n [(themeClass)]=\"styling.contentClass\"\n [(headerClass)]=\"styling.headerClass\"\n [possibleStylingTheme]=\"possibleStyling.WIDGET_CONTENT_CLASSES\"\n [possibleStylingHeader]=\"possibleStyling.WIDGET_HEADER_CLASSES\"\n [defaultThemeClass]=\"defaultStyling.contentClass\"\n [defaultHeaderClass]=\"defaultStyling.headerClass\"\n [columns]=\"2\"\n ></c8y-appearance-settings>\n </div>\n </c8y-resizable-grid>\n\n <div class=\"card-footer separator text-center\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n data-cy=\"widget-config--save-widget\"\n (click)=\"save()\"\n [disabled]=\"(contextDashboardService.formDisabled$ | async) || isSaveDisabled()\"\n c8yProductExperience\n [actionName]=\"current ? 'editWidget' : 'createWidget'\"\n [actionData]=\"{ widgetName: selected && selected.id }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: C8yComponentOutlet, selector: "[c8yComponentOutlet]", inputs: ["c8yComponentOutlet", "c8yComponentOutletInjector", "c8yComponentOutletEnvironmentInjector", "c8yComponentOutletProviders", "c8yComponentOutletInitialState"] }, { kind: "component", type: WidgetPreviewComponent, selector: "c8y-widget-preview", inputs: ["previewClasses"] }, { kind: "component", type: AppearanceSettingsComponent, selector: "c8y-appearance-settings", inputs: ["themeClass", "headerClass", "defaultThemeClass", "defaultHeaderClass", "dashboardSettings", "possibleStylingTheme", "possibleStylingHeader", "columns"], outputs: ["themeClassChange", "headerClassChange", "onChange"] }, { kind: "directive", type: ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: ResizableGridComponent, selector: "c8y-resizable-grid", inputs: ["leftColumnWidth", "trackId", "collapseThreshold", "collapsible"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
2753
2790
  }
2754
2791
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: WidgetConfigComponent, decorators: [{
2755
2792
  type: Component,
@@ -2768,7 +2805,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
2768
2805
  C8yTranslatePipe,
2769
2806
  AsyncPipe,
2770
2807
  ResizableGridComponent
2771
- ], standalone: true, template: "<!-- select widget -->\n@if (!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header j-c-center separator\">\n <div\n class=\"h4 text-center\"\n id=\"drawerTitle\"\n >\n {{ 'Select widget' | translate }}\n </div>\n </div>\n <div class=\"card-inner-scroll fit-h bg-level-2\">\n <div\n class=\"bg-level-0 p-l-24 p-r-24 p-t-8 p-b-8 sticky-header-top-0 elevation-md\"\n style=\"z-index: 2\"\n >\n <div class=\"row\">\n <div class=\"col-sm-6 col-sm-offset-3\">\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Search' | translate\"\n placeholder=\"{{ 'Search\u2026' | translate }}\"\n type=\"text\"\n #searchInput\n data-cy=\"widget-config--Search\"\n [(ngModel)]=\"searchTerm\"\n [ngModelOptions]=\"{ standalone: true }\"\n (keydown)=\"searchChange$.next($event)\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n <i [c8yIcon]=\"searchTerm.length === 0 ? 'search' : 'close'\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"card-block\">\n <div class=\"card-group p-l-24 p-r-24 d-grid grid__col--auto-300 gap-24 card-select m-b-0\">\n @for (cmp of searchResult || components; track cmp) {\n <button\n class=\"btn-clean d-col card m-b-0\"\n [title]=\"cmp.description || cmp.label | translate\"\n type=\"button\"\n data-cy=\"widget-config--widget-list\"\n (click)=\"select(cmp)\"\n >\n <div\n class=\"border-bottom\"\n role=\"presentation\"\n >\n @if (!cmp.previewImage) {\n <div class=\"h1\"><i c8yIcon=\"file-image-o\"></i></div>\n <small translate>Preview not available</small>\n } @else {\n <img\n class=\"widget-thumbnail\"\n alt=\"{{ cmp.label | translate }}\"\n [src]=\"cmp.previewImage\"\n />\n }\n </div>\n <div class=\"card-block\">\n <p class=\"card-title text-truncate text-medium\">\n <c8y-highlight\n text=\"{{ cmp.label | translate }}\"\n [pattern]=\"searchTerm\"\n ></c8y-highlight>\n </p>\n <p\n class=\"small text-default\"\n style=\"white-space: wrap\"\n >\n {{ cmp.description | translate }}\n </p>\n </div>\n </button>\n }\n @if (searchResult && searchResult.length === 0) {\n <c8y-ui-empty-state\n class=\"p-24 grid__col--fullspan\"\n [icon]=\"'search'\"\n [title]=\"'No widgets found.' | translate\"\n [subtitle]=\"'Rephrase your search term.' | translate\"\n >\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n {{ 'Reset search' | translate }}\n </button>\n </c8y-ui-empty-state>\n }\n </div>\n </div>\n </div>\n <div class=\"card-footer text-center separator flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n </div>\n}\n\n<!-- widget configuration -->\n@if (!!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header d-block separator-bottom flex-no-shrink\">\n <div\n class=\"h3 p-t-16\"\n title=\"{{ selected?.label | translate }}\"\n >\n <span>{{ selected?.label | translate }}</span>\n <button\n class=\"btn btn-default btn-sm m-l-8\"\n [title]=\"'Change widget' | translate\"\n (click)=\"backToWidgetSelection(); (false)\"\n >\n <i c8yIcon=\"replace\"></i>\n {{ 'Change widget' | translate }}\n </button>\n </div>\n @if (selected) {\n <div class=\"p-t-8\">\n <p>\n {{ selected.description | translate }}\n </p>\n </div>\n }\n </div>\n\n <c8y-resizable-grid\n class=\"min-height-0 flex-grow\"\n [collapsible]=\"false\"\n [trackId]=\"'c8y-widget-resizable-grid-size-' + (widgetConfigService.instanceId$ | async)\"\n [leftColumnWidth]=\"\n (widgetConfigService.currentConfig$ | async)?.settings?.configurationViewGridSize ||\n WIDGET_CONFIGURATION_GRID_SIZE.HALF\n \"\n >\n <div\n class=\"bg-level-1 inner-scroll\"\n left-pane\n >\n <div class=\"p-16 flex-no-shrink separator-bottom bg-level-1\">\n <c8y-form-group>\n <label\n for=\"widgetTitle\"\n translate\n >\n Widget title\n </label>\n <input\n class=\"form-control\"\n id=\"widgetTitle\"\n placeholder=\"{{ 'e.g.' | translate }} {{ componentLabel | translate }}\"\n name=\"widgetTitle\"\n type=\"text\"\n required\n [(ngModel)]=\"widgetTitle\"\n (ngModelChange)=\"onWidgetTitleChange($event)\"\n />\n </c8y-form-group>\n </div>\n\n @if (!(widgetConfigService.hasConfig$ | async)) {\n <c8y-ui-empty-state\n class=\"p-24\"\n [icon]=\"'settings'\"\n [title]=\"'No configuration needed.' | translate\"\n [subtitle]=\"'This widget does not need any specific configuration.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <div>\n <form\n name=\"form\"\n #configForm=\"ngForm\"\n >\n @if (widgetConfigService.hasConfig$ | async) {\n @if (widgetConfigService.providers$ | async; as providers) {\n <ng-container\n *c8yComponentOutlet=\"widgetConfigRoot; providers: providers\"\n ></ng-container>\n }\n }\n </form>\n </div>\n </div>\n\n <div\n class=\"inner-scroll p-32 p-t-0\"\n right-pane\n >\n <c8y-widget-preview [previewClasses]=\"getStyle(true)\"></c8y-widget-preview>\n\n <c8y-appearance-settings\n [(themeClass)]=\"styling.contentClass\"\n [(headerClass)]=\"styling.headerClass\"\n [possibleStylingTheme]=\"possibleStyling.WIDGET_CONTENT_CLASSES\"\n [possibleStylingHeader]=\"possibleStyling.WIDGET_HEADER_CLASSES\"\n [defaultThemeClass]=\"defaultStyling.contentClass\"\n [defaultHeaderClass]=\"defaultStyling.headerClass\"\n [columns]=\"2\"\n ></c8y-appearance-settings>\n </div>\n </c8y-resizable-grid>\n\n <div class=\"card-footer separator text-center\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n data-cy=\"widget-config--save-widget\"\n (click)=\"save()\"\n [disabled]=\"(contextDashboardService.formDisabled$ | async) || isSaveDisabled()\"\n c8yProductExperience\n [actionName]=\"current ? 'editWidget' : 'createWidget'\"\n [actionData]=\"{ widgetName: selected && selected.id }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n}\n" }]
2808
+ ], standalone: true, template: "<!-- select widget -->\n@if (!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header j-c-center separator\">\n <div\n class=\"h4 text-center\"\n id=\"drawerTitle\"\n >\n {{ 'Select widget' | translate }}\n </div>\n </div>\n <div class=\"card-inner-scroll fit-h bg-level-2\">\n <div\n class=\"bg-level-0 p-l-24 p-r-24 p-t-8 p-b-8 sticky-header-top-0 elevation-md\"\n style=\"z-index: 2\"\n >\n <div class=\"row\">\n <div class=\"col-sm-6 col-sm-offset-3\">\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Search' | translate\"\n placeholder=\"{{ 'Search\u2026' | translate }}\"\n type=\"text\"\n #searchInput\n data-cy=\"widget-config--Search\"\n [(ngModel)]=\"searchTerm\"\n [ngModelOptions]=\"{ standalone: true }\"\n (keydown)=\"searchChange$.next($event)\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot\"\n title=\"{{ 'Search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n <i [c8yIcon]=\"searchTerm.length === 0 ? 'search' : 'close'\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"card-block\">\n <div class=\"card-group p-l-24 p-r-24 d-grid grid__col--auto-300 gap-24 card-select m-b-0\">\n @for (cmp of searchResult || components; track cmp) {\n <button\n class=\"btn-clean d-col card m-b-0\"\n [title]=\"cmp.description || cmp.label | translate\"\n type=\"button\"\n data-cy=\"widget-config--widget-list\"\n (click)=\"select(cmp)\"\n >\n <div\n class=\"border-bottom\"\n role=\"presentation\"\n >\n @if (!cmp.previewImage) {\n <div class=\"h1\"><i c8yIcon=\"file-image-o\"></i></div>\n <small translate>Preview not available</small>\n } @else {\n <img\n class=\"widget-thumbnail\"\n alt=\"{{ cmp.label | translate }}\"\n [src]=\"cmp.previewImage\"\n />\n }\n </div>\n <div class=\"card-block\">\n <p class=\"card-title text-truncate text-medium\">\n <c8y-highlight\n text=\"{{ cmp.label | translate }}\"\n [pattern]=\"searchTerm\"\n ></c8y-highlight>\n </p>\n <p\n class=\"small text-default\"\n style=\"white-space: wrap\"\n >\n {{ cmp.description | translate }}\n </p>\n </div>\n </button>\n }\n @if (searchResult && searchResult.length === 0) {\n <c8y-ui-empty-state\n class=\"p-24 grid__col--fullspan\"\n [icon]=\"'search'\"\n [title]=\"'No widgets found.' | translate\"\n [subtitle]=\"'Rephrase your search term.' | translate\"\n >\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset search' | translate }}\"\n type=\"button\"\n (click)=\"resetSearch()\"\n >\n {{ 'Reset search' | translate }}\n </button>\n </c8y-ui-empty-state>\n }\n </div>\n </div>\n </div>\n <div class=\"card-footer text-center separator flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n </div>\n}\n\n<!-- widget configuration -->\n@if (!!(widgetConfigService.selected$ | async)) {\n <div class=\"card-header d-block separator-bottom flex-no-shrink\">\n <div\n class=\"h3 p-t-16\"\n title=\"{{ selected?.label | translate }}\"\n >\n <span>{{ selected?.label | translate }}</span>\n <button\n class=\"btn btn-default btn-sm m-l-8\"\n [title]=\"'Change widget' | translate\"\n (click)=\"backToWidgetSelection(); (false)\"\n >\n <i c8yIcon=\"replace\"></i>\n {{ 'Change widget' | translate }}\n </button>\n </div>\n @if (selected) {\n <div class=\"p-t-8\">\n <p>\n {{ selected.description | translate }}\n </p>\n </div>\n }\n </div>\n\n <c8y-resizable-grid\n class=\"min-height-0 flex-grow\"\n [collapsible]=\"false\"\n [trackId]=\"'c8y-widget-resizable-grid-size-' + (widgetConfigService.instanceId$ | async)\"\n [leftColumnWidth]=\"\n (widgetConfigService.currentConfig$ | async)?.settings?.configurationViewGridSize ||\n WIDGET_CONFIGURATION_GRID_SIZE.DEFAULT\n \"\n >\n <div\n class=\"bg-level-1 inner-scroll\"\n left-pane\n >\n <div class=\"p-16 flex-no-shrink separator-bottom bg-level-1\">\n <c8y-form-group>\n <label\n for=\"widgetTitle\"\n translate\n >\n Widget title\n </label>\n <input\n class=\"form-control\"\n id=\"widgetTitle\"\n placeholder=\"{{ 'e.g.' | translate }} {{ componentLabel | translate }}\"\n name=\"widgetTitle\"\n type=\"text\"\n required\n [(ngModel)]=\"widgetTitle\"\n (ngModelChange)=\"onWidgetTitleChange($event)\"\n />\n </c8y-form-group>\n </div>\n\n @if (!(widgetConfigService.hasConfig$ | async)) {\n <c8y-ui-empty-state\n class=\"p-24\"\n [icon]=\"'settings'\"\n [title]=\"'No configuration needed.' | translate\"\n [subtitle]=\"'This widget does not need any specific configuration.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <div>\n <form\n name=\"form\"\n #configForm=\"ngForm\"\n >\n @if (widgetConfigService.hasConfig$ | async) {\n @if (widgetConfigService.providers$ | async; as providers) {\n <ng-container\n *c8yComponentOutlet=\"widgetConfigRoot; providers: providers\"\n ></ng-container>\n }\n }\n </form>\n </div>\n </div>\n\n <div\n class=\"inner-scroll p-32 p-t-0\"\n right-pane\n >\n <c8y-widget-preview [previewClasses]=\"getStyle(true)\"></c8y-widget-preview>\n\n <c8y-appearance-settings\n [(themeClass)]=\"styling.contentClass\"\n [(headerClass)]=\"styling.headerClass\"\n [possibleStylingTheme]=\"possibleStyling.WIDGET_CONTENT_CLASSES\"\n [possibleStylingHeader]=\"possibleStyling.WIDGET_HEADER_CLASSES\"\n [defaultThemeClass]=\"defaultStyling.contentClass\"\n [defaultHeaderClass]=\"defaultStyling.headerClass\"\n [columns]=\"2\"\n ></c8y-appearance-settings>\n </div>\n </c8y-resizable-grid>\n\n <div class=\"card-footer separator text-center\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n data-cy=\"widget-config--cancel-widget\"\n (click)=\"close()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n data-cy=\"widget-config--save-widget\"\n (click)=\"save()\"\n [disabled]=\"(contextDashboardService.formDisabled$ | async) || isSaveDisabled()\"\n c8yProductExperience\n [actionName]=\"current ? 'editWidget' : 'createWidget'\"\n [actionData]=\"{ widgetName: selected && selected.id }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n}\n" }]
2772
2809
  }], ctorParameters: () => [{ type: WidgetService }, { type: i2.BottomDrawerRef }, { type: ContextDashboardService }, { type: WidgetConfigService }, { type: i2.BottomDrawerService }, { type: i0.ChangeDetectorRef }], propDecorators: { searchInput: [{
2773
2810
  type: ViewChild,
2774
2811
  args: ['searchInput', { static: false }]
@@ -3751,7 +3788,7 @@ class ContextDashboardModule {
3751
3788
  TooltipModule,
3752
3789
  PopoverModule,
3753
3790
  AssetSelectorModule,
3754
- IconSelectorModule, i1$3.BsDropdownModule, i2$3.CollapseModule, RouterModule,
3791
+ IconSelectorModule, i1$4.BsDropdownModule, i2$3.CollapseModule, RouterModule,
3755
3792
  AppearanceSettingsComponent,
3756
3793
  TypeDashboardInfoComponent,
3757
3794
  WidgetPreviewComponent,
@@ -3777,13 +3814,13 @@ class ContextDashboardModule {
3777
3814
  hookRoute([
3778
3815
  {
3779
3816
  path: DashboardDetailsTabId.GENERAL,
3780
- loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-general-settings.component-RdLW5nde.mjs').then(m => m.DashboardGeneralSettingsComponent),
3817
+ loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-general-settings.component-w8N16Z3t.mjs').then(m => m.DashboardGeneralSettingsComponent),
3781
3818
  outlet: DASHBOARD_DETAILS_OUTLET,
3782
3819
  context: ViewContext.Dashboard
3783
3820
  },
3784
3821
  {
3785
3822
  path: DashboardDetailsTabId.APPEARANCE,
3786
- loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-DsCDppJx.mjs').then(m => m.DashboardAppearanceSettingsComponent),
3823
+ loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-C7yXSDYC.mjs').then(m => m.DashboardAppearanceSettingsComponent),
3787
3824
  outlet: DASHBOARD_DETAILS_OUTLET,
3788
3825
  context: ViewContext.Dashboard
3789
3826
  },
@@ -3850,13 +3887,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
3850
3887
  hookRoute([
3851
3888
  {
3852
3889
  path: DashboardDetailsTabId.GENERAL,
3853
- loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-general-settings.component-RdLW5nde.mjs').then(m => m.DashboardGeneralSettingsComponent),
3890
+ loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-general-settings.component-w8N16Z3t.mjs').then(m => m.DashboardGeneralSettingsComponent),
3854
3891
  outlet: DASHBOARD_DETAILS_OUTLET,
3855
3892
  context: ViewContext.Dashboard
3856
3893
  },
3857
3894
  {
3858
3895
  path: DashboardDetailsTabId.APPEARANCE,
3859
- loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-DsCDppJx.mjs').then(m => m.DashboardAppearanceSettingsComponent),
3896
+ loadComponent: () => import('./c8y-ngx-components-context-dashboard-dashboard-appearance-settings.component-C7yXSDYC.mjs').then(m => m.DashboardAppearanceSettingsComponent),
3860
3897
  outlet: DASHBOARD_DETAILS_OUTLET,
3861
3898
  context: ViewContext.Dashboard
3862
3899
  },
@@ -4419,9 +4456,512 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
4419
4456
  type: Input
4420
4457
  }] } });
4421
4458
 
4459
+ class AssetPropertyMappingsService {
4460
+ constructor() {
4461
+ this.injector = inject(Injector);
4462
+ this.inventory = inject(InventoryService);
4463
+ this.moRealtime = inject(ManagedObjectRealtimeService);
4464
+ this.assetProperties = inject(AssetPropertiesService);
4465
+ this.computedProperties = inject(ComputedPropertiesService);
4466
+ }
4467
+ /**
4468
+ * Creates an Observable stream of asset property values that emits updates with realtime changes.
4469
+ * Uses realtimeControl$ to enable/disable underlying realtime notifications.
4470
+ *
4471
+ * @param mappings - The asset property mappings configuration.
4472
+ * @param realtimeControl$ - Observable that controls realtime notifications (true = enabled, false = disabled, default = enabled).
4473
+ * @returns Observable emitting updated asset property values as they change.
4474
+ */
4475
+ getValues$(mappings, realtimeControl$ = of(true)) {
4476
+ if (!mappings) {
4477
+ return of({});
4478
+ }
4479
+ const { regular, computed } = this.groupByType(mappings);
4480
+ const _regularByAssetId = this.groupByAssetId(regular);
4481
+ return merge(...computed.map(mapping => this.getComputedPropertyValues$(mapping, realtimeControl$)), ...Object.entries(_regularByAssetId).map(([assetId, mappings]) => this.getRegularPropertyValues$(assetId, mappings, realtimeControl$))).pipe(scan((acc, update) => ({ ...acc, ...update }), {}), startWith({}));
4482
+ }
4483
+ groupByType(mappings) {
4484
+ const regular = [];
4485
+ const computed = [];
4486
+ for (const [name, mapping] of Object.entries(mappings)) {
4487
+ if (!mapping) {
4488
+ continue;
4489
+ }
4490
+ if (mapping.assetProperty) {
4491
+ if (mapping.assetProperty.computed) {
4492
+ computed.push({ name, ...mapping });
4493
+ }
4494
+ else {
4495
+ regular.push({ name, ...mapping });
4496
+ }
4497
+ }
4498
+ }
4499
+ return { regular, computed };
4500
+ }
4501
+ groupByAssetId(mappings) {
4502
+ return mappings.reduce((acc, mapping) => {
4503
+ const assetId = mapping.assetProperty.asset.id;
4504
+ if (!acc[assetId]) {
4505
+ acc[assetId] = [];
4506
+ }
4507
+ acc[assetId].push(mapping);
4508
+ return acc;
4509
+ }, {});
4510
+ }
4511
+ getComputedPropertyValues$(mapping, realtimeControl$) {
4512
+ if (!mapping.assetProperty) {
4513
+ return of(null);
4514
+ }
4515
+ const metadata = {
4516
+ mode: 'realtime',
4517
+ realtimeControl$
4518
+ };
4519
+ const computedValue$ = from(this.inventory.detail(mapping.assetProperty.asset.id, { withLatestValues: true })).pipe(switchMap(({ data: asset }) => from(this.computedProperties.getByName(mapping.assetProperty.name)).pipe(switchMap(definition => {
4520
+ let value = null;
4521
+ runInInjectionContext(definition.injector || this.injector, () => {
4522
+ value = definition.value({
4523
+ config: mapping.assetProperty.config,
4524
+ context: asset,
4525
+ metadata
4526
+ });
4527
+ });
4528
+ if (isObservable(value)) {
4529
+ return value;
4530
+ }
4531
+ else if (value instanceof Promise) {
4532
+ return from(value);
4533
+ }
4534
+ else {
4535
+ return of(value);
4536
+ }
4537
+ }))));
4538
+ return realtimeControl$.pipe(distinctUntilChanged(), switchMap(enabled => (enabled ? computedValue$ : computedValue$.pipe(take$1(1)))), map(value => ({ [mapping.name]: value })), catchError(err => {
4539
+ // eslint-disable-next-line no-console
4540
+ console.warn(`Error in computed property stream for asset ${mapping.assetProperty.asset.id}, property ${mapping.assetProperty.name}:`, err);
4541
+ return of({ [mapping.name]: null });
4542
+ }), shareReplay({ bufferSize: 1, refCount: true }));
4543
+ }
4544
+ getRegularPropertyValues$(assetId, mappings, realtimeControl$) {
4545
+ return realtimeControl$.pipe(distinctUntilChanged(), switchMap(enabled => {
4546
+ if (!enabled) {
4547
+ return from(this.inventory.detail(assetId, { withLatestValues: true })).pipe(map(res => res?.data));
4548
+ }
4549
+ else {
4550
+ return from(this.inventory.detail(assetId, { withLatestValues: true })).pipe(switchMap(initial => this.moRealtime.onAll$(assetId).pipe(map(update => update?.data), startWith(initial?.data))));
4551
+ }
4552
+ }), map(asset => mappings.reduce((acc, mapping) => ({
4553
+ ...acc,
4554
+ [mapping.name]: this.getRegularPropertyValue(asset, mapping.assetProperty)
4555
+ }), {})), catchError(err => {
4556
+ // eslint-disable-next-line no-console
4557
+ console.warn(`Error in controlled asset stream for asset ${assetId}:`, err);
4558
+ return of(mappings.reduce((acc, m) => ({ ...acc, [m.name]: null }), {}));
4559
+ }), shareReplay({ bufferSize: 1, refCount: true }));
4560
+ }
4561
+ getRegularPropertyValue(asset, property) {
4562
+ if (!asset || !property) {
4563
+ return null;
4564
+ }
4565
+ let value;
4566
+ if (this.assetProperties.isComplexProperty(property)) {
4567
+ value = asset[property.name];
4568
+ }
4569
+ else if ('keyPath' in property) {
4570
+ value = get(asset, property.keyPath);
4571
+ }
4572
+ else {
4573
+ value = asset[property.name];
4574
+ }
4575
+ return value ?? null;
4576
+ }
4577
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssetPropertyMappingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4578
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssetPropertyMappingsService, providedIn: 'root' }); }
4579
+ }
4580
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssetPropertyMappingsService, decorators: [{
4581
+ type: Injectable,
4582
+ args: [{ providedIn: 'root' }]
4583
+ }] });
4584
+
4585
+ const IDENTIFIER_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
4586
+ function stripC8yPrefix(s) {
4587
+ return s.startsWith('c8y_') ? s.slice(4) : s;
4588
+ }
4589
+ /**
4590
+ * Returns a semantically meaningful base key for the given asset property.
4591
+ *
4592
+ * - Computed properties with a configured data point (e.g. Last measurement):
4593
+ * strips `c8y_` from fragment and series, deduplicates if they resolve to the
4594
+ * same word (e.g. `c8y_Humidity` / `Humidity` → `humidity`), then camelCases.
4595
+ * - Nested properties with a keyPath longer than one segment:
4596
+ * uses `camelCase` of the joined, `c8y_`-stripped path segments, e.g. `addressCity`.
4597
+ * - All other properties: strips leading `c8y_` and camelCases the name.
4598
+ */
4599
+ function getPropertyBaseKey(property) {
4600
+ if (property.computed) {
4601
+ const dp = property.config?.dp?.[0];
4602
+ if (dp?.fragment) {
4603
+ const strippedFragment = stripC8yPrefix(dp.fragment);
4604
+ const strippedSeries = stripC8yPrefix(dp.series);
4605
+ const seriesLower = strippedSeries.toLowerCase();
4606
+ const isDuplicate = words(strippedFragment).some(w => w.toLowerCase() === seriesLower);
4607
+ const raw = isDuplicate ? strippedFragment : `${strippedFragment}_${strippedSeries}`;
4608
+ return camelCase(raw);
4609
+ }
4610
+ }
4611
+ if ('keyPath' in property && Array.isArray(property.keyPath) && property.keyPath.length > 1) {
4612
+ return camelCase(property.keyPath.map(stripC8yPrefix).join('_'));
4613
+ }
4614
+ return camelCase(stripC8yPrefix(property.name));
4615
+ }
4616
+ function escapeForRegExp(key) {
4617
+ return key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
4618
+ }
4619
+ /** Wraps key in quotes for bracket notation, choosing the quote style that requires fewest escapes. */
4620
+ function quoteAndEscape(key) {
4621
+ const escaped = key.replace(/\\/g, '\\\\');
4622
+ if (!key.includes("'")) {
4623
+ return `'${escaped}'`;
4624
+ }
4625
+ if (!key.includes('"')) {
4626
+ return `"${escaped}"`;
4627
+ }
4628
+ return `'${escaped.replace(/'/g, "\\'")}'`;
4629
+ }
4630
+ /** How the key would appear inside a JS single-quoted string literal. */
4631
+ function encodeForSingleQuote(key) {
4632
+ return key.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
4633
+ }
4634
+ /** How the key would appear inside a JS double-quoted string literal. */
4635
+ function encodeForDoubleQuote(key) {
4636
+ return key.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
4637
+ }
4638
+ /**
4639
+ * Replaces all references to `oldKey` via `expressionPrefixes` in the given code string with
4640
+ * `newKey`, handling both bracket notation (`prefix?.['key']`, `prefix?.["key"]`) and dot notation
4641
+ * (`prefix?.key`, `prefix.key`).
4642
+ *
4643
+ * Bracket notation matching correctly handles JS string escape sequences (e.g. `['it\'s']`).
4644
+ *
4645
+ * @param code - Source code to transform.
4646
+ * @param oldKey - The property key to rename.
4647
+ * @param newKey - The new property key.
4648
+ * @param expressionPrefixes - One or more expression prefixes to match against (e.g. `['this.c8yProperties', 'c8yProperties']`).
4649
+ */
4650
+ function renamePropertyKeyInCode(code, oldKey, newKey, expressionPrefixes = ['this.c8yProperties']) {
4651
+ const encodedSingle = encodeForSingleQuote(oldKey);
4652
+ const encodedDouble = encodeForDoubleQuote(oldKey);
4653
+ const escapedDot = escapeForRegExp(oldKey);
4654
+ for (const prefix of expressionPrefixes) {
4655
+ const escapedPrefix = escapeForRegExp(prefix);
4656
+ // Replace bracket notation: prefix?.['oldKey'] and prefix?.["oldKey"] (combined, handles escaped quotes)
4657
+ code = code.replace(new RegExp(`(?<![.\\w$])(${escapedPrefix})(\\?\\.)?\\[(?:'${escapeForRegExp(encodedSingle)}'|"${escapeForRegExp(encodedDouble)}")\\]`, 'g'), (_match, obj, chain) => `${obj}${chain ?? ''}[${quoteAndEscape(newKey)}]`);
4658
+ // Replace dot notation: prefix?.oldKey and prefix.oldKey
4659
+ // Only applicable when the old key is a valid JS identifier.
4660
+ if (IDENTIFIER_REGEX.test(oldKey)) {
4661
+ code = code.replace(new RegExp(`(?<![.\\w$])(${escapedPrefix})(\\??)\\.(${escapedDot})(?=[^\\w$]|$)`, 'g'), (_match, obj, chain, _key) => {
4662
+ if (IDENTIFIER_REGEX.test(newKey)) {
4663
+ return `${obj}${chain}.${newKey}`;
4664
+ }
4665
+ // newKey is not a valid identifier — convert to bracket notation
4666
+ return `${obj}${chain ? '?.' : ''}[${quoteAndEscape(newKey)}]`;
4667
+ });
4668
+ }
4669
+ }
4670
+ return code;
4671
+ }
4672
+
4673
+ class AssetPropertyMappingsComponent {
4674
+ constructor() {
4675
+ this.widgetConfigService = inject(WidgetConfigService);
4676
+ this.bottomDrawerService = inject(BottomDrawerService);
4677
+ this.inventory = inject(InventoryService);
4678
+ this.clipboardService = inject(ClipboardService);
4679
+ this.alert = inject(AlertService);
4680
+ this.widgetConfigPath = input(['mappings'], ...(ngDevMode ? [{ debugName: "widgetConfigPath" }] : []));
4681
+ this.initialMappings = input({}, ...(ngDevMode ? [{ debugName: "initialMappings" }] : []));
4682
+ this.allowAddingNewMappings = input(true, ...(ngDevMode ? [{ debugName: "allowAddingNewMappings" }] : []));
4683
+ this.allowRenamingMappings = input(true, ...(ngDevMode ? [{ debugName: "allowRenamingMappings" }] : []));
4684
+ this.allowRelabellingMappings = input(true, ...(ngDevMode ? [{ debugName: "allowRelabellingMappings" }] : []));
4685
+ this.allowEditingMappings = input(true, ...(ngDevMode ? [{ debugName: "allowEditingMappings" }] : []));
4686
+ this.allowRemovingMappings = input(true, ...(ngDevMode ? [{ debugName: "allowRemovingMappings" }] : []));
4687
+ this.showLabels = input(true, ...(ngDevMode ? [{ debugName: "showLabels" }] : []));
4688
+ this.showNames = input(true, ...(ngDevMode ? [{ debugName: "showNames" }] : []));
4689
+ this.showAssets = input(true, ...(ngDevMode ? [{ debugName: "showAssets" }] : []));
4690
+ this.showProperties = input(true, ...(ngDevMode ? [{ debugName: "showProperties" }] : []));
4691
+ this.showValues = input(true, ...(ngDevMode ? [{ debugName: "showValues" }] : []));
4692
+ this.actionsColumnSpan = input(3, ...(ngDevMode ? [{ debugName: "actionsColumnSpan" }] : []));
4693
+ /**
4694
+ * Callback to transform a mapping into the text that gets copied to the clipboard.
4695
+ * Exposed as an input so widget config factories can override the default (e.g. to
4696
+ * produce a template expression like `${this.c8yProperties?.temperature}`).
4697
+ */
4698
+ this.onBeforeCopyMappingToClipboard = input((mapping) => String(mapping.name), ...(ngDevMode ? [{ debugName: "onBeforeCopyMappingToClipboard" }] : []));
4699
+ this.emptyStateTitle = gettext('No asset property mappings');
4700
+ this.emptyStateSubtitle = gettext('Add first asset property mapping.');
4701
+ this.mappings$ = this.widgetConfigService.currentConfig$.pipe(map$1(config => get(config, this.widgetConfigPath())));
4702
+ this.keys$ = this.mappings$.pipe(map$1(mappings => Object.keys(mappings || {}).sort((a, b) => a.localeCompare(b))));
4703
+ this.mappingsSignal = toSignal(this.mappings$, { initialValue: null });
4704
+ this.keysSignal = toSignal(this.keys$, { initialValue: null });
4705
+ this.isDrawerOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDrawerOpen" }] : []));
4706
+ this.labelValidatorCache = new Map();
4707
+ this.nameValidatorCache = new Map();
4708
+ this.assetsCache = new Map();
4709
+ this.resolvedAssets$ = this.mappings$.pipe(switchMap$1(mappings => {
4710
+ const ids = [
4711
+ ...new Set(Object.values(mappings || {})
4712
+ .map(m => m?.assetProperty?.asset?.id)
4713
+ .filter((id) => Boolean(id)))
4714
+ ];
4715
+ if (!ids.length)
4716
+ return of(new Map(this.assetsCache));
4717
+ return forkJoin(ids.map(id => from(this.getAsset(id)))).pipe(map$1(() => new Map(this.assetsCache)));
4718
+ }));
4719
+ }
4720
+ /** Distributes (12 - actionsColumnSpan) columns evenly among visible row-1 columns (label, name). */
4721
+ get row1ColumnSpans() {
4722
+ return this.distributeColumns([
4723
+ { key: 'label', visible: this.showLabels() },
4724
+ { key: 'name', visible: this.showNames() }
4725
+ ], 12 - this.actionsColumnSpan());
4726
+ }
4727
+ /** Distributes all 12 columns evenly among visible row-2 columns (asset, property, value). */
4728
+ get row2ColumnSpans() {
4729
+ return this.distributeColumns([
4730
+ { key: 'asset', visible: this.showAssets() },
4731
+ { key: 'property', visible: this.showProperties() },
4732
+ { key: 'value', visible: this.showValues() }
4733
+ ], 12);
4734
+ }
4735
+ async ngOnInit() {
4736
+ const config = await firstValueFrom(this.widgetConfigService.currentConfig$);
4737
+ if (!get(config, this.widgetConfigPath())) {
4738
+ const newConfig = { ...config };
4739
+ const mappings = structuredClone(this.initialMappings());
4740
+ for (const [key, mapping] of Object.entries(mappings)) {
4741
+ if (mapping.assetProperty && !mapping.assetProperty.asset) {
4742
+ if (!config.device) {
4743
+ delete mappings[key];
4744
+ continue;
4745
+ }
4746
+ mapping.assetProperty.asset = { id: config.device.id, name: config.device.name };
4747
+ }
4748
+ }
4749
+ set(newConfig, this.widgetConfigPath(), mappings);
4750
+ this.widgetConfigService.updateConfig(newConfig);
4751
+ }
4752
+ }
4753
+ async getAsset(id) {
4754
+ if (!this.assetsCache.has(id)) {
4755
+ const asset = (await this.inventory.detail(id, { withLatestValues: true })).data;
4756
+ this.assetsCache.set(id, asset);
4757
+ }
4758
+ return this.assetsCache.get(id);
4759
+ }
4760
+ async addMappings() {
4761
+ if (this.isDrawerOpen())
4762
+ return;
4763
+ this.isDrawerOpen.set(true);
4764
+ let latestConfig = await firstValueFrom(this.widgetConfigService.currentConfig$);
4765
+ const drawer = this.bottomDrawerService.openDrawer(AssetPropertySelectorDrawerComponent, {
4766
+ disableClickOutside: true,
4767
+ initialState: {
4768
+ allowChangingContext: true,
4769
+ contextAsset: latestConfig.device ? await this.getAsset(latestConfig.device.id) : null,
4770
+ hideSelection: false,
4771
+ config: {
4772
+ selectMode: 'plus',
4773
+ expansionMode: 'collapsedByDefault',
4774
+ showValue: true,
4775
+ showKey: true,
4776
+ allowAddingCustomProperties: true,
4777
+ addAssetToProperty: true
4778
+ }
4779
+ }
4780
+ });
4781
+ try {
4782
+ latestConfig = await firstValueFrom(this.widgetConfigService.currentConfig$);
4783
+ const selectedProperties = await drawer.instance.result;
4784
+ const newConfig = { ...latestConfig };
4785
+ const mappings = (get(newConfig, this.widgetConfigPath()) || {});
4786
+ for (const property of selectedProperties) {
4787
+ const baseKey = getPropertyBaseKey(property);
4788
+ let key = baseKey;
4789
+ let counter = 0;
4790
+ while (key in mappings) {
4791
+ key = `${baseKey}${++counter}`;
4792
+ }
4793
+ mappings[key] = {
4794
+ label: property.label,
4795
+ assetProperty: property
4796
+ };
4797
+ }
4798
+ set(newConfig, this.widgetConfigPath(), mappings);
4799
+ this.widgetConfigService.updateConfig(newConfig);
4800
+ }
4801
+ catch (ex) {
4802
+ // cancelled
4803
+ }
4804
+ finally {
4805
+ this.isDrawerOpen.set(false);
4806
+ }
4807
+ }
4808
+ async editMapping(placeholderName, mapping) {
4809
+ if (this.isDrawerOpen())
4810
+ return;
4811
+ this.isDrawerOpen.set(true);
4812
+ let latestConfig = await firstValueFrom(this.widgetConfigService.currentConfig$);
4813
+ const drawer = this.bottomDrawerService.openDrawer(AssetPropertySelectorDrawerComponent, {
4814
+ disableClickOutside: true,
4815
+ initialState: {
4816
+ allowChangingContext: true,
4817
+ contextAsset: latestConfig.device ? await this.getAsset(latestConfig.device.id) : null,
4818
+ hideSelection: false,
4819
+ config: {
4820
+ selectMode: 'single',
4821
+ expansionMode: 'collapsedByDefault',
4822
+ showValue: true,
4823
+ showKey: true,
4824
+ allowAddingCustomProperties: true,
4825
+ addAssetToProperty: true
4826
+ }
4827
+ }
4828
+ });
4829
+ try {
4830
+ latestConfig = await firstValueFrom(this.widgetConfigService.currentConfig$);
4831
+ const [selectedProperty] = await drawer.instance.result;
4832
+ const newConfig = { ...latestConfig };
4833
+ const mappings = (get(newConfig, this.widgetConfigPath()) || {});
4834
+ mappings[placeholderName] = {
4835
+ label: mapping.label,
4836
+ assetProperty: selectedProperty
4837
+ };
4838
+ set(newConfig, this.widgetConfigPath(), mappings);
4839
+ this.widgetConfigService.updateConfig(newConfig);
4840
+ }
4841
+ catch (ex) {
4842
+ // cancelled
4843
+ }
4844
+ finally {
4845
+ this.isDrawerOpen.set(false);
4846
+ }
4847
+ }
4848
+ async clearMapping(placeholderName) {
4849
+ const config = await firstValueFrom(this.widgetConfigService.currentConfig$);
4850
+ set(config, [...this.widgetConfigPath(), placeholderName, 'assetProperty'], null);
4851
+ this.widgetConfigService.updateConfig(config);
4852
+ }
4853
+ async copyMappingToClipboard(name, mapping) {
4854
+ const mappingToTextFn = this.onBeforeCopyMappingToClipboard();
4855
+ const text = mappingToTextFn({ name, ...mapping });
4856
+ await this.clipboardService.writeText(text);
4857
+ }
4858
+ async removeMapping(name) {
4859
+ const config = await firstValueFrom(this.widgetConfigService.currentConfig$);
4860
+ const mappings = (get(config, this.widgetConfigPath()) || {});
4861
+ delete mappings[name];
4862
+ set(config, this.widgetConfigPath(), mappings);
4863
+ this.widgetConfigService.updateConfig(config);
4864
+ }
4865
+ async removeAllMappings() {
4866
+ const config = await firstValueFrom(this.widgetConfigService.currentConfig$);
4867
+ set(config, this.widgetConfigPath(), {});
4868
+ this.widgetConfigService.updateConfig(config);
4869
+ }
4870
+ getLabelValidators(key) {
4871
+ if (!this.labelValidatorCache.has(key)) {
4872
+ this.labelValidatorCache.set(key, [
4873
+ Validators.required,
4874
+ ctrl => this.isLabelAlreadyUsed(ctrl.value, key, this.mappingsSignal())
4875
+ ? { 'label-already-used': true }
4876
+ : null
4877
+ ]);
4878
+ }
4879
+ return this.labelValidatorCache.get(key);
4880
+ }
4881
+ getNameValidators(key) {
4882
+ if (!this.nameValidatorCache.has(key)) {
4883
+ this.nameValidatorCache.set(key, [
4884
+ Validators.required,
4885
+ ctrl => this.isNameAlreadyUsed(ctrl.value, key, this.keysSignal())
4886
+ ? { 'key-already-used': true }
4887
+ : null
4888
+ ]);
4889
+ }
4890
+ return this.nameValidatorCache.get(key);
4891
+ }
4892
+ isLabelAlreadyUsed(value, key, mappings) {
4893
+ const trimmed = value.trim();
4894
+ return (!!trimmed &&
4895
+ Object.entries(mappings || {})
4896
+ .filter(([k]) => k !== key)
4897
+ .some(([k, m]) => (m?.label || k) === trimmed));
4898
+ }
4899
+ isNameAlreadyUsed(value, key, keys) {
4900
+ const trimmed = value.trim();
4901
+ return trimmed !== key && (keys || []).includes(trimmed);
4902
+ }
4903
+ async saveLabel(key, newLabel) {
4904
+ const config = await firstValueFrom(this.widgetConfigService.currentConfig$);
4905
+ const mappings = (get(config, this.widgetConfigPath()) || {});
4906
+ if (!mappings[key]) {
4907
+ return;
4908
+ }
4909
+ mappings[key] = { ...mappings[key], label: newLabel.trim() };
4910
+ set(config, this.widgetConfigPath(), mappings);
4911
+ this.widgetConfigService.updateConfig(config);
4912
+ }
4913
+ async saveName(key, newName) {
4914
+ const trimmedName = newName.trim();
4915
+ if (trimmedName === key) {
4916
+ return;
4917
+ }
4918
+ const config = await firstValueFrom(this.widgetConfigService.currentConfig$);
4919
+ const mappings = (get(config, this.widgetConfigPath()) || {});
4920
+ mappings[trimmedName] = mappings[key];
4921
+ delete mappings[key];
4922
+ set(config, this.widgetConfigPath(), mappings);
4923
+ this.widgetConfigService.updateConfig(config);
4924
+ this.widgetConfigService.notify$.next({
4925
+ type: 'asset-property-mapping-key-renamed',
4926
+ oldKey: key,
4927
+ newKey: trimmedName
4928
+ });
4929
+ }
4930
+ distributeColumns(columns, available) {
4931
+ const visible = columns.filter(c => c.visible);
4932
+ const n = visible.length;
4933
+ const base = n > 0 ? Math.floor(available / n) : 0;
4934
+ const remainder = n > 0 ? available % n : 0;
4935
+ const result = Object.fromEntries(columns.map(c => [c.key, 0]));
4936
+ visible.forEach((col, i) => {
4937
+ result[col.key] = base + (i < remainder ? 1 : 0);
4938
+ });
4939
+ return result;
4940
+ }
4941
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssetPropertyMappingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4942
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AssetPropertyMappingsComponent, isStandalone: true, selector: "c8y-asset-property-mappings", inputs: { widgetConfigPath: { classPropertyName: "widgetConfigPath", publicName: "widgetConfigPath", isSignal: true, isRequired: false, transformFunction: null }, initialMappings: { classPropertyName: "initialMappings", publicName: "initialMappings", isSignal: true, isRequired: false, transformFunction: null }, allowAddingNewMappings: { classPropertyName: "allowAddingNewMappings", publicName: "allowAddingNewMappings", isSignal: true, isRequired: false, transformFunction: null }, allowRenamingMappings: { classPropertyName: "allowRenamingMappings", publicName: "allowRenamingMappings", isSignal: true, isRequired: false, transformFunction: null }, allowRelabellingMappings: { classPropertyName: "allowRelabellingMappings", publicName: "allowRelabellingMappings", isSignal: true, isRequired: false, transformFunction: null }, allowEditingMappings: { classPropertyName: "allowEditingMappings", publicName: "allowEditingMappings", isSignal: true, isRequired: false, transformFunction: null }, allowRemovingMappings: { classPropertyName: "allowRemovingMappings", publicName: "allowRemovingMappings", isSignal: true, isRequired: false, transformFunction: null }, showLabels: { classPropertyName: "showLabels", publicName: "showLabels", isSignal: true, isRequired: false, transformFunction: null }, showNames: { classPropertyName: "showNames", publicName: "showNames", isSignal: true, isRequired: false, transformFunction: null }, showAssets: { classPropertyName: "showAssets", publicName: "showAssets", isSignal: true, isRequired: false, transformFunction: null }, showProperties: { classPropertyName: "showProperties", publicName: "showProperties", isSignal: true, isRequired: false, transformFunction: null }, showValues: { classPropertyName: "showValues", publicName: "showValues", isSignal: true, isRequired: false, transformFunction: null }, actionsColumnSpan: { classPropertyName: "actionsColumnSpan", publicName: "actionsColumnSpan", isSignal: true, isRequired: false, transformFunction: null }, onBeforeCopyMappingToClipboard: { classPropertyName: "onBeforeCopyMappingToClipboard", publicName: "onBeforeCopyMappingToClipboard", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"responsive-grid-table-wrapper--300 responsive-grid-table-wrapper--striped inner-scroll separator-top\"\n style=\"max-height: 300px\"\n>\n @let keys = keys$ | async;\n @let resolvedAssets = resolvedAssets$ | async;\n @let allMappings = mappings$ | async;\n @if (!keys?.length) {\n <div class=\"p-24\">\n <c8y-ui-empty-state\n icon=\"code\"\n [title]=\"emptyStateTitle | translate\"\n [subtitle]=\"emptyStateSubtitle | translate\"\n ></c8y-ui-empty-state>\n </div>\n } @else {\n @for (key of keys; track key) {\n @let mapping = allMappings?.[key];\n @let property = mapping?.assetProperty;\n @let asset = resolvedAssets?.get(property?.asset?.id);\n <div\n class=\"responsive-grid-table responsive-grid-table__body responsive-grid-table--condensed responsive-grid-table--separator p-l-16\"\n >\n @if (showLabels()) {\n <div\n [class]=\"'col-' + row1ColumnSpans.label\"\n [attr.aria-label]=\"'Label' | translate\"\n >\n <div class=\"fit-w\">\n <p class=\"text-label-small\">{{ 'Label' | translate }}</p>\n @if (allowRelabellingMappings()) {\n <c8y-input-group-editable\n name=\"label-{{ key }}\"\n size=\"sm\"\n [ariaLabel]=\"'Label' | translate\"\n [ngModel]=\"mapping?.label || key\"\n [validators]=\"getLabelValidators(key)\"\n (ngModelChange)=\"saveLabel(key, $event)\"\n >\n <c8y-message\n name=\"label-already-used\"\n [text]=\"'Label already used. Use a different one.' | translate\"\n ></c8y-message>\n </c8y-input-group-editable>\n } @else {\n <span class=\"tag tag--default text-bold\">{{ mapping?.label || key }}</span>\n }\n </div>\n </div>\n }\n @if (showNames()) {\n <div\n [class]=\"'col-' + row1ColumnSpans.name\"\n [attr.aria-label]=\"'Name' | translate\"\n >\n <div class=\"fit-w\">\n <p class=\"text-label-small\">{{ 'Name' | translate }}</p>\n @if (allowRenamingMappings()) {\n <c8y-input-group-editable\n class=\"text-bold\"\n name=\"name-{{ key }}\"\n size=\"sm\"\n [ariaLabel]=\"'Name' | translate\"\n [ngModel]=\"key\"\n [validators]=\"getNameValidators(key)\"\n (ngModelChange)=\"saveName(key, $event)\"\n >\n <c8y-message\n name=\"key-already-used\"\n [text]=\"'Name already used. Use a different one.' | translate\"\n ></c8y-message>\n </c8y-input-group-editable>\n } @else {\n {{ key }}\n }\n </div>\n </div>\n }\n <div [class]=\"'showOnHover col-' + actionsColumnSpan()\">\n <div class=\"col-actions fit-w min-width-0\">\n <button\n class=\"btn-dot btn-sm m-0\"\n [attr.aria-label]=\"'Copy mapping to clipboard' | translate\"\n tooltip=\"{{ 'Copy mapping to clipboard' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"copyMappingToClipboard(key, mapping!)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"clipboard\"\n aria-hidden=\"true\"\n ></i>\n </button>\n @if (allowEditingMappings() && !mapping?.assetProperty) {\n <button\n class=\"btn-dot btn-sm m-0\"\n [attr.aria-label]=\"'Assign property' | translate\"\n tooltip=\"{{ 'Assign property' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n [disabled]=\"isDrawerOpen()\"\n (click)=\"editMapping(key, mapping!)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"pencil\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n @if (allowEditingMappings() && mapping?.assetProperty) {\n <button\n class=\"btn-dot btn-sm m-0\"\n [attr.aria-label]=\"'Clear mapping' | translate\"\n tooltip=\"{{ 'Clear mapping' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"clearMapping(key)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"remove-property\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n @if (allowRemovingMappings()) {\n <button\n class=\"btn-dot btn-sm btn-dot--danger m-0\"\n [attr.aria-label]=\"'Remove mapping' | translate\"\n tooltip=\"{{ 'Remove mapping' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"removeMapping(key)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"minus-circle\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n </div>\n @if (showAssets()) {\n <div\n [class]=\"'p-b-16 col-' + row2ColumnSpans.asset\"\n [attr.aria-label]=\"'Asset' | translate\"\n >\n <div class=\"min-width-0\">\n <p class=\"text-label-small\">{{ 'Asset' | translate }}</p>\n {{ mapping?.assetProperty?.asset?.name || mapping?.assetProperty?.asset?.id || '\u2014' }}\n </div>\n </div>\n }\n @if (showProperties()) {\n <div\n [class]=\"'p-b-16 col-' + row2ColumnSpans.property\"\n [attr.aria-label]=\"'Property' | translate\"\n >\n <div class=\"min-width-0\">\n <p class=\"text-label-small\">{{ 'Property' | translate }}</p>\n {{ property?.label || property?.name || '\u2014' }}\n </div>\n </div>\n }\n @if (showValues()) {\n <div\n [class]=\"'p-b-16 col-' + row2ColumnSpans.value\"\n [attr.aria-label]=\"'Value' | translate\"\n >\n <div class=\"min-width-0\">\n <p class=\"text-label-small\">{{ 'Value' | translate }}</p>\n @if (property && asset) {\n @let value = (property | c8yAssetPropertyValue: asset | async) ?? '\u2014';\n <samp\n class=\"text-truncate min-width-0\"\n title=\"{{ value }}\"\n >\n {{ value }}\n </samp>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n</div>\n@if (allowAddingNewMappings() || (allowRemovingMappings() && (keys$ | async)?.length)) {\n <div class=\"p-16 separator-top d-flex j-c-between a-i-center\">\n @if (allowAddingNewMappings()) {\n <button\n class=\"btn btn-default btn-sm\"\n type=\"button\"\n [disabled]=\"isDrawerOpen()\"\n (click)=\"addMappings()\"\n >\n <i\n c8yIcon=\"plus-circle\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Add mappings' | translate }}\n </button>\n }\n @if (allowRemovingMappings() && (keys$ | async)?.length) {\n <button\n class=\"btn btn-danger btn-sm\"\n type=\"button\"\n [disabled]=\"isDrawerOpen()\"\n (click)=\"removeAllMappings()\"\n >\n <i\n c8yIcon=\"minus-circle\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Remove all mappings' | translate }}\n </button>\n }\n </div>\n}\n\n<c8y-widget-config-feedback>\n <span\n class=\"tag tag--info chip text-12 m-4\"\n ngNonBindable\n translate\n [translateParams]=\"{\n count: (keys$ | async)?.length ?? 0\n }\"\n >\n {{ count }} selected\n </span>\n</c8y-widget-config-feedback>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.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: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: InputGroupEditableComponent, selector: "c8y-input-group-editable", inputs: ["ariaLabel", "name", "size", "placeholder", "validators", "asyncValidators"], outputs: ["save", "cancel"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2$4.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: "component", type: WidgetConfigFeedbackComponent, selector: "c8y-widget-config-feedback" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AssetPropertyValuePipe, name: "c8yAssetPropertyValue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4943
+ }
4944
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssetPropertyMappingsComponent, decorators: [{
4945
+ type: Component,
4946
+ args: [{ selector: 'c8y-asset-property-mappings', imports: [
4947
+ AsyncPipe,
4948
+ FormsModule,
4949
+ IconDirective,
4950
+ C8yTranslatePipe,
4951
+ C8yTranslateDirective,
4952
+ InputGroupEditableComponent,
4953
+ MessageDirective,
4954
+ EmptyStateComponent,
4955
+ AssetPropertyValuePipe,
4956
+ BsDropdownModule,
4957
+ TooltipModule,
4958
+ WidgetConfigFeedbackComponent
4959
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"responsive-grid-table-wrapper--300 responsive-grid-table-wrapper--striped inner-scroll separator-top\"\n style=\"max-height: 300px\"\n>\n @let keys = keys$ | async;\n @let resolvedAssets = resolvedAssets$ | async;\n @let allMappings = mappings$ | async;\n @if (!keys?.length) {\n <div class=\"p-24\">\n <c8y-ui-empty-state\n icon=\"code\"\n [title]=\"emptyStateTitle | translate\"\n [subtitle]=\"emptyStateSubtitle | translate\"\n ></c8y-ui-empty-state>\n </div>\n } @else {\n @for (key of keys; track key) {\n @let mapping = allMappings?.[key];\n @let property = mapping?.assetProperty;\n @let asset = resolvedAssets?.get(property?.asset?.id);\n <div\n class=\"responsive-grid-table responsive-grid-table__body responsive-grid-table--condensed responsive-grid-table--separator p-l-16\"\n >\n @if (showLabels()) {\n <div\n [class]=\"'col-' + row1ColumnSpans.label\"\n [attr.aria-label]=\"'Label' | translate\"\n >\n <div class=\"fit-w\">\n <p class=\"text-label-small\">{{ 'Label' | translate }}</p>\n @if (allowRelabellingMappings()) {\n <c8y-input-group-editable\n name=\"label-{{ key }}\"\n size=\"sm\"\n [ariaLabel]=\"'Label' | translate\"\n [ngModel]=\"mapping?.label || key\"\n [validators]=\"getLabelValidators(key)\"\n (ngModelChange)=\"saveLabel(key, $event)\"\n >\n <c8y-message\n name=\"label-already-used\"\n [text]=\"'Label already used. Use a different one.' | translate\"\n ></c8y-message>\n </c8y-input-group-editable>\n } @else {\n <span class=\"tag tag--default text-bold\">{{ mapping?.label || key }}</span>\n }\n </div>\n </div>\n }\n @if (showNames()) {\n <div\n [class]=\"'col-' + row1ColumnSpans.name\"\n [attr.aria-label]=\"'Name' | translate\"\n >\n <div class=\"fit-w\">\n <p class=\"text-label-small\">{{ 'Name' | translate }}</p>\n @if (allowRenamingMappings()) {\n <c8y-input-group-editable\n class=\"text-bold\"\n name=\"name-{{ key }}\"\n size=\"sm\"\n [ariaLabel]=\"'Name' | translate\"\n [ngModel]=\"key\"\n [validators]=\"getNameValidators(key)\"\n (ngModelChange)=\"saveName(key, $event)\"\n >\n <c8y-message\n name=\"key-already-used\"\n [text]=\"'Name already used. Use a different one.' | translate\"\n ></c8y-message>\n </c8y-input-group-editable>\n } @else {\n {{ key }}\n }\n </div>\n </div>\n }\n <div [class]=\"'showOnHover col-' + actionsColumnSpan()\">\n <div class=\"col-actions fit-w min-width-0\">\n <button\n class=\"btn-dot btn-sm m-0\"\n [attr.aria-label]=\"'Copy mapping to clipboard' | translate\"\n tooltip=\"{{ 'Copy mapping to clipboard' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"copyMappingToClipboard(key, mapping!)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"clipboard\"\n aria-hidden=\"true\"\n ></i>\n </button>\n @if (allowEditingMappings() && !mapping?.assetProperty) {\n <button\n class=\"btn-dot btn-sm m-0\"\n [attr.aria-label]=\"'Assign property' | translate\"\n tooltip=\"{{ 'Assign property' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n [disabled]=\"isDrawerOpen()\"\n (click)=\"editMapping(key, mapping!)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"pencil\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n @if (allowEditingMappings() && mapping?.assetProperty) {\n <button\n class=\"btn-dot btn-sm m-0\"\n [attr.aria-label]=\"'Clear mapping' | translate\"\n tooltip=\"{{ 'Clear mapping' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"clearMapping(key)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"remove-property\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n @if (allowRemovingMappings()) {\n <button\n class=\"btn-dot btn-sm btn-dot--danger m-0\"\n [attr.aria-label]=\"'Remove mapping' | translate\"\n tooltip=\"{{ 'Remove mapping' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"removeMapping(key)\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"minus-circle\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n </div>\n @if (showAssets()) {\n <div\n [class]=\"'p-b-16 col-' + row2ColumnSpans.asset\"\n [attr.aria-label]=\"'Asset' | translate\"\n >\n <div class=\"min-width-0\">\n <p class=\"text-label-small\">{{ 'Asset' | translate }}</p>\n {{ mapping?.assetProperty?.asset?.name || mapping?.assetProperty?.asset?.id || '\u2014' }}\n </div>\n </div>\n }\n @if (showProperties()) {\n <div\n [class]=\"'p-b-16 col-' + row2ColumnSpans.property\"\n [attr.aria-label]=\"'Property' | translate\"\n >\n <div class=\"min-width-0\">\n <p class=\"text-label-small\">{{ 'Property' | translate }}</p>\n {{ property?.label || property?.name || '\u2014' }}\n </div>\n </div>\n }\n @if (showValues()) {\n <div\n [class]=\"'p-b-16 col-' + row2ColumnSpans.value\"\n [attr.aria-label]=\"'Value' | translate\"\n >\n <div class=\"min-width-0\">\n <p class=\"text-label-small\">{{ 'Value' | translate }}</p>\n @if (property && asset) {\n @let value = (property | c8yAssetPropertyValue: asset | async) ?? '\u2014';\n <samp\n class=\"text-truncate min-width-0\"\n title=\"{{ value }}\"\n >\n {{ value }}\n </samp>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n</div>\n@if (allowAddingNewMappings() || (allowRemovingMappings() && (keys$ | async)?.length)) {\n <div class=\"p-16 separator-top d-flex j-c-between a-i-center\">\n @if (allowAddingNewMappings()) {\n <button\n class=\"btn btn-default btn-sm\"\n type=\"button\"\n [disabled]=\"isDrawerOpen()\"\n (click)=\"addMappings()\"\n >\n <i\n c8yIcon=\"plus-circle\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Add mappings' | translate }}\n </button>\n }\n @if (allowRemovingMappings() && (keys$ | async)?.length) {\n <button\n class=\"btn btn-danger btn-sm\"\n type=\"button\"\n [disabled]=\"isDrawerOpen()\"\n (click)=\"removeAllMappings()\"\n >\n <i\n c8yIcon=\"minus-circle\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Remove all mappings' | translate }}\n </button>\n }\n </div>\n}\n\n<c8y-widget-config-feedback>\n <span\n class=\"tag tag--info chip text-12 m-4\"\n ngNonBindable\n translate\n [translateParams]=\"{\n count: (keys$ | async)?.length ?? 0\n }\"\n >\n {{ count }} selected\n </span>\n</c8y-widget-config-feedback>\n" }]
4960
+ }], propDecorators: { widgetConfigPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetConfigPath", required: false }] }], initialMappings: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialMappings", required: false }] }], allowAddingNewMappings: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAddingNewMappings", required: false }] }], allowRenamingMappings: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowRenamingMappings", required: false }] }], allowRelabellingMappings: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowRelabellingMappings", required: false }] }], allowEditingMappings: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowEditingMappings", required: false }] }], allowRemovingMappings: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowRemovingMappings", required: false }] }], showLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabels", required: false }] }], showNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNames", required: false }] }], showAssets: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAssets", required: false }] }], showProperties: [{ type: i0.Input, args: [{ isSignal: true, alias: "showProperties", required: false }] }], showValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValues", required: false }] }], actionsColumnSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionsColumnSpan", required: false }] }], onBeforeCopyMappingToClipboard: [{ type: i0.Input, args: [{ isSignal: true, alias: "onBeforeCopyMappingToClipboard", required: false }] }] } });
4961
+
4422
4962
  /**
4423
4963
  * Generated bundle index. Do not edit.
4424
4964
  */
4425
4965
 
4426
- export { ALL_GLOBAL_ROLES_SELECTED, AddDashboardComponent, AddDashboardFactory, AppearanceSettingsComponent, CONTEXT_DASHBOARD_CONFIG, ContextDashboardComponent, ContextDashboardModule, ContextDashboardService, ContextDashboardType, DASHBOARD_CHILDREN_STATE_NAME, DASHBOARD_DETAILS_OUTLET, DASHBOARD_DETAILS_TABS_OUTLET_NAME, DASHBOARD_SETTINGS_CHANGES, DASHBOARD_THEME_CLASSES, DashboardActionBarFactory, DashboardDetailComponent, DashboardDetailService, DashboardDetailsTabId, DeviceInfoDashboardComponent, DeviceInfoDashboardModule, DeviceManagementHomeDashboardComponent, DeviceManagementHomeDashboardModule, GlobalContextSectionComponent, HOOK_WIDGET_CONFIG, NewDashboardGuard, PRODUCT_EXPERIENCE, PasteDashboardActionComponent, REPORT_DEFAULT_NAVIGATION_NODE_PRIORITY, STYLING_CLASS_PREFIXES, TypeDashboardInfoComponent, WIDGET_CONTENT_CLASSES, WIDGET_HEADER_CLASSES, WidgetAssetSelectorComponent, WidgetConfigAppearanceComponent, WidgetConfigComponent, WidgetConfigFeedbackComponent, WidgetConfigGeneralComponent, WidgetConfigSectionComponent, WidgetConfigSectionService, WidgetConfigService, WidgetPreviewComponent, WidgetPreviewWrapperComponent, WidgetService, hookWidgetConfig, newDashboardTab };
4966
+ export { ALL_GLOBAL_ROLES_SELECTED, AddDashboardComponent, AddDashboardFactory, AppearanceSettingsComponent, AssetPropertyMappingsComponent, AssetPropertyMappingsService, CONTEXT_DASHBOARD_CONFIG, ContextDashboardComponent, ContextDashboardModule, ContextDashboardService, ContextDashboardType, DASHBOARD_CHILDREN_STATE_NAME, DASHBOARD_DETAILS_OUTLET, DASHBOARD_DETAILS_TABS_OUTLET_NAME, DASHBOARD_SETTINGS_CHANGES, DASHBOARD_THEME_CLASSES, DashboardActionBarFactory, DashboardDetailComponent, DashboardDetailService, DashboardDetailsTabId, DeviceInfoDashboardComponent, DeviceInfoDashboardModule, DeviceManagementHomeDashboardComponent, DeviceManagementHomeDashboardModule, GlobalContextSectionComponent, HOOK_WIDGET_CONFIG, NewDashboardGuard, PRODUCT_EXPERIENCE, PasteDashboardActionComponent, REPORT_DEFAULT_NAVIGATION_NODE_PRIORITY, STYLING_CLASS_PREFIXES, TypeDashboardInfoComponent, WIDGET_CONTENT_CLASSES, WIDGET_HEADER_CLASSES, WidgetAssetSelectorComponent, WidgetConfigAppearanceComponent, WidgetConfigComponent, WidgetConfigFeedbackComponent, WidgetConfigGeneralComponent, WidgetConfigSectionComponent, WidgetConfigSectionService, WidgetConfigService, WidgetPreviewComponent, WidgetPreviewWrapperComponent, WidgetService, getPropertyBaseKey, hookWidgetConfig, newDashboardTab, quoteAndEscape, renamePropertyKeyInCode };
4427
4967
  //# sourceMappingURL=c8y-ngx-components-context-dashboard.mjs.map