@c8y/ngx-components 1022.13.0 → 1022.21.3

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 (430) hide show
  1. package/alarms/alarms.helper.d.ts.map +1 -1
  2. package/auth-configuration/sso-configuration/templates/template.component.d.ts +1 -1
  3. package/core/asset-property/asset-property.model.d.ts +0 -6
  4. package/core/asset-property/asset-property.model.d.ts.map +1 -1
  5. package/core/authentication/authentication.module.d.ts.map +1 -1
  6. package/core/authentication/new-password.component.d.ts +3 -2
  7. package/core/authentication/new-password.component.d.ts.map +1 -1
  8. package/core/dashboard/widget-auto-refresh-context/auto-refresh-control.component.d.ts.map +1 -1
  9. package/core/drop-area/drop-area.component.d.ts +2 -0
  10. package/core/drop-area/drop-area.component.d.ts.map +1 -1
  11. package/core/dynamic-forms/file/file.type.component.d.ts.map +1 -1
  12. package/core/modal/modal.module.d.ts.map +1 -1
  13. package/core/modal/modal.service.d.ts +1 -0
  14. package/core/modal/modal.service.d.ts.map +1 -1
  15. package/core/plugins/plugins.module.d.ts.map +1 -1
  16. package/core/plugins/plugins.service.d.ts +1 -2
  17. package/core/plugins/plugins.service.d.ts.map +1 -1
  18. package/core/select/select.component.d.ts.map +1 -1
  19. package/core/user/user-edit-modal.component.d.ts +1 -0
  20. package/core/user/user-edit-modal.component.d.ts.map +1 -1
  21. package/core/user/user-edit.component.d.ts +4 -1
  22. package/core/user/user-edit.component.d.ts.map +1 -1
  23. package/datapoint-explorer/datapoint-explorer.module.d.ts +2 -0
  24. package/datapoint-explorer/datapoint-explorer.module.d.ts.map +1 -1
  25. package/datapoint-explorer/devicemanagement/c8y-ngx-components-datapoint-explorer-devicemanagement.d.ts.map +1 -0
  26. package/datapoint-explorer/devicemanagement/index.d.ts +2 -0
  27. package/datapoint-explorer/devicemanagement/index.d.ts.map +1 -0
  28. package/datapoint-explorer/view/datapoint-explorer.component.d.ts +6 -3
  29. package/datapoint-explorer/view/datapoint-explorer.component.d.ts.map +1 -1
  30. package/datapoint-explorer/view/datapoint-explorer.model.d.ts +8 -0
  31. package/datapoint-explorer/view/datapoint-explorer.model.d.ts.map +1 -0
  32. package/datapoint-explorer/view/index.d.ts +1 -0
  33. package/datapoint-explorer/view/index.d.ts.map +1 -1
  34. package/device-list/devices.breadcrumb-factory.d.ts +1 -0
  35. package/device-list/devices.breadcrumb-factory.d.ts.map +1 -1
  36. package/device-profile/add-device-profile.component.d.ts +1 -1
  37. package/device-profile/add-device-profile.component.d.ts.map +1 -1
  38. package/device-profile/device-profile-list.component.d.ts +1 -1
  39. package/device-profile/device-profile-list.component.d.ts.map +1 -1
  40. package/device-profile/device-profile.component.d.ts +1 -1
  41. package/device-profile/device-profile.component.d.ts.map +1 -1
  42. package/device-profile/device-profile.module.d.ts +17 -17
  43. package/device-profile/device-profile.module.d.ts.map +1 -1
  44. package/device-profile/device-tab-profile/device-profile-item-list.component.d.ts +1 -1
  45. package/device-profile/device-tab-profile/device-profile-item-list.component.d.ts.map +1 -1
  46. package/device-profile/device-tab-profile/device-tab-profile-detail.component.d.ts +1 -1
  47. package/device-profile/device-tab-profile/device-tab-profile-detail.component.d.ts.map +1 -1
  48. package/device-profile/device-tab-profile/device-tab-profile.component.d.ts +1 -1
  49. package/device-profile/device-tab-profile/device-tab-profile.component.d.ts.map +1 -1
  50. package/device-profile/select-configuration-modal.component.d.ts +1 -1
  51. package/device-profile/select-configuration-modal.component.d.ts.map +1 -1
  52. package/device-provisioned-certificates/device-tab-provisioned-certificates.component.d.ts +4 -2
  53. package/device-provisioned-certificates/device-tab-provisioned-certificates.component.d.ts.map +1 -1
  54. package/device-shell/command-templates/command-templates.component.d.ts +1 -1
  55. package/device-shell/command-templates/command-templates.component.d.ts.map +1 -1
  56. package/device-shell/command-templates/command-templates.directive.d.ts +1 -1
  57. package/device-shell/command-templates/command-templates.directive.d.ts.map +1 -1
  58. package/device-shell/command-templates/command-templates.module.d.ts +1 -1
  59. package/device-shell/shell/shell.component.d.ts +1 -1
  60. package/device-shell/shell/shell.component.d.ts.map +1 -1
  61. package/device-shell/shell/shell.module.d.ts +7 -7
  62. package/diagnostics/diagnostics.component.d.ts +1 -1
  63. package/diagnostics/diagnostics.component.d.ts.map +1 -1
  64. package/diagnostics/diagnostics.module.d.ts +8 -8
  65. package/diagnostics/diagnostics.module.d.ts.map +1 -1
  66. package/echart/services/chart-realtime.service.d.ts +2 -0
  67. package/echart/services/chart-realtime.service.d.ts.map +1 -1
  68. package/echart/services/echarts-options.service.d.ts +4 -4
  69. package/echart/services/echarts-options.service.d.ts.map +1 -1
  70. package/events/c8y-ngx-components-events.d.ts.map +1 -0
  71. package/events/events-timeline/c8y-ngx-components-events-events-timeline.d.ts.map +1 -0
  72. package/events/events-timeline/events-timeline.component.d.ts +19 -0
  73. package/events/events-timeline/events-timeline.component.d.ts.map +1 -0
  74. package/events/events-timeline/index.d.ts +2 -0
  75. package/events/events-timeline/index.d.ts.map +1 -0
  76. package/events/events.model.d.ts +6 -0
  77. package/events/events.model.d.ts.map +1 -0
  78. package/events/events.service.d.ts +10 -0
  79. package/events/events.service.d.ts.map +1 -0
  80. package/events/index.d.ts +3 -0
  81. package/events/index.d.ts.map +1 -0
  82. package/fesm2022/c8y-ngx-components-alarms.mjs +2 -1
  83. package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
  84. package/fesm2022/c8y-ngx-components-auth-configuration.mjs +2 -2
  85. package/fesm2022/c8y-ngx-components-auth-configuration.mjs.map +1 -1
  86. package/fesm2022/c8y-ngx-components-datapoint-explorer-devicemanagement.mjs +38 -0
  87. package/fesm2022/c8y-ngx-components-datapoint-explorer-devicemanagement.mjs.map +1 -0
  88. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +143 -142
  89. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  90. package/fesm2022/c8y-ngx-components-datapoint-explorer.mjs +1 -1
  91. package/fesm2022/c8y-ngx-components-datapoint-explorer.mjs.map +1 -1
  92. package/fesm2022/c8y-ngx-components-device-list.mjs +10 -3
  93. package/fesm2022/c8y-ngx-components-device-list.mjs.map +1 -1
  94. package/fesm2022/c8y-ngx-components-device-profile.mjs +126 -49
  95. package/fesm2022/c8y-ngx-components-device-profile.mjs.map +1 -1
  96. package/fesm2022/c8y-ngx-components-device-provisioned-certificates.mjs +44 -12
  97. package/fesm2022/c8y-ngx-components-device-provisioned-certificates.mjs.map +1 -1
  98. package/fesm2022/c8y-ngx-components-device-shell.mjs +31 -22
  99. package/fesm2022/c8y-ngx-components-device-shell.mjs.map +1 -1
  100. package/fesm2022/c8y-ngx-components-diagnostics.mjs +36 -19
  101. package/fesm2022/c8y-ngx-components-diagnostics.mjs.map +1 -1
  102. package/fesm2022/c8y-ngx-components-echart.mjs +53 -17
  103. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  104. package/fesm2022/c8y-ngx-components-events-events-timeline.mjs +45 -0
  105. package/fesm2022/c8y-ngx-components-events-events-timeline.mjs.map +1 -0
  106. package/fesm2022/c8y-ngx-components-events.mjs +44 -0
  107. package/fesm2022/c8y-ngx-components-events.mjs.map +1 -0
  108. package/fesm2022/c8y-ngx-components-operations-bulk-operation-from-single.mjs +8 -14
  109. package/fesm2022/c8y-ngx-components-operations-bulk-operation-from-single.mjs.map +1 -1
  110. package/fesm2022/c8y-ngx-components-operations-bulk-operation-list-item.mjs +49 -49
  111. package/fesm2022/c8y-ngx-components-operations-bulk-operation-list-item.mjs.map +1 -1
  112. package/fesm2022/c8y-ngx-components-operations-bulk-operation-scheduler.mjs +27 -14
  113. package/fesm2022/c8y-ngx-components-operations-bulk-operation-scheduler.mjs.map +1 -1
  114. package/fesm2022/c8y-ngx-components-operations-bulk-operation-stepper.mjs +27 -33
  115. package/fesm2022/c8y-ngx-components-operations-bulk-operation-stepper.mjs.map +1 -1
  116. package/fesm2022/c8y-ngx-components-operations-bulk-operations-list.mjs +51 -39
  117. package/fesm2022/c8y-ngx-components-operations-bulk-operations-list.mjs.map +1 -1
  118. package/fesm2022/c8y-ngx-components-operations-bulk-operations-stepper-container.mjs +10 -8
  119. package/fesm2022/c8y-ngx-components-operations-bulk-operations-stepper-container.mjs.map +1 -1
  120. package/fesm2022/c8y-ngx-components-operations-create-bulk-operation-details.mjs +16 -11
  121. package/fesm2022/c8y-ngx-components-operations-create-bulk-operation-details.mjs.map +1 -1
  122. package/fesm2022/c8y-ngx-components-operations-device-selector.mjs +8 -11
  123. package/fesm2022/c8y-ngx-components-operations-device-selector.mjs.map +1 -1
  124. package/fesm2022/c8y-ngx-components-operations-operation-details.mjs +25 -21
  125. package/fesm2022/c8y-ngx-components-operations-operation-details.mjs.map +1 -1
  126. package/fesm2022/c8y-ngx-components-operations-operation-summary.mjs +7 -9
  127. package/fesm2022/c8y-ngx-components-operations-operation-summary.mjs.map +1 -1
  128. package/fesm2022/c8y-ngx-components-operations-operations-list-item-details.mjs +31 -31
  129. package/fesm2022/c8y-ngx-components-operations-operations-list-item-details.mjs.map +1 -1
  130. package/fesm2022/c8y-ngx-components-operations-operations-list.mjs +3 -3
  131. package/fesm2022/c8y-ngx-components-operations-operations-list.mjs.map +1 -1
  132. package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs +33 -13
  133. package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs.map +1 -1
  134. package/fesm2022/c8y-ngx-components-operations-status-filter.mjs +19 -13
  135. package/fesm2022/c8y-ngx-components-operations-status-filter.mjs.map +1 -1
  136. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-configuration.mjs +40 -36
  137. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-configuration.mjs.map +1 -1
  138. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs +60 -41
  139. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs.map +1 -1
  140. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-firmware.mjs +122 -109
  141. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-firmware.mjs.map +1 -1
  142. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs +66 -41
  143. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs.map +1 -1
  144. package/fesm2022/c8y-ngx-components-operations-stepper-frames.mjs +11 -16
  145. package/fesm2022/c8y-ngx-components-operations-stepper-frames.mjs.map +1 -1
  146. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +212 -83
  147. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
  148. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +113 -54
  149. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  150. package/fesm2022/c8y-ngx-components-repository-firmware.mjs +130 -62
  151. package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
  152. package/fesm2022/c8y-ngx-components-repository-shared.mjs +37 -28
  153. package/fesm2022/c8y-ngx-components-repository-shared.mjs.map +1 -1
  154. package/fesm2022/c8y-ngx-components-repository-software.mjs +156 -83
  155. package/fesm2022/c8y-ngx-components-repository-software.mjs.map +1 -1
  156. package/fesm2022/c8y-ngx-components-services.mjs +32 -19
  157. package/fesm2022/c8y-ngx-components-services.mjs.map +1 -1
  158. package/fesm2022/c8y-ngx-components-time-context.mjs +12 -5
  159. package/fesm2022/c8y-ngx-components-time-context.mjs.map +1 -1
  160. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs +68 -31
  161. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs.map +1 -1
  162. package/fesm2022/c8y-ngx-components-upgrade-upgraded-services.mjs +16 -3
  163. package/fesm2022/c8y-ngx-components-upgrade-upgraded-services.mjs.map +1 -1
  164. package/fesm2022/c8y-ngx-components-upgrade.mjs +1 -14
  165. package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
  166. package/fesm2022/c8y-ngx-components-user-roles.mjs +8 -3
  167. package/fesm2022/c8y-ngx-components-user-roles.mjs.map +1 -1
  168. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +4 -4
  169. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  170. package/fesm2022/c8y-ngx-components.mjs +1219 -1190
  171. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  172. package/locales/de.po +53 -35
  173. package/locales/es.po +26 -5
  174. package/locales/fr.po +51 -30
  175. package/locales/ja_JP.po +90 -67
  176. package/locales/ko.po +26 -5
  177. package/locales/locales.pot +22 -13
  178. package/locales/nl.po +26 -5
  179. package/locales/pl.po +26 -5
  180. package/locales/pt_BR.po +26 -5
  181. package/locales/zh_CN.po +27 -6
  182. package/locales/zh_TW.po +26 -5
  183. package/operations/bulk-operation-from-single/bulk-operation-from-single.component.d.ts +1 -1
  184. package/operations/bulk-operation-from-single/bulk-operation-from-single.component.d.ts.map +1 -1
  185. package/operations/bulk-operation-from-single/bulk-operation-from-single.module.d.ts +3 -5
  186. package/operations/bulk-operation-from-single/bulk-operation-from-single.module.d.ts.map +1 -1
  187. package/operations/bulk-operation-list-item/bulk-operation-list-item.component.d.ts +1 -1
  188. package/operations/bulk-operation-list-item/bulk-operation-list-item.component.d.ts.map +1 -1
  189. package/operations/bulk-operation-list-item/bulk-operation-list-item.module.d.ts +1 -7
  190. package/operations/bulk-operation-list-item/bulk-operation-list-item.module.d.ts.map +1 -1
  191. package/operations/bulk-operation-list-item/bulk-operation-wrapper.component.d.ts +1 -1
  192. package/operations/bulk-operation-list-item/bulk-operation-wrapper.component.d.ts.map +1 -1
  193. package/operations/bulk-operation-list-item/modal-body-host.directive.d.ts +1 -1
  194. package/operations/bulk-operation-list-item/modal-body-host.directive.d.ts.map +1 -1
  195. package/operations/bulk-operation-list-item/modals/bulk-operations-reschedule-modal.component.d.ts +1 -1
  196. package/operations/bulk-operation-list-item/modals/bulk-operations-reschedule-modal.component.d.ts.map +1 -1
  197. package/operations/bulk-operation-scheduler/bulk-operation-scheduler.module.d.ts +6 -6
  198. package/operations/bulk-operation-scheduler/operation-scheduler.component.d.ts +1 -1
  199. package/operations/bulk-operation-scheduler/operation-scheduler.component.d.ts.map +1 -1
  200. package/operations/bulk-operation-stepper/base-stepper.component.d.ts +1 -1
  201. package/operations/bulk-operation-stepper/bulk-operation-stepper.component.d.ts +1 -1
  202. package/operations/bulk-operation-stepper/bulk-operation-stepper.component.d.ts.map +1 -1
  203. package/operations/bulk-operation-stepper/bulk-operation-stepper.module.d.ts +1 -5
  204. package/operations/bulk-operation-stepper/bulk-operation-stepper.module.d.ts.map +1 -1
  205. package/operations/bulk-operation-stepper/custom-step.directive.d.ts +1 -1
  206. package/operations/bulk-operation-stepper/custom-step.directive.d.ts.map +1 -1
  207. package/operations/bulk-operations-list/bulk-operations-list.component.d.ts +1 -1
  208. package/operations/bulk-operations-list/bulk-operations-list.component.d.ts.map +1 -1
  209. package/operations/bulk-operations-list/bulk-operations-list.module.d.ts +4 -10
  210. package/operations/bulk-operations-list/bulk-operations-list.module.d.ts.map +1 -1
  211. package/operations/bulk-operations-list/modals/bulk-operations-modal.component.d.ts +1 -1
  212. package/operations/bulk-operations-list/modals/bulk-operations-modal.component.d.ts.map +1 -1
  213. package/operations/bulk-operations-stepper-container/bulk-operations-stepper-container.component.d.ts +1 -1
  214. package/operations/bulk-operations-stepper-container/bulk-operations-stepper-container.component.d.ts.map +1 -1
  215. package/operations/bulk-operations-stepper-container/bulk-operations-stepper-container.module.d.ts +3 -4
  216. package/operations/bulk-operations-stepper-container/bulk-operations-stepper-container.module.d.ts.map +1 -1
  217. package/operations/create-bulk-operation-details/create-bulk-operation-details.component.d.ts +1 -1
  218. package/operations/create-bulk-operation-details/create-bulk-operation-details.component.d.ts.map +1 -1
  219. package/operations/create-bulk-operation-details/create-bulk-operation-details.module.d.ts +1 -4
  220. package/operations/create-bulk-operation-details/create-bulk-operation-details.module.d.ts.map +1 -1
  221. package/operations/device-selector/device-selector.component.d.ts +1 -1
  222. package/operations/device-selector/device-selector.component.d.ts.map +1 -1
  223. package/operations/device-selector/device-selector.module.d.ts +1 -3
  224. package/operations/device-selector/device-selector.module.d.ts.map +1 -1
  225. package/operations/operation-details/operation-details-modal.component.d.ts +1 -1
  226. package/operations/operation-details/operation-details-modal.component.d.ts.map +1 -1
  227. package/operations/operation-details/operation-details.component.d.ts +1 -1
  228. package/operations/operation-details/operation-details.component.d.ts.map +1 -1
  229. package/operations/operation-details/operation-details.module.d.ts +1 -7
  230. package/operations/operation-details/operation-details.module.d.ts.map +1 -1
  231. package/operations/operation-details/operation-details.service.d.ts.map +1 -1
  232. package/operations/operation-summary/operation-summary.component.d.ts +1 -1
  233. package/operations/operation-summary/operation-summary.component.d.ts.map +1 -1
  234. package/operations/operation-summary/operation-summary.module.d.ts +1 -2
  235. package/operations/operation-summary/operation-summary.module.d.ts.map +1 -1
  236. package/operations/operations-list/operations-list-item.component.d.ts.map +1 -1
  237. package/operations/operations-list/operations-list.component.d.ts.map +1 -1
  238. package/operations/operations-list/operations-list.service.d.ts +1 -1
  239. package/operations/operations-list/operations-list.service.d.ts.map +1 -1
  240. package/operations/operations-list-item-details/operation-details-tabs.component.d.ts +1 -1
  241. package/operations/operations-list-item-details/operation-details-tabs.component.d.ts.map +1 -1
  242. package/operations/operations-list-item-details/operation-details.component.d.ts +1 -1
  243. package/operations/operations-list-item-details/operation-details.component.d.ts.map +1 -1
  244. package/operations/operations-list-item-details/operations-list-item-details.module.d.ts +1 -6
  245. package/operations/operations-list-item-details/operations-list-item-details.module.d.ts.map +1 -1
  246. package/operations/operations-timeline/operations-timeline.component.d.ts +5 -5
  247. package/operations/operations-timeline/operations-timeline.component.d.ts.map +1 -1
  248. package/operations/operations-timeline/operations-timeline.module.d.ts +4 -6
  249. package/operations/operations-timeline/operations-timeline.module.d.ts.map +1 -1
  250. package/operations/status-filter/status-filter.component.d.ts +1 -1
  251. package/operations/status-filter/status-filter.component.d.ts.map +1 -1
  252. package/operations/status-filter/status-filter.module.d.ts +1 -4
  253. package/operations/status-filter/status-filter.module.d.ts.map +1 -1
  254. package/operations/stepper-bulk-type-configuration/stepper-bulk-type-configuration.component.d.ts +1 -1
  255. package/operations/stepper-bulk-type-configuration/stepper-bulk-type-configuration.component.d.ts.map +1 -1
  256. package/operations/stepper-bulk-type-configuration/stepper-bulk-type-configuration.module.d.ts +1 -6
  257. package/operations/stepper-bulk-type-configuration/stepper-bulk-type-configuration.module.d.ts.map +1 -1
  258. package/operations/stepper-bulk-type-device-profile/confirm-device-profile-selection-step.component.d.ts +1 -1
  259. package/operations/stepper-bulk-type-device-profile/confirm-device-profile-selection-step.component.d.ts.map +1 -1
  260. package/operations/stepper-bulk-type-device-profile/select-device-profile-step.component.d.ts +1 -1
  261. package/operations/stepper-bulk-type-device-profile/select-device-profile-step.component.d.ts.map +1 -1
  262. package/operations/stepper-bulk-type-device-profile/stepper-bulk-type-device-profile.component.d.ts +1 -1
  263. package/operations/stepper-bulk-type-device-profile/stepper-bulk-type-device-profile.component.d.ts.map +1 -1
  264. package/operations/stepper-bulk-type-device-profile/stepper-bulk-type-device-profile.module.d.ts +1 -6
  265. package/operations/stepper-bulk-type-device-profile/stepper-bulk-type-device-profile.module.d.ts.map +1 -1
  266. package/operations/stepper-bulk-type-firmware/select-firmware.component.d.ts +1 -1
  267. package/operations/stepper-bulk-type-firmware/select-firmware.component.d.ts.map +1 -1
  268. package/operations/stepper-bulk-type-firmware/stepper-bulk-type-firmware.component.d.ts +1 -1
  269. package/operations/stepper-bulk-type-firmware/stepper-bulk-type-firmware.component.d.ts.map +1 -1
  270. package/operations/stepper-bulk-type-firmware/stepper-bulk-type-firmware.module.d.ts +1 -6
  271. package/operations/stepper-bulk-type-firmware/stepper-bulk-type-firmware.module.d.ts.map +1 -1
  272. package/operations/stepper-bulk-type-firmware/version-or-patch.component.d.ts +1 -1
  273. package/operations/stepper-bulk-type-firmware/version-or-patch.component.d.ts.map +1 -1
  274. package/operations/stepper-bulk-type-software/confirm-software-selection-step.component.d.ts +1 -1
  275. package/operations/stepper-bulk-type-software/confirm-software-selection-step.component.d.ts.map +1 -1
  276. package/operations/stepper-bulk-type-software/select-software-step.component.d.ts +1 -1
  277. package/operations/stepper-bulk-type-software/select-software-step.component.d.ts.map +1 -1
  278. package/operations/stepper-bulk-type-software/stepper-bulk-type-software.component.d.ts +1 -1
  279. package/operations/stepper-bulk-type-software/stepper-bulk-type-software.component.d.ts.map +1 -1
  280. package/operations/stepper-bulk-type-software/stepper-bulk-type-software.module.d.ts +1 -6
  281. package/operations/stepper-bulk-type-software/stepper-bulk-type-software.module.d.ts.map +1 -1
  282. package/operations/stepper-frames/preview-block.directive.d.ts +1 -1
  283. package/operations/stepper-frames/preview-block.directive.d.ts.map +1 -1
  284. package/operations/stepper-frames/preview-selection-frame.component.d.ts +1 -1
  285. package/operations/stepper-frames/preview-selection-frame.component.d.ts.map +1 -1
  286. package/operations/stepper-frames/select-step-frame.component.d.ts +1 -1
  287. package/operations/stepper-frames/select-step-frame.component.d.ts.map +1 -1
  288. package/operations/stepper-frames/stepper-frames.modules.d.ts +1 -2
  289. package/operations/stepper-frames/stepper-frames.modules.d.ts.map +1 -1
  290. package/package.json +1 -1
  291. package/protocol-opcua/opcua-address-space-detail.component.d.ts +1 -1
  292. package/protocol-opcua/opcua-address-space-detail.component.d.ts.map +1 -1
  293. package/protocol-opcua/opcua-address-space-tree.component.d.ts +1 -1
  294. package/protocol-opcua/opcua-address-space-tree.component.d.ts.map +1 -1
  295. package/protocol-opcua/opcua-address-space.component.d.ts +1 -1
  296. package/protocol-opcua/opcua-address-space.component.d.ts.map +1 -1
  297. package/protocol-opcua/opcua-auto-apply-settings.component.d.ts +1 -1
  298. package/protocol-opcua/opcua-auto-apply-settings.component.d.ts.map +1 -1
  299. package/protocol-opcua/opcua-device-protocol-browse-path-validation.directive.d.ts +1 -1
  300. package/protocol-opcua/opcua-device-protocol-browse-path-validation.directive.d.ts.map +1 -1
  301. package/protocol-opcua/opcua-device-protocol-data-reporting.component.d.ts +1 -1
  302. package/protocol-opcua/opcua-device-protocol-data-reporting.component.d.ts.map +1 -1
  303. package/protocol-opcua/opcua-device-protocol-description.component.d.ts +1 -1
  304. package/protocol-opcua/opcua-device-protocol-description.component.d.ts.map +1 -1
  305. package/protocol-opcua/opcua-device-protocol-detail.component.d.ts +1 -1
  306. package/protocol-opcua/opcua-device-protocol-detail.component.d.ts.map +1 -1
  307. package/protocol-opcua/opcua-device-protocol-mapping.component.d.ts +1 -1
  308. package/protocol-opcua/opcua-device-protocol-mapping.component.d.ts.map +1 -1
  309. package/protocol-opcua/opcua-device-protocol-object-mapping-status-icon.component.d.ts +1 -1
  310. package/protocol-opcua/opcua-device-protocol-object-mapping-status-icon.component.d.ts.map +1 -1
  311. package/protocol-opcua/opcua-protocol.module.d.ts +26 -26
  312. package/protocol-opcua/opcua-protocol.module.d.ts.map +1 -1
  313. package/protocol-opcua/opcua-server-config.component.d.ts +1 -1
  314. package/protocol-opcua/opcua-server-config.component.d.ts.map +1 -1
  315. package/protocol-opcua/opcua-server-list.component.d.ts +1 -1
  316. package/protocol-opcua/opcua-server-list.component.d.ts.map +1 -1
  317. package/protocol-opcua/opcua-servers.component.d.ts +1 -1
  318. package/protocol-opcua/opcua-servers.component.d.ts.map +1 -1
  319. package/repository/configuration/device-tab/configuration-filter.pipe.d.ts +1 -1
  320. package/repository/configuration/device-tab/configuration-filter.pipe.d.ts.map +1 -1
  321. package/repository/configuration/device-tab/configuration-preview.component.d.ts +1 -1
  322. package/repository/configuration/device-tab/configuration-preview.component.d.ts.map +1 -1
  323. package/repository/configuration/device-tab/configuration-repository-device-tab.module.d.ts +11 -13
  324. package/repository/configuration/device-tab/configuration-repository-device-tab.module.d.ts.map +1 -1
  325. package/repository/configuration/device-tab/device-configuration-list.component.d.ts +1 -1
  326. package/repository/configuration/device-tab/device-configuration-list.component.d.ts.map +1 -1
  327. package/repository/configuration/device-tab/device-configuration.component.d.ts +1 -1
  328. package/repository/configuration/device-tab/device-configuration.component.d.ts.map +1 -1
  329. package/repository/configuration/device-tab/save-to-repository.component.d.ts +1 -1
  330. package/repository/configuration/device-tab/save-to-repository.component.d.ts.map +1 -1
  331. package/repository/configuration/device-tab/source-code-preview.component.d.ts +1 -1
  332. package/repository/configuration/device-tab/source-code-preview.component.d.ts.map +1 -1
  333. package/repository/configuration/device-tab/text-based-configuration.component.d.ts +1 -1
  334. package/repository/configuration/device-tab/text-based-configuration.component.d.ts.map +1 -1
  335. package/repository/configuration/list/configuration-detail.component.d.ts +1 -1
  336. package/repository/configuration/list/configuration-detail.component.d.ts.map +1 -1
  337. package/repository/configuration/list/configuration-list.component.d.ts +1 -1
  338. package/repository/configuration/list/configuration-list.component.d.ts.map +1 -1
  339. package/repository/configuration/list/configuration-repository-list.module.d.ts +4 -7
  340. package/repository/configuration/list/configuration-repository-list.module.d.ts.map +1 -1
  341. package/repository/firmware/device-tab/firmware-device-tab.component.d.ts +1 -1
  342. package/repository/firmware/device-tab/firmware-device-tab.component.d.ts.map +1 -1
  343. package/repository/firmware/device-tab/firmware-repository-device-tab.module.d.ts +4 -6
  344. package/repository/firmware/device-tab/firmware-repository-device-tab.module.d.ts.map +1 -1
  345. package/repository/firmware/list/add-firmware-modal.component.d.ts +1 -1
  346. package/repository/firmware/list/add-firmware-modal.component.d.ts.map +1 -1
  347. package/repository/firmware/list/add-firmware-patch-modal.component.d.ts +1 -1
  348. package/repository/firmware/list/add-firmware-patch-modal.component.d.ts.map +1 -1
  349. package/repository/firmware/list/firmware-details.component.d.ts +1 -1
  350. package/repository/firmware/list/firmware-details.component.d.ts.map +1 -1
  351. package/repository/firmware/list/firmware-list.component.d.ts +1 -1
  352. package/repository/firmware/list/firmware-list.component.d.ts.map +1 -1
  353. package/repository/firmware/list/firmware-repository-list.module.d.ts +6 -11
  354. package/repository/firmware/list/firmware-repository-list.module.d.ts.map +1 -1
  355. package/repository/shared/file-download/file-download.component.d.ts +1 -1
  356. package/repository/shared/file-download/file-download.component.d.ts.map +1 -1
  357. package/repository/shared/select-modal/repository-select-modal.component.d.ts +1 -1
  358. package/repository/shared/select-modal/repository-select-modal.component.d.ts.map +1 -1
  359. package/repository/shared/shared-repository.module.d.ts +1 -4
  360. package/repository/shared/shared-repository.module.d.ts.map +1 -1
  361. package/repository/shared/software-type/software-type.component.d.ts +1 -1
  362. package/repository/shared/software-type/software-type.component.d.ts.map +1 -1
  363. package/repository/software/device-tab/device-software-changes.component.d.ts +1 -1
  364. package/repository/software/device-tab/device-software-changes.component.d.ts.map +1 -1
  365. package/repository/software/device-tab/device-software-list.component.d.ts +1 -1
  366. package/repository/software/device-tab/device-software-list.component.d.ts.map +1 -1
  367. package/repository/software/device-tab/installed-software.component.d.ts +1 -1
  368. package/repository/software/device-tab/installed-software.component.d.ts.map +1 -1
  369. package/repository/software/device-tab/software-device-tab.component.d.ts +1 -1
  370. package/repository/software/device-tab/software-device-tab.component.d.ts.map +1 -1
  371. package/repository/software/device-tab/software-repository-device-tab.module.d.ts +7 -11
  372. package/repository/software/device-tab/software-repository-device-tab.module.d.ts.map +1 -1
  373. package/repository/software/list/add-software-modal.component.d.ts +1 -1
  374. package/repository/software/list/add-software-modal.component.d.ts.map +1 -1
  375. package/repository/software/list/software-details.component.d.ts +1 -1
  376. package/repository/software/list/software-details.component.d.ts.map +1 -1
  377. package/repository/software/list/software-list.component.d.ts +1 -1
  378. package/repository/software/list/software-list.component.d.ts.map +1 -1
  379. package/repository/software/list/software-repository-list.module.d.ts +5 -11
  380. package/repository/software/list/software-repository-list.module.d.ts.map +1 -1
  381. package/services/services-device-tab/columns/last-updated-date.cell-renderer.component.d.ts +1 -1
  382. package/services/services-device-tab/columns/last-updated-date.cell-renderer.component.d.ts.map +1 -1
  383. package/services/services-device-tab/columns/name.cell-renderer.component.d.ts +1 -1
  384. package/services/services-device-tab/columns/name.cell-renderer.component.d.ts.map +1 -1
  385. package/services/services-device-tab/columns/status.cell-renderer.component.d.ts +1 -1
  386. package/services/services-device-tab/columns/status.cell-renderer.component.d.ts.map +1 -1
  387. package/services/services-device-tab/services-device-tab.component.d.ts +1 -1
  388. package/services/services-device-tab/services-device-tab.component.d.ts.map +1 -1
  389. package/services/services-device-tab/services-device-tab.module.d.ts +1 -4
  390. package/services/services-device-tab/services-device-tab.module.d.ts.map +1 -1
  391. package/time-context/index.d.ts +1 -0
  392. package/time-context/index.d.ts.map +1 -1
  393. package/time-context/time-context.component.d.ts +6 -3
  394. package/time-context/time-context.component.d.ts.map +1 -1
  395. package/time-context/time-context.model.d.ts +10 -0
  396. package/time-context/time-context.model.d.ts.map +1 -0
  397. package/time-context/time-context.service.d.ts +2 -6
  398. package/time-context/time-context.service.d.ts.map +1 -1
  399. package/trusted-certificates/crl/crl-settings.component.d.ts +5 -1
  400. package/trusted-certificates/crl/crl-settings.component.d.ts.map +1 -1
  401. package/trusted-certificates/factories/tabs.factory.d.ts +3 -2
  402. package/trusted-certificates/factories/tabs.factory.d.ts.map +1 -1
  403. package/trusted-certificates/factories/trusted-certificates-navigation.factory.d.ts +2 -0
  404. package/trusted-certificates/factories/trusted-certificates-navigation.factory.d.ts.map +1 -1
  405. package/trusted-certificates/list/trusted-certificate-list.component.d.ts +5 -1
  406. package/trusted-certificates/list/trusted-certificate-list.component.d.ts.map +1 -1
  407. package/trusted-certificates/trusted-certificates.guard.d.ts +11 -0
  408. package/trusted-certificates/trusted-certificates.guard.d.ts.map +1 -0
  409. package/upgrade/index.d.ts +0 -1
  410. package/upgrade/index.d.ts.map +1 -1
  411. package/upgrade/upgrade.module.d.ts.map +1 -1
  412. package/upgrade/upgraded-services/index.d.ts +1 -0
  413. package/upgrade/upgraded-services/index.d.ts.map +1 -1
  414. package/upgrade/upgraded-services/smart-rules.service.d.ts.map +1 -0
  415. package/upgrade/upgraded-services/upgraded-services.module.d.ts.map +1 -1
  416. package/user-roles/inventory-role-selector/inventory-role-selector.component.d.ts +2 -1
  417. package/user-roles/inventory-role-selector/inventory-role-selector.component.d.ts.map +1 -1
  418. package/user-roles/roles-asset-tree/roles-asset-tree.component.d.ts +2 -1
  419. package/user-roles/roles-asset-tree/roles-asset-tree.component.d.ts.map +1 -1
  420. package/device-parameters/c8y-ngx-components-device-parameters.d.ts.map +0 -1
  421. package/device-parameters/device-parameters-list.component.d.ts +0 -22
  422. package/device-parameters/device-parameters-list.component.d.ts.map +0 -1
  423. package/device-parameters/device-parameters-tab.guard.d.ts +0 -11
  424. package/device-parameters/device-parameters-tab.guard.d.ts.map +0 -1
  425. package/device-parameters/index.d.ts +0 -2
  426. package/device-parameters/index.d.ts.map +0 -1
  427. package/fesm2022/c8y-ngx-components-device-parameters.mjs +0 -118
  428. package/fesm2022/c8y-ngx-components-device-parameters.mjs.map +0 -1
  429. package/upgrade/smart-rules.service.d.ts.map +0 -1
  430. /package/upgrade/{smart-rules.service.d.ts → upgraded-services/smart-rules.service.d.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Input, Directive, Injectable, Injector, InjectionToken, NgModuleRef, createNgModule, Optional, Inject, isDevMode, inject, Pipe, EventEmitter, NgModule, LOCALE_ID, EnvironmentInjector, createEnvironmentInjector, HostListener, Component, HostBinding, Output, forwardRef, DestroyRef, ViewChild, SecurityContext, TemplateRef, provideAppInitializer, Self, SkipSelf, Attribute, ContentChild, ViewContainerRef, ElementRef, ContentChildren, ViewChildren, createComponent, runInInjectionContext, importProvidersFrom, ChangeDetectionStrategy, SimpleChange, reflectComponentType, signal, effect, Type, computed, input, output } from '@angular/core';
