@c8y/ngx-components 1023.71.1 → 1023.76.0

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