2
+ import { Input, Directive, Injectable, Injector, InjectionToken, NgModuleRef, createNgModule, Optional, Inject, isDevMode, inject, Pipe, EventEmitter, NgModule, LOCALE_ID, EnvironmentInjector, createEnvironmentInjector, HostListener, Component, HostBinding, Output, forwardRef, DestroyRef, ViewChild, SecurityContext, TemplateRef, provideAppInitializer, Self, SkipSelf, Attribute, ContentChild, ViewContainerRef, ElementRef, ContentChildren, ViewChildren, viewChild, effect, createComponent, runInInjectionContext, importProvidersFrom, ChangeDetectionStrategy, SimpleChange, reflectComponentType, signal, Type, computed, input, output } from '@angular/core';
3
3
  import * as i1$3 from 'ngx-bootstrap/dropdown';
4
4
  import { BsDropdownModule, BsDropdownDirective } from 'ngx-bootstrap/dropdown';
5
5
  import { CdkTrapFocus, A11yModule } from '@angular/cdk/a11y';
@@ -15122,102 +15122,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
15122
15122
  args: ['document:keydown.enter', ['$event']]
15123
15123
  }] } });
15124
15124
 
15125
- /**
15126
- * Service to show a modal.
15127
- */
15128
- class ModalService {
15129
- constructor(modalService, gainsightService) {
15130
- this.modalService = modalService;
15131
- this.gainsightService = gainsightService;
15132
- }
15133
- /**
15134
- * Shows a quick confirm message modal.
15135
- * @param title The title of that modal.
15136
- * @param body The text body to display.
15137
- * @param status The status.
15138
- * @param labels The labels to use. Default: { ok: 'Confirm', cancel: 'Cancel'}
15139
- * @param confirmOptions Selection options to display as checkbox list.
15140
- * @param productExperienceEvent Additional data to attach to custom product experience events.
15141
- */
15142
- async confirm(title, body, status = Status.INFO, labels = {}, confirmOptions = {}, productExperienceEvent = { eventName: 'confirmModal' }) {
15143
- const modalLabels = {
15144
- ok: labels.ok || gettext$1('Confirm'),
15145
- cancel: labels.cancel || gettext$1('Cancel')
15146
- };
15147
- const modalRef = this.modalService.show(ConfirmModalComponent, {
15148
- initialState: { title, body, labels: modalLabels, status, confirmOptions },
15149
- ariaDescribedby: 'modal-body',
15150
- ariaLabelledBy: 'modal-title',
15151
- ignoreBackdropClick: true
15152
- });
15153
- if (productExperienceEvent) {
15154
- productExperienceEvent.data = { ...productExperienceEvent.data, title };
15155
- }
15156
- this.triggerEvent(modalRef.content.result, modalLabels, productExperienceEvent);
15157
- return await modalRef.content.result;
15158
- }
15159
- /**
15160
- * Shows a quick acknowledge message modal.
15161
- * @param title The title of that modal.
15162
- * @param body The text body to display.
15163
- * @param status The status.
15164
- * @param acknowledgeLabel The label to use.
15165
- * @param productExperienceEvent Additional data to attach to custom product experience events.
15166
- */
15167
- async acknowledge(title, body, status = Status.INFO, acknowledgeLabel = gettext$1('Confirm'), productExperienceEvent = { eventName: 'confirmModal' }) {
15168
- const labels = { ok: acknowledgeLabel, cancel: null };
15169
- const modalRef = this.modalService.show(ConfirmModalComponent, {
15170
- initialState: { title, body, labels, status },
15171
- ariaDescribedby: 'modal-body',
15172
- ariaLabelledBy: 'modal-title',
15173
- ignoreBackdropClick: true
15174
- });
15175
- if (productExperienceEvent) {
15176
- productExperienceEvent.data = { ...productExperienceEvent.data, title };
15177
- }
15178
- this.triggerEvent(modalRef.content.result, labels, productExperienceEvent);
15179
- return await modalRef.content.result;
15180
- }
15181
- /**
15182
- * Shows a quick logout confirmation modal.
15183
- * @param body The text body to display. Default: 'You will be logged out to apply your changes. Do you want to proceed?'
15184
- * @param status The status.
15185
- * @param labels The labels to use. Default: { ok: 'Confirm and log out', cancel: 'Cancel' }
15186
- */
15187
- async confirmLogout(body, status = Status.WARNING, labels = {}) {
15188
- const modalLabels = {
15189
- ok: labels.ok || gettext$1('Confirm and log out'),
15190
- cancel: labels.cancel || gettext$1('Cancel')
15191
- };
15192
- const modalBody = body || gettext$1('You must log out to apply your changes. Do you want to proceed?');
15193
- return await this.confirm(gettext$1('Logout required'), modalBody, status, modalLabels);
15194
- }
15195
- triggerEvent(result, labels, productExperienceEvent) {
15196
- const data = { ...productExperienceEvent.data, url: window.location.href };
15197
- result
15198
- .then(() => {
15199
- this.gainsightService.triggerEvent(productExperienceEvent.eventName, {
15200
- ...data,
15201
- result: labels.ok
15202
- });
15203
- })
15204
- .catch(() => {
15205
- this.gainsightService.triggerEvent(productExperienceEvent.eventName, {
15206
- ...data,
15207
- result: labels.cancel
15208
- });
15209
- });
15210
- }
15211
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalService, deps: [{ token: i1$7.BsModalService }, { token: GainsightService }], target: i0.ɵɵFactoryTarget.Injectable }); }
15212
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalService, providedIn: 'root' }); }
15213
- }
15214
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalService, decorators: [{
15215
- type: Injectable,
15216
- args: [{
15217
- providedIn: 'root'
15218
- }]
15219
- }], ctorParameters: () => [{ type: i1$7.BsModalService }, { type: GainsightService }] });
15220
-
15221
15125
  /**
15222
15126
  * The angular module definition for modal.
15223
15127
  * @exports ConfirmModalComponent
@@ -15229,7 +15133,7 @@ class ModalModule {
15229
15133
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: ModalModule, imports: [i1$7.ModalModule, CommonModule, i1$9.PopoverModule, ConfirmModalComponent,
15230
15134
  ModalComponent,
15231
15135
  PopoverConfirmComponent], exports: [ConfirmModalComponent, ModalComponent, PopoverConfirmComponent] }); }
15232
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalModule, providers: [ModalService], imports: [ModalModule$1.forRoot(),
15136
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalModule, imports: [ModalModule$1.forRoot(),
15233
15137
  CommonModule,
15234
15138
  PopoverModule.forRoot(),
15235
15139
  PopoverConfirmComponent] }); }
@@ -15245,8 +15149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
15245
15149
  ModalComponent,
15246
15150
  PopoverConfirmComponent
15247
15151
  ],
15248
- exports: [ConfirmModalComponent, ModalComponent, PopoverConfirmComponent],
15249
- providers: [ModalService]
15152
+ exports: [ConfirmModalComponent, ModalComponent, PopoverConfirmComponent]
15250
15153
  }]
15251
15154
  }] });
15252
15155
 
@@ -19203,299 +19106,89 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
19203
19106
  }]
19204
19107
  }] });
19205
19108
 
19206
- class ThemeSwitcherService {
19207
- constructor(options) {
19208
- this.options = options;
19209
- this.darkThemeClass = `c8y-dark-theme`;
19210
- this.themeOptions = [
19211
- {
19212
- label: gettext$1('Light'),
19213
- value: 'light',
19214
- icon: 'sun'
19215
- },
19216
- {
19217
- label: gettext$1('Dark'),
19218
- value: 'dark',
19219
- icon: 'moon'
19220
- },
19221
- {
19222
- label: gettext$1('System'),
19223
- value: 'system',
19224
- icon: 'imac-settings'
19109
+ class PasswordConfirmModalComponent {
19110
+ constructor(user, ui, client, alert) {
19111
+ this.user = user;
19112
+ this.ui = ui;
19113
+ this.client = client;
19114
+ this.alert = alert;
19115
+ this.passwordConfirmedEmitter = new EventEmitter();
19116
+ this.loading = false;
19117
+ }
19118
+ async passwordConfirm() {
19119
+ if (this.password) {
19120
+ const supportUserName = this.ui.currentSupportUserName.value;
19121
+ const userId = this.ui.currentUser.value.id;
19122
+ const credentials = {
19123
+ password: this.password,
19124
+ user: `${supportUserName ? `${supportUserName}$` : ''}${userId}`,
19125
+ tenant: this.client.tenant
19126
+ };
19127
+ try {
19128
+ this.loading = true;
19129
+ const auth = new BasicAuth(credentials);
19130
+ const newClient = this.createNewClient(auth, this.client.baseUrl);
19131
+ await newClient.user.current();
19132
+ this.emitSuccessAndClose();
19225
19133
  }
19226
- ];
19227
- this._userSelectedThemePreference$ = new BehaviorSubject(this.getCurrentThemePreference());
19228
- this._temporaryThemePreference$ = new BehaviorSubject('none');
19229
- this.userSelectedThemePreference$ = this._userSelectedThemePreference$.asObservable();
19230
- const userSelectedTheme$ = this.userSelectedThemePreference$.pipe(switchMap(preference => {
19231
- if (preference === 'system') {
19232
- return this.getUsersSystemPreferenceForTheme$();
19134
+ catch (e) {
19135
+ if (e.res && e.res.status === 401 && e.data && /pin|totp/i.test(e.data.message)) {
19136
+ this.emitSuccessAndClose();
19137
+ }
19138
+ else {
19139
+ this.alert.danger(gettext$1("Provided password doesn't match your current one."));
19140
+ }
19233
19141
  }
19234
- return of(preference);
19235
- }));
19236
- this.disableThemeSelection$ = this._temporaryThemePreference$.pipe(map(preference => preference !== 'none'));
19237
- this.currentlyAppliedTheme$ = this._temporaryThemePreference$.pipe(switchMap(temporaryPreference => {
19238
- if (temporaryPreference !== 'none') {
19239
- return of(temporaryPreference);
19142
+ finally {
19143
+ this.loading = false;
19240
19144
  }
19241
- return userSelectedTheme$;
19242
- }));
19243
- this.darkThemeAvailable$ = this.options.get$('darkThemeAvailable').pipe(map(value => !!value));
19244
- }
19245
- getCurrentThemePreference() {
19246
- const value = getThemePreference();
19247
- if (value === 'system' || value === 'dark') {
19248
- return value;
19249
19145
  }
19250
- return 'light';
19251
- }
19252
- getUsersSystemPreferenceForTheme$() {
19253
- return fromEvent(window.matchMedia('(prefers-color-scheme: dark)'), 'change').pipe(startWith(window.matchMedia('(prefers-color-scheme: dark)')), map((e) => (e.matches ? 'dark' : 'light')));
19254
- }
19255
- changeUserPreference(preference) {
19256
- setThemePreference(preference);
19257
- this._userSelectedThemePreference$.next(preference);
19258
- this.applyTheme(preference);
19259
19146
  }
19260
- temporaryChangeTheme(preference) {
19261
- this._temporaryThemePreference$.next(preference);
19262
- this.applyTheme(preference);
19147
+ cancel() {
19148
+ this.passwordConfirmedEmitter.emit(false);
19149
+ this.modal._dismiss();
19263
19150
  }
19264
- resetTemporaryTheme() {
19265
- this._temporaryThemePreference$.next('none');
19266
- this.applyTheme(this.getCurrentThemePreference());
19151
+ createNewClient(auth, baseUrl) {
19152
+ return new Client(auth, baseUrl);
19267
19153
  }
19268
- applyTheme(preference) {
19269
- applyTheme(preference);
19154
+ emitSuccessAndClose() {
19155
+ this.passwordConfirmedEmitter.emit(true);
19156
+ this.modal._dismiss();
19270
19157
  }
19271
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeSwitcherService, deps: [{ token: OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
19272
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeSwitcherService, providedIn: 'root' }); }
19158
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordConfirmModalComponent, deps: [{ token: i1.UserService }, { token: AppStateService }, { token: i1.FetchClient }, { token: AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
19159
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PasswordConfirmModalComponent, isStandalone: true, selector: "c8y-password-confirm-modal", outputs: { passwordConfirmedEmitter: "passwordConfirmedEmitter" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], ngImport: i0, template: "<c8y-modal [customFooter]=\"true\" [title]=\"'Confirm your current password' | translate\" #modal>\r\n <form #confirmForm=\"ngForm\" (ngSubmit)=\"confirmForm.form.valid && passwordConfirm()\">\r\n <div class=\"d-block p-24 p-b-0\">\r\n <c8y-form-group [hasWarning]=\"true\">\r\n <label translate for=\"currentPassword\">Enter your password</label>\r\n <input\r\n id=\"currentPassword\"\r\n [(ngModel)]=\"password\"\r\n type=\"password\"\r\n name=\"password\"\r\n class=\"form-control\"\r\n placeholder=\"{{ 'Enter your password' | translate }}\"\r\n required\r\n />\r\n <c8y-messages>\r\n <c8y-message translate>\r\n Enter the password of the user that you are currently logged in with.\r\n </c8y-message>\r\n </c8y-messages>\r\n </c8y-form-group>\r\n </div>\r\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\r\n <button\r\n title=\"{{ 'Cancel' | translate }}\"\r\n class=\"btn btn-default\"\r\n type=\"button\"\r\n (click)=\"cancel()\"\r\n >\r\n {{ 'Cancel' | translate }}\r\n </button>\r\n <button\r\n title=\"{{ 'Confirm' | translate }}\"\r\n class=\"btn btn-primary\"\r\n type=\"submit\"\r\n [disabled]=\"!confirmForm.form.valid || loading\"\r\n >\r\n {{ 'Confirm' | translate }}\r\n </button>\r\n </div>\r\n </form>\r\n</c8y-modal>\r\n", dependencies: [{ kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$8.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$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$8.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
19273
19160
  }
19274
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeSwitcherService, decorators: [{
19275
- type: Injectable,
19276
- args: [{
19277
- providedIn: 'root'
19278
- }]
19279
- }], ctorParameters: () => [{ type: OptionsService }] });
19161
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordConfirmModalComponent, decorators: [{
19162
+ type: Component,
19163
+ args: [{ selector: 'c8y-password-confirm-modal', standalone: true, imports: [
19164
+ ModalComponent,
19165
+ FormsModule$1,
19166
+ FormGroupComponent,
19167
+ C8yTranslateDirective,
19168
+ RequiredInputPlaceholderDirective,
19169
+ MessagesComponent,
19170
+ MessageDirective,
19171
+ C8yTranslatePipe
19172
+ ], template: "<c8y-modal [customFooter]=\"true\" [title]=\"'Confirm your current password' | translate\" #modal>\r\n <form #confirmForm=\"ngForm\" (ngSubmit)=\"confirmForm.form.valid && passwordConfirm()\">\r\n <div class=\"d-block p-24 p-b-0\">\r\n <c8y-form-group [hasWarning]=\"true\">\r\n <label translate for=\"currentPassword\">Enter your password</label>\r\n <input\r\n id=\"currentPassword\"\r\n [(ngModel)]=\"password\"\r\n type=\"password\"\r\n name=\"password\"\r\n class=\"form-control\"\r\n placeholder=\"{{ 'Enter your password' | translate }}\"\r\n required\r\n />\r\n <c8y-messages>\r\n <c8y-message translate>\r\n Enter the password of the user that you are currently logged in with.\r\n </c8y-message>\r\n </c8y-messages>\r\n </c8y-form-group>\r\n </div>\r\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\r\n <button\r\n title=\"{{ 'Cancel' | translate }}\"\r\n class=\"btn btn-default\"\r\n type=\"button\"\r\n (click)=\"cancel()\"\r\n >\r\n {{ 'Cancel' | translate }}\r\n </button>\r\n <button\r\n title=\"{{ 'Confirm' | translate }}\"\r\n class=\"btn btn-primary\"\r\n type=\"submit\"\r\n [disabled]=\"!confirmForm.form.valid || loading\"\r\n >\r\n {{ 'Confirm' | translate }}\r\n </button>\r\n </div>\r\n </form>\r\n</c8y-modal>\r\n" }]
19173
+ }], ctorParameters: () => [{ type: i1.UserService }, { type: AppStateService }, { type: i1.FetchClient }, { type: AlertService }], propDecorators: { passwordConfirmedEmitter: [{
19174
+ type: Output
19175
+ }], modal: [{
19176
+ type: ViewChild,
19177
+ args: ['modal', { static: false }]
19178
+ }] } });
19280
19179
 
19281
- class UiSettingsComponent {
19282
- constructor(translate, state, ui, userPreferences, c8yModalService, headerService, themeSwitcher) {
19283
- this.translate = translate;
19284
- this.state = state;
19285
- this.ui = ui;
19286
- this.userPreferences = userPreferences;
19287
- this.c8yModalService = c8yModalService;
19288
- this.headerService = headerService;
19289
- this.themeSwitcher = themeSwitcher;
19290
- this.destroyed$ = new Subject();
19291
- this.currentLang = this.ui.state.lang;
19292
- this.ui.state$
19293
- .pipe(filter(({ lang }) => lang !== this.currentLang), takeUntil(this.destroyed$), first$1())
19294
- .subscribe(({ lang }) => (this.currentLang = lang));
19295
- this.open$ = this.headerService.rightDrawerOpen$;
19180
+ class CurrentPasswordModalComponent {
19181
+ constructor(modal) {
19182
+ this.modal = modal;
19183
+ this.currentPasswordEmitter = new EventEmitter();
19296
19184
  }
19297
- ngOnInit() {
19298
- this.languages = this.state.state.langs.map(l => ({
19299
- lang: l,
19300
- nativeLanguage: this.translate.getNativeLanguage(l)
19301
- }));
19185
+ passwordConfirm() {
19186
+ this.currentPasswordEmitter.emit(this.password);
19187
+ this.modal.hide();
19302
19188
  }
19303
- ngOnDestroy() {
19304
- this.destroyed$.next();
19305
- this.destroyed$.complete();
19306
- }
19307
- async onLanguageChange(changedLang) {
19308
- if (!changedLang) {
19309
- return;
19310
- }
19311
- await this.translate.switchToLanguage(changedLang);
19312
- if (await this.persistLanguage(changedLang)) {
19313
- location.reload();
19314
- }
19315
- }
19316
- async persistLanguage(lang) {
19317
- let shouldReload = true;
19318
- try {
19319
- await this.c8yModalService.confirm(gettext$1('Reload recommended'), gettext$1('To change the language in the entire application, we recommend you to reload the page. If you have any unsaved changes, you can reload later. How would you like to proceed?'), Status.WARNING, {
19320
- ok: gettext$1('Reload now'),
19321
- cancel: gettext$1('Reload later')
19322
- });
19323
- }
19324
- catch (ex) {
19325
- shouldReload = false;
19326
- }
19327
- finally {
19328
- this.translate.saveInLocalStorage(lang);
19329
- await this.userPreferences.set('language', lang);
19330
- this.currentLang = lang;
19331
- }
19332
- return shouldReload;
19333
- }
19334
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsComponent, deps: [{ token: TranslateService }, { token: AppStateService }, { token: AppStateService }, { token: UserPreferencesService }, { token: ModalService }, { token: HeaderService }, { token: ThemeSwitcherService }], target: i0.ɵɵFactoryTarget.Component }); }
19335
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UiSettingsComponent, isStandalone: true, selector: "c8y-ui-settings", ngImport: i0, template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"eyedropper\"></i>\n <span class=\"text-bold\">{{ 'UI settings' | translate }}</span>\n </div>\n\n <div\n class=\"p-l-16 p-r-16 p-b-16\"\n *ngIf=\"themeSwitcher.darkThemeAvailable$ | async\"\n >\n <p translate>Theme</p>\n <div\n class=\"c8y-switch-multistate\"\n *ngIf=\"themeSwitcher.userSelectedThemePreference$ | async as themePreference\"\n >\n <ng-container *ngFor=\"let themeOption of themeSwitcher.themeOptions; index as i\">\n <input\n [attr.aria-label]=\"themeOption.label\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n name=\"theme-switcher\"\n type=\"radio\"\n [id]=\"'theme-option-' + i\"\n [disabled]=\"themeSwitcher.disableThemeSelection$ | async\"\n [checked]=\"themePreference === themeOption.value\"\n (click)=\"themeSwitcher.changeUserPreference(themeOption.value)\"\n />\n <label\n title=\"{{ themeOption.label | translate }}\"\n [for]=\"'theme-option-' + i\"\n >\n <i [c8yIcon]=\"themeOption.icon\"></i>\n </label>\n </ng-container>\n <div class=\"c8y-switch-multistate__handle\"></div>\n </div>\n </div>\n\n <div class=\"form-group p-l-16 p-r-16\">\n <label\n for=\"userLang\"\n translate\n >\n Language\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n id=\"userLang\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n #selectLang\n [ngModel]=\"currentLang\"\n (change)=\"onLanguageChange(selectLang.value)\"\n >\n <option\n *ngFor=\"let language of languages\"\n [value]=\"language.lang\"\n >\n {{ language.nativeLanguage }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$8.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$8.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
19336
- }
19337
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsComponent, decorators: [{
19338
- type: Component,
19339
- args: [{ selector: 'c8y-ui-settings', standalone: true, imports: [
19340
- IconDirective,
19341
- NgIf,
19342
- C8yTranslateDirective,
19343
- NgFor,
19344
- FormsModule$1,
19345
- C8yTranslatePipe,
19346
- AsyncPipe
19347
- ], template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"eyedropper\"></i>\n <span class=\"text-bold\">{{ 'UI settings' | translate }}</span>\n </div>\n\n <div\n class=\"p-l-16 p-r-16 p-b-16\"\n *ngIf=\"themeSwitcher.darkThemeAvailable$ | async\"\n >\n <p translate>Theme</p>\n <div\n class=\"c8y-switch-multistate\"\n *ngIf=\"themeSwitcher.userSelectedThemePreference$ | async as themePreference\"\n >\n <ng-container *ngFor=\"let themeOption of themeSwitcher.themeOptions; index as i\">\n <input\n [attr.aria-label]=\"themeOption.label\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n name=\"theme-switcher\"\n type=\"radio\"\n [id]=\"'theme-option-' + i\"\n [disabled]=\"themeSwitcher.disableThemeSelection$ | async\"\n [checked]=\"themePreference === themeOption.value\"\n (click)=\"themeSwitcher.changeUserPreference(themeOption.value)\"\n />\n <label\n title=\"{{ themeOption.label | translate }}\"\n [for]=\"'theme-option-' + i\"\n >\n <i [c8yIcon]=\"themeOption.icon\"></i>\n </label>\n </ng-container>\n <div class=\"c8y-switch-multistate__handle\"></div>\n </div>\n </div>\n\n <div class=\"form-group p-l-16 p-r-16\">\n <label\n for=\"userLang\"\n translate\n >\n Language\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n id=\"userLang\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n #selectLang\n [ngModel]=\"currentLang\"\n (change)=\"onLanguageChange(selectLang.value)\"\n >\n <option\n *ngFor=\"let language of languages\"\n [value]=\"language.lang\"\n >\n {{ language.nativeLanguage }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n</div>\n" }]
19348
- }], ctorParameters: () => [{ type: TranslateService }, { type: AppStateService }, { type: AppStateService }, { type: UserPreferencesService }, { type: ModalService }, { type: HeaderService }, { type: ThemeSwitcherService }] });
19349
-
19350
- class UiSettingsModule {
19351
- static providers() {
19352
- return [
19353
- hookDrawer({
19354
- component: UiSettingsComponent,
19355
- position: 'right',
19356
- priority: 90,
19357
- id: 'uiSettings'
19358
- })
19359
- ];
19360
- }
19361
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
19362
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, imports: [CommonModule, FormsModule$1, UiSettingsComponent], exports: [UiSettingsComponent] }); }
19363
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, imports: [CommonModule, FormsModule$1, UiSettingsComponent] }); }
19364
- }
19365
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, decorators: [{
19366
- type: NgModule,
19367
- args: [{
19368
- imports: [CommonModule, FormsModule$1, UiSettingsComponent],
19369
- exports: [UiSettingsComponent]
19370
- }]
19371
- }] });
19372
-
19373
- class UserMenuItemComponent {
19374
- constructor(userService, headerService) {
19375
- this.userService = userService;
19376
- this.headerService = headerService;
19377
- this.priority = 0;
19378
- this.click = new EventEmitter();
19379
- this.open$ = this.headerService.rightDrawerOpen$;
19380
- }
19381
- ngAfterViewInit() {
19382
- this.viewInitTimeout = setTimeout(() => this.userService.add(this));
19383
- }
19384
- ngOnDestroy() {
19385
- clearTimeout(this.viewInitTimeout);
19386
- this.userService.remove(this);
19387
- }
19388
- onClick() {
19389
- this.click.emit(this);
19390
- }
19391
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuItemComponent, deps: [{ token: UserMenuService }, { token: HeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
19392
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserMenuItemComponent, isStandalone: true, selector: "c8y-user-menu-item", inputs: { icon: "icon", label: "label", link: "link", target: "target", priority: "priority", dataCy: "dataCy" }, outputs: { click: "click" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true }], ngImport: i0, template: "<ng-template #template>\n <li>\n <a\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n *ngIf=\"link\"\n [attr.href]=\"link\"\n [attr.target]=\"target\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </a>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n *ngIf=\"!link\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </button>\n </li>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
19393
- }
19394
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuItemComponent, decorators: [{
19395
- type: Component,
19396
- args: [{ selector: 'c8y-user-menu-item', standalone: true, imports: [NgIf, C8yTranslatePipe, AsyncPipe], template: "<ng-template #template>\n <li>\n <a\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n *ngIf=\"link\"\n [attr.href]=\"link\"\n [attr.target]=\"target\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </a>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n *ngIf=\"!link\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </button>\n </li>\n</ng-template>\n" }]
19397
- }], ctorParameters: () => [{ type: UserMenuService }, { type: HeaderService }], propDecorators: { icon: [{
19398
- type: Input
19399
- }], label: [{
19400
- type: Input
19401
- }], link: [{
19402
- type: Input
19403
- }], target: [{
19404
- type: Input
19405
- }], priority: [{
19406
- type: Input
19407
- }], dataCy: [{
19408
- type: Input
19409
- }], template: [{
19410
- type: ViewChild,
19411
- args: ['template', { static: false }]
19412
- }], click: [{
19413
- type: Output
19414
- }] } });
19415
-
19416
- class PasswordConfirmModalComponent {
19417
- constructor(user, ui, client, alert) {
19418
- this.user = user;
19419
- this.ui = ui;
19420
- this.client = client;
19421
- this.alert = alert;
19422
- this.passwordConfirmedEmitter = new EventEmitter();
19423
- this.loading = false;
19424
- }
19425
- async passwordConfirm() {
19426
- if (this.password) {
19427
- const supportUserName = this.ui.currentSupportUserName.value;
19428
- const userId = this.ui.currentUser.value.id;
19429
- const credentials = {
19430
- password: this.password,
19431
- user: `${supportUserName ? `${supportUserName}$` : ''}${userId}`,
19432
- tenant: this.client.tenant
19433
- };
19434
- try {
19435
- this.loading = true;
19436
- const auth = new BasicAuth(credentials);
19437
- const newClient = this.createNewClient(auth, this.client.baseUrl);
19438
- await newClient.user.current();
19439
- this.emitSuccessAndClose();
19440
- }
19441
- catch (e) {
19442
- if (e.res && e.res.status === 401 && e.data && /pin|totp/i.test(e.data.message)) {
19443
- this.emitSuccessAndClose();
19444
- }
19445
- else {
19446
- this.alert.danger(gettext$1("Provided password doesn't match your current one."));
19447
- }
19448
- }
19449
- finally {
19450
- this.loading = false;
19451
- }
19452
- }
19453
- }
19454
- cancel() {
19455
- this.passwordConfirmedEmitter.emit(false);
19456
- this.modal._dismiss();
19457
- }
19458
- createNewClient(auth, baseUrl) {
19459
- return new Client(auth, baseUrl);
19460
- }
19461
- emitSuccessAndClose() {
19462
- this.passwordConfirmedEmitter.emit(true);
19463
- this.modal._dismiss();
19464
- }
19465
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordConfirmModalComponent, deps: [{ token: i1.UserService }, { token: AppStateService }, { token: i1.FetchClient }, { token: AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
19466
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PasswordConfirmModalComponent, isStandalone: true, selector: "c8y-password-confirm-modal", outputs: { passwordConfirmedEmitter: "passwordConfirmedEmitter" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], ngImport: i0, template: "<c8y-modal [customFooter]=\"true\" [title]=\"'Confirm your current password' | translate\" #modal>\r\n <form #confirmForm=\"ngForm\" (ngSubmit)=\"confirmForm.form.valid && passwordConfirm()\">\r\n <div class=\"d-block p-24 p-b-0\">\r\n <c8y-form-group [hasWarning]=\"true\">\r\n <label translate for=\"currentPassword\">Enter your password</label>\r\n <input\r\n id=\"currentPassword\"\r\n [(ngModel)]=\"password\"\r\n type=\"password\"\r\n name=\"password\"\r\n class=\"form-control\"\r\n placeholder=\"{{ 'Enter your password' | translate }}\"\r\n required\r\n />\r\n <c8y-messages>\r\n <c8y-message translate>\r\n Enter the password of the user that you are currently logged in with.\r\n </c8y-message>\r\n </c8y-messages>\r\n </c8y-form-group>\r\n </div>\r\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\r\n <button\r\n title=\"{{ 'Cancel' | translate }}\"\r\n class=\"btn btn-default\"\r\n type=\"button\"\r\n (click)=\"cancel()\"\r\n >\r\n {{ 'Cancel' | translate }}\r\n </button>\r\n <button\r\n title=\"{{ 'Confirm' | translate }}\"\r\n class=\"btn btn-primary\"\r\n type=\"submit\"\r\n [disabled]=\"!confirmForm.form.valid || loading\"\r\n >\r\n {{ 'Confirm' | translate }}\r\n </button>\r\n </div>\r\n </form>\r\n</c8y-modal>\r\n", dependencies: [{ kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$8.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$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$8.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
19467
- }
19468
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordConfirmModalComponent, decorators: [{
19469
- type: Component,
19470
- args: [{ selector: 'c8y-password-confirm-modal', standalone: true, imports: [
19471
- ModalComponent,
19472
- FormsModule$1,
19473
- FormGroupComponent,
19474
- C8yTranslateDirective,
19475
- RequiredInputPlaceholderDirective,
19476
- MessagesComponent,
19477
- MessageDirective,
19478
- C8yTranslatePipe
19479
- ], template: "<c8y-modal [customFooter]=\"true\" [title]=\"'Confirm your current password' | translate\" #modal>\r\n <form #confirmForm=\"ngForm\" (ngSubmit)=\"confirmForm.form.valid && passwordConfirm()\">\r\n <div class=\"d-block p-24 p-b-0\">\r\n <c8y-form-group [hasWarning]=\"true\">\r\n <label translate for=\"currentPassword\">Enter your password</label>\r\n <input\r\n id=\"currentPassword\"\r\n [(ngModel)]=\"password\"\r\n type=\"password\"\r\n name=\"password\"\r\n class=\"form-control\"\r\n placeholder=\"{{ 'Enter your password' | translate }}\"\r\n required\r\n />\r\n <c8y-messages>\r\n <c8y-message translate>\r\n Enter the password of the user that you are currently logged in with.\r\n </c8y-message>\r\n </c8y-messages>\r\n </c8y-form-group>\r\n </div>\r\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\r\n <button\r\n title=\"{{ 'Cancel' | translate }}\"\r\n class=\"btn btn-default\"\r\n type=\"button\"\r\n (click)=\"cancel()\"\r\n >\r\n {{ 'Cancel' | translate }}\r\n </button>\r\n <button\r\n title=\"{{ 'Confirm' | translate }}\"\r\n class=\"btn btn-primary\"\r\n type=\"submit\"\r\n [disabled]=\"!confirmForm.form.valid || loading\"\r\n >\r\n {{ 'Confirm' | translate }}\r\n </button>\r\n </div>\r\n </form>\r\n</c8y-modal>\r\n" }]
19480
- }], ctorParameters: () => [{ type: i1.UserService }, { type: AppStateService }, { type: i1.FetchClient }, { type: AlertService }], propDecorators: { passwordConfirmedEmitter: [{
19481
- type: Output
19482
- }], modal: [{
19483
- type: ViewChild,
19484
- args: ['modal', { static: false }]
19485
- }] } });
19486
-
19487
- class CurrentPasswordModalComponent {
19488
- constructor(modal) {
19489
- this.modal = modal;
19490
- this.currentPasswordEmitter = new EventEmitter();
19491
- }
19492
- passwordConfirm() {
19493
- this.currentPasswordEmitter.emit(this.password);
19494
- this.modal.hide();
19495
- }
19496
- cancel() {
19497
- this.currentPasswordEmitter.emit(null);
19498
- this.modal.hide();
19189
+ cancel() {
19190
+ this.currentPasswordEmitter.emit(null);
19191
+ this.modal.hide();
19499
19192
  }
19500
19193
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CurrentPasswordModalComponent, deps: [{ token: i1$7.BsModalRef }], target: i0.ɵɵFactoryTarget.Component }); }
19501
19194
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: CurrentPasswordModalComponent, isStandalone: true, selector: "c8y-current-password-modal", outputs: { currentPasswordEmitter: "currentPasswordEmitter" }, ngImport: i0, template: "<c8y-modal [customFooter]=\"true\" [title]=\"'Confirm your current password' | translate\" #modal>\n <form #confirmForm=\"ngForm\" (ngSubmit)=\"confirmForm.form.valid && passwordConfirm()\">\n <div class=\"d-block p-24\">\n <c8y-form-group [hasWarning]=\"true\">\n <label translate for=\"currentPassword\">Enter your password</label>\n <input\n id=\"currentPassword\"\n [(ngModel)]=\"password\"\n type=\"password\"\n name=\"password\"\n class=\"form-control\"\n required\n />\n <c8y-messages>\n <c8y-message translate>\n The password of the user that you are currently logged in with.\n </c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\n <button\n title=\"{{ 'Cancel' | translate }}\"\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n title=\"{{ 'Confirm' | translate }}\"\n class=\"btn btn-primary\"\n [attr.data-cy]=\"'confirm-current-password-confirm-button'\"\n type=\"submit\"\n [disabled]=\"!confirmForm.form.valid\"\n >\n {{ 'Confirm' | translate }}\n </button>\n </div>\n </form>\n</c8y-modal>\n", dependencies: [{ kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$8.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$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$8.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
@@ -19594,10 +19287,11 @@ class PasswordService {
19594
19287
  return this.DEFAULT_PASSWORD_MIN_LENGTH;
19595
19288
  }
19596
19289
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordService, deps: [{ token: i1$7.BsModalService }], target: i0.ɵɵFactoryTarget.Injectable }); }
19597
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordService }); }
19290
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordService, providedIn: 'root' }); }
19598
19291
  }
19599
19292
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordService, decorators: [{
19600
- type: Injectable
19293
+ type: Injectable,
19294
+ args: [{ providedIn: 'root' }]
19601
19295
  }], ctorParameters: () => [{ type: i1$7.BsModalService }] });
19602
19296
 
19603
19297
  class TotpSetupComponent {
@@ -20049,9 +19743,10 @@ class NewPasswordComponent {
20049
19743
  ngModel.control.addValidators(this.passwordChecklistValidator);
20050
19744
  }
20051
19745
  }
20052
- constructor(passwordStrength, cdRef) {
19746
+ constructor(passwordStrength, cdRef, elementRef) {
20053
19747
  this.passwordStrength = passwordStrength;
20054
19748
  this.cdRef = cdRef;
19749
+ this.elementRef = elementRef;
20055
19750
  this.password = new EventEmitter();
20056
19751
  this.showChangePasswordButton = true;
20057
19752
  this.model = {};
@@ -20107,7 +19802,7 @@ class NewPasswordComponent {
20107
19802
  this.model = {};
20108
19803
  }
20109
19804
  }
20110
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NewPasswordComponent, deps: [{ token: PasswordStrengthService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
19805
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NewPasswordComponent, deps: [{ token: PasswordStrengthService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
20111
19806
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: NewPasswordComponent, isStandalone: true, selector: "c8y-new-password", inputs: { showChangePasswordButton: "showChangePasswordButton", requireStrongPassword: "requireStrongPassword" }, outputs: { password: "password" }, viewQueries: [{ propertyName: "_newPasswordModel", first: true, predicate: ["newPassword"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"showChangePasswordButton\" class=\"form-group\">\n <button\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"toggleChangePassword()\"\n data-cy=\"c8y-new-password--change-button\"\n >\n <ng-container *ngIf=\"!changePassword\">\n {{ 'Change password' | translate }}\n </ng-container>\n <ng-container *ngIf=\"changePassword\">\n {{ 'Cancel password change' | translate }}\n </ng-container>\n </button>\n</div>\n\n<div\n class=\"row content-flex-50\"\n *ngIf=\"changePassword\"\n>\n <div class=\"col-6\">\n <c8y-form-group>\n <label\n for=\"newPassword\"\n translate\n >\n Password\n </label>\n <c8y-password-input\n name=\"newPassword\"\n required\n [id]=\"'newPassword'\"\n #newPassword=\"ngModel\"\n [(ngModel)]=\"model.newPassword\"\n (change)=\"newPasswordChanged()\"\n (input)=\"newPasswordConfirm.control.updateValueAndValidity()\"\n c8yDefaultValidation=\"password\"\n [autocomplete]=\"'new-password'\"\n ></c8y-password-input>\n </c8y-form-group>\n\n <c8y-form-group>\n <label\n for=\"newConfirmPassword\"\n translate\n >\n Confirm password\n </label>\n <c8y-password-input\n name=\"newPasswordConfirm\"\n required\n [id]=\"'newConfirmPassword'\"\n #newPasswordConfirm=\"ngModel\"\n [(ngModel)]=\"model.newPasswordConfirm\"\n passwordConfirm=\"newPassword\"\n [autocomplete]=\"'new-password'\"\n ></c8y-password-input>\n </c8y-form-group>\n </div>\n <div class=\"col-6\">\n <c8y-password-check-list\n [password]=\"model.newPassword\"\n [strengthEnforced]=\"passwordEnforced\"\n (onRequirementsFulfilled)=\"updateValidity($event)\"\n ></c8y-password-check-list>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: PasswordInputComponent, selector: "c8y-password-input", inputs: ["id", "autocomplete"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: DefaultValidationDirective, selector: "[c8yDefaultValidation]", inputs: ["c8yDefaultValidation"] }, { kind: "directive", type: PasswordConfirm, selector: "[passwordConfirm]" }, { kind: "component", type: PasswordCheckListComponent, selector: "c8y-password-check-list", inputs: ["strengthEnforced", "password"], outputs: ["onRequirementsFulfilled"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
20112
19807
  }
20113
19808
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NewPasswordComponent, decorators: [{
@@ -20123,7 +19818,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
20123
19818
  PasswordCheckListComponent,
20124
19819
  C8yTranslatePipe
20125
19820
  ], template: "<div *ngIf=\"showChangePasswordButton\" class=\"form-group\">\n <button\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"toggleChangePassword()\"\n data-cy=\"c8y-new-password--change-button\"\n >\n <ng-container *ngIf=\"!changePassword\">\n {{ 'Change password' | translate }}\n </ng-container>\n <ng-container *ngIf=\"changePassword\">\n {{ 'Cancel password change' | translate }}\n </ng-container>\n </button>\n</div>\n\n<div\n class=\"row content-flex-50\"\n *ngIf=\"changePassword\"\n>\n <div class=\"col-6\">\n <c8y-form-group>\n <label\n for=\"newPassword\"\n translate\n >\n Password\n </label>\n <c8y-password-input\n name=\"newPassword\"\n required\n [id]=\"'newPassword'\"\n #newPassword=\"ngModel\"\n [(ngModel)]=\"model.newPassword\"\n (change)=\"newPasswordChanged()\"\n (input)=\"newPasswordConfirm.control.updateValueAndValidity()\"\n c8yDefaultValidation=\"password\"\n [autocomplete]=\"'new-password'\"\n ></c8y-password-input>\n </c8y-form-group>\n\n <c8y-form-group>\n <label\n for=\"newConfirmPassword\"\n translate\n >\n Confirm password\n </label>\n <c8y-password-input\n name=\"newPasswordConfirm\"\n required\n [id]=\"'newConfirmPassword'\"\n #newPasswordConfirm=\"ngModel\"\n [(ngModel)]=\"model.newPasswordConfirm\"\n passwordConfirm=\"newPassword\"\n [autocomplete]=\"'new-password'\"\n ></c8y-password-input>\n </c8y-form-group>\n </div>\n <div class=\"col-6\">\n <c8y-password-check-list\n [password]=\"model.newPassword\"\n [strengthEnforced]=\"passwordEnforced\"\n (onRequirementsFulfilled)=\"updateValidity($event)\"\n ></c8y-password-check-list>\n </div>\n</div>\n" }]
20126
- }], ctorParameters: () => [{ type: PasswordStrengthService }, { type: i0.ChangeDetectorRef }], propDecorators: { password: [{
19821
+ }], ctorParameters: () => [{ type: PasswordStrengthService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], propDecorators: { password: [{
20127
19822
  type: Output
20128
19823
  }], showChangePasswordButton: [{
20129
19824
  type: Input
@@ -20157,13 +19852,26 @@ class UserEditComponent {
20157
19852
  this.showProductExperienceOptions = false;
20158
19853
  this.isUsageTrackingEnabled = true;
20159
19854
  this.isUserEngagementPreferenceEnabled = true;
19855
+ this.focusOnNewPassword = false;
20160
19856
  this.onUser = new EventEmitter();
20161
19857
  this.onUsageTrackingChange = new EventEmitter();
20162
19858
  this.onUserEngagementPreferenceChange = new EventEmitter();
20163
19859
  this.onCancel = new EventEmitter();
19860
+ this.newPasswordComponent = viewChild(NewPasswordComponent);
20164
19861
  this.userHasActiveTotp = false;
20165
19862
  this.userCanSetupTotp = false;
20166
19863
  this.isPhoneRequired = false;
19864
+ effect(() => {
19865
+ if (this.focusOnNewPassword && this.newPasswordComponent()) {
19866
+ this.newPasswordComponent().toggleChangePassword();
19867
+ setTimeout(() => {
19868
+ this.newPasswordComponent().elementRef.nativeElement.scrollIntoView({
19869
+ behavior: 'smooth',
19870
+ block: 'center'
19871
+ });
19872
+ }, 100);
19873
+ }
19874
+ });
20167
19875
  }
20168
19876
  async ngOnInit() {
20169
19877
  const currentTenant = (await this.tenantService.current()).data;
@@ -20220,7 +19928,7 @@ class UserEditComponent {
20220
19928
  return loginOptions.some(({ tfaStrategy = '' }) => tfaStrategy.toLowerCase() === 'totp');
20221
19929
  }
20222
19930
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserEditComponent, deps: [{ token: AppStateService }, { token: TranslateService }, { token: i1$7.BsModalService }, { token: AlertService }, { token: i1.UserService }, { token: i1.TenantLoginOptionsService }, { token: i1.TenantService }], target: i0.ɵɵFactoryTarget.Component }); }
20223
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserEditComponent, isStandalone: true, selector: "c8y-user-edit", inputs: { loading: "loading", user: "user", showProductExperienceOptions: "showProductExperienceOptions", isUsageTrackingEnabled: "isUsageTrackingEnabled", isUserEngagementPreferenceEnabled: "isUserEngagementPreferenceEnabled" }, outputs: { onUser: "onUser", onUsageTrackingChange: "onUsageTrackingChange", onUserEngagementPreferenceChange: "onUserEngagementPreferenceChange", onCancel: "onCancel" }, ngImport: i0, template: "<form #userForm=\"ngForm\" (ngSubmit)=\"userForm.form.valid && save()\">\n <div class=\"d-block p-24 p-b-0\">\n <div class=\"alert alert-warning\" role=\"alert\" *ngIf=\"userIsExternal\" translate>\n Some of the user settings are not editable here because they are managed via your\n authorization server.\n </div>\n <c8y-form-group>\n <label translate for=\"userName\">Username</label>\n <input\n id=\"userName\"\n class=\"form-control\"\n [(ngModel)]=\"user.userName\"\n name=\"userName\"\n autocomplete=\"off\"\n required\n maxlength=\"254\"\n placeholder=\"{{ 'e.g. joe.doe@example.com`LOCALIZE`' | translate }}\"\n [disabled]=\"user.id\"\n c8yDefaultValidation=\"user\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate for=\"displayName\">Login alias</label>\n <input\n id=\"displayName\"\n class=\"form-control\"\n [(ngModel)]=\"user.displayName\"\n name=\"displayName\"\n autocomplete=\"off\"\n maxlength=\"254\"\n placeholder=\"{{ 'e.g. joe.doe`LOCALIZE`' | translate }}\"\n [disabled]=\"userIsExternal\"\n c8yDefaultValidation=\"loginAlias\"\n />\n </c8y-form-group>\n\n <c8y-form-group [hasWarning]=\"!user.email\">\n <label translate for=\"userEmail\">Email</label>\n <input\n id=\"userEmail\"\n class=\"form-control\"\n type=\"email\"\n name=\"email\"\n [maxlength]=\"254\"\n autocomplete=\"off\"\n placeholder=\"{{ 'e.g. joe.doe@example.com`LOCALIZE`' | translate }}\"\n [(ngModel)]=\"user.email\"\n email\n [required]=\"true\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n\n <div class=\"row\">\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label translate for=\"userFirstName\">First name</label>\n <input\n id=\"userFirstName\"\n class=\"form-control\"\n autocomplete=\"off\"\n placeholder=\"{{ 'e.g. Joe`LOCALIZE`' | translate }}\"\n maxlength=\"50\"\n name=\"firstName\"\n [(ngModel)]=\"user.firstName\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label translate for=\"userLastName\">Last name</label>\n <input\n id=\"userLastName\"\n class=\"form-control\"\n autocomplete=\"off\"\n placeholder=\"{{ 'e.g. Doe`LOCALIZE`' | translate }}\"\n maxlength=\"50\"\n name=\"lastName\"\n [(ngModel)]=\"user.lastName\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <c8y-form-group>\n <label translate for=\"userTelephone\">Telephone</label>\n <input\n id=\"userTelephone\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"phone\"\n maxlength=\"254\"\n [(ngModel)]=\"user.phone\"\n placeholder=\"{{ 'e.g. +49 9 876 543 210`LOCALIZE`' | translate }}\"\n c8yPhoneValidation\n [required]=\"isPhoneRequired\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"p-t-16 separator-top\" *ngIf=\"showProductExperienceOptions\">\n <label translate>Product experience</label>\n <label class=\"c8y-switch\" for=\"productUsageTracking\">\n <input\n id=\"productUsageTracking\"\n name=\"productUsageTracking\"\n type=\"checkbox\"\n [(ngModel)]=\"isUsageTrackingEnabled\"\n />\n <span></span>\n {{ 'Enable personalized product experience tracking' | translate }}\n </label>\n <ng-container *ngIf=\"isUsageTrackingEnabled\">\n <label class=\"c8y-switch m-l-0\" for=\"userEngagementPreference\">\n <input\n id=\"userEngagementPreference\"\n name=\"userEngagementPreference\"\n type=\"checkbox\"\n [(ngModel)]=\"isUserEngagementPreferenceEnabled\"\n />\n <span></span>\n {{ 'Enable in-product information & communication' | translate }}\n </label>\n </ng-container>\n </c8y-form-group>\n\n <div class=\"form-group p-t-16 separator-top\" *ngIf=\"!userIsExternal\">\n <label class=\"control-label\">{{ 'Login options' | translate }}</label>\n <c8y-new-password (password)=\"onNewPasswordChanged($event)\"></c8y-new-password>\n <button\n class=\"btn btn-default\"\n type=\"button\"\n title=\"{{ 'Set up two-factor authentication' | translate }}\"\n (click)=\"setupTotp()\"\n *ngIf=\"userCanSetupTotp && !userHasActiveTotp && isTfaEnabled\"\n >\n {{ 'Set up two-factor authentication' | translate }}\n </button>\n </div>\n\n <c8y-form-group *ngIf=\"!!(state.state$ | async).newsletter\">\n <label translate>Newsletter</label>\n <label\n title=\"{{ 'Send me information about outages, maintenance or updates.' | translate }}\"\n class=\"c8y-checkbox\"\n >\n <input\n type=\"checkbox\"\n name=\"newsletter\"\n [(ngModel)]=\"user.newsletter\"\n [disabled]=\"userIsExternal\"\n />\n <span></span>\n <span>\n {{ 'Send me information about outages, maintenance or updates.' | translate }}\n </span>\n </label>\n </c8y-form-group>\n </div>\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\n <button\n class=\"btn btn-default\"\n type=\"button\"\n title=\"{{ 'Cancel' | translate }}\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ 'Save' | translate }}\"\n [disabled]=\"!userForm.form.valid || userForm.form.pristine || loading\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n</form>\n", dependencies: [{ kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$8.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$8.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$8.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$8.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { 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: DefaultValidationDirective, selector: "[c8yDefaultValidation]", inputs: ["c8yDefaultValidation"] }, { kind: "directive", type: PhoneValidationDirective, selector: "[c8yPhoneValidation]" }, { kind: "component", type: NewPasswordComponent, selector: "c8y-new-password", inputs: ["showChangePasswordButton", "requireStrongPassword"], outputs: ["password"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
19931
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.14", type: UserEditComponent, isStandalone: true, selector: "c8y-user-edit", inputs: { loading: "loading", user: "user", showProductExperienceOptions: "showProductExperienceOptions", isUsageTrackingEnabled: "isUsageTrackingEnabled", isUserEngagementPreferenceEnabled: "isUserEngagementPreferenceEnabled", focusOnNewPassword: "focusOnNewPassword" }, outputs: { onUser: "onUser", onUsageTrackingChange: "onUsageTrackingChange", onUserEngagementPreferenceChange: "onUserEngagementPreferenceChange", onCancel: "onCancel" }, viewQueries: [{ propertyName: "newPasswordComponent", first: true, predicate: NewPasswordComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<form #userForm=\"ngForm\" (ngSubmit)=\"userForm.form.valid && save()\">\n <div class=\"d-block p-24 p-b-0\">\n <div class=\"alert alert-warning\" role=\"alert\" *ngIf=\"userIsExternal\" translate>\n Some of the user settings are not editable here because they are managed via your\n authorization server.\n </div>\n <c8y-form-group>\n <label translate for=\"userName\">Username</label>\n <input\n id=\"userName\"\n class=\"form-control\"\n [(ngModel)]=\"user.userName\"\n name=\"userName\"\n autocomplete=\"off\"\n required\n maxlength=\"254\"\n placeholder=\"{{ 'e.g. joe.doe@example.com`LOCALIZE`' | translate }}\"\n [disabled]=\"user.id\"\n c8yDefaultValidation=\"user\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate for=\"displayName\">Login alias</label>\n <input\n id=\"displayName\"\n class=\"form-control\"\n [(ngModel)]=\"user.displayName\"\n name=\"displayName\"\n autocomplete=\"off\"\n maxlength=\"254\"\n placeholder=\"{{ 'e.g. joe.doe`LOCALIZE`' | translate }}\"\n [disabled]=\"userIsExternal\"\n c8yDefaultValidation=\"loginAlias\"\n />\n </c8y-form-group>\n\n <c8y-form-group [hasWarning]=\"!user.email\">\n <label translate for=\"userEmail\">Email</label>\n <input\n id=\"userEmail\"\n class=\"form-control\"\n type=\"email\"\n name=\"email\"\n [maxlength]=\"254\"\n autocomplete=\"off\"\n placeholder=\"{{ 'e.g. joe.doe@example.com`LOCALIZE`' | translate }}\"\n [(ngModel)]=\"user.email\"\n email\n [required]=\"true\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n\n <div class=\"row\">\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label translate for=\"userFirstName\">First name</label>\n <input\n id=\"userFirstName\"\n class=\"form-control\"\n autocomplete=\"off\"\n placeholder=\"{{ 'e.g. Joe`LOCALIZE`' | translate }}\"\n maxlength=\"50\"\n name=\"firstName\"\n [(ngModel)]=\"user.firstName\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label translate for=\"userLastName\">Last name</label>\n <input\n id=\"userLastName\"\n class=\"form-control\"\n autocomplete=\"off\"\n placeholder=\"{{ 'e.g. Doe`LOCALIZE`' | translate }}\"\n maxlength=\"50\"\n name=\"lastName\"\n [(ngModel)]=\"user.lastName\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <c8y-form-group>\n <label translate for=\"userTelephone\">Telephone</label>\n <input\n id=\"userTelephone\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"phone\"\n maxlength=\"254\"\n [(ngModel)]=\"user.phone\"\n placeholder=\"{{ 'e.g. +49 9 876 543 210`LOCALIZE`' | translate }}\"\n c8yPhoneValidation\n [required]=\"isPhoneRequired\"\n [disabled]=\"userIsExternal\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"p-t-16 separator-top\" *ngIf=\"showProductExperienceOptions\">\n <label translate>Product experience</label>\n <label class=\"c8y-switch\" for=\"productUsageTracking\">\n <input\n id=\"productUsageTracking\"\n name=\"productUsageTracking\"\n type=\"checkbox\"\n [(ngModel)]=\"isUsageTrackingEnabled\"\n />\n <span></span>\n {{ 'Enable personalized product experience tracking' | translate }}\n </label>\n <ng-container *ngIf=\"isUsageTrackingEnabled\">\n <label class=\"c8y-switch m-l-0\" for=\"userEngagementPreference\">\n <input\n id=\"userEngagementPreference\"\n name=\"userEngagementPreference\"\n type=\"checkbox\"\n [(ngModel)]=\"isUserEngagementPreferenceEnabled\"\n />\n <span></span>\n {{ 'Enable in-product information & communication' | translate }}\n </label>\n </ng-container>\n </c8y-form-group>\n\n <div class=\"form-group p-t-16 separator-top\" *ngIf=\"!userIsExternal\">\n <label class=\"control-label\">{{ 'Login options' | translate }}</label>\n <c8y-new-password (password)=\"onNewPasswordChanged($event)\"></c8y-new-password>\n <button\n class=\"btn btn-default\"\n type=\"button\"\n title=\"{{ 'Set up two-factor authentication' | translate }}\"\n (click)=\"setupTotp()\"\n *ngIf=\"userCanSetupTotp && !userHasActiveTotp && isTfaEnabled\"\n >\n {{ 'Set up two-factor authentication' | translate }}\n </button>\n </div>\n\n <c8y-form-group *ngIf=\"!!(state.state$ | async).newsletter\">\n <label translate>Newsletter</label>\n <label\n title=\"{{ 'Send me information about outages, maintenance or updates.' | translate }}\"\n class=\"c8y-checkbox\"\n >\n <input\n type=\"checkbox\"\n name=\"newsletter\"\n [(ngModel)]=\"user.newsletter\"\n [disabled]=\"userIsExternal\"\n />\n <span></span>\n <span>\n {{ 'Send me information about outages, maintenance or updates.' | translate }}\n </span>\n </label>\n </c8y-form-group>\n </div>\n <div class=\"modal-footer separator-top bg-level-0 sticky-bottom\">\n <button\n class=\"btn btn-default\"\n type=\"button\"\n title=\"{{ 'Cancel' | translate }}\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ 'Save' | translate }}\"\n [disabled]=\"!userForm.form.valid || userForm.form.pristine || loading\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n</form>\n", dependencies: [{ kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$8.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$8.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$8.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$8.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { 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: DefaultValidationDirective, selector: "[c8yDefaultValidation]", inputs: ["c8yDefaultValidation"] }, { kind: "directive", type: PhoneValidationDirective, selector: "[c8yPhoneValidation]" }, { kind: "component", type: NewPasswordComponent, selector: "c8y-new-password", inputs: ["showChangePasswordButton", "requireStrongPassword"], outputs: ["password"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20224
19932
  }
20225
19933
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserEditComponent, decorators: [{
20226
19934
  type: Component,
@@ -20246,6 +19954,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
20246
19954
  type: Input
20247
19955
  }], isUserEngagementPreferenceEnabled: [{
20248
19956
  type: Input
19957
+ }], focusOnNewPassword: [{
19958
+ type: Input
20249
19959
  }], onUser: [{
20250
19960
  type: Output
20251
19961
  }], onUsageTrackingChange: [{
@@ -20272,6 +19982,7 @@ class UserEditModalComponent {
20272
19982
  this.userEngagementsService = userEngagementsService;
20273
19983
  this.loading = false;
20274
19984
  this.showProductExperienceOptions = false;
19985
+ this.passwordChange = false;
20275
19986
  }
20276
19987
  async ngOnInit() {
20277
19988
  this.updateUserInAppState();
@@ -20390,127 +20101,383 @@ class UserEditModalComponent {
20390
20101
  this.auth.updateCredentials(newCredentials);
20391
20102
  }
20392
20103
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserEditModalComponent, deps: [{ token: i1$7.BsModalRef }, { token: i1.UserService }, { token: AppStateService }, { token: i1.BasicAuth }, { token: i1.FetchClient }, { token: AlertService }, { token: UserPreferencesService }, { token: ModalService }, { token: GainsightService }, { token: CookieBannerService }, { token: PasswordService }, { token: UserEngagementsService }], target: i0.ɵɵFactoryTarget.Component }); }
20393
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserEditModalComponent, isStandalone: true, selector: "c8y-user-edit-modal", ngImport: i0, template: "<c8y-modal\n [title]=\"'Edit user' | translate\"\n [customFooter]=\"true\"\n (onDismiss)=\"onDismiss()\"\n>\n <c8y-user-edit\n [user]=\"ui.currentUser | async\"\n [loading]=\"loading\"\n [isUsageTrackingEnabled]=\"currentUsageTrackingState\"\n [isUserEngagementPreferenceEnabled]=\"currentUserEngagementPreferenceInitialState\"\n [showProductExperienceOptions]=\"showProductExperienceOptions\"\n (onUsageTrackingChange)=\"onUsageTrackingChange($event)\"\n (onUserEngagementPreferenceChange)=\"onUserEngagementPreferenceChange($event)\"\n (onUser)=\"updateAndClose($event)\"\n (onCancel)=\"onDismiss()\"\n ></c8y-user-edit>\n</c8y-modal>\n", dependencies: [{ kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: UserEditComponent, selector: "c8y-user-edit", inputs: ["loading", "user", "showProductExperienceOptions", "isUsageTrackingEnabled", "isUserEngagementPreferenceEnabled"], outputs: ["onUser", "onUsageTrackingChange", "onUserEngagementPreferenceChange", "onCancel"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20104
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserEditModalComponent, isStandalone: true, selector: "c8y-user-edit-modal", ngImport: i0, template: "<c8y-modal\n [title]=\"'Edit user' | translate\"\n [customFooter]=\"true\"\n (onDismiss)=\"onDismiss()\"\n>\n <c8y-user-edit\n [user]=\"ui.currentUser | async\"\n [loading]=\"loading\"\n [isUsageTrackingEnabled]=\"currentUsageTrackingState\"\n [isUserEngagementPreferenceEnabled]=\"currentUserEngagementPreferenceInitialState\"\n [showProductExperienceOptions]=\"showProductExperienceOptions\"\n [focusOnNewPassword]=\"passwordChange\"\n (onUsageTrackingChange)=\"onUsageTrackingChange($event)\"\n (onUserEngagementPreferenceChange)=\"onUserEngagementPreferenceChange($event)\"\n (onUser)=\"updateAndClose($event)\"\n (onCancel)=\"onDismiss()\"\n ></c8y-user-edit>\n</c8y-modal>\n", dependencies: [{ kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: UserEditComponent, selector: "c8y-user-edit", inputs: ["loading", "user", "showProductExperienceOptions", "isUsageTrackingEnabled", "isUserEngagementPreferenceEnabled", "focusOnNewPassword"], outputs: ["onUser", "onUsageTrackingChange", "onUserEngagementPreferenceChange", "onCancel"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20394
20105
  }
20395
20106
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserEditModalComponent, decorators: [{
20396
20107
  type: Component,
20397
- args: [{ selector: 'c8y-user-edit-modal', standalone: true, imports: [ModalComponent, UserEditComponent, C8yTranslatePipe, AsyncPipe], template: "<c8y-modal\n [title]=\"'Edit user' | translate\"\n [customFooter]=\"true\"\n (onDismiss)=\"onDismiss()\"\n>\n <c8y-user-edit\n [user]=\"ui.currentUser | async\"\n [loading]=\"loading\"\n [isUsageTrackingEnabled]=\"currentUsageTrackingState\"\n [isUserEngagementPreferenceEnabled]=\"currentUserEngagementPreferenceInitialState\"\n [showProductExperienceOptions]=\"showProductExperienceOptions\"\n (onUsageTrackingChange)=\"onUsageTrackingChange($event)\"\n (onUserEngagementPreferenceChange)=\"onUserEngagementPreferenceChange($event)\"\n (onUser)=\"updateAndClose($event)\"\n (onCancel)=\"onDismiss()\"\n ></c8y-user-edit>\n</c8y-modal>\n" }]
20108
+ args: [{ selector: 'c8y-user-edit-modal', standalone: true, imports: [ModalComponent, UserEditComponent, C8yTranslatePipe, AsyncPipe], template: "<c8y-modal\n [title]=\"'Edit user' | translate\"\n [customFooter]=\"true\"\n (onDismiss)=\"onDismiss()\"\n>\n <c8y-user-edit\n [user]=\"ui.currentUser | async\"\n [loading]=\"loading\"\n [isUsageTrackingEnabled]=\"currentUsageTrackingState\"\n [isUserEngagementPreferenceEnabled]=\"currentUserEngagementPreferenceInitialState\"\n [showProductExperienceOptions]=\"showProductExperienceOptions\"\n [focusOnNewPassword]=\"passwordChange\"\n (onUsageTrackingChange)=\"onUsageTrackingChange($event)\"\n (onUserEngagementPreferenceChange)=\"onUserEngagementPreferenceChange($event)\"\n (onUser)=\"updateAndClose($event)\"\n (onCancel)=\"onDismiss()\"\n ></c8y-user-edit>\n</c8y-modal>\n" }]
20398
20109
  }], ctorParameters: () => [{ type: i1$7.BsModalRef }, { type: i1.UserService }, { type: AppStateService }, { type: i1.BasicAuth }, { type: i1.FetchClient }, { type: AlertService }, { type: UserPreferencesService }, { type: ModalService }, { type: GainsightService }, { type: CookieBannerService }, { type: PasswordService }, { type: UserEngagementsService }] });
20399
20110
 
20400
- class UserMenuOutletComponent {
20401
- constructor(ui, bsModalService, authService, userMenu, headerService) {
20402
- this.ui = ui;
20403
- this.bsModalService = bsModalService;
20404
- this.authService = authService;
20405
- this.userMenu = userMenu;
20406
- this.headerService = headerService;
20407
- this.items$ = this.userMenu.items$;
20408
- this.open$ = this.headerService.rightDrawerOpen$;
20111
+ /**
20112
+ * Service to show a modal.
20113
+ */
20114
+ class ModalService {
20115
+ constructor(modalService, gainsightService) {
20116
+ this.modalService = modalService;
20117
+ this.gainsightService = gainsightService;
20409
20118
  }
20410
- async editUser() {
20411
- this.bsModalService.show(UserEditModalComponent, {
20119
+ /**
20120
+ * Shows a quick confirm message modal.
20121
+ * @param title The title of that modal.
20122
+ * @param body The text body to display.
20123
+ * @param status The status.
20124
+ * @param labels The labels to use. Default: { ok: 'Confirm', cancel: 'Cancel'}
20125
+ * @param confirmOptions Selection options to display as checkbox list.
20126
+ * @param productExperienceEvent Additional data to attach to custom product experience events.
20127
+ */
20128
+ async confirm(title, body, status = Status.INFO, labels = {}, confirmOptions = {}, productExperienceEvent = { eventName: 'confirmModal' }) {
20129
+ const modalLabels = {
20130
+ ok: labels.ok || gettext$1('Confirm'),
20131
+ cancel: labels.cancel || gettext$1('Cancel')
20132
+ };
20133
+ const modalRef = this.modalService.show(ConfirmModalComponent, {
20134
+ initialState: { title, body, labels: modalLabels, status, confirmOptions },
20412
20135
  ariaDescribedby: 'modal-body',
20413
- ariaLabelledBy: 'modal-title'
20136
+ ariaLabelledBy: 'modal-title',
20137
+ ignoreBackdropClick: true
20414
20138
  });
20139
+ if (productExperienceEvent) {
20140
+ productExperienceEvent.data = { ...productExperienceEvent.data, title };
20141
+ }
20142
+ this.triggerEvent(modalRef.content.result, modalLabels, productExperienceEvent);
20143
+ return await modalRef.content.result;
20415
20144
  }
20416
- async logout() {
20417
- await this.authService.logout();
20418
- }
20419
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuOutletComponent, deps: [{ token: AppStateService }, { token: i1$7.BsModalService }, { token: SimplifiedAuthService }, { token: UserMenuService }, { token: HeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
20420
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserMenuOutletComponent, isStandalone: true, selector: "c8y-user-menu-outlet", ngImport: i0, template: "<ng-container *ngIf=\"items$ | async as items\">\n <div\n class=\"p-t-8 p-b-8\"\n *ngIf=\"items.length\"\n >\n <ul class=\"list-unstyled m-b-0\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container *ngIf=\"item.template\">\n <ng-container *c8yOutlet=\"item.template\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!item.template\">\n <li>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.aria-label]=\"item.label | translate\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"item.click()\"\n [attr.href]=\"item.link\"\n [attr.target]=\"item.target\"\n >\n {{ item.label | translate }}\n </button>\n </li>\n </ng-container>\n </ng-container>\n </ul>\n </div>\n</ng-container>\n\n<!-- the default items -->\n<c8y-user-menu-item\n [icon]=\"'user-menu-male'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'User settings' | translate\"\n [priority]=\"20\"\n [dataCy]=\"'user-menu-user-settings-button'\"\n (click)=\"editUser()\"\n></c8y-user-menu-item>\n<c8y-user-menu-item\n [icon]=\"'sign-out'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'Logout' | translate\"\n [dataCy]=\"'user-menu-logout-button'\"\n (click)=\"logout()\"\n></c8y-user-menu-item>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: OutletDirective, selector: "[c8yOutlet]", inputs: ["c8yOutlet", "c8yOutletProperties", "c8yOutletInjector"] }, { kind: "component", type: UserMenuItemComponent, selector: "c8y-user-menu-item", inputs: ["icon", "label", "link", "target", "priority", "dataCy"], outputs: ["click"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20421
- }
20422
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuOutletComponent, decorators: [{
20423
- type: Component,
20424
- args: [{ selector: 'c8y-user-menu-outlet', standalone: true, imports: [NgIf, NgFor, OutletDirective, UserMenuItemComponent, C8yTranslatePipe, AsyncPipe], template: "<ng-container *ngIf=\"items$ | async as items\">\n <div\n class=\"p-t-8 p-b-8\"\n *ngIf=\"items.length\"\n >\n <ul class=\"list-unstyled m-b-0\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container *ngIf=\"item.template\">\n <ng-container *c8yOutlet=\"item.template\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!item.template\">\n <li>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.aria-label]=\"item.label | translate\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"item.click()\"\n [attr.href]=\"item.link\"\n [attr.target]=\"item.target\"\n >\n {{ item.label | translate }}\n </button>\n </li>\n </ng-container>\n </ng-container>\n </ul>\n </div>\n</ng-container>\n\n<!-- the default items -->\n<c8y-user-menu-item\n [icon]=\"'user-menu-male'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'User settings' | translate\"\n [priority]=\"20\"\n [dataCy]=\"'user-menu-user-settings-button'\"\n (click)=\"editUser()\"\n></c8y-user-menu-item>\n<c8y-user-menu-item\n [icon]=\"'sign-out'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'Logout' | translate\"\n [dataCy]=\"'user-menu-logout-button'\"\n (click)=\"logout()\"\n></c8y-user-menu-item>\n" }]
20425
- }], ctorParameters: () => [{ type: AppStateService }, { type: i1$7.BsModalService }, { type: SimplifiedAuthService }, { type: UserMenuService }, { type: HeaderService }] });
20426
-
20427
- class PasswordStrengthCheckerService {
20428
- constructor() {
20429
- this.GREEN = {
20430
- colorName: 'green',
20431
- color: 'rgb(0, 128, 0)',
20432
- description: gettext$1('strong'),
20433
- passwordStrength: PasswordStrength.GREEN
20434
- };
20435
- this.YELLOW = {
20436
- colorName: 'yellow',
20437
- color: 'rgb(255, 204, 51)',
20438
- description: gettext$1('medium'),
20439
- passwordStrength: PasswordStrength.YELLOW
20440
- };
20441
- this.RED = {
20442
- colorName: 'red',
20443
- color: 'rgb(170, 0, 51)',
20444
- description: gettext$1('weak'),
20445
- passwordStrength: PasswordStrength.RED
20446
- };
20145
+ /**
20146
+ * Shows a quick acknowledge message modal.
20147
+ * @param title The title of that modal.
20148
+ * @param body The text body to display.
20149
+ * @param status The status.
20150
+ * @param acknowledgeLabel The label to use.
20151
+ * @param productExperienceEvent Additional data to attach to custom product experience events.
20152
+ */
20153
+ async acknowledge(title, body, status = Status.INFO, acknowledgeLabel = gettext$1('Confirm'), productExperienceEvent = { eventName: 'confirmModal' }) {
20154
+ const labels = { ok: acknowledgeLabel, cancel: null };
20155
+ const modalRef = this.modalService.show(ConfirmModalComponent, {
20156
+ initialState: { title, body, labels, status },
20157
+ ariaDescribedby: 'modal-body',
20158
+ ariaLabelledBy: 'modal-title',
20159
+ ignoreBackdropClick: true
20160
+ });
20161
+ if (productExperienceEvent) {
20162
+ productExperienceEvent.data = { ...productExperienceEvent.data, title };
20163
+ }
20164
+ this.triggerEvent(modalRef.content.result, labels, productExperienceEvent);
20165
+ return await modalRef.content.result;
20447
20166
  }
20448
- hasLowerCase(password) {
20449
- return password.search(/[a-z]/) !== -1;
20167
+ /**
20168
+ * Shows a quick logout confirmation modal.
20169
+ * @param body The text body to display. Default: 'You will be logged out to apply your changes. Do you want to proceed?'
20170
+ * @param status The status.
20171
+ * @param labels The labels to use. Default: { ok: 'Confirm and log out', cancel: 'Cancel' }
20172
+ */
20173
+ async confirmLogout(body, status = Status.WARNING, labels = {}) {
20174
+ const modalLabels = {
20175
+ ok: labels.ok || gettext$1('Confirm and log out'),
20176
+ cancel: labels.cancel || gettext$1('Cancel')
20177
+ };
20178
+ const modalBody = body || gettext$1('You must log out to apply your changes. Do you want to proceed?');
20179
+ return await this.confirm(gettext$1('Logout required'), modalBody, status, modalLabels);
20450
20180
  }
20451
- hasUpperCase(password) {
20452
- return password.search(/[A-Z]/) !== -1;
20181
+ async changeCurrentUserPassword() {
20182
+ this.modalService.show(UserEditModalComponent, {
20183
+ initialState: { passwordChange: true },
20184
+ ariaDescribedby: 'modal-body',
20185
+ ariaLabelledBy: 'modal-title'
20186
+ });
20453
20187
  }
20454
- hasNumbers(password) {
20455
- return password.search(/[0-9]/) !== -1;
20188
+ triggerEvent(result, labels, productExperienceEvent) {
20189
+ const data = { ...productExperienceEvent.data, url: window.location.href };
20190
+ result
20191
+ .then(() => {
20192
+ this.gainsightService.triggerEvent(productExperienceEvent.eventName, {
20193
+ ...data,
20194
+ result: labels.ok
20195
+ });
20196
+ })
20197
+ .catch(() => {
20198
+ this.gainsightService.triggerEvent(productExperienceEvent.eventName, {
20199
+ ...data,
20200
+ result: labels.cancel
20201
+ });
20202
+ });
20456
20203
  }
20457
- hasSpecialChars(password) {
20458
- return password.search(/[^0-9a-zA-Z]+/) !== -1;
20204
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalService, deps: [{ token: i1$7.BsModalService }, { token: GainsightService }], target: i0.ɵɵFactoryTarget.Injectable }); }
20205
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalService, providedIn: 'root' }); }
20206
+ }
20207
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModalService, decorators: [{
20208
+ type: Injectable,
20209
+ args: [{
20210
+ providedIn: 'root'
20211
+ }]
20212
+ }], ctorParameters: () => [{ type: i1$7.BsModalService }, { type: GainsightService }] });
20213
+
20214
+ class ThemeSwitcherService {
20215
+ constructor(options) {
20216
+ this.options = options;
20217
+ this.darkThemeClass = `c8y-dark-theme`;
20218
+ this.themeOptions = [
20219
+ {
20220
+ label: gettext$1('Light'),
20221
+ value: 'light',
20222
+ icon: 'sun'
20223
+ },
20224
+ {
20225
+ label: gettext$1('Dark'),
20226
+ value: 'dark',
20227
+ icon: 'moon'
20228
+ },
20229
+ {
20230
+ label: gettext$1('System'),
20231
+ value: 'system',
20232
+ icon: 'imac-settings'
20233
+ }
20234
+ ];
20235
+ this._userSelectedThemePreference$ = new BehaviorSubject(this.getCurrentThemePreference());
20236
+ this._temporaryThemePreference$ = new BehaviorSubject('none');
20237
+ this.userSelectedThemePreference$ = this._userSelectedThemePreference$.asObservable();
20238
+ const userSelectedTheme$ = this.userSelectedThemePreference$.pipe(switchMap(preference => {
20239
+ if (preference === 'system') {
20240
+ return this.getUsersSystemPreferenceForTheme$();
20241
+ }
20242
+ return of(preference);
20243
+ }));
20244
+ this.disableThemeSelection$ = this._temporaryThemePreference$.pipe(map(preference => preference !== 'none'));
20245
+ this.currentlyAppliedTheme$ = this._temporaryThemePreference$.pipe(switchMap(temporaryPreference => {
20246
+ if (temporaryPreference !== 'none') {
20247
+ return of(temporaryPreference);
20248
+ }
20249
+ return userSelectedTheme$;
20250
+ }));
20251
+ this.darkThemeAvailable$ = this.options.get$('darkThemeAvailable').pipe(map(value => !!value));
20459
20252
  }
20460
- getStrengthColor(password) {
20461
- const passwordStrength = filter$2([
20462
- this.hasLowerCase(password),
20463
- this.hasUpperCase(password),
20464
- this.hasNumbers(password),
20465
- this.hasSpecialChars(password)
20466
- ]).length;
20467
- if (passwordStrength > 3) {
20468
- return this.GREEN;
20469
- }
20470
- else if (passwordStrength >= 3) {
20471
- return this.YELLOW;
20472
- }
20473
- else {
20474
- return this.RED;
20253
+ getCurrentThemePreference() {
20254
+ const value = getThemePreference();
20255
+ if (value === 'system' || value === 'dark') {
20256
+ return value;
20475
20257
  }
20258
+ return 'light';
20476
20259
  }
20477
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthCheckerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
20478
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthCheckerService }); }
20260
+ getUsersSystemPreferenceForTheme$() {
20261
+ return fromEvent(window.matchMedia('(prefers-color-scheme: dark)'), 'change').pipe(startWith(window.matchMedia('(prefers-color-scheme: dark)')), map((e) => (e.matches ? 'dark' : 'light')));
20262
+ }
20263
+ changeUserPreference(preference) {
20264
+ setThemePreference(preference);
20265
+ this._userSelectedThemePreference$.next(preference);
20266
+ this.applyTheme(preference);
20267
+ }
20268
+ temporaryChangeTheme(preference) {
20269
+ this._temporaryThemePreference$.next(preference);
20270
+ this.applyTheme(preference);
20271
+ }
20272
+ resetTemporaryTheme() {
20273
+ this._temporaryThemePreference$.next('none');
20274
+ this.applyTheme(this.getCurrentThemePreference());
20275
+ }
20276
+ applyTheme(preference) {
20277
+ applyTheme(preference);
20278
+ }
20279
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeSwitcherService, deps: [{ token: OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
20280
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeSwitcherService, providedIn: 'root' }); }
20479
20281
  }
20480
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthCheckerService, decorators: [{
20481
- type: Injectable
20482
- }] });
20282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeSwitcherService, decorators: [{
20283
+ type: Injectable,
20284
+ args: [{
20285
+ providedIn: 'root'
20286
+ }]
20287
+ }], ctorParameters: () => [{ type: OptionsService }] });
20483
20288
 
20484
- /**
20485
- * @deprecated: [MTM-56403] Password strength indicator removed from UI in favor of the enhanced password strength check list.
20486
- */
20487
- class PasswordStrengthComponent {
20488
- set password(password) {
20489
- if (typeof password === 'string') {
20490
- this.model = this.passwordStrengthCheckerService.getStrengthColor(password);
20491
- this.strength.emit(this.model);
20289
+ class UiSettingsComponent {
20290
+ constructor(translate, state, ui, userPreferences, c8yModalService, headerService, themeSwitcher) {
20291
+ this.translate = translate;
20292
+ this.state = state;
20293
+ this.ui = ui;
20294
+ this.userPreferences = userPreferences;
20295
+ this.c8yModalService = c8yModalService;
20296
+ this.headerService = headerService;
20297
+ this.themeSwitcher = themeSwitcher;
20298
+ this.destroyed$ = new Subject();
20299
+ this.currentLang = this.ui.state.lang;
20300
+ this.ui.state$
20301
+ .pipe(filter(({ lang }) => lang !== this.currentLang), takeUntil(this.destroyed$), first$1())
20302
+ .subscribe(({ lang }) => (this.currentLang = lang));
20303
+ this.open$ = this.headerService.rightDrawerOpen$;
20304
+ }
20305
+ ngOnInit() {
20306
+ this.languages = this.state.state.langs.map(l => ({
20307
+ lang: l,
20308
+ nativeLanguage: this.translate.getNativeLanguage(l)
20309
+ }));
20310
+ }
20311
+ ngOnDestroy() {
20312
+ this.destroyed$.next();
20313
+ this.destroyed$.complete();
20314
+ }
20315
+ async onLanguageChange(changedLang) {
20316
+ if (!changedLang) {
20317
+ return;
20318
+ }
20319
+ await this.translate.switchToLanguage(changedLang);
20320
+ if (await this.persistLanguage(changedLang)) {
20321
+ location.reload();
20492
20322
  }
20493
20323
  }
20494
- constructor(passwordStrengthCheckerService) {
20495
- this.passwordStrengthCheckerService = passwordStrengthCheckerService;
20496
- this.strength = new EventEmitter();
20497
- this.password = '';
20324
+ async persistLanguage(lang) {
20325
+ let shouldReload = true;
20326
+ try {
20327
+ await this.c8yModalService.confirm(gettext$1('Reload recommended'), gettext$1('To change the language in the entire application, we recommend you to reload the page. If you have any unsaved changes, you can reload later. How would you like to proceed?'), Status.WARNING, {
20328
+ ok: gettext$1('Reload now'),
20329
+ cancel: gettext$1('Reload later')
20330
+ });
20331
+ }
20332
+ catch (ex) {
20333
+ shouldReload = false;
20334
+ }
20335
+ finally {
20336
+ this.translate.saveInLocalStorage(lang);
20337
+ await this.userPreferences.set('language', lang);
20338
+ this.currentLang = lang;
20339
+ }
20340
+ return shouldReload;
20498
20341
  }
20499
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthComponent, deps: [{ token: PasswordService }], target: i0.ɵɵFactoryTarget.Component }); }
20500
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PasswordStrengthComponent, isStandalone: true, selector: "c8y-password-strength", inputs: { password: "password" }, outputs: { strength: "strength" }, ngImport: i0, template: "<div class=\"password-strength password-{{ model.colorName }}\">\r\n <label class=\"password-strength-label small\" translate>\r\n Password strength\r\n </label>\r\n <div>\r\n <div class=\"password-bar\"></div>\r\n </div>\r\n <span class=\"small\">\r\n {{ model.description | translate }}\r\n </span>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
20342
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsComponent, deps: [{ token: TranslateService }, { token: AppStateService }, { token: AppStateService }, { token: UserPreferencesService }, { token: ModalService }, { token: HeaderService }, { token: ThemeSwitcherService }], target: i0.ɵɵFactoryTarget.Component }); }
20343
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UiSettingsComponent, isStandalone: true, selector: "c8y-ui-settings", ngImport: i0, template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"eyedropper\"></i>\n <span class=\"text-bold\">{{ 'UI settings' | translate }}</span>\n </div>\n\n <div\n class=\"p-l-16 p-r-16 p-b-16\"\n *ngIf=\"themeSwitcher.darkThemeAvailable$ | async\"\n >\n <p translate>Theme</p>\n <div\n class=\"c8y-switch-multistate\"\n *ngIf=\"themeSwitcher.userSelectedThemePreference$ | async as themePreference\"\n >\n <ng-container *ngFor=\"let themeOption of themeSwitcher.themeOptions; index as i\">\n <input\n [attr.aria-label]=\"themeOption.label\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n name=\"theme-switcher\"\n type=\"radio\"\n [id]=\"'theme-option-' + i\"\n [disabled]=\"themeSwitcher.disableThemeSelection$ | async\"\n [checked]=\"themePreference === themeOption.value\"\n (click)=\"themeSwitcher.changeUserPreference(themeOption.value)\"\n />\n <label\n title=\"{{ themeOption.label | translate }}\"\n [for]=\"'theme-option-' + i\"\n >\n <i [c8yIcon]=\"themeOption.icon\"></i>\n </label>\n </ng-container>\n <div class=\"c8y-switch-multistate__handle\"></div>\n </div>\n </div>\n\n <div class=\"form-group p-l-16 p-r-16\">\n <label\n for=\"userLang\"\n translate\n >\n Language\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n id=\"userLang\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n #selectLang\n [ngModel]=\"currentLang\"\n (change)=\"onLanguageChange(selectLang.value)\"\n >\n <option\n *ngFor=\"let language of languages\"\n [value]=\"language.lang\"\n >\n {{ language.nativeLanguage }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$8.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$8.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20501
20344
  }
20502
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthComponent, decorators: [{
20345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsComponent, decorators: [{
20503
20346
  type: Component,
20504
- args: [{ selector: 'c8y-password-strength', standalone: true, imports: [C8yTranslateDirective, C8yTranslatePipe], template: "<div class=\"password-strength password-{{ model.colorName }}\">\r\n <label class=\"password-strength-label small\" translate>\r\n Password strength\r\n </label>\r\n <div>\r\n <div class=\"password-bar\"></div>\r\n </div>\r\n <span class=\"small\">\r\n {{ model.description | translate }}\r\n </span>\r\n</div>\r\n" }]
20505
- }], ctorParameters: () => [{ type: PasswordService }], propDecorators: { password: [{
20506
- type: Input,
20507
- args: ['password']
20508
- }], strength: [{
20509
- type: Output
20510
- }] } });
20511
-
20512
- /**
20513
- * The angular module definition for new password.
20347
+ args: [{ selector: 'c8y-ui-settings', standalone: true, imports: [
20348
+ IconDirective,
20349
+ NgIf,
20350
+ C8yTranslateDirective,
20351
+ NgFor,
20352
+ FormsModule$1,
20353
+ C8yTranslatePipe,
20354
+ AsyncPipe
20355
+ ], template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"eyedropper\"></i>\n <span class=\"text-bold\">{{ 'UI settings' | translate }}</span>\n </div>\n\n <div\n class=\"p-l-16 p-r-16 p-b-16\"\n *ngIf=\"themeSwitcher.darkThemeAvailable$ | async\"\n >\n <p translate>Theme</p>\n <div\n class=\"c8y-switch-multistate\"\n *ngIf=\"themeSwitcher.userSelectedThemePreference$ | async as themePreference\"\n >\n <ng-container *ngFor=\"let themeOption of themeSwitcher.themeOptions; index as i\">\n <input\n [attr.aria-label]=\"themeOption.label\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n name=\"theme-switcher\"\n type=\"radio\"\n [id]=\"'theme-option-' + i\"\n [disabled]=\"themeSwitcher.disableThemeSelection$ | async\"\n [checked]=\"themePreference === themeOption.value\"\n (click)=\"themeSwitcher.changeUserPreference(themeOption.value)\"\n />\n <label\n title=\"{{ themeOption.label | translate }}\"\n [for]=\"'theme-option-' + i\"\n >\n <i [c8yIcon]=\"themeOption.icon\"></i>\n </label>\n </ng-container>\n <div class=\"c8y-switch-multistate__handle\"></div>\n </div>\n </div>\n\n <div class=\"form-group p-l-16 p-r-16\">\n <label\n for=\"userLang\"\n translate\n >\n Language\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n id=\"userLang\"\n tabindex=\"{{ (open$ | async) ? '0' : '-1' }}\"\n #selectLang\n [ngModel]=\"currentLang\"\n (change)=\"onLanguageChange(selectLang.value)\"\n >\n <option\n *ngFor=\"let language of languages\"\n [value]=\"language.lang\"\n >\n {{ language.nativeLanguage }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n</div>\n" }]
20356
+ }], ctorParameters: () => [{ type: TranslateService }, { type: AppStateService }, { type: AppStateService }, { type: UserPreferencesService }, { type: ModalService }, { type: HeaderService }, { type: ThemeSwitcherService }] });
20357
+
20358
+ class UiSettingsModule {
20359
+ static providers() {
20360
+ return [
20361
+ hookDrawer({
20362
+ component: UiSettingsComponent,
20363
+ position: 'right',
20364
+ priority: 90,
20365
+ id: 'uiSettings'
20366
+ })
20367
+ ];
20368
+ }
20369
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
20370
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, imports: [CommonModule, FormsModule$1, UiSettingsComponent], exports: [UiSettingsComponent] }); }
20371
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, imports: [CommonModule, FormsModule$1, UiSettingsComponent] }); }
20372
+ }
20373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UiSettingsModule, decorators: [{
20374
+ type: NgModule,
20375
+ args: [{
20376
+ imports: [CommonModule, FormsModule$1, UiSettingsComponent],
20377
+ exports: [UiSettingsComponent]
20378
+ }]
20379
+ }] });
20380
+
20381
+ class UserMenuItemComponent {
20382
+ constructor(userService, headerService) {
20383
+ this.userService = userService;
20384
+ this.headerService = headerService;
20385
+ this.priority = 0;
20386
+ this.click = new EventEmitter();
20387
+ this.open$ = this.headerService.rightDrawerOpen$;
20388
+ }
20389
+ ngAfterViewInit() {
20390
+ this.viewInitTimeout = setTimeout(() => this.userService.add(this));
20391
+ }
20392
+ ngOnDestroy() {
20393
+ clearTimeout(this.viewInitTimeout);
20394
+ this.userService.remove(this);
20395
+ }
20396
+ onClick() {
20397
+ this.click.emit(this);
20398
+ }
20399
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuItemComponent, deps: [{ token: UserMenuService }, { token: HeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
20400
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserMenuItemComponent, isStandalone: true, selector: "c8y-user-menu-item", inputs: { icon: "icon", label: "label", link: "link", target: "target", priority: "priority", dataCy: "dataCy" }, outputs: { click: "click" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true }], ngImport: i0, template: "<ng-template #template>\n <li>\n <a\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n *ngIf=\"link\"\n [attr.href]=\"link\"\n [attr.target]=\"target\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </a>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n *ngIf=\"!link\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </button>\n </li>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20401
+ }
20402
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuItemComponent, decorators: [{
20403
+ type: Component,
20404
+ args: [{ selector: 'c8y-user-menu-item', standalone: true, imports: [NgIf, C8yTranslatePipe, AsyncPipe], template: "<ng-template #template>\n <li>\n <a\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n *ngIf=\"link\"\n [attr.href]=\"link\"\n [attr.target]=\"target\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </a>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n *ngIf=\"!link\"\n (click)=\"onClick()\"\n [attr.data-cy]=\"dataCy\"\n >\n {{ label | translate }}\n <ng-content></ng-content>\n </button>\n </li>\n</ng-template>\n" }]
20405
+ }], ctorParameters: () => [{ type: UserMenuService }, { type: HeaderService }], propDecorators: { icon: [{
20406
+ type: Input
20407
+ }], label: [{
20408
+ type: Input
20409
+ }], link: [{
20410
+ type: Input
20411
+ }], target: [{
20412
+ type: Input
20413
+ }], priority: [{
20414
+ type: Input
20415
+ }], dataCy: [{
20416
+ type: Input
20417
+ }], template: [{
20418
+ type: ViewChild,
20419
+ args: ['template', { static: false }]
20420
+ }], click: [{
20421
+ type: Output
20422
+ }] } });
20423
+
20424
+ class UserMenuOutletComponent {
20425
+ constructor(ui, bsModalService, authService, userMenu, headerService) {
20426
+ this.ui = ui;
20427
+ this.bsModalService = bsModalService;
20428
+ this.authService = authService;
20429
+ this.userMenu = userMenu;
20430
+ this.headerService = headerService;
20431
+ this.items$ = this.userMenu.items$;
20432
+ this.open$ = this.headerService.rightDrawerOpen$;
20433
+ }
20434
+ async editUser() {
20435
+ this.bsModalService.show(UserEditModalComponent, {
20436
+ ariaDescribedby: 'modal-body',
20437
+ ariaLabelledBy: 'modal-title'
20438
+ });
20439
+ }
20440
+ async logout() {
20441
+ await this.authService.logout();
20442
+ }
20443
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuOutletComponent, deps: [{ token: AppStateService }, { token: i1$7.BsModalService }, { token: SimplifiedAuthService }, { token: UserMenuService }, { token: HeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
20444
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UserMenuOutletComponent, isStandalone: true, selector: "c8y-user-menu-outlet", ngImport: i0, template: "<ng-container *ngIf=\"items$ | async as items\">\n <div\n class=\"p-t-8 p-b-8\"\n *ngIf=\"items.length\"\n >\n <ul class=\"list-unstyled m-b-0\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container *ngIf=\"item.template\">\n <ng-container *c8yOutlet=\"item.template\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!item.template\">\n <li>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.aria-label]=\"item.label | translate\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"item.click()\"\n [attr.href]=\"item.link\"\n [attr.target]=\"item.target\"\n >\n {{ item.label | translate }}\n </button>\n </li>\n </ng-container>\n </ng-container>\n </ul>\n </div>\n</ng-container>\n\n<!-- the default items -->\n<c8y-user-menu-item\n [icon]=\"'user-menu-male'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'User settings' | translate\"\n [priority]=\"20\"\n [dataCy]=\"'user-menu-user-settings-button'\"\n (click)=\"editUser()\"\n></c8y-user-menu-item>\n<c8y-user-menu-item\n [icon]=\"'sign-out'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'Logout' | translate\"\n [dataCy]=\"'user-menu-logout-button'\"\n (click)=\"logout()\"\n></c8y-user-menu-item>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: OutletDirective, selector: "[c8yOutlet]", inputs: ["c8yOutlet", "c8yOutletProperties", "c8yOutletInjector"] }, { kind: "component", type: UserMenuItemComponent, selector: "c8y-user-menu-item", inputs: ["icon", "label", "link", "target", "priority", "dataCy"], outputs: ["click"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
20445
+ }
20446
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserMenuOutletComponent, decorators: [{
20447
+ type: Component,
20448
+ args: [{ selector: 'c8y-user-menu-outlet', standalone: true, imports: [NgIf, NgFor, OutletDirective, UserMenuItemComponent, C8yTranslatePipe, AsyncPipe], template: "<ng-container *ngIf=\"items$ | async as items\">\n <div\n class=\"p-t-8 p-b-8\"\n *ngIf=\"items.length\"\n >\n <ul class=\"list-unstyled m-b-0\">\n <ng-container *ngFor=\"let item of items\">\n <ng-container *ngIf=\"item.template\">\n <ng-container *c8yOutlet=\"item.template\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!item.template\">\n <li>\n <button\n class=\"c8y-right-drawer__link\"\n [attr.aria-label]=\"item.label | translate\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"item.click()\"\n [attr.href]=\"item.link\"\n [attr.target]=\"item.target\"\n >\n {{ item.label | translate }}\n </button>\n </li>\n </ng-container>\n </ng-container>\n </ul>\n </div>\n</ng-container>\n\n<!-- the default items -->\n<c8y-user-menu-item\n [icon]=\"'user-menu-male'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'User settings' | translate\"\n [priority]=\"20\"\n [dataCy]=\"'user-menu-user-settings-button'\"\n (click)=\"editUser()\"\n></c8y-user-menu-item>\n<c8y-user-menu-item\n [icon]=\"'sign-out'\"\n *ngIf=\"(ui.currentUser | async) && (ui.currentUser | async).id !== 'NO_LOGIN'\"\n [label]=\"'Logout' | translate\"\n [dataCy]=\"'user-menu-logout-button'\"\n (click)=\"logout()\"\n></c8y-user-menu-item>\n" }]
20449
+ }], ctorParameters: () => [{ type: AppStateService }, { type: i1$7.BsModalService }, { type: SimplifiedAuthService }, { type: UserMenuService }, { type: HeaderService }] });
20450
+
20451
+ /**
20452
+ * @deprecated: [MTM-56403] Password strength indicator removed from UI in favor of the enhanced password strength check list.
20453
+ */
20454
+ class PasswordStrengthComponent {
20455
+ set password(password) {
20456
+ if (typeof password === 'string') {
20457
+ this.model = this.passwordStrengthCheckerService.getStrengthColor(password);
20458
+ this.strength.emit(this.model);
20459
+ }
20460
+ }
20461
+ constructor(passwordStrengthCheckerService) {
20462
+ this.passwordStrengthCheckerService = passwordStrengthCheckerService;
20463
+ this.strength = new EventEmitter();
20464
+ this.password = '';
20465
+ }
20466
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthComponent, deps: [{ token: PasswordService }], target: i0.ɵɵFactoryTarget.Component }); }
20467
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PasswordStrengthComponent, isStandalone: true, selector: "c8y-password-strength", inputs: { password: "password" }, outputs: { strength: "strength" }, ngImport: i0, template: "<div class=\"password-strength password-{{ model.colorName }}\">\r\n <label class=\"password-strength-label small\" translate>\r\n Password strength\r\n </label>\r\n <div>\r\n <div class=\"password-bar\"></div>\r\n </div>\r\n <span class=\"small\">\r\n {{ model.description | translate }}\r\n </span>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
20468
+ }
20469
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthComponent, decorators: [{
20470
+ type: Component,
20471
+ args: [{ selector: 'c8y-password-strength', standalone: true, imports: [C8yTranslateDirective, C8yTranslatePipe], template: "<div class=\"password-strength password-{{ model.colorName }}\">\r\n <label class=\"password-strength-label small\" translate>\r\n Password strength\r\n </label>\r\n <div>\r\n <div class=\"password-bar\"></div>\r\n </div>\r\n <span class=\"small\">\r\n {{ model.description | translate }}\r\n </span>\r\n</div>\r\n" }]
20472
+ }], ctorParameters: () => [{ type: PasswordService }], propDecorators: { password: [{
20473
+ type: Input,
20474
+ args: ['password']
20475
+ }], strength: [{
20476
+ type: Output
20477
+ }] } });
20478
+
20479
+ /**
20480
+ * The angular module definition for new password.
20514
20481
  * @exports PasswordStrengthComponent
20515
20482
  * @exports PasswordCheckListComponent
20516
20483
  * @exports PasswordConfirm
@@ -20541,7 +20508,7 @@ class AuthenticationModule {
20541
20508
  CurrentPasswordModalComponent,
20542
20509
  TotpSetupComponent,
20543
20510
  PasswordInputComponent] }); }
20544
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthenticationModule, providers: [PasswordStrengthCheckerService, PasswordService], imports: [FormsModule,
20511
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthenticationModule, imports: [FormsModule,
20545
20512
  TooltipModule,
20546
20513
  CommonModule,
20547
20514
  ModalModule,
@@ -20581,8 +20548,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
20581
20548
  CurrentPasswordModalComponent,
20582
20549
  TotpSetupComponent,
20583
20550
  PasswordInputComponent
20584
- ],
20585
- providers: [PasswordStrengthCheckerService, PasswordService]
20551
+ ]
20586
20552
  }]
20587
20553
  }] });
20588
20554
 
@@ -20827,769 +20793,770 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
20827
20793
  }]
20828
20794
  }] });
20829
20795
 
20830
- var ApplicationPluginStatus;
20831
- (function (ApplicationPluginStatus) {
20832
- ApplicationPluginStatus["ORPHANED"] = "ORPHANED";
20833
- ApplicationPluginStatus["LATEST"] = "LATEST";
20834
- ApplicationPluginStatus["OUTDATED"] = "OUTDATED";
20835
- ApplicationPluginStatus["REVOKED"] = "REVOKED";
20836
- ApplicationPluginStatus["AUTO"] = "AUTO";
20837
- })(ApplicationPluginStatus || (ApplicationPluginStatus = {}));
20838
- var PackageType;
20839
- (function (PackageType) {
20840
- /**
20841
- * A package coming from the official Cumulocity github enterprise.
20842
- */
20843
- PackageType["OFFICIAL"] = "OFFICIAL";
20844
- /**
20845
- * A package coming from any connected partner repository.
20846
- */
20847
- PackageType["COMMUNITY"] = "COMMUNITY";
20848
- /**
20849
- * A package where the origin is unknown (e.g. uploaded to management with an unknown label)
20850
- */
20851
- PackageType["UNKNOWN"] = "UNKNOWN";
20852
- /**
20853
- * A custom package e.g. uploaded to the tenant by a user
20854
- */
20855
- PackageType["CUSTOM"] = "CUSTOM";
20856
- /**
20857
- * A package that was archived by the user
20858
- */
20859
- PackageType["ARCHIVED"] = "ARCHIVED";
20860
- })(PackageType || (PackageType = {}));
20796
+ class PluginsModule {
20797
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
20798
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule }); }
20799
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule }); }
20800
+ }
20801
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule, decorators: [{
20802
+ type: NgModule,
20803
+ args: [{
20804
+ providers: []
20805
+ }]
20806
+ }] });
20861
20807
 
20862
- class PluginsService {
20863
- static convertInstalledRemotesToIds(remotes) {
20864
- if (!remotes) {
20808
+ /**
20809
+ * An extension HOOK can use either a pure value:
20810
+ * ```typescript
20811
+ * { provide: HOOK_X, useValue: { ...hookValue }, multi: true }
20812
+ * ```
20813
+ *
20814
+ * Or an array to directly register multiple:
20815
+ * ```typescript
20816
+ * { provide: HOOK_X, useValue: [{ ...hookValues }], multi: true }
20817
+ * ```
20818
+ *
20819
+ * Or an ExtensionFactory which allows to define a get() function. This function
20820
+ * gets called on each navigation with the current route and can return values
20821
+ * async (observable or promise).
20822
+ * ```typescript
20823
+ * { provide: HOOK_X, useFactory: { get: (route) => doSomethingAsync(route) }, multi: true }
20824
+ * ```
20825
+ * @deprecated Consider using the `hookVersion` function instead.
20826
+ */
20827
+ const HOOK_VERSION = new InjectionToken('HOOK_VERSION');
20828
+ const VERSION_MODULE_CONFIG = new InjectionToken('VERSION_MODULE_CONFIG');
20829
+ /**
20830
+ * You can either provide a single `Version` as parameter:
20831
+ * ```typescript
20832
+ * hookVersion(...)
20833
+ * ```
20834
+ *
20835
+ * Or an array to directly register multiple:
20836
+ * ```typescript
20837
+ * hookVersion([...])
20838
+ * ```
20839
+ *
20840
+ * Or you provide an Service that implements `ExtensionFactory<Version>`
20841
+ * ```typescript
20842
+ * export class MyVersionFactory implements ExtensionFactory<Version> {...}
20843
+ * ...
20844
+ * hookVersion(MyVersionFactory)
20845
+ * ```
20846
+ * A typed alternative to `HOOK_VERSION`.
20847
+ * @param versions The `Version`'s or `ExtensionFactory` to be provided.
20848
+ * @returns An `Provider` to be provided in your module.
20849
+ */
20850
+ function hookVersion(versions, options) {
20851
+ return hookGeneric(versions, HOOK_VERSION, options);
20852
+ }
20853
+
20854
+ /**
20855
+ * Will provide the backend versions of the tenant.
20856
+ * The system option 'system' -> 'version' is used for this.
20857
+ */
20858
+ class BackendVersionFactory {
20859
+ constructor(config, appState) {
20860
+ this.config = config;
20861
+ this.appState = appState;
20862
+ this.backendVersion$ = of([]);
20863
+ if (this.config?.disableBackendVersionFactory) {
20865
20864
  return;
20866
20865
  }
20867
- const importContextPaths = Object.keys(remotes);
20868
- const plugins = [];
20869
- importContextPaths.forEach(contextPath => {
20870
- const moduleNames = remotes[contextPath] || [];
20871
- plugins.push(...moduleNames.map(module => PluginsService.createPluginId(contextPath, module, '', true)));
20872
- });
20873
- return plugins;
20866
+ this.backendVersion$ = this.appState.state$.pipe(map(state => state?.versions?.backend), filter(backendVersion => !!backendVersion), distinctUntilChanged(), map(backendVersion => this.buildBackendVersion(backendVersion)), shareReplay(1));
20874
20867
  }
20875
- static createPluginId(contextPath, plugin, version, useLatest = false) {
20876
- const moduleName = typeof plugin === 'string' ? plugin : plugin.module;
20877
- if (useLatest) {
20878
- return `${contextPath}/${moduleName}`;
20879
- }
20880
- return `${contextPath}@${version}/${moduleName}`;
20868
+ get() {
20869
+ return this.backendVersion$;
20881
20870
  }
20882
- constructor(applicationService, appStateService, client) {
20883
- this.applicationService = applicationService;
20884
- this.appStateService = appStateService;
20885
- this.client = client;
20871
+ buildBackendVersion(backendVersion) {
20872
+ return {
20873
+ label: gettext$1('Backend'),
20874
+ version: backendVersion,
20875
+ priority: 20,
20876
+ type: 'SYSTEM',
20877
+ hidden: true
20878
+ };
20886
20879
  }
20887
- /**
20888
- * Fetches a list of available packages.
20889
- * @param params Additional query parameters.
20890
- * @returns Returns a list of packages.
20891
- */
20892
- async listPackages(params = {}) {
20893
- const apps = await this.listApplicationsByCurrentTenant(params);
20894
- const webApps = apps.filter(app => this.isPackage(app));
20895
- const uniqueWebApps = this.removeDuplicates(webApps, 'contextPath');
20896
- return uniqueWebApps.sort((a, b) => a.name.localeCompare(b.name));
20880
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BackendVersionFactory, deps: [{ token: VERSION_MODULE_CONFIG, optional: true }, { token: AppStateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
20881
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BackendVersionFactory, providedIn: 'root' }); }
20882
+ }
20883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BackendVersionFactory, decorators: [{
20884
+ type: Injectable,
20885
+ args: [{
20886
+ providedIn: 'root'
20887
+ }]
20888
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
20889
+ type: Optional
20890
+ }, {
20891
+ type: Inject,
20892
+ args: [VERSION_MODULE_CONFIG]
20893
+ }] }, { type: AppStateService }] });
20894
+
20895
+ class VersionService extends ExtensionPointForPlugins {
20896
+ constructor(rootInjector, pluginService) {
20897
+ super(rootInjector, pluginService);
20898
+ this.items$ = this.setupItemsObservable();
20899
+ this.nonHiddenItems$ = this.items$.pipe(map(versions => versions.filter(version => !version.hidden)));
20897
20900
  }
20898
- /**
20899
- * Checks if an application is a package.
20900
- * @param application Application managed object.
20901
- * @returns Returns true if the application is a package.
20902
- */
20903
- isPackage(application) {
20904
- return application.manifest?.isPackage === true;
20901
+ get state() {
20902
+ return this.state$.value;
20905
20903
  }
20906
- /**
20907
- * Updates the remotes field in the application configuration by adding new plugins.
20908
- * Important: if the remotes object is not set on the configuration object,
20909
- * remotes will not be added. Make sure that this object exists in the application configuration.
20910
- * @param application Application managed object.
20911
- * @param plugins List of remotes to be added.
20912
- * @returns Returns updated application remotes.
20913
- */
20914
- async addRemotes(application, plugins) {
20915
- const pluginsArray = Array.isArray(plugins) ? plugins : [plugins];
20916
- const manifestRemotes = application.manifest?.remotes || {};
20917
- const appConfig = application?.config;
20918
- const appConfigRemotes = appConfig?.remotes || manifestRemotes;
20919
- const appConfigExcludedRemotes = appConfig?.excludedRemotes || {};
20920
- // only normal and self optional scoped plugins should be added to remotes
20921
- // self scoped plugins will be automatically added
20922
- const allPluginsExceptSelfScoped = this.getAllPluginsExceptSelfScoped(pluginsArray, application.contextPath);
20923
- const newRemotes = this.addPluginToRemotesConfig(appConfigRemotes, allPluginsExceptSelfScoped);
20924
- // should be unproblematic to remove all categories of plugins from excluded remotes
20925
- const newExcludedRemotes = this.removePluginsFromRemotesConfig(appConfigExcludedRemotes, plugins);
20926
- return await this.updateRemotesInAppConfig(application, newRemotes, newExcludedRemotes);
20904
+ add(version) {
20905
+ this.state.add(version);
20906
+ this.emitNewState();
20927
20907
  }
20928
- /**
20929
- * Updates the remotes field in the application configuration by removing plugins.
20930
- * @param application Application managed object.
20931
- * @param plugins List of remotes to be removed.
20932
- * @returns Returns updated application remotes.
20933
- */
20934
- async removeRemotes(application, plugins) {
20935
- const pluginsArray = Array.isArray(plugins) ? plugins : [plugins];
20936
- const manifestRemotes = application.manifest?.remotes || {};
20937
- const appConfig = application?.config;
20938
- const appConfigRemotes = appConfig?.remotes || manifestRemotes;
20939
- const appConfigExcludedRemotes = appConfig?.excludedRemotes || {};
20940
- // app plugins need to be removed from remotes
20941
- const newRemotes = this.removePluginsFromRemotesConfig(appConfigRemotes, plugins);
20942
- // self scoped plugins need to be added to excluded remotes
20943
- // as they would be otherwise automatically added to remotes
20944
- const selfScopedPlugins = this.getSelfScopedPlugins(pluginsArray, application.contextPath);
20945
- const newExcludedRemotes = this.addPluginToRemotesConfig(appConfigExcludedRemotes, selfScopedPlugins);
20946
- return await this.updateRemotesInAppConfig(application, newRemotes, newExcludedRemotes);
20908
+ remove(version) {
20909
+ this.state.delete(version);
20910
+ this.emitNewState();
20947
20911
  }
20948
- /**
20949
- * Updates the remotes field in the application configuration.
20950
- * @param application Application managed object.
20951
- * @param plugins List of remotes to be added.
20952
- * @returns Returns updated application remotes.
20953
- */
20954
- async updateRemotesInAppConfig(application, plugins, excludedRemotes) {
20955
- const updatedAppWithConfig = await this.applicationService.updateApplicationConfig(application, {
20956
- remotes: plugins,
20957
- excludedRemotes: excludedRemotes || {}
20958
- });
20959
- return updatedAppWithConfig?.config || { remotes: {} };
20912
+ cleanUpVersions(versions) {
20913
+ return versions.map(version => pick(version, 'label', 'version', 'type', 'custom'));
20960
20914
  }
20961
- /**
20962
- * Fetches the application manifest.
20963
- * @param application Application managed object.
20964
- * @returns Returns the application manifest.
20965
- */
20966
- async getCumulocityJsonFile(application) {
20967
- const c8yJson = await this.applicationService.getAppManifest(application);
20968
- if (!c8yJson.remotes) {
20969
- c8yJson.remotes = {};
20970
- }
20971
- return c8yJson;
20915
+ setupItemsObservable() {
20916
+ return fromTriggerOnce(undefined, this.refresh$, [
20917
+ getInjectedHooks(HOOK_VERSION, this.injectors),
20918
+ () => this.factories,
20919
+ stateToFactory(this.state$)
20920
+ ]).pipe(distinctUntilChanged(), map(versions => sortByPriority(versions)), shareReplay(1));
20972
20921
  }
20973
- /**
20974
- * Sets the initial state of remotes in the configuration (when it's missing), based on the list of remotes being in the application manifest.
20975
- * @param application Application managed object.
20976
- * @returns Returns a list of remotes that has been assigned to the configuration object.
20977
- */
20978
- async setInitialRemotes(application) {
20979
- try {
20980
- const manifest = await this.getCumulocityJsonFile(application);
20981
- const manifestRemotes = manifest.remotes;
20982
- return await this.updateRemotesInAppConfig(application, manifestRemotes || {}, {});
20983
- }
20984
- catch (er) {
20985
- return undefined;
20986
- }
20922
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionService, deps: [{ token: i0.Injector }, { token: PluginsResolveService }], target: i0.ɵɵFactoryTarget.Injectable }); }
20923
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionService, providedIn: 'root' }); }
20924
+ }
20925
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionService, decorators: [{
20926
+ type: Injectable,
20927
+ args: [{
20928
+ providedIn: 'root'
20929
+ }]
20930
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: PluginsResolveService }] });
20931
+
20932
+ class PlatformDetailsService {
20933
+ constructor(version, appState, apps) {
20934
+ this.version = version;
20935
+ this.appState = appState;
20936
+ this.apps = apps;
20987
20937
  }
20988
- async resetRemotes(application) {
20989
- return await this.applicationService.updateApplicationConfig(application, {
20990
- remotes: undefined,
20991
- excludedRemotes: undefined
20992
- });
20938
+ async getPlatformDetailsObject() {
20939
+ const currentUser = this.appState.currentUser.value;
20940
+ const userId = currentUser?.id;
20941
+ const userPermissions = this.getUserPermissions(currentUser);
20942
+ const [hookedVersions, microserviceVersions] = await Promise.all([
20943
+ this.getVersions(),
20944
+ this.getMicroserviceVersions(userId)
20945
+ ]);
20946
+ const versions = [...hookedVersions, ...microserviceVersions];
20947
+ const groupedVersions = groupBy(versions, 'type');
20948
+ const tenantId = this.appState.currentTenant.value?.name;
20949
+ // useful as `domainName` might be pointing to a custom domain
20950
+ // self link should still allow to identify the actual environment of the tenant
20951
+ const tenantSelfLink = this.appState.currentTenant.value?.self;
20952
+ const tenantDomainName = this.appState.currentTenant.value?.domainName;
20953
+ const applicationKey = this.appState.currentApplication.value?.key;
20954
+ const applicationId = this.appState.currentApplication.value?.id;
20955
+ const time = new Date().toISOString();
20956
+ const url = document.URL;
20957
+ const obj = {
20958
+ time,
20959
+ tenantId,
20960
+ tenantSelfLink,
20961
+ tenantDomainName,
20962
+ url,
20963
+ userId,
20964
+ userPermissions,
20965
+ applicationId,
20966
+ applicationKey,
20967
+ versions: groupedVersions
20968
+ };
20969
+ return obj;
20993
20970
  }
20994
- sortVersions(source, order) {
20995
- const sourceCopy = cloneDeep(source);
20996
- if (source.list && source.path) {
20997
- const path = sourceCopy.path.join('.');
20998
- return sourceCopy.list.sort((a, b) => compare(coerce(get(a, path)), coerce(get(b, path))) * (order === 'asc' ? 1 : -1));
20971
+ async getVersions() {
20972
+ const versions = await this.version.items$
20973
+ .pipe(take(1), map(versions => this.version.cleanUpVersions(versions)))
20974
+ .toPromise();
20975
+ return versions;
20976
+ }
20977
+ async getMicroserviceVersions(userId) {
20978
+ try {
20979
+ const { data: apps } = await this.apps.listByUser(userId, {
20980
+ pageSize: 2000,
20981
+ dropOverwrittenApps: true,
20982
+ noPaging: true
20983
+ });
20984
+ return apps
20985
+ .filter(app => !!app.manifest?.version && app.type === ApplicationType.MICROSERVICE)
20986
+ .map(app => {
20987
+ return {
20988
+ label: app.name,
20989
+ version: app.manifest.version,
20990
+ type: app.type,
20991
+ custom: {
20992
+ owner: app.owner?.tenant?.id,
20993
+ provider: app.manifest?.provider
20994
+ }
20995
+ };
20996
+ });
20999
20997
  }
21000
- else {
21001
- return sourceCopy.sort((a, b) => compare(coerce(a), coerce(b)) * (order === 'asc' ? 1 : -1));
20998
+ catch (e) {
20999
+ console.warn(e);
21000
+ return [];
21002
21001
  }
21003
21002
  }
21004
- /**
21005
- * Extracts a list of exported plugins from the application object.
21006
- * @param application Application managed object.
21007
- * @param useLatest Set this to true, to not bind the plugin to any version.
21008
- * @returns Returns a list of exported plugins.
21009
- */
21010
- getMFExports(application, excludedScopes = [
21011
- PluginsExportScopes.SELF,
21012
- PluginsExportScopes.SELF_OPTIONAL,
21013
- PluginsExportScopes.GLOBAL
21014
- ], useLatest = false) {
21015
- const manifest = application.manifest;
21016
- if (!manifest || !manifest.exports) {
21017
- return [];
21003
+ getUserPermissions(user) {
21004
+ if (!user) {
21005
+ return null;
21018
21006
  }
21019
- return this.extendPluginsDetails(application, {
21020
- version: manifest.version,
21021
- binaryId: undefined
21022
- }, useLatest).filter(plugin => !excludedScopes.includes(plugin.scope));
21007
+ const userPermissions = this.getDirectPermissionsOfUser(user);
21008
+ const groupPermissions = this.getPermissionsOfAssignedGroups(user);
21009
+ return { user: userPermissions, groups: groupPermissions };
21023
21010
  }
21024
- /**
21025
- * Extracts a list of exports from each available package.
21026
- * @param allVersions If set to true, all and not only latest versions are included.
21027
- * @param excludedScopes Defines which scopes should not be loaded.
21028
- * @returns Returns a list of all exported plugins.
21029
- */
21030
- async getAllMFExports(allVersions = false, excludedScopes = [
21031
- PluginsExportScopes.SELF,
21032
- PluginsExportScopes.SELF_OPTIONAL,
21033
- PluginsExportScopes.GLOBAL
21034
- ]) {
21035
- const plugins = new Array();
21036
- const packages = await this.listPackages();
21037
- for (const pkg of packages) {
21038
- if (!pkg?.manifest?.exports) {
21039
- continue;
21040
- }
21041
- if (allVersions && Array.isArray(pkg.applicationVersions)) {
21042
- pkg.applicationVersions.forEach(version => {
21043
- plugins.push(...this.extendPluginsDetails(pkg, version));
21044
- });
21011
+ getDirectPermissionsOfUser(user) {
21012
+ const userChangedType = user;
21013
+ const userRoleReferences = userChangedType.roles?.references || [];
21014
+ return userRoleReferences.map(ref => ref.role.id);
21015
+ }
21016
+ getPermissionsOfAssignedGroups(user) {
21017
+ const groups = user.groups?.references || [];
21018
+ return groups.map(ref => {
21019
+ const roleReferences = ref.group?.roles?.references || [];
21020
+ const permissions = roleReferences.map(ref => ref.role.id);
21021
+ return {
21022
+ id: ref.group.id,
21023
+ name: ref.group.name,
21024
+ permissions
21025
+ };
21026
+ });
21027
+ }
21028
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformDetailsService, deps: [{ token: VersionService }, { token: AppStateService }, { token: i1.ApplicationService }], target: i0.ɵɵFactoryTarget.Injectable }); }
21029
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformDetailsService, providedIn: 'root' }); }
21030
+ }
21031
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformDetailsService, decorators: [{
21032
+ type: Injectable,
21033
+ args: [{ providedIn: 'root' }]
21034
+ }], ctorParameters: () => [{ type: VersionService }, { type: AppStateService }, { type: i1.ApplicationService }] });
21035
+
21036
+ class VersionListComponent {
21037
+ constructor(version, appState, clipboardService, modalService, platformDetails, headerService) {
21038
+ this.version = version;
21039
+ this.appState = appState;
21040
+ this.clipboardService = clipboardService;
21041
+ this.modalService = modalService;
21042
+ this.platformDetails = platformDetails;
21043
+ this.headerService = headerService;
21044
+ this.versionsToDirectlyDisplay$ = this.version.nonHiddenItems$;
21045
+ this.currentTenantId$ = this.appState.currentTenant.pipe(map(tenant => tenant?.name), filter(tenantId => !!tenantId), distinctUntilChanged());
21046
+ this.open$ = this.headerService.rightDrawerOpen$;
21047
+ }
21048
+ async downloadPlatformDetails() {
21049
+ const obj = await this.platformDetails.getPlatformDetailsObject();
21050
+ const json = JSON.stringify(obj, undefined, 2);
21051
+ const blob = new Blob([json]);
21052
+ saveAs$1(blob, 'platform-details.json');
21053
+ }
21054
+ copyIt(text) {
21055
+ this.clipboardService.writeText(text);
21056
+ }
21057
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionListComponent, deps: [{ token: VersionService }, { token: AppStateService }, { token: ClipboardService }, { token: i1$7.BsModalService }, { token: PlatformDetailsService }, { token: HeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
21058
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: VersionListComponent, isStandalone: true, selector: "c8y-version-list", ngImport: i0, template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"c8y-c8y-c\"></i>\n <span class=\"text-bold\">{{ 'Platform info' | translate }}</span>\n </div>\n\n <ul class=\"list-unstyled\">\n <li\n class=\"c8y-right-drawer__item\"\n *ngIf=\"currentTenantId$ | async as tenantId\"\n >\n <span\n class=\"flex-grow text-muted m-0 text-12 text-truncate\"\n translate\n >\n Tenant ID\n </span>\n <button\n class=\"m-l-auto flex-no-shrink btn-clean p-0 btn-link\"\n title=\"{{ 'Copy tenant ID to the clipboard' | translate }}\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); copyIt(tenantId)\"\n >\n {{ tenantId }}\n <i\n class=\"text-14 m-0\"\n [c8yIcon]=\"'clipboard'\"\n ></i>\n </button>\n </li>\n <li\n class=\"c8y-right-drawer__item\"\n *ngFor=\"let versionEntry of versionsToDirectlyDisplay$ | async\"\n >\n <span\n class=\"flex-no-shrink text-muted text-12 text-truncate m-r-8\"\n [title]=\"versionEntry.label | translate\"\n >\n {{ versionEntry.label | translate }}\n </span>\n <span\n class=\"flex-grow text-right text-truncate\"\n [title]=\"versionEntry.version | translate\"\n >\n {{ versionEntry.version }}\n </span>\n </li>\n <li class=\"c8y-right-drawer__item\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n title=\"{{ 'Download platform details' | translate }}\"\n (click)=\"downloadPlatformDetails()\"\n >\n <i c8yIcon=\"download\" class=\"m-t-0 m-b-0 text-14\"></i>\n <span translate>Download platform details</span>\n </button>\n </li>\n </ul>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
21059
+ }
21060
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionListComponent, decorators: [{
21061
+ type: Component,
21062
+ args: [{ selector: 'c8y-version-list', standalone: true, imports: [IconDirective, NgIf, C8yTranslateDirective, NgFor, C8yTranslatePipe, AsyncPipe], template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"c8y-c8y-c\"></i>\n <span class=\"text-bold\">{{ 'Platform info' | translate }}</span>\n </div>\n\n <ul class=\"list-unstyled\">\n <li\n class=\"c8y-right-drawer__item\"\n *ngIf=\"currentTenantId$ | async as tenantId\"\n >\n <span\n class=\"flex-grow text-muted m-0 text-12 text-truncate\"\n translate\n >\n Tenant ID\n </span>\n <button\n class=\"m-l-auto flex-no-shrink btn-clean p-0 btn-link\"\n title=\"{{ 'Copy tenant ID to the clipboard' | translate }}\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); copyIt(tenantId)\"\n >\n {{ tenantId }}\n <i\n class=\"text-14 m-0\"\n [c8yIcon]=\"'clipboard'\"\n ></i>\n </button>\n </li>\n <li\n class=\"c8y-right-drawer__item\"\n *ngFor=\"let versionEntry of versionsToDirectlyDisplay$ | async\"\n >\n <span\n class=\"flex-no-shrink text-muted text-12 text-truncate m-r-8\"\n [title]=\"versionEntry.label | translate\"\n >\n {{ versionEntry.label | translate }}\n </span>\n <span\n class=\"flex-grow text-right text-truncate\"\n [title]=\"versionEntry.version | translate\"\n >\n {{ versionEntry.version }}\n </span>\n </li>\n <li class=\"c8y-right-drawer__item\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n title=\"{{ 'Download platform details' | translate }}\"\n (click)=\"downloadPlatformDetails()\"\n >\n <i c8yIcon=\"download\" class=\"m-t-0 m-b-0 text-14\"></i>\n <span translate>Download platform details</span>\n </button>\n </li>\n </ul>\n</div>\n" }]
21063
+ }], ctorParameters: () => [{ type: VersionService }, { type: AppStateService }, { type: ClipboardService }, { type: i1$7.BsModalService }, { type: PlatformDetailsService }, { type: HeaderService }] });
21064
+
21065
+ class VersionDrawerFactory {
21066
+ constructor(options) {
21067
+ this.options = options;
21068
+ this.drawerItem = {
21069
+ component: VersionListComponent,
21070
+ position: 'right',
21071
+ priority: 80,
21072
+ id: 'platformInformation'
21073
+ };
21074
+ }
21075
+ get() {
21076
+ return this.shouldShowPlatformInformation$().pipe(distinctUntilChanged(), map(shouldShowPlatformInformation => {
21077
+ if (shouldShowPlatformInformation) {
21078
+ return this.drawerItem;
21045
21079
  }
21046
- else {
21047
- plugins.push(...this.extendPluginsDetails(pkg, {
21048
- version: pkg.manifest.version,
21049
- binaryId: undefined
21050
- }));
21080
+ return [];
21081
+ }));
21082
+ }
21083
+ shouldShowPlatformInformation$() {
21084
+ return combineLatest([
21085
+ this.options.get$('hidePowered'),
21086
+ this.options.get$('hidePlatformInformation')
21087
+ ]).pipe(map(([hidePowered, hidePlatformInformation]) => {
21088
+ if (hidePlatformInformation === undefined) {
21089
+ return !hidePowered;
21051
21090
  }
21052
- }
21053
- return plugins.filter(plugin => !excludedScopes.includes(plugin.scope));
21091
+ return !hidePlatformInformation;
21092
+ }));
21054
21093
  }
21094
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionDrawerFactory, deps: [{ token: OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
21095
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionDrawerFactory }); }
21096
+ }
21097
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionDrawerFactory, decorators: [{
21098
+ type: Injectable
21099
+ }], ctorParameters: () => [{ type: OptionsService }] });
21100
+
21101
+ var ApplicationPluginStatus;
21102
+ (function (ApplicationPluginStatus) {
21103
+ ApplicationPluginStatus["ORPHANED"] = "ORPHANED";
21104
+ ApplicationPluginStatus["LATEST"] = "LATEST";
21105
+ ApplicationPluginStatus["OUTDATED"] = "OUTDATED";
21106
+ ApplicationPluginStatus["REVOKED"] = "REVOKED";
21107
+ ApplicationPluginStatus["AUTO"] = "AUTO";
21108
+ })(ApplicationPluginStatus || (ApplicationPluginStatus = {}));
21109
+ var PackageType;
21110
+ (function (PackageType) {
21055
21111
  /**
21056
- * Extracts a list of remotes from the application object.
21057
- * @param application Application managed object.
21058
- * @returns Returns list of remotes.
21112
+ * A package coming from the official Cumulocity github enterprise.
21059
21113
  */
21060
- getMFRemotes(application) {
21061
- const manifest = application.manifest || {};
21062
- const config = application?.config;
21063
- let remotes = config?.remotes || manifest.remotes || {};
21064
- const manifestExports = manifest.exports || manifest.manifest?.exports || [];
21065
- const selfRemotes = manifestExports
21066
- .filter(plugin => plugin.scope === PluginsExportScopes.SELF)
21067
- .map(plugin => plugin.module || plugin.name);
21068
- if (selfRemotes.length) {
21069
- remotes = mergeRemotes([{ [application.contextPath]: selfRemotes }, remotes]);
21070
- }
21071
- remotes = removeRemotes(remotes, config?.excludedRemotes);
21072
- return remotes;
21073
- }
21114
+ PackageType["OFFICIAL"] = "OFFICIAL";
21074
21115
  /**
21075
- * Determines the type of a package.
21076
- * A package is OFFICIAL if it comes from management tenant and has a label attached called OFFICIAL.
21077
- * A package is COMMUNITY if it has a label called COMMUNITY.
21078
- * A package is CUSTOM if it does not have any label attached.
21079
- * A package is UNKNOWN if it has a label attached but it does not match COMMUNITY or OFFICIAL.
21080
- *
21081
- * Labels can be used to identify the status of a package. Community packages always need
21082
- * a license validation. The label will be shown on the application card to tell a user
21083
- * whether they are looking into an official or community package.
21084
- *
21085
- * @param packageApplication The package application object to check.
21086
- * @returns The package type.
21116
+ * A package coming from any connected partner repository.
21087
21117
  */
21088
- getPackageType(packageApplication) {
21089
- const label = packageApplication.label || packageApplication.manifest?.label;
21090
- if (label === PackageType.ARCHIVED) {
21091
- return PackageType.ARCHIVED;
21092
- }
21093
- if (!label) {
21094
- return PackageType.CUSTOM;
21095
- }
21096
- if (label === PackageType.OFFICIAL && this.isOwnedByManagement(packageApplication)) {
21097
- return PackageType.OFFICIAL;
21098
- }
21099
- if (label === PackageType.COMMUNITY) {
21100
- return PackageType.COMMUNITY;
21101
- }
21102
- return PackageType.UNKNOWN;
21103
- }
21118
+ PackageType["COMMUNITY"] = "COMMUNITY";
21104
21119
  /**
21105
- * Verifies if an application is owned by management tenant.
21106
- *
21107
- * @param app The application to verify.
21108
- * @returns True if owned by management tenant.
21120
+ * A package where the origin is unknown (e.g. uploaded to management with an unknown label)
21109
21121
  */
21110
- isOwnedByManagement(app) {
21111
- const appOwner = get(app, 'owner.tenant.id');
21112
- return appOwner === 'management';
21113
- }
21114
- pluginsFromManifest(manifest) {
21115
- const plugins = manifest.exports;
21116
- const extendedPlugins = plugins
21117
- .filter(p => p.scope === PluginsExportScopes.SELF)
21118
- .map(p => ({
21119
- ...p,
21120
- id: PluginsService.createPluginId(manifest.contextPath, p, manifest.version),
21121
- contextPath: manifest.contextPath,
21122
- version: manifest.version,
21123
- versioningMatrix: manifest.versioningMatrix,
21124
- license: manifest.license,
21125
- type: PackageType.CUSTOM
21126
- }));
21127
- return extendedPlugins;
21128
- }
21129
- async getReadmeFileContent(baseUrl) {
21130
- return this.getFileContent(baseUrl, 'readme');
21131
- }
21132
- async getChangelogFileContent(baseUrl) {
21133
- return this.getFileContent(baseUrl, 'changelog');
21134
- }
21135
- async getFileContent(baseUrl, fileType) {
21136
- const file = await this.getFile(baseUrl, fileType);
21137
- if (file.status === 200) {
21138
- return await file.text();
21122
+ PackageType["UNKNOWN"] = "UNKNOWN";
21123
+ /**
21124
+ * A custom package e.g. uploaded to the tenant by a user
21125
+ */
21126
+ PackageType["CUSTOM"] = "CUSTOM";
21127
+ /**
21128
+ * A package that was archived by the user
21129
+ */
21130
+ PackageType["ARCHIVED"] = "ARCHIVED";
21131
+ })(PackageType || (PackageType = {}));
21132
+
21133
+ class PluginsService {
21134
+ static convertInstalledRemotesToIds(remotes) {
21135
+ if (!remotes) {
21136
+ return;
21139
21137
  }
21140
- return '';
21138
+ const importContextPaths = Object.keys(remotes);
21139
+ const plugins = [];
21140
+ importContextPaths.forEach(contextPath => {
21141
+ const moduleNames = remotes[contextPath] || [];
21142
+ plugins.push(...moduleNames.map(module => PluginsService.createPluginId(contextPath, module, '', true)));
21143
+ });
21144
+ return plugins;
21141
21145
  }
21142
- async getFile(baseUrl, fileType) {
21143
- const options = {
21144
- method: 'GET',
21145
- headers: { 'Content-Type': 'text/markdown' }
21146
- };
21147
- const uppercaseFilename = fileType === 'readme' ? 'README.md' : 'CHANGELOG.md';
21148
- let result = await this.client.fetch(`${baseUrl}${uppercaseFilename}`, options);
21149
- if (result && result.status === 404) {
21150
- result = await this.client.fetch(`${baseUrl}${uppercaseFilename.toLowerCase()}`, options);
21146
+ static createPluginId(contextPath, plugin, version, useLatest = false) {
21147
+ const moduleName = typeof plugin === 'string' ? plugin : plugin.module;
21148
+ if (useLatest) {
21149
+ return `${contextPath}/${moduleName}`;
21151
21150
  }
21152
- return result;
21153
- }
21154
- isSelfScopedPlugin(plugin, contextPath) {
21155
- return (plugin.scope === PluginsExportScopes.SELF &&
21156
- (!contextPath || plugin.contextPath === contextPath));
21157
- }
21158
- getSelfScopedPlugins(plugins, contextPath) {
21159
- return plugins.filter(plugin => this.isSelfScopedPlugin(plugin, contextPath));
21151
+ return `${contextPath}@${version}/${moduleName}`;
21160
21152
  }
21161
- getAllPluginsExceptSelfScoped(plugins, contextPath) {
21162
- return plugins.filter(plugin => !this.isSelfScopedPlugin(plugin, contextPath));
21153
+ constructor(applicationService, appStateService, client) {
21154
+ this.applicationService = applicationService;
21155
+ this.appStateService = appStateService;
21156
+ this.client = client;
21163
21157
  }
21164
- removeDuplicates(apps, key) {
21165
- const uniqueList = [];
21166
- const groupedAppsByKey = groupBy(apps, key);
21167
- const groupedApps = Object.keys(groupedAppsByKey).map(key => groupedAppsByKey[key]);
21168
- for (const appsGroup of groupedApps) {
21169
- if (appsGroup.length < 2) {
21170
- uniqueList.push(...appsGroup);
21171
- }
21172
- else {
21173
- const appFromCurrentTenant = appsGroup.find(app => this.isFromCurrentTenant(app));
21174
- if (appFromCurrentTenant) {
21175
- uniqueList.push(appFromCurrentTenant);
21176
- continue;
21177
- }
21178
- const appNotOwnedByManagement = appsGroup.find(app => !this.isOwnedByManagement(app));
21179
- uniqueList.push(appNotOwnedByManagement);
21180
- }
21181
- }
21182
- return uniqueList;
21158
+ /**
21159
+ * Fetches a list of available packages.
21160
+ * @param params Additional query parameters.
21161
+ * @returns Returns a list of packages.
21162
+ */
21163
+ async listPackages(params = {}) {
21164
+ const apps = await this.listApplicationsByCurrentTenant(params);
21165
+ const webApps = apps.filter(app => this.isPackage(app));
21166
+ const uniqueWebApps = this.removeDuplicates(webApps, 'contextPath');
21167
+ return uniqueWebApps.sort((a, b) => a.name.localeCompare(b.name));
21183
21168
  }
21184
- isFromCurrentTenant(app) {
21185
- return app.owner.tenant.id === this.appStateService.currentTenant.value.name;
21169
+ /**
21170
+ * Checks if an application is a package.
21171
+ * @param application Application managed object.
21172
+ * @returns Returns true if the application is a package.
21173
+ */
21174
+ isPackage(application) {
21175
+ return application.manifest?.isPackage === true;
21186
21176
  }
21187
21177
  /**
21188
- * Modifies the list of plugins to have additional information such as id.
21189
- * @ignore
21178
+ * Updates the remotes field in the application configuration by adding new plugins.
21179
+ * Important: if the remotes object is not set on the configuration object,
21180
+ * remotes will not be added. Make sure that this object exists in the application configuration.
21181
+ * @param application Application managed object.
21182
+ * @param plugins List of remotes to be added.
21183
+ * @returns Returns updated application remotes.
21190
21184
  */
21191
- extendPluginsDetails(application, version, useLatest = false) {
21192
- const plugins = application.manifest.exports;
21193
- const extendedPlugins = plugins.map(p => ({
21194
- ...p,
21195
- id: PluginsService.createPluginId(application.contextPath, p, version.version, useLatest),
21196
- idLatest: PluginsService.createPluginId(application.contextPath, p, version.version, true),
21197
- contextPath: application.contextPath,
21198
- version: version.version,
21199
- versioningMatrix: application.manifest.versioningMatrix,
21200
- tags: useLatest ? ['latest'] : version.tags || [],
21201
- license: application.manifest.license,
21202
- type: this.getPackageType(application),
21203
- originApp: application
21204
- }));
21205
- return extendedPlugins;
21185
+ async addRemotes(application, plugins) {
21186
+ const pluginsArray = Array.isArray(plugins) ? plugins : [plugins];
21187
+ const manifestRemotes = application.manifest?.remotes || {};
21188
+ const appConfig = application?.config;
21189
+ const appConfigRemotes = appConfig?.remotes || manifestRemotes;
21190
+ const appConfigExcludedRemotes = appConfig?.excludedRemotes || {};
21191
+ // only normal and self optional scoped plugins should be added to remotes
21192
+ // self scoped plugins will be automatically added
21193
+ const allPluginsExceptSelfScoped = this.getAllPluginsExceptSelfScoped(pluginsArray, application.contextPath);
21194
+ const newRemotes = this.addPluginToRemotesConfig(appConfigRemotes, allPluginsExceptSelfScoped);
21195
+ // should be unproblematic to remove all categories of plugins from excluded remotes
21196
+ const newExcludedRemotes = this.removePluginsFromRemotesConfig(appConfigExcludedRemotes, plugins);
21197
+ return await this.updateRemotesInAppConfig(application, newRemotes, newExcludedRemotes);
21206
21198
  }
21207
- async listApplicationsByCurrentTenant(params = {}) {
21208
- const filter = Object.assign({
21209
- type: 'HOSTED',
21210
- pageSize: 2000,
21211
- withTotalPages: true
21212
- }, params);
21213
- const sharedFilter = Object.assign({
21214
- availability: ApplicationAvailability.SHARED,
21215
- type: 'HOSTED',
21216
- pageSize: 2000,
21217
- withTotalPages: true
21218
- }, params);
21219
- const tenantName = this.appStateService.currentTenant.value.name;
21220
- const [resultAppsOwnedByTenant, resultSharedApps] = await Promise.all([
21221
- this.applicationService.listByTenant(tenantName, filter),
21222
- this.applicationService.list(sharedFilter)
21223
- ]);
21224
- const { data: appsOwnedByTenant } = resultAppsOwnedByTenant;
21225
- const { data: sharedApps } = resultSharedApps;
21226
- const webApps = [...appsOwnedByTenant, ...sharedApps];
21227
- return uniqBy(webApps, (app) => app.id);
21199
+ /**
21200
+ * Updates the remotes field in the application configuration by removing plugins.
21201
+ * @param application Application managed object.
21202
+ * @param plugins List of remotes to be removed.
21203
+ * @returns Returns updated application remotes.
21204
+ */
21205
+ async removeRemotes(application, plugins) {
21206
+ const pluginsArray = Array.isArray(plugins) ? plugins : [plugins];
21207
+ const manifestRemotes = application.manifest?.remotes || {};
21208
+ const appConfig = application?.config;
21209
+ const appConfigRemotes = appConfig?.remotes || manifestRemotes;
21210
+ const appConfigExcludedRemotes = appConfig?.excludedRemotes || {};
21211
+ // app plugins need to be removed from remotes
21212
+ const newRemotes = this.removePluginsFromRemotesConfig(appConfigRemotes, plugins);
21213
+ // self scoped plugins need to be added to excluded remotes
21214
+ // as they would be otherwise automatically added to remotes
21215
+ const selfScopedPlugins = this.getSelfScopedPlugins(pluginsArray, application.contextPath);
21216
+ const newExcludedRemotes = this.addPluginToRemotesConfig(appConfigExcludedRemotes, selfScopedPlugins);
21217
+ return await this.updateRemotesInAppConfig(application, newRemotes, newExcludedRemotes);
21228
21218
  }
21229
- addPluginToRemotesConfig(remotesConfig, plugins) {
21230
- if (!plugins) {
21231
- return;
21232
- }
21233
- const remotesCopy = cloneDeep(remotesConfig);
21234
- const temp = Array.isArray(plugins) ? plugins : [plugins];
21235
- temp.forEach(plugin => {
21236
- const { contextPath, moduleName } = this.parsePluginId(plugin.id);
21237
- if (!contextPath || !moduleName) {
21238
- return;
21239
- }
21240
- remotesCopy[contextPath]?.length >= 0
21241
- ? remotesCopy[contextPath].push(moduleName)
21242
- : (remotesCopy[contextPath] = []).push(moduleName);
21243
- remotesCopy[contextPath] = [...new Set(remotesCopy[contextPath])];
21219
+ /**
21220
+ * Updates the remotes field in the application configuration.
21221
+ * @param application Application managed object.
21222
+ * @param plugins List of remotes to be added.
21223
+ * @returns Returns updated application remotes.
21224
+ */
21225
+ async updateRemotesInAppConfig(application, plugins, excludedRemotes) {
21226
+ const updatedAppWithConfig = await this.applicationService.updateApplicationConfig(application, {
21227
+ remotes: plugins,
21228
+ excludedRemotes: excludedRemotes || {}
21244
21229
  });
21245
- return remotesCopy;
21230
+ return updatedAppWithConfig?.config || { remotes: {} };
21246
21231
  }
21247
- removePluginsFromRemotesConfig(remotesConfig, plugins) {
21248
- const remotesCopy = cloneDeep(remotesConfig);
21249
- const temp = Array.isArray(plugins) ? plugins : [plugins];
21250
- temp.forEach(plugin => {
21251
- const { rawContextPath, moduleName } = this.parsePluginId(plugin.id);
21252
- if (!rawContextPath || !moduleName) {
21253
- return;
21254
- }
21255
- // Find all keys in remotesConfig that match the plugin context (regardless of version)
21256
- Object.keys(remotesCopy).forEach(key => {
21257
- if (key === rawContextPath || key.startsWith(`${rawContextPath}@`)) {
21258
- remotesCopy[key] = remotesCopy[key].filter(p => p !== moduleName);
21259
- remotesCopy[key] = [...new Set(remotesCopy[key])];
21260
- if (remotesCopy[key].length === 0) {
21261
- delete remotesCopy[key];
21262
- }
21263
- }
21264
- });
21232
+ /**
21233
+ * Fetches the application manifest.
21234
+ * @param application Application managed object.
21235
+ * @returns Returns the application manifest.
21236
+ */
21237
+ async getCumulocityJsonFile(application) {
21238
+ const c8yJson = await this.applicationService.getAppManifest(application);
21239
+ if (!c8yJson.remotes) {
21240
+ c8yJson.remotes = {};
21241
+ }
21242
+ return c8yJson;
21243
+ }
21244
+ /**
21245
+ * Sets the initial state of remotes in the configuration (when it's missing), based on the list of remotes being in the application manifest.
21246
+ * @param application Application managed object.
21247
+ * @returns Returns a list of remotes that has been assigned to the configuration object.
21248
+ */
21249
+ async setInitialRemotes(application) {
21250
+ try {
21251
+ const manifest = await this.getCumulocityJsonFile(application);
21252
+ const manifestRemotes = manifest.remotes;
21253
+ return await this.updateRemotesInAppConfig(application, manifestRemotes || {}, {});
21254
+ }
21255
+ catch (er) {
21256
+ return undefined;
21257
+ }
21258
+ }
21259
+ async resetRemotes(application) {
21260
+ return await this.applicationService.updateApplicationConfig(application, {
21261
+ remotes: undefined,
21262
+ excludedRemotes: undefined
21265
21263
  });
21266
- return remotesCopy;
21264
+ }
21265
+ sortVersions(source, order) {
21266
+ const sourceCopy = cloneDeep(source);
21267
+ if (source.list && source.path) {
21268
+ const path = sourceCopy.path.join('.');
21269
+ return sourceCopy.list.sort((a, b) => compare(coerce(get(a, path)), coerce(get(b, path))) * (order === 'asc' ? 1 : -1));
21270
+ }
21271
+ else {
21272
+ return sourceCopy.sort((a, b) => compare(coerce(a), coerce(b)) * (order === 'asc' ? 1 : -1));
21273
+ }
21267
21274
  }
21268
21275
  /**
21269
- * Parses id of the plugin and returns object with context path, raw context path (without version) and module name.
21270
- * For example:
21271
- * ```ts
21272
- * const id = 'widget-plugin@1021.0.1/WidgetPluginModule'
21273
- * const parsed = parsePluginId(id); // { contextPath: 'widget-plugin@1021.0.1', moduleName: 'WidgetPluginModule', rawContextPath: 'widget-plugin' }
21274
- * @param id Plugin id in the format of `<contextPath>@<version>/<moduleName>`
21275
- * @returns Object with context path, module name and raw context path (without version).
21276
+ * Extracts a list of exported plugins from the application object.
21277
+ * @param application Application managed object.
21278
+ * @param useLatest Set this to true, to not bind the plugin to any version.
21279
+ * @returns Returns a list of exported plugins.
21276
21280
  */
21277
- parsePluginId(id) {
21278
- const [contextPath, moduleName] = id.split('/');
21279
- const [rawContextPath] = contextPath.split('@');
21280
- return { rawContextPath, contextPath, moduleName };
21281
+ getMFExports(application, excludedScopes = [
21282
+ PluginsExportScopes.SELF,
21283
+ PluginsExportScopes.SELF_OPTIONAL,
21284
+ PluginsExportScopes.GLOBAL
21285
+ ], useLatest = false) {
21286
+ const manifest = application.manifest;
21287
+ if (!manifest || !manifest.exports) {
21288
+ return [];
21289
+ }
21290
+ return this.extendPluginsDetails(application, {
21291
+ version: manifest.version,
21292
+ binaryId: undefined
21293
+ }, useLatest).filter(plugin => !excludedScopes.includes(plugin.scope));
21281
21294
  }
21282
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsService, deps: [{ token: i1.ApplicationService }, { token: AppStateService }, { token: i1.FetchClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
21283
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsService }); }
21284
- }
21285
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsService, decorators: [{
21286
- type: Injectable
21287
- }], ctorParameters: () => [{ type: i1.ApplicationService }, { type: AppStateService }, { type: i1.FetchClient }] });
21288
-
21289
- class PluginsModule {
21290
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
21291
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule }); }
21292
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule, providers: [PluginsService] }); }
21293
- }
21294
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsModule, decorators: [{
21295
- type: NgModule,
21296
- args: [{
21297
- providers: [PluginsService]
21298
- }]
21299
- }] });
21300
-
21301
- /**
21302
- * An extension HOOK can use either a pure value:
21303
- * ```typescript
21304
- * { provide: HOOK_X, useValue: { ...hookValue }, multi: true }
21305
- * ```
21306
- *
21307
- * Or an array to directly register multiple:
21308
- * ```typescript
21309
- * { provide: HOOK_X, useValue: [{ ...hookValues }], multi: true }
21310
- * ```
21311
- *
21312
- * Or an ExtensionFactory which allows to define a get() function. This function
21313
- * gets called on each navigation with the current route and can return values
21314
- * async (observable or promise).
21315
- * ```typescript
21316
- * { provide: HOOK_X, useFactory: { get: (route) => doSomethingAsync(route) }, multi: true }
21317
- * ```
21318
- * @deprecated Consider using the `hookVersion` function instead.
21319
- */
21320
- const HOOK_VERSION = new InjectionToken('HOOK_VERSION');
21321
- const VERSION_MODULE_CONFIG = new InjectionToken('VERSION_MODULE_CONFIG');
21322
- /**
21323
- * You can either provide a single `Version` as parameter:
21324
- * ```typescript
21325
- * hookVersion(...)
21326
- * ```
21327
- *
21328
- * Or an array to directly register multiple:
21329
- * ```typescript
21330
- * hookVersion([...])
21331
- * ```
21332
- *
21333
- * Or you provide an Service that implements `ExtensionFactory<Version>`
21334
- * ```typescript
21335
- * export class MyVersionFactory implements ExtensionFactory<Version> {...}
21336
- * ...
21337
- * hookVersion(MyVersionFactory)
21338
- * ```
21339
- * A typed alternative to `HOOK_VERSION`.
21340
- * @param versions The `Version`'s or `ExtensionFactory` to be provided.
21341
- * @returns An `Provider` to be provided in your module.
21342
- */
21343
- function hookVersion(versions, options) {
21344
- return hookGeneric(versions, HOOK_VERSION, options);
21345
- }
21346
-
21347
- /**
21348
- * Will provide the backend versions of the tenant.
21349
- * The system option 'system' -> 'version' is used for this.
21350
- */
21351
- class BackendVersionFactory {
21352
- constructor(config, appState) {
21353
- this.config = config;
21354
- this.appState = appState;
21355
- this.backendVersion$ = of([]);
21356
- if (this.config?.disableBackendVersionFactory) {
21357
- return;
21295
+ /**
21296
+ * Extracts a list of exports from each available package.
21297
+ * @param allVersions If set to true, all and not only latest versions are included.
21298
+ * @param excludedScopes Defines which scopes should not be loaded.
21299
+ * @returns Returns a list of all exported plugins.
21300
+ */
21301
+ async getAllMFExports(allVersions = false, excludedScopes = [
21302
+ PluginsExportScopes.SELF,
21303
+ PluginsExportScopes.SELF_OPTIONAL,
21304
+ PluginsExportScopes.GLOBAL
21305
+ ]) {
21306
+ const plugins = new Array();
21307
+ const packages = await this.listPackages();
21308
+ for (const pkg of packages) {
21309
+ if (!pkg?.manifest?.exports) {
21310
+ continue;
21311
+ }
21312
+ if (allVersions && Array.isArray(pkg.applicationVersions)) {
21313
+ pkg.applicationVersions.forEach(version => {
21314
+ plugins.push(...this.extendPluginsDetails(pkg, version));
21315
+ });
21316
+ }
21317
+ else {
21318
+ plugins.push(...this.extendPluginsDetails(pkg, {
21319
+ version: pkg.manifest.version,
21320
+ binaryId: undefined
21321
+ }));
21322
+ }
21358
21323
  }
21359
- this.backendVersion$ = this.appState.state$.pipe(map(state => state?.versions?.backend), filter(backendVersion => !!backendVersion), distinctUntilChanged(), map(backendVersion => this.buildBackendVersion(backendVersion)), shareReplay(1));
21360
- }
21361
- get() {
21362
- return this.backendVersion$;
21363
- }
21364
- buildBackendVersion(backendVersion) {
21365
- return {
21366
- label: gettext$1('Backend'),
21367
- version: backendVersion,
21368
- priority: 20,
21369
- type: 'SYSTEM',
21370
- hidden: true
21371
- };
21372
- }
21373
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BackendVersionFactory, deps: [{ token: VERSION_MODULE_CONFIG, optional: true }, { token: AppStateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
21374
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BackendVersionFactory, providedIn: 'root' }); }
21375
- }
21376
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BackendVersionFactory, decorators: [{
21377
- type: Injectable,
21378
- args: [{
21379
- providedIn: 'root'
21380
- }]
21381
- }], ctorParameters: () => [{ type: undefined, decorators: [{
21382
- type: Optional
21383
- }, {
21384
- type: Inject,
21385
- args: [VERSION_MODULE_CONFIG]
21386
- }] }, { type: AppStateService }] });
21387
-
21388
- class VersionService extends ExtensionPointForPlugins {
21389
- constructor(rootInjector, pluginService) {
21390
- super(rootInjector, pluginService);
21391
- this.items$ = this.setupItemsObservable();
21392
- this.nonHiddenItems$ = this.items$.pipe(map(versions => versions.filter(version => !version.hidden)));
21393
- }
21394
- get state() {
21395
- return this.state$.value;
21396
- }
21397
- add(version) {
21398
- this.state.add(version);
21399
- this.emitNewState();
21400
- }
21401
- remove(version) {
21402
- this.state.delete(version);
21403
- this.emitNewState();
21404
- }
21405
- cleanUpVersions(versions) {
21406
- return versions.map(version => pick(version, 'label', 'version', 'type', 'custom'));
21407
- }
21408
- setupItemsObservable() {
21409
- return fromTriggerOnce(undefined, this.refresh$, [
21410
- getInjectedHooks(HOOK_VERSION, this.injectors),
21411
- () => this.factories,
21412
- stateToFactory(this.state$)
21413
- ]).pipe(distinctUntilChanged(), map(versions => sortByPriority(versions)), shareReplay(1));
21414
- }
21415
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionService, deps: [{ token: i0.Injector }, { token: PluginsResolveService }], target: i0.ɵɵFactoryTarget.Injectable }); }
21416
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionService, providedIn: 'root' }); }
21417
- }
21418
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionService, decorators: [{
21419
- type: Injectable,
21420
- args: [{
21421
- providedIn: 'root'
21422
- }]
21423
- }], ctorParameters: () => [{ type: i0.Injector }, { type: PluginsResolveService }] });
21424
-
21425
- class PlatformDetailsService {
21426
- constructor(version, appState, apps) {
21427
- this.version = version;
21428
- this.appState = appState;
21429
- this.apps = apps;
21430
- }
21431
- async getPlatformDetailsObject() {
21432
- const currentUser = this.appState.currentUser.value;
21433
- const userId = currentUser?.id;
21434
- const userPermissions = this.getUserPermissions(currentUser);
21435
- const [hookedVersions, microserviceVersions] = await Promise.all([
21436
- this.getVersions(),
21437
- this.getMicroserviceVersions(userId)
21438
- ]);
21439
- const versions = [...hookedVersions, ...microserviceVersions];
21440
- const groupedVersions = groupBy(versions, 'type');
21441
- const tenantId = this.appState.currentTenant.value?.name;
21442
- // useful as `domainName` might be pointing to a custom domain
21443
- // self link should still allow to identify the actual environment of the tenant
21444
- const tenantSelfLink = this.appState.currentTenant.value?.self;
21445
- const tenantDomainName = this.appState.currentTenant.value?.domainName;
21446
- const applicationKey = this.appState.currentApplication.value?.key;
21447
- const applicationId = this.appState.currentApplication.value?.id;
21448
- const time = new Date().toISOString();
21449
- const url = document.URL;
21450
- const obj = {
21451
- time,
21452
- tenantId,
21453
- tenantSelfLink,
21454
- tenantDomainName,
21455
- url,
21456
- userId,
21457
- userPermissions,
21458
- applicationId,
21459
- applicationKey,
21460
- versions: groupedVersions
21461
- };
21462
- return obj;
21324
+ return plugins.filter(plugin => !excludedScopes.includes(plugin.scope));
21463
21325
  }
21464
- async getVersions() {
21465
- const versions = await this.version.items$
21466
- .pipe(take(1), map(versions => this.version.cleanUpVersions(versions)))
21467
- .toPromise();
21468
- return versions;
21326
+ /**
21327
+ * Extracts a list of remotes from the application object.
21328
+ * @param application Application managed object.
21329
+ * @returns Returns list of remotes.
21330
+ */
21331
+ getMFRemotes(application) {
21332
+ const manifest = application.manifest || {};
21333
+ const config = application?.config;
21334
+ let remotes = config?.remotes || manifest.remotes || {};
21335
+ const manifestExports = manifest.exports || manifest.manifest?.exports || [];
21336
+ const selfRemotes = manifestExports
21337
+ .filter(plugin => plugin.scope === PluginsExportScopes.SELF)
21338
+ .map(plugin => plugin.module || plugin.name);
21339
+ if (selfRemotes.length) {
21340
+ remotes = mergeRemotes([{ [application.contextPath]: selfRemotes }, remotes]);
21341
+ }
21342
+ remotes = removeRemotes(remotes, config?.excludedRemotes);
21343
+ return remotes;
21469
21344
  }
21470
- async getMicroserviceVersions(userId) {
21471
- try {
21472
- const { data: apps } = await this.apps.listByUser(userId, {
21473
- pageSize: 2000,
21474
- dropOverwrittenApps: true,
21475
- noPaging: true
21476
- });
21477
- return apps
21478
- .filter(app => !!app.manifest?.version && app.type === ApplicationType.MICROSERVICE)
21479
- .map(app => {
21480
- return {
21481
- label: app.name,
21482
- version: app.manifest.version,
21483
- type: app.type,
21484
- custom: {
21485
- owner: app.owner?.tenant?.id,
21486
- provider: app.manifest?.provider
21487
- }
21488
- };
21489
- });
21345
+ /**
21346
+ * Determines the type of a package.
21347
+ * A package is OFFICIAL if it comes from management tenant and has a label attached called OFFICIAL.
21348
+ * A package is COMMUNITY if it has a label called COMMUNITY.
21349
+ * A package is CUSTOM if it does not have any label attached.
21350
+ * A package is UNKNOWN if it has a label attached but it does not match COMMUNITY or OFFICIAL.
21351
+ *
21352
+ * Labels can be used to identify the status of a package. Community packages always need
21353
+ * a license validation. The label will be shown on the application card to tell a user
21354
+ * whether they are looking into an official or community package.
21355
+ *
21356
+ * @param packageApplication The package application object to check.
21357
+ * @returns The package type.
21358
+ */
21359
+ getPackageType(packageApplication) {
21360
+ const label = packageApplication.label || packageApplication.manifest?.label;
21361
+ if (label === PackageType.ARCHIVED) {
21362
+ return PackageType.ARCHIVED;
21490
21363
  }
21491
- catch (e) {
21492
- console.warn(e);
21493
- return [];
21364
+ if (!label) {
21365
+ return PackageType.CUSTOM;
21494
21366
  }
21495
- }
21496
- getUserPermissions(user) {
21497
- if (!user) {
21498
- return null;
21367
+ if (label === PackageType.OFFICIAL && this.isOwnedByManagement(packageApplication)) {
21368
+ return PackageType.OFFICIAL;
21499
21369
  }
21500
- const userPermissions = this.getDirectPermissionsOfUser(user);
21501
- const groupPermissions = this.getPermissionsOfAssignedGroups(user);
21502
- return { user: userPermissions, groups: groupPermissions };
21503
- }
21504
- getDirectPermissionsOfUser(user) {
21505
- const userChangedType = user;
21506
- const userRoleReferences = userChangedType.roles?.references || [];
21507
- return userRoleReferences.map(ref => ref.role.id);
21370
+ if (label === PackageType.COMMUNITY) {
21371
+ return PackageType.COMMUNITY;
21372
+ }
21373
+ return PackageType.UNKNOWN;
21508
21374
  }
21509
- getPermissionsOfAssignedGroups(user) {
21510
- const groups = user.groups?.references || [];
21511
- return groups.map(ref => {
21512
- const roleReferences = ref.group?.roles?.references || [];
21513
- const permissions = roleReferences.map(ref => ref.role.id);
21514
- return {
21515
- id: ref.group.id,
21516
- name: ref.group.name,
21517
- permissions
21518
- };
21519
- });
21375
+ /**
21376
+ * Verifies if an application is owned by management tenant.
21377
+ *
21378
+ * @param app The application to verify.
21379
+ * @returns True if owned by management tenant.
21380
+ */
21381
+ isOwnedByManagement(app) {
21382
+ const appOwner = get(app, 'owner.tenant.id');
21383
+ return appOwner === 'management';
21520
21384
  }
21521
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformDetailsService, deps: [{ token: VersionService }, { token: AppStateService }, { token: i1.ApplicationService }], target: i0.ɵɵFactoryTarget.Injectable }); }
21522
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformDetailsService, providedIn: 'root' }); }
21523
- }
21524
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformDetailsService, decorators: [{
21525
- type: Injectable,
21526
- args: [{ providedIn: 'root' }]
21527
- }], ctorParameters: () => [{ type: VersionService }, { type: AppStateService }, { type: i1.ApplicationService }] });
21528
-
21529
- class VersionListComponent {
21530
- constructor(version, appState, clipboardService, modalService, platformDetails, headerService) {
21531
- this.version = version;
21532
- this.appState = appState;
21533
- this.clipboardService = clipboardService;
21534
- this.modalService = modalService;
21535
- this.platformDetails = platformDetails;
21536
- this.headerService = headerService;
21537
- this.versionsToDirectlyDisplay$ = this.version.nonHiddenItems$;
21538
- this.currentTenantId$ = this.appState.currentTenant.pipe(map(tenant => tenant?.name), filter(tenantId => !!tenantId), distinctUntilChanged());
21539
- this.open$ = this.headerService.rightDrawerOpen$;
21385
+ pluginsFromManifest(manifest) {
21386
+ const plugins = manifest.exports;
21387
+ const extendedPlugins = plugins
21388
+ .filter(p => p.scope === PluginsExportScopes.SELF)
21389
+ .map(p => ({
21390
+ ...p,
21391
+ id: PluginsService.createPluginId(manifest.contextPath, p, manifest.version),
21392
+ contextPath: manifest.contextPath,
21393
+ version: manifest.version,
21394
+ versioningMatrix: manifest.versioningMatrix,
21395
+ license: manifest.license,
21396
+ type: PackageType.CUSTOM
21397
+ }));
21398
+ return extendedPlugins;
21540
21399
  }
21541
- async downloadPlatformDetails() {
21542
- const obj = await this.platformDetails.getPlatformDetailsObject();
21543
- const json = JSON.stringify(obj, undefined, 2);
21544
- const blob = new Blob([json]);
21545
- saveAs$1(blob, 'platform-details.json');
21400
+ async getReadmeFileContent(baseUrl) {
21401
+ return this.getFileContent(baseUrl, 'readme');
21546
21402
  }
21547
- copyIt(text) {
21548
- this.clipboardService.writeText(text);
21403
+ async getChangelogFileContent(baseUrl) {
21404
+ return this.getFileContent(baseUrl, 'changelog');
21549
21405
  }
21550
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionListComponent, deps: [{ token: VersionService }, { token: AppStateService }, { token: ClipboardService }, { token: i1$7.BsModalService }, { token: PlatformDetailsService }, { token: HeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
21551
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: VersionListComponent, isStandalone: true, selector: "c8y-version-list", ngImport: i0, template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"c8y-c8y-c\"></i>\n <span class=\"text-bold\">{{ 'Platform info' | translate }}</span>\n </div>\n\n <ul class=\"list-unstyled\">\n <li\n class=\"c8y-right-drawer__item\"\n *ngIf=\"currentTenantId$ | async as tenantId\"\n >\n <span\n class=\"flex-grow text-muted m-0 text-12 text-truncate\"\n translate\n >\n Tenant ID\n </span>\n <button\n class=\"m-l-auto flex-no-shrink btn-clean p-0 btn-link\"\n title=\"{{ 'Copy tenant ID to the clipboard' | translate }}\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); copyIt(tenantId)\"\n >\n {{ tenantId }}\n <i\n class=\"text-14 m-0\"\n [c8yIcon]=\"'clipboard'\"\n ></i>\n </button>\n </li>\n <li\n class=\"c8y-right-drawer__item\"\n *ngFor=\"let versionEntry of versionsToDirectlyDisplay$ | async\"\n >\n <span\n class=\"flex-no-shrink text-muted text-12 text-truncate m-r-8\"\n [title]=\"versionEntry.label | translate\"\n >\n {{ versionEntry.label | translate }}\n </span>\n <span\n class=\"flex-grow text-right text-truncate\"\n [title]=\"versionEntry.version | translate\"\n >\n {{ versionEntry.version }}\n </span>\n </li>\n <li class=\"c8y-right-drawer__item\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n title=\"{{ 'Download platform details' | translate }}\"\n (click)=\"downloadPlatformDetails()\"\n >\n <i c8yIcon=\"download\" class=\"m-t-0 m-b-0 text-14\"></i>\n <span translate>Download platform details</span>\n </button>\n </li>\n </ul>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
21552
- }
21553
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionListComponent, decorators: [{
21554
- type: Component,
21555
- args: [{ selector: 'c8y-version-list', standalone: true, imports: [IconDirective, NgIf, C8yTranslateDirective, NgFor, C8yTranslatePipe, AsyncPipe], template: "<div class=\"separator-top p-t-8 p-b-8\">\n <div class=\"c8y-right-drawer__item sticky-top\">\n <i c8yIcon=\"c8y-c8y-c\"></i>\n <span class=\"text-bold\">{{ 'Platform info' | translate }}</span>\n </div>\n\n <ul class=\"list-unstyled\">\n <li\n class=\"c8y-right-drawer__item\"\n *ngIf=\"currentTenantId$ | async as tenantId\"\n >\n <span\n class=\"flex-grow text-muted m-0 text-12 text-truncate\"\n translate\n >\n Tenant ID\n </span>\n <button\n class=\"m-l-auto flex-no-shrink btn-clean p-0 btn-link\"\n title=\"{{ 'Copy tenant ID to the clipboard' | translate }}\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); copyIt(tenantId)\"\n >\n {{ tenantId }}\n <i\n class=\"text-14 m-0\"\n [c8yIcon]=\"'clipboard'\"\n ></i>\n </button>\n </li>\n <li\n class=\"c8y-right-drawer__item\"\n *ngFor=\"let versionEntry of versionsToDirectlyDisplay$ | async\"\n >\n <span\n class=\"flex-no-shrink text-muted text-12 text-truncate m-r-8\"\n [title]=\"versionEntry.label | translate\"\n >\n {{ versionEntry.label | translate }}\n </span>\n <span\n class=\"flex-grow text-right text-truncate\"\n [title]=\"versionEntry.version | translate\"\n >\n {{ versionEntry.version }}\n </span>\n </li>\n <li class=\"c8y-right-drawer__item\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.tabindex]=\"(open$ | async) ? '0' : '-1'\"\n title=\"{{ 'Download platform details' | translate }}\"\n (click)=\"downloadPlatformDetails()\"\n >\n <i c8yIcon=\"download\" class=\"m-t-0 m-b-0 text-14\"></i>\n <span translate>Download platform details</span>\n </button>\n </li>\n </ul>\n</div>\n" }]
21556
- }], ctorParameters: () => [{ type: VersionService }, { type: AppStateService }, { type: ClipboardService }, { type: i1$7.BsModalService }, { type: PlatformDetailsService }, { type: HeaderService }] });
21557
-
21558
- class VersionDrawerFactory {
21559
- constructor(options) {
21560
- this.options = options;
21561
- this.drawerItem = {
21562
- component: VersionListComponent,
21563
- position: 'right',
21564
- priority: 80,
21565
- id: 'platformInformation'
21406
+ async getFileContent(baseUrl, fileType) {
21407
+ const file = await this.getFile(baseUrl, fileType);
21408
+ if (file.status === 200) {
21409
+ return await file.text();
21410
+ }
21411
+ return '';
21412
+ }
21413
+ async getFile(baseUrl, fileType) {
21414
+ const options = {
21415
+ method: 'GET',
21416
+ headers: { 'Content-Type': 'text/markdown' }
21566
21417
  };
21418
+ const uppercaseFilename = fileType === 'readme' ? 'README.md' : 'CHANGELOG.md';
21419
+ let result = await this.client.fetch(`${baseUrl}${uppercaseFilename}`, options);
21420
+ if (result && result.status === 404) {
21421
+ result = await this.client.fetch(`${baseUrl}${uppercaseFilename.toLowerCase()}`, options);
21422
+ }
21423
+ return result;
21567
21424
  }
21568
- get() {
21569
- return this.shouldShowPlatformInformation$().pipe(distinctUntilChanged(), map(shouldShowPlatformInformation => {
21570
- if (shouldShowPlatformInformation) {
21571
- return this.drawerItem;
21425
+ isSelfScopedPlugin(plugin, contextPath) {
21426
+ return (plugin.scope === PluginsExportScopes.SELF &&
21427
+ (!contextPath || plugin.contextPath === contextPath));
21428
+ }
21429
+ getSelfScopedPlugins(plugins, contextPath) {
21430
+ return plugins.filter(plugin => this.isSelfScopedPlugin(plugin, contextPath));
21431
+ }
21432
+ getAllPluginsExceptSelfScoped(plugins, contextPath) {
21433
+ return plugins.filter(plugin => !this.isSelfScopedPlugin(plugin, contextPath));
21434
+ }
21435
+ removeDuplicates(apps, key) {
21436
+ const uniqueList = [];
21437
+ const groupedAppsByKey = groupBy(apps, key);
21438
+ const groupedApps = Object.keys(groupedAppsByKey).map(key => groupedAppsByKey[key]);
21439
+ for (const appsGroup of groupedApps) {
21440
+ if (appsGroup.length < 2) {
21441
+ uniqueList.push(...appsGroup);
21572
21442
  }
21573
- return [];
21443
+ else {
21444
+ const appFromCurrentTenant = appsGroup.find(app => this.isFromCurrentTenant(app));
21445
+ if (appFromCurrentTenant) {
21446
+ uniqueList.push(appFromCurrentTenant);
21447
+ continue;
21448
+ }
21449
+ const appNotOwnedByManagement = appsGroup.find(app => !this.isOwnedByManagement(app));
21450
+ uniqueList.push(appNotOwnedByManagement);
21451
+ }
21452
+ }
21453
+ return uniqueList;
21454
+ }
21455
+ isFromCurrentTenant(app) {
21456
+ return app.owner.tenant.id === this.appStateService.currentTenant.value.name;
21457
+ }
21458
+ /**
21459
+ * Modifies the list of plugins to have additional information such as id.
21460
+ * @ignore
21461
+ */
21462
+ extendPluginsDetails(application, version, useLatest = false) {
21463
+ const plugins = application.manifest.exports;
21464
+ const extendedPlugins = plugins.map(p => ({
21465
+ ...p,
21466
+ id: PluginsService.createPluginId(application.contextPath, p, version.version, useLatest),
21467
+ idLatest: PluginsService.createPluginId(application.contextPath, p, version.version, true),
21468
+ contextPath: application.contextPath,
21469
+ version: version.version,
21470
+ versioningMatrix: application.manifest.versioningMatrix,
21471
+ tags: useLatest ? ['latest'] : version.tags || [],
21472
+ license: application.manifest.license,
21473
+ type: this.getPackageType(application),
21474
+ originApp: application
21574
21475
  }));
21476
+ return extendedPlugins;
21575
21477
  }
21576
- shouldShowPlatformInformation$() {
21577
- return combineLatest([
21578
- this.options.get$('hidePowered'),
21579
- this.options.get$('hidePlatformInformation')
21580
- ]).pipe(map(([hidePowered, hidePlatformInformation]) => {
21581
- if (hidePlatformInformation === undefined) {
21582
- return !hidePowered;
21478
+ async listApplicationsByCurrentTenant(params = {}) {
21479
+ const filter = Object.assign({
21480
+ type: 'HOSTED',
21481
+ pageSize: 2000,
21482
+ withTotalPages: true
21483
+ }, params);
21484
+ const sharedFilter = Object.assign({
21485
+ availability: ApplicationAvailability.SHARED,
21486
+ type: 'HOSTED',
21487
+ pageSize: 2000,
21488
+ withTotalPages: true
21489
+ }, params);
21490
+ const tenantName = this.appStateService.currentTenant.value.name;
21491
+ const [resultAppsOwnedByTenant, resultSharedApps] = await Promise.all([
21492
+ this.applicationService.listByTenant(tenantName, filter),
21493
+ this.applicationService.list(sharedFilter)
21494
+ ]);
21495
+ const { data: appsOwnedByTenant } = resultAppsOwnedByTenant;
21496
+ const { data: sharedApps } = resultSharedApps;
21497
+ const webApps = [...appsOwnedByTenant, ...sharedApps];
21498
+ return uniqBy(webApps, (app) => app.id);
21499
+ }
21500
+ addPluginToRemotesConfig(remotesConfig, plugins) {
21501
+ if (!plugins) {
21502
+ return;
21503
+ }
21504
+ const remotesCopy = cloneDeep(remotesConfig);
21505
+ const temp = Array.isArray(plugins) ? plugins : [plugins];
21506
+ temp.forEach(plugin => {
21507
+ const { contextPath, moduleName } = this.parsePluginId(plugin.id);
21508
+ if (!contextPath || !moduleName) {
21509
+ return;
21583
21510
  }
21584
- return !hidePlatformInformation;
21585
- }));
21511
+ remotesCopy[contextPath]?.length >= 0
21512
+ ? remotesCopy[contextPath].push(moduleName)
21513
+ : (remotesCopy[contextPath] = []).push(moduleName);
21514
+ remotesCopy[contextPath] = [...new Set(remotesCopy[contextPath])];
21515
+ });
21516
+ return remotesCopy;
21586
21517
  }
21587
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionDrawerFactory, deps: [{ token: OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
21588
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionDrawerFactory }); }
21518
+ removePluginsFromRemotesConfig(remotesConfig, plugins) {
21519
+ const remotesCopy = cloneDeep(remotesConfig);
21520
+ const temp = Array.isArray(plugins) ? plugins : [plugins];
21521
+ temp.forEach(plugin => {
21522
+ const { rawContextPath, moduleName } = this.parsePluginId(plugin.id);
21523
+ if (!rawContextPath || !moduleName) {
21524
+ return;
21525
+ }
21526
+ // Find all keys in remotesConfig that match the plugin context (regardless of version)
21527
+ Object.keys(remotesCopy).forEach(key => {
21528
+ if (key === rawContextPath || key.startsWith(`${rawContextPath}@`)) {
21529
+ remotesCopy[key] = remotesCopy[key].filter(p => p !== moduleName);
21530
+ remotesCopy[key] = [...new Set(remotesCopy[key])];
21531
+ if (remotesCopy[key].length === 0) {
21532
+ delete remotesCopy[key];
21533
+ }
21534
+ }
21535
+ });
21536
+ });
21537
+ return remotesCopy;
21538
+ }
21539
+ /**
21540
+ * Parses id of the plugin and returns object with context path, raw context path (without version) and module name.
21541
+ * For example:
21542
+ * ```ts
21543
+ * const id = 'widget-plugin@1021.0.1/WidgetPluginModule'
21544
+ * const parsed = parsePluginId(id); // { contextPath: 'widget-plugin@1021.0.1', moduleName: 'WidgetPluginModule', rawContextPath: 'widget-plugin' }
21545
+ * @param id Plugin id in the format of `<contextPath>@<version>/<moduleName>`
21546
+ * @returns Object with context path, module name and raw context path (without version).
21547
+ */
21548
+ parsePluginId(id) {
21549
+ const [contextPath, moduleName] = id.split('/');
21550
+ const [rawContextPath] = contextPath.split('@');
21551
+ return { rawContextPath, contextPath, moduleName };
21552
+ }
21553
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsService, deps: [{ token: i1.ApplicationService }, { token: AppStateService }, { token: i1.FetchClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
21554
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsService, providedIn: 'root' }); }
21589
21555
  }
21590
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VersionDrawerFactory, decorators: [{
21591
- type: Injectable
21592
- }], ctorParameters: () => [{ type: OptionsService }] });
21556
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PluginsService, decorators: [{
21557
+ type: Injectable,
21558
+ args: [{ providedIn: 'root' }]
21559
+ }], ctorParameters: () => [{ type: i1.ApplicationService }, { type: AppStateService }, { type: i1.FetchClient }] });
21593
21560
 
21594
21561
  /**
21595
21562
  * Will provide the version of plugins installed to the current application.
@@ -22557,6 +22524,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
22557
22524
  args: [{}]
22558
22525
  }] });
22559
22526
 
22527
+ class PasswordStrengthCheckerService {
22528
+ constructor() {
22529
+ this.GREEN = {
22530
+ colorName: 'green',
22531
+ color: 'rgb(0, 128, 0)',
22532
+ description: gettext$1('strong'),
22533
+ passwordStrength: PasswordStrength.GREEN
22534
+ };
22535
+ this.YELLOW = {
22536
+ colorName: 'yellow',
22537
+ color: 'rgb(255, 204, 51)',
22538
+ description: gettext$1('medium'),
22539
+ passwordStrength: PasswordStrength.YELLOW
22540
+ };
22541
+ this.RED = {
22542
+ colorName: 'red',
22543
+ color: 'rgb(170, 0, 51)',
22544
+ description: gettext$1('weak'),
22545
+ passwordStrength: PasswordStrength.RED
22546
+ };
22547
+ }
22548
+ hasLowerCase(password) {
22549
+ return password.search(/[a-z]/) !== -1;
22550
+ }
22551
+ hasUpperCase(password) {
22552
+ return password.search(/[A-Z]/) !== -1;
22553
+ }
22554
+ hasNumbers(password) {
22555
+ return password.search(/[0-9]/) !== -1;
22556
+ }
22557
+ hasSpecialChars(password) {
22558
+ return password.search(/[^0-9a-zA-Z]+/) !== -1;
22559
+ }
22560
+ getStrengthColor(password) {
22561
+ const passwordStrength = filter$2([
22562
+ this.hasLowerCase(password),
22563
+ this.hasUpperCase(password),
22564
+ this.hasNumbers(password),
22565
+ this.hasSpecialChars(password)
22566
+ ]).length;
22567
+ if (passwordStrength > 3) {
22568
+ return this.GREEN;
22569
+ }
22570
+ else if (passwordStrength >= 3) {
22571
+ return this.YELLOW;
22572
+ }
22573
+ else {
22574
+ return this.RED;
22575
+ }
22576
+ }
22577
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthCheckerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22578
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthCheckerService, providedIn: 'root' }); }
22579
+ }
22580
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordStrengthCheckerService, decorators: [{
22581
+ type: Injectable,
22582
+ args: [{ providedIn: 'root' }]
22583
+ }] });
22584
+
22560
22585
  /**
22561
22586
  * A drop-zone which is a file selector allowing users to select file(s) from their file system, either natively or by drag and drop.
22562
22587
  *
@@ -22594,6 +22619,7 @@ class DropAreaComponent {
22594
22619
  this.maxAllowedFiles = Infinity;
22595
22620
  this.isOver = false;
22596
22621
  this.errors = false;
22622
+ this.disabled = false;
22597
22623
  this.onChange = _ => undefined;
22598
22624
  this.onTouched = () => undefined;
22599
22625
  }
@@ -22700,6 +22726,9 @@ class DropAreaComponent {
22700
22726
  registerOnTouched(fn) {
22701
22727
  this.onTouched = fn;
22702
22728
  }
22729
+ setDisabledState(isDisabled) {
22730
+ this.disabled = isDisabled;
22731
+ }
22703
22732
  async onFilesSelected(files) {
22704
22733
  this.onTouched();
22705
22734
  const hasValidNameLength = this.filesService.checkMaxLength(files);
@@ -22839,11 +22868,11 @@ class DropAreaComponent {
22839
22868
  resolve(reader.result);
22840
22869
  }
22841
22870
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DropAreaComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: FilesService }, { token: i1$1.TranslateService }, { token: BytesPipe }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
22842
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DropAreaComponent, isStandalone: true, selector: "c8y-drop-area", inputs: { formControl: "formControl", title: "title", message: "message", icon: "icon", loadingMessage: "loadingMessage", forceHideList: "forceHideList", alwaysShow: "alwaysShow", clickToOpen: "clickToOpen", loading: "loading", progress: "progress", maxAllowedFiles: "maxAllowedFiles", files: "files", maxFileSizeInMegaBytes: "maxFileSizeInMegaBytes", accept: "accept" }, outputs: { dropped: "dropped" }, host: { listeners: { "keyup": "onkeyup($event)" } }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: DropAreaComponent, multi: true }], viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, static: true }, { propertyName: "zone", first: true, predicate: ["zone"], descendants: true }, { propertyName: "picker", first: true, predicate: ["picker"], descendants: true }], ngImport: i0, template: "<div\n class=\"drop-zone\"\n [style.pointerEvents]=\"loading ? 'none' : 'auto'\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"!shouldShowFilesList()\"\n [ngClass]=\"{ 'has-errors': errors, disabled: formControl?.disabled }\"\n #zone\n (dragleave)=\"stopDragging()\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onOver()\"\n (click)=\"showPicker($event)\"\n>\n <div\n class=\"file-placeholder\"\n data-cy=\"c8y-file-placeholder--drop-zone\"\n [ngClass]=\"{ 'drag-over': isOver }\"\n >\n <div\n class=\"d-flex d-col p-4 flex-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 50%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div\n class=\"spinner-snake\"\n *ngIf=\"progress === -1\"\n ></div>\n <p\n class=\"m-t-auto m-b-auto m-r-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n {{ loadingMessage | translate }}\n </p>\n </div>\n <div\n class=\"hint-placeholder pointer\"\n *ngIf=\"!loading\"\n data-cy=\"drop-zone--hint-placeholder\"\n >\n <i class=\"dlt-c8y-icon-{{ icon }}\"></i>\n <p *ngIf=\"!errors\" class=\"text-truncate\" title=\"{{ message | translate }}\">\n <b>{{ message | translate }}</b>\n <br />\n <span\n *ngIf=\"alwaysShow && clickToOpen\"\n translate\n ></span>\n </p>\n <div\n class=\"has-errors\"\n *ngIf=\"errors\"\n >\n <p class=\"form-control-feedback-message\">\n {{ errorMessage | translate }}\n </p>\n </div>\n </div>\n </div>\n</div>\n\n<div\n class=\"drop-zone\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"shouldShowFilesList()\"\n>\n <div\n class=\"p-absolute p-4 fit-w fit-h d-flex d-col j-c-center a-i-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 80%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div *ngIf=\"progress === -1\">\n <c8y-loading></c8y-loading>\n </div>\n <p\n class=\"m-b-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n <strong>\n {{ loadingMessage | translate }}\n </strong>\n </p>\n </div>\n <div\n class=\"file-placeholder p-4\"\n *ngIf=\"!loading\"\n >\n <div class=\"d-flex p-4 a-i-center\">\n <i\n class=\"icon-20 m-r-8\"\n c8yIcon=\"file-o\"\n ></i>\n <span\n class=\"text-truncate\"\n title=\"{{ filesNameString }}\"\n >\n {{ filesNameString }}\n </span>\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto\"\n title=\"{{ 'Remove' | translate }}\"\n [attr.aria-label]=\"'Remove' | translate\"\n type=\"button\"\n >\n <i\n c8yIcon=\"minus-circle\"\n (click)=\"onDelete()\"\n ></i>\n </button>\n </div>\n </div>\n</div>\n<label\n class=\"sr-only\"\n for=\"file\"\n>\n {{ 'Select file' | translate }}\n</label>\n<input\n class=\"hidden\"\n id=\"file\"\n type=\"file\"\n #picker\n *ngIf=\"clickToOpen\"\n (change)=\"onPick($event)\"\n (click)=\"picker.focus()\"\n (blur)=\"onTouched()\"\n [accept]=\"acceptedExts\"\n [multiple]=\"maxAllowedFiles > 1\"\n [disabled]=\"formControl?.disabled\"\n/>\n<div\n #area\n [hidden]=\"isOver || loading\"\n (dragover)=\"toggle()\"\n>\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1$a.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$a.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
22871
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DropAreaComponent, isStandalone: true, selector: "c8y-drop-area", inputs: { formControl: "formControl", title: "title", message: "message", icon: "icon", loadingMessage: "loadingMessage", forceHideList: "forceHideList", alwaysShow: "alwaysShow", clickToOpen: "clickToOpen", loading: "loading", progress: "progress", maxAllowedFiles: "maxAllowedFiles", files: "files", maxFileSizeInMegaBytes: "maxFileSizeInMegaBytes", accept: "accept" }, outputs: { dropped: "dropped" }, host: { listeners: { "keyup": "onkeyup($event)" } }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: DropAreaComponent, multi: true }], viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, static: true }, { propertyName: "zone", first: true, predicate: ["zone"], descendants: true }, { propertyName: "picker", first: true, predicate: ["picker"], descendants: true }], ngImport: i0, template: "<div\n class=\"drop-zone\"\n [style.pointerEvents]=\"loading ? 'none' : 'auto'\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"!shouldShowFilesList()\"\n [ngClass]=\"{ 'has-errors': errors, disabled: formControl?.disabled || disabled }\"\n #zone\n (dragleave)=\"stopDragging()\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onOver()\"\n (click)=\"showPicker($event)\"\n>\n <div\n class=\"file-placeholder\"\n data-cy=\"c8y-file-placeholder--drop-zone\"\n [ngClass]=\"{ 'drag-over': isOver }\"\n >\n <div\n class=\"d-flex d-col p-4 flex-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 50%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div\n class=\"spinner-snake\"\n *ngIf=\"progress === -1\"\n ></div>\n <p\n class=\"m-t-auto m-b-auto m-r-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n {{ loadingMessage | translate }}\n </p>\n </div>\n <div\n class=\"hint-placeholder pointer\"\n *ngIf=\"!loading\"\n data-cy=\"drop-zone--hint-placeholder\"\n >\n <i class=\"dlt-c8y-icon-{{ icon }}\"></i>\n <p\n class=\"text-truncate\"\n title=\"{{ message | translate }}\"\n *ngIf=\"!errors\"\n >\n <b>{{ message | translate }}</b>\n <br />\n <span\n *ngIf=\"alwaysShow && clickToOpen\"\n translate\n ></span>\n </p>\n <div\n class=\"has-errors\"\n *ngIf=\"errors\"\n >\n <p class=\"form-control-feedback-message\">\n {{ errorMessage | translate }}\n </p>\n </div>\n </div>\n </div>\n</div>\n\n<div\n class=\"drop-zone\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"shouldShowFilesList()\"\n>\n <div\n class=\"p-absolute p-4 fit-w fit-h d-flex d-col j-c-center a-i-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 80%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div *ngIf=\"progress === -1\">\n <c8y-loading></c8y-loading>\n </div>\n <p\n class=\"m-b-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n <strong>\n {{ loadingMessage | translate }}\n </strong>\n </p>\n </div>\n <div\n class=\"file-placeholder p-4\"\n *ngIf=\"!loading\"\n >\n <div class=\"d-flex p-4 a-i-center\">\n <i\n class=\"icon-20 m-r-8\"\n c8yIcon=\"file-o\"\n ></i>\n <span\n class=\"text-truncate\"\n title=\"{{ filesNameString }}\"\n >\n {{ filesNameString }}\n </span>\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto\"\n title=\"{{ 'Remove' | translate }}\"\n [attr.aria-label]=\"'Remove' | translate\"\n type=\"button\"\n >\n <i\n c8yIcon=\"minus-circle\"\n (click)=\"onDelete()\"\n ></i>\n </button>\n </div>\n </div>\n</div>\n<label\n class=\"sr-only\"\n for=\"file\"\n>\n {{ 'Select file' | translate }}\n</label>\n<input\n class=\"hidden\"\n id=\"file\"\n type=\"file\"\n #picker\n *ngIf=\"clickToOpen\"\n (change)=\"onPick($event)\"\n (click)=\"picker.focus()\"\n (blur)=\"onTouched()\"\n [accept]=\"acceptedExts\"\n [multiple]=\"maxAllowedFiles > 1\"\n [disabled]=\"formControl?.disabled || disabled\"\n/>\n<div\n #area\n [hidden]=\"isOver || loading\"\n (dragover)=\"toggle()\"\n>\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1$a.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$a.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
22843
22872
  }
22844
22873
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DropAreaComponent, decorators: [{
22845
22874
  type: Component,
22846
- args: [{ selector: 'c8y-drop-area', providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: DropAreaComponent, multi: true }], standalone: true, imports: [CommonModule, C8yTranslatePipe, NgIf, NgClass, IconDirective], template: "<div\n class=\"drop-zone\"\n [style.pointerEvents]=\"loading ? 'none' : 'auto'\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"!shouldShowFilesList()\"\n [ngClass]=\"{ 'has-errors': errors, disabled: formControl?.disabled }\"\n #zone\n (dragleave)=\"stopDragging()\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onOver()\"\n (click)=\"showPicker($event)\"\n>\n <div\n class=\"file-placeholder\"\n data-cy=\"c8y-file-placeholder--drop-zone\"\n [ngClass]=\"{ 'drag-over': isOver }\"\n >\n <div\n class=\"d-flex d-col p-4 flex-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 50%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div\n class=\"spinner-snake\"\n *ngIf=\"progress === -1\"\n ></div>\n <p\n class=\"m-t-auto m-b-auto m-r-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n {{ loadingMessage | translate }}\n </p>\n </div>\n <div\n class=\"hint-placeholder pointer\"\n *ngIf=\"!loading\"\n data-cy=\"drop-zone--hint-placeholder\"\n >\n <i class=\"dlt-c8y-icon-{{ icon }}\"></i>\n <p *ngIf=\"!errors\" class=\"text-truncate\" title=\"{{ message | translate }}\">\n <b>{{ message | translate }}</b>\n <br />\n <span\n *ngIf=\"alwaysShow && clickToOpen\"\n translate\n ></span>\n </p>\n <div\n class=\"has-errors\"\n *ngIf=\"errors\"\n >\n <p class=\"form-control-feedback-message\">\n {{ errorMessage | translate }}\n </p>\n </div>\n </div>\n </div>\n</div>\n\n<div\n class=\"drop-zone\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"shouldShowFilesList()\"\n>\n <div\n class=\"p-absolute p-4 fit-w fit-h d-flex d-col j-c-center a-i-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 80%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div *ngIf=\"progress === -1\">\n <c8y-loading></c8y-loading>\n </div>\n <p\n class=\"m-b-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n <strong>\n {{ loadingMessage | translate }}\n </strong>\n </p>\n </div>\n <div\n class=\"file-placeholder p-4\"\n *ngIf=\"!loading\"\n >\n <div class=\"d-flex p-4 a-i-center\">\n <i\n class=\"icon-20 m-r-8\"\n c8yIcon=\"file-o\"\n ></i>\n <span\n class=\"text-truncate\"\n title=\"{{ filesNameString }}\"\n >\n {{ filesNameString }}\n </span>\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto\"\n title=\"{{ 'Remove' | translate }}\"\n [attr.aria-label]=\"'Remove' | translate\"\n type=\"button\"\n >\n <i\n c8yIcon=\"minus-circle\"\n (click)=\"onDelete()\"\n ></i>\n </button>\n </div>\n </div>\n</div>\n<label\n class=\"sr-only\"\n for=\"file\"\n>\n {{ 'Select file' | translate }}\n</label>\n<input\n class=\"hidden\"\n id=\"file\"\n type=\"file\"\n #picker\n *ngIf=\"clickToOpen\"\n (change)=\"onPick($event)\"\n (click)=\"picker.focus()\"\n (blur)=\"onTouched()\"\n [accept]=\"acceptedExts\"\n [multiple]=\"maxAllowedFiles > 1\"\n [disabled]=\"formControl?.disabled\"\n/>\n<div\n #area\n [hidden]=\"isOver || loading\"\n (dragover)=\"toggle()\"\n>\n <ng-content></ng-content>\n</div>\n" }]
22875
+ args: [{ selector: 'c8y-drop-area', providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: DropAreaComponent, multi: true }], standalone: true, imports: [CommonModule, C8yTranslatePipe, NgIf, NgClass, IconDirective], template: "<div\n class=\"drop-zone\"\n [style.pointerEvents]=\"loading ? 'none' : 'auto'\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"!shouldShowFilesList()\"\n [ngClass]=\"{ 'has-errors': errors, disabled: formControl?.disabled || disabled }\"\n #zone\n (dragleave)=\"stopDragging()\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onOver()\"\n (click)=\"showPicker($event)\"\n>\n <div\n class=\"file-placeholder\"\n data-cy=\"c8y-file-placeholder--drop-zone\"\n [ngClass]=\"{ 'drag-over': isOver }\"\n >\n <div\n class=\"d-flex d-col p-4 flex-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 50%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div\n class=\"spinner-snake\"\n *ngIf=\"progress === -1\"\n ></div>\n <p\n class=\"m-t-auto m-b-auto m-r-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n {{ loadingMessage | translate }}\n </p>\n </div>\n <div\n class=\"hint-placeholder pointer\"\n *ngIf=\"!loading\"\n data-cy=\"drop-zone--hint-placeholder\"\n >\n <i class=\"dlt-c8y-icon-{{ icon }}\"></i>\n <p\n class=\"text-truncate\"\n title=\"{{ message | translate }}\"\n *ngIf=\"!errors\"\n >\n <b>{{ message | translate }}</b>\n <br />\n <span\n *ngIf=\"alwaysShow && clickToOpen\"\n translate\n ></span>\n </p>\n <div\n class=\"has-errors\"\n *ngIf=\"errors\"\n >\n <p class=\"form-control-feedback-message\">\n {{ errorMessage | translate }}\n </p>\n </div>\n </div>\n </div>\n</div>\n\n<div\n class=\"drop-zone\"\n [style.display]=\"isOver || alwaysShow || loading ? 'block' : 'none'\"\n tabindex=\"0\"\n *ngIf=\"shouldShowFilesList()\"\n>\n <div\n class=\"p-absolute p-4 fit-w fit-h d-flex d-col j-c-center a-i-center\"\n *ngIf=\"loading\"\n >\n <div\n class=\"progress progress-striped active m-0\"\n style=\"min-width: 80%\"\n *ngIf=\"progress !== -1\"\n >\n <div\n class=\"progress-bar\"\n [style.width]=\"progress + '%'\"\n [attr.aria-label]=\"progress + '%'\"\n aria-valuenow=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n role=\"progressbar\"\n ></div>\n </div>\n <div *ngIf=\"progress === -1\">\n <c8y-loading></c8y-loading>\n </div>\n <p\n class=\"m-b-8\"\n *ngIf=\"!hasDropAreaSmallClass\"\n >\n <strong>\n {{ loadingMessage | translate }}\n </strong>\n </p>\n </div>\n <div\n class=\"file-placeholder p-4\"\n *ngIf=\"!loading\"\n >\n <div class=\"d-flex p-4 a-i-center\">\n <i\n class=\"icon-20 m-r-8\"\n c8yIcon=\"file-o\"\n ></i>\n <span\n class=\"text-truncate\"\n title=\"{{ filesNameString }}\"\n >\n {{ filesNameString }}\n </span>\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto\"\n title=\"{{ 'Remove' | translate }}\"\n [attr.aria-label]=\"'Remove' | translate\"\n type=\"button\"\n >\n <i\n c8yIcon=\"minus-circle\"\n (click)=\"onDelete()\"\n ></i>\n </button>\n </div>\n </div>\n</div>\n<label\n class=\"sr-only\"\n for=\"file\"\n>\n {{ 'Select file' | translate }}\n</label>\n<input\n class=\"hidden\"\n id=\"file\"\n type=\"file\"\n #picker\n *ngIf=\"clickToOpen\"\n (change)=\"onPick($event)\"\n (click)=\"picker.focus()\"\n (blur)=\"onTouched()\"\n [accept]=\"acceptedExts\"\n [multiple]=\"maxAllowedFiles > 1\"\n [disabled]=\"formControl?.disabled || disabled\"\n/>\n<div\n #area\n [hidden]=\"isOver || loading\"\n (dragover)=\"toggle()\"\n>\n <ng-content></ng-content>\n</div>\n" }]
22847
22876
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: FilesService }, { type: i1$1.TranslateService }, { type: BytesPipe }, { type: i0.ElementRef }], propDecorators: { formControl: [{
22848
22877
  type: Input
22849
22878
  }], title: [{
@@ -22994,7 +23023,7 @@ class FilePickerComponent {
22994
23023
  this.onFilesPicked.emit(this.fileToSave);
22995
23024
  }
22996
23025
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FilePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
22997
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: FilePickerComponent, isStandalone: true, selector: "c8y-file-picker", inputs: { maxAllowedFiles: "maxAllowedFiles", uploadChoice: "uploadChoice", allowedUploadChoices: "allowedUploadChoices", fileUrl: "fileUrl", fileBinary: "fileBinary", config: "config", filePickerIndex: "filePickerIndex", fileUrlPopover: "fileUrlPopover" }, outputs: { onFilesPicked: "onFilesPicked" }, viewQueries: [{ propertyName: "dropArea", first: true, predicate: DropAreaComponent, descendants: true, static: true }], ngImport: i0, template: "<div class=\"form-group\">\n <label\n class=\"c8y-radio\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadBinary\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearInputFromUrl()\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Provide a file path' | translate }}\"\n data-cy=\"file-picker--file-path-input\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadUrl\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearSelectedFiles()\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ fileUrlPopover | translate }}\"\n placement=\"top\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n *ngIf=\"isPopoverUsed()\"\n ></button>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Mark as provided' | translate }}\"\n *ngIf=\"allowedUploadChoices.includes('provided')\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"provided\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"setProvidedOption()\"\n />\n <span></span>\n <span>{{ 'Provided' | translate }}</span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ providedPopover | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </label>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [attr.aria-label]=\"'Drop file or click to browse' | translate\"\n (dropped)=\"onFileDropped($event)\"\n [maxAllowedFiles]=\"maxAllowedFiles\"\n [files]=\"droppedFiles\"\n ></c8y-drop-area>\n </c8y-form-group>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadUrl'\">\n <c8y-form-group class=\"m-0\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n name=\"fileUrl\"\n type=\"text\"\n required\n data-cy=\"file-picker--fileUrl\"\n [(ngModel)]=\"fileUrl\"\n (ngModelChange)=\"onFileUrlChange($event)\"\n maxlength=\"{{ config.maxlength }}\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </div>\n </div>\n </c8y-form-group>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.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$8.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$8.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i1$9.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
23026
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: FilePickerComponent, isStandalone: true, selector: "c8y-file-picker", inputs: { maxAllowedFiles: "maxAllowedFiles", uploadChoice: "uploadChoice", allowedUploadChoices: "allowedUploadChoices", fileUrl: "fileUrl", fileBinary: "fileBinary", config: "config", filePickerIndex: "filePickerIndex", fileUrlPopover: "fileUrlPopover" }, outputs: { onFilesPicked: "onFilesPicked" }, viewQueries: [{ propertyName: "dropArea", first: true, predicate: DropAreaComponent, descendants: true, static: true }], ngImport: i0, template: "<div class=\"form-group\">\n <label\n class=\"c8y-radio\"\n [class.m-l-8]=\"allowedUploadChoices.includes('provided')\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadBinary\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearInputFromUrl()\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Provide a file path' | translate }}\"\n data-cy=\"file-picker--file-path-input\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadUrl\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearSelectedFiles()\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ fileUrlPopover | translate }}\"\n placement=\"top\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n *ngIf=\"isPopoverUsed()\"\n ></button>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Mark as provided' | translate }}\"\n *ngIf=\"allowedUploadChoices.includes('provided')\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"provided\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"setProvidedOption()\"\n />\n <span></span>\n <span>{{ 'Provided' | translate }}</span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ providedPopover | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </label>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [attr.aria-label]=\"'Drop file or click to browse' | translate\"\n (dropped)=\"onFileDropped($event)\"\n [maxAllowedFiles]=\"maxAllowedFiles\"\n [files]=\"droppedFiles\"\n ></c8y-drop-area>\n </c8y-form-group>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadUrl'\">\n <c8y-form-group class=\"m-0\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n name=\"fileUrl\"\n type=\"text\"\n required\n data-cy=\"file-picker--fileUrl\"\n [(ngModel)]=\"fileUrl\"\n (ngModelChange)=\"onFileUrlChange($event)\"\n maxlength=\"{{ config.maxlength }}\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </div>\n </div>\n </c8y-form-group>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1$8.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$8.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$8.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$8.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i1$9.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
22998
23027
  }
22999
23028
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FilePickerComponent, decorators: [{
23000
23029
  type: Component,
@@ -23007,7 +23036,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
23007
23036
  IconDirective,
23008
23037
  RequiredInputPlaceholderDirective,
23009
23038
  C8yTranslatePipe
23010
- ], template: "<div class=\"form-group\">\n <label\n class=\"c8y-radio\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadBinary\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearInputFromUrl()\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Provide a file path' | translate }}\"\n data-cy=\"file-picker--file-path-input\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadUrl\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearSelectedFiles()\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ fileUrlPopover | translate }}\"\n placement=\"top\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n *ngIf=\"isPopoverUsed()\"\n ></button>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Mark as provided' | translate }}\"\n *ngIf=\"allowedUploadChoices.includes('provided')\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"provided\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"setProvidedOption()\"\n />\n <span></span>\n <span>{{ 'Provided' | translate }}</span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ providedPopover | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </label>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [attr.aria-label]=\"'Drop file or click to browse' | translate\"\n (dropped)=\"onFileDropped($event)\"\n [maxAllowedFiles]=\"maxAllowedFiles\"\n [files]=\"droppedFiles\"\n ></c8y-drop-area>\n </c8y-form-group>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadUrl'\">\n <c8y-form-group class=\"m-0\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n name=\"fileUrl\"\n type=\"text\"\n required\n data-cy=\"file-picker--fileUrl\"\n [(ngModel)]=\"fileUrl\"\n (ngModelChange)=\"onFileUrlChange($event)\"\n maxlength=\"{{ config.maxlength }}\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </div>\n </div>\n </c8y-form-group>\n</div>\n" }]
23039
+ ], template: "<div class=\"form-group\">\n <label\n class=\"c8y-radio\"\n [class.m-l-8]=\"allowedUploadChoices.includes('provided')\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadBinary\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearInputFromUrl()\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Provide a file path' | translate }}\"\n data-cy=\"file-picker--file-path-input\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"uploadUrl\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearSelectedFiles()\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ fileUrlPopover | translate }}\"\n placement=\"top\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n *ngIf=\"isPopoverUsed()\"\n ></button>\n </label>\n <label\n class=\"c8y-radio m-l-8\"\n title=\"{{ 'Mark as provided' | translate }}\"\n *ngIf=\"allowedUploadChoices.includes('provided')\"\n >\n <input\n name=\"uploadChoice-{{ filePickerIndex }}\"\n type=\"radio\"\n value=\"provided\"\n #radio\n [(ngModel)]=\"uploadChoice\"\n (click)=\"setProvidedOption()\"\n />\n <span></span>\n <span>{{ 'Provided' | translate }}</span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ providedPopover | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </label>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [attr.aria-label]=\"'Drop file or click to browse' | translate\"\n (dropped)=\"onFileDropped($event)\"\n [maxAllowedFiles]=\"maxAllowedFiles\"\n [files]=\"droppedFiles\"\n ></c8y-drop-area>\n </c8y-form-group>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadUrl'\">\n <c8y-form-group class=\"m-0\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n name=\"fileUrl\"\n type=\"text\"\n required\n data-cy=\"file-picker--fileUrl\"\n [(ngModel)]=\"fileUrl\"\n (ngModelChange)=\"onFileUrlChange($event)\"\n maxlength=\"{{ config.maxlength }}\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </div>\n </div>\n </c8y-form-group>\n</div>\n" }]
23011
23040
  }], propDecorators: { dropArea: [{
23012
23041
  type: ViewChild,
23013
23042
  args: [DropAreaComponent, { static: true }]