@c8y/ngx-components 1021.38.1 → 1021.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (524) hide show
  1. package/api/services.d.ts +1 -1
  2. package/api/services.d.ts.map +1 -1
  3. package/auth-configuration/sso-configuration/template-parts/access-mapping/access-mapping.component.d.ts.map +1 -1
  4. package/connectivity/abstract-connectivity-tab.factory.d.ts +1 -1
  5. package/context-dashboard/add-dashboard.component.d.ts.map +1 -1
  6. package/context-dashboard/context-dashboard.model.d.ts +4 -2
  7. package/context-dashboard/context-dashboard.model.d.ts.map +1 -1
  8. package/context-dashboard/dashboard-detail.component.d.ts.map +1 -1
  9. package/context-dashboard/dashboard-manager/dashboard-manager.model.d.ts +1 -0
  10. package/context-dashboard/dashboard-manager/dashboard-manager.model.d.ts.map +1 -1
  11. package/context-dashboard/dashboard-manager/dashboard-manager.service.d.ts +0 -1
  12. package/context-dashboard/dashboard-manager/dashboard-manager.service.d.ts.map +1 -1
  13. package/context-dashboard/dashboard-manager/type-dashboards-list/type-dashboards-list.component.d.ts.map +1 -1
  14. package/context-dashboard/new-dashboard.guard.d.ts +1 -1
  15. package/context-dashboard/new-dashboard.guard.d.ts.map +1 -1
  16. package/core/action/action.component.d.ts +2 -1
  17. package/core/action/action.component.d.ts.map +1 -1
  18. package/core/action/action.model.d.ts +3 -2
  19. package/core/action/action.model.d.ts.map +1 -1
  20. package/core/breadcrumb/breadcrumb-item.component.d.ts +2 -1
  21. package/core/breadcrumb/breadcrumb-item.component.d.ts.map +1 -1
  22. package/core/breadcrumb/breadcrumb.model.d.ts +2 -1
  23. package/core/breadcrumb/breadcrumb.model.d.ts.map +1 -1
  24. package/core/common/ApplicationOptions.d.ts +1 -0
  25. package/core/common/ApplicationOptions.d.ts.map +1 -1
  26. package/core/common/empty-state/empty-state.component.d.ts +2 -1
  27. package/core/common/empty-state/empty-state.component.d.ts.map +1 -1
  28. package/core/common/get-group-icon.pipe.d.ts +2 -1
  29. package/core/common/get-group-icon.pipe.d.ts.map +1 -1
  30. package/core/common/group.service.d.ts +22 -7
  31. package/core/common/group.service.d.ts.map +1 -1
  32. package/core/common/icon.directive.d.ts +5 -5
  33. package/core/common/icon.directive.d.ts.map +1 -1
  34. package/core/common/service-registry.model.d.ts +2 -1
  35. package/core/common/service-registry.model.d.ts.map +1 -1
  36. package/core/data-grid/data-grid.model.d.ts +2 -1
  37. package/core/data-grid/data-grid.model.d.ts.map +1 -1
  38. package/core/docs/docs.models.d.ts +2 -1
  39. package/core/docs/docs.models.d.ts.map +1 -1
  40. package/core/docs/help-and-support-outlet/help-and-support-outlet.component.d.ts +5 -1
  41. package/core/docs/help-and-support-outlet/help-and-support-outlet.component.d.ts.map +1 -1
  42. package/core/docs/legal-notices-outlet/legal-notices-outlet.component.d.ts +5 -1
  43. package/core/docs/legal-notices-outlet/legal-notices-outlet.component.d.ts.map +1 -1
  44. package/core/docs/support-outlet/support-outlet.component.d.ts +5 -1
  45. package/core/docs/support-outlet/support-outlet.component.d.ts.map +1 -1
  46. package/core/forms/filter-input.component.d.ts +8 -3
  47. package/core/forms/filter-input.component.d.ts.map +1 -1
  48. package/core/list-group/list-item-action.component.d.ts +2 -1
  49. package/core/list-group/list-item-action.component.d.ts.map +1 -1
  50. package/core/list-group/list-item-icon.component.d.ts +2 -1
  51. package/core/list-group/list-item-icon.component.d.ts.map +1 -1
  52. package/core/login/login.service.d.ts.map +1 -1
  53. package/core/navigator/navigator-icon.component.d.ts +1 -1
  54. package/core/navigator/navigator-icon.component.d.ts.map +1 -1
  55. package/core/navigator/navigator-node-data.d.ts +2 -1
  56. package/core/navigator/navigator-node-data.d.ts.map +1 -1
  57. package/core/navigator/navigator-node.component.d.ts.map +1 -1
  58. package/core/navigator/navigator-node.d.ts +2 -1
  59. package/core/navigator/navigator-node.d.ts.map +1 -1
  60. package/core/plugins/plugins.model.d.ts +7 -2
  61. package/core/plugins/plugins.model.d.ts.map +1 -1
  62. package/core/plugins/plugins.service.d.ts.map +1 -1
  63. package/core/properties-list/properties-list.component.d.ts +2 -1
  64. package/core/properties-list/properties-list.component.d.ts.map +1 -1
  65. package/core/provider-configuration/model/dynamic-provider-config.model.d.ts +2 -2
  66. package/core/provider-configuration/model/dynamic-provider-config.model.d.ts.map +1 -1
  67. package/core/router/context-route.service.d.ts.map +1 -1
  68. package/core/router/router.model.d.ts +1 -1
  69. package/core/router/router.model.d.ts.map +1 -1
  70. package/core/router/scoped-context-route.service.d.ts.map +1 -1
  71. package/core/search/search.model.d.ts +2 -1
  72. package/core/search/search.model.d.ts.map +1 -1
  73. package/core/select/select-keyboard.service.d.ts +4 -0
  74. package/core/select/select-keyboard.service.d.ts.map +1 -1
  75. package/core/select/select.component.d.ts +14 -3
  76. package/core/select/select.component.d.ts.map +1 -1
  77. package/core/select-modal/select-modal.component.d.ts +2 -1
  78. package/core/select-modal/select-modal.component.d.ts.map +1 -1
  79. package/core/shared/core.model.d.ts +5 -1
  80. package/core/shared/core.model.d.ts.map +1 -1
  81. package/core/tabs/conditional-tabs-outlet.component.d.ts.map +1 -1
  82. package/core/tabs/tab.component.d.ts +3 -2
  83. package/core/tabs/tab.component.d.ts.map +1 -1
  84. package/core/tabs/tab.model.d.ts +10 -5
  85. package/core/tabs/tab.model.d.ts.map +1 -1
  86. package/core/tabs/tabs-outlet.component.d.ts +7 -4
  87. package/core/tabs/tabs-outlet.component.d.ts.map +1 -1
  88. package/core/user/user-menu-item.component.d.ts +2 -1
  89. package/core/user/user-menu-item.component.d.ts.map +1 -1
  90. package/core/user/user.model.d.ts +2 -1
  91. package/core/user/user.model.d.ts.map +1 -1
  92. package/core/wizard/wizard.model.d.ts +4 -3
  93. package/core/wizard/wizard.model.d.ts.map +1 -1
  94. package/data-grid-columns/asset-type/asset-type.cell-renderer.component.d.ts.map +1 -1
  95. package/datapoint-selector/datapoint-attributes-form/datapoint-attributes-form.component.d.ts +15 -46
  96. package/datapoint-selector/datapoint-attributes-form/datapoint-attributes-form.component.d.ts.map +1 -1
  97. package/datapoint-selector/datapoint-attributes-form/datapoint-attributes.model.d.ts +3 -0
  98. package/datapoint-selector/datapoint-attributes-form/datapoint-attributes.model.d.ts.map +1 -1
  99. package/datapoint-selector/datapoint-selection.model.d.ts +6 -7
  100. package/datapoint-selector/datapoint-selection.model.d.ts.map +1 -1
  101. package/datapoints-export-selector/datapoints-export-selector.model.d.ts +2 -1
  102. package/datapoints-export-selector/datapoints-export-selector.model.d.ts.map +1 -1
  103. package/device-grid/columns/icon.cell-renderer.component.d.ts +14 -0
  104. package/device-grid/columns/icon.cell-renderer.component.d.ts.map +1 -0
  105. package/device-grid/columns/index.d.ts +1 -0
  106. package/device-grid/columns/index.d.ts.map +1 -1
  107. package/device-grid/device-grid.component.d.ts.map +1 -1
  108. package/device-grid/device-grid.service.d.ts +0 -2
  109. package/device-grid/device-grid.service.d.ts.map +1 -1
  110. package/device-provisioned-certificates/c8y-ngx-components-device-provisioned-certificates.d.ts.map +1 -0
  111. package/device-provisioned-certificates/device-provisioned-certificates.guard.d.ts +11 -0
  112. package/device-provisioned-certificates/device-provisioned-certificates.guard.d.ts.map +1 -0
  113. package/device-provisioned-certificates/device-provisioned-certificates.module.d.ts +13 -0
  114. package/device-provisioned-certificates/device-provisioned-certificates.module.d.ts.map +1 -0
  115. package/device-provisioned-certificates/device-provisioned-certificates.service.d.ts +13 -0
  116. package/device-provisioned-certificates/device-provisioned-certificates.service.d.ts.map +1 -0
  117. package/device-provisioned-certificates/device-tab-provisioned-certificates.component.d.ts +57 -0
  118. package/device-provisioned-certificates/device-tab-provisioned-certificates.component.d.ts.map +1 -0
  119. package/device-provisioned-certificates/index.d.ts +2 -0
  120. package/device-provisioned-certificates/index.d.ts.map +1 -0
  121. package/ecosystem/application-plugins/application-plugins.component.d.ts +4 -0
  122. package/ecosystem/application-plugins/application-plugins.component.d.ts.map +1 -1
  123. package/ecosystem/application-plugins/application-plugins.module.d.ts +2 -2
  124. package/ecosystem/application-plugins/application-plugins.module.d.ts.map +1 -1
  125. package/ecosystem/application-plugins/index.d.ts +1 -0
  126. package/ecosystem/application-plugins/index.d.ts.map +1 -1
  127. package/ecosystem/application-plugins/install-plugin.component.d.ts +9 -11
  128. package/ecosystem/application-plugins/install-plugin.component.d.ts.map +1 -1
  129. package/ecosystem/application-plugins/only-latest-filter/only-latest-filter.component.d.ts +12 -0
  130. package/ecosystem/application-plugins/only-latest-filter/only-latest-filter.component.d.ts.map +1 -0
  131. package/ecosystem/application-plugins/plugin-list-item.component.d.ts +8 -3
  132. package/ecosystem/application-plugins/plugin-list-item.component.d.ts.map +1 -1
  133. package/ecosystem/application-plugins/plugin-list.component.d.ts.map +1 -1
  134. package/ecosystem/application-plugins/update-plugin-of-app/update-plugin-of-app.component.d.ts.map +1 -1
  135. package/ecosystem/applications/application-list/application-list.component.d.ts +2 -2
  136. package/ecosystem/applications/application-list/application-list.component.d.ts.map +1 -1
  137. package/ecosystem/applications/install-from-package/install-from-package.component.d.ts.map +1 -1
  138. package/ecosystem/archived-confirm/archived-confirm-modal.component.d.ts +11 -0
  139. package/ecosystem/archived-confirm/archived-confirm-modal.component.d.ts.map +1 -0
  140. package/ecosystem/archived-confirm/archived-confirm.module.d.ts +10 -0
  141. package/ecosystem/archived-confirm/archived-confirm.module.d.ts.map +1 -0
  142. package/ecosystem/archived-confirm/c8y-ngx-components-ecosystem-archived-confirm.d.ts.map +1 -0
  143. package/ecosystem/archived-confirm/index.d.ts +3 -0
  144. package/ecosystem/archived-confirm/index.d.ts.map +1 -0
  145. package/ecosystem/ecosystem.module.d.ts +2 -1
  146. package/ecosystem/ecosystem.module.d.ts.map +1 -1
  147. package/ecosystem/features/feature-list.component.d.ts +2 -2
  148. package/ecosystem/features/feature-list.component.d.ts.map +1 -1
  149. package/ecosystem/microservices/microservice-list.component.d.ts +2 -2
  150. package/ecosystem/microservices/microservice-list.component.d.ts.map +1 -1
  151. package/ecosystem/packages/deploy-application/deploy-application.component.d.ts.map +1 -1
  152. package/ecosystem/packages/package-details/package-details.component.d.ts +7 -2
  153. package/ecosystem/packages/package-details/package-details.component.d.ts.map +1 -1
  154. package/ecosystem/packages/package-list/packages-list.component.d.ts +2 -2
  155. package/ecosystem/packages/package-list/packages-list.component.d.ts.map +1 -1
  156. package/ecosystem/shared/add-application.component.d.ts +2 -1
  157. package/ecosystem/shared/add-application.component.d.ts.map +1 -1
  158. package/ecosystem/shared/application-card.component.d.ts +4 -0
  159. package/ecosystem/shared/application-card.component.d.ts.map +1 -1
  160. package/ecosystem/shared/archived-filter/archived-filter.component.d.ts +12 -0
  161. package/ecosystem/shared/archived-filter/archived-filter.component.d.ts.map +1 -0
  162. package/ecosystem/shared/ecosystem.constants.d.ts +4 -0
  163. package/ecosystem/shared/ecosystem.constants.d.ts.map +1 -1
  164. package/ecosystem/shared/ecosystem.model.d.ts +5 -1
  165. package/ecosystem/shared/ecosystem.model.d.ts.map +1 -1
  166. package/ecosystem/shared/ecosystem.service.d.ts +7 -0
  167. package/ecosystem/shared/ecosystem.service.d.ts.map +1 -1
  168. package/ecosystem/shared/index.d.ts +1 -0
  169. package/ecosystem/shared/index.d.ts.map +1 -1
  170. package/ecosystem/shared/list-filters/list-filters.component.d.ts +14 -4
  171. package/ecosystem/shared/list-filters/list-filters.component.d.ts.map +1 -1
  172. package/ecosystem/shared/list-filters/list-filters.model.d.ts +8 -2
  173. package/ecosystem/shared/list-filters/list-filters.model.d.ts.map +1 -1
  174. package/ecosystem/shared/shared-ecosystem.module.d.ts +9 -8
  175. package/ecosystem/shared/shared-ecosystem.module.d.ts.map +1 -1
  176. package/ecosystem/shared/translate-package-label.pipe.d.ts +1 -1
  177. package/ecosystem/shared/translate-package-label.pipe.d.ts.map +1 -1
  178. package/esm2022/alarms/alarm-info.component.mjs +1 -1
  179. package/esm2022/api/services.mjs +2 -2
  180. package/esm2022/auth-configuration/sso-configuration/template-parts/access-mapping/access-mapping.component.mjs +10 -5
  181. package/esm2022/auth-configuration/sso-configuration/template-parts/user-data-mapping.component.mjs +4 -4
  182. package/esm2022/context-dashboard/add-dashboard.component.mjs +4 -2
  183. package/esm2022/context-dashboard/context-dashboard.model.mjs +3 -2
  184. package/esm2022/context-dashboard/context-dashboard.service.mjs +2 -2
  185. package/esm2022/context-dashboard/dashboard-detail.component.mjs +5 -3
  186. package/esm2022/context-dashboard/dashboard-manager/dashboard-manager.model.mjs +1 -1
  187. package/esm2022/context-dashboard/dashboard-manager/dashboard-manager.service.mjs +5 -15
  188. package/esm2022/context-dashboard/dashboard-manager/type-dashboards-list/type-dashboards-list.component.mjs +2 -2
  189. package/esm2022/context-dashboard/new-dashboard.guard.mjs +1 -1
  190. package/esm2022/core/action/action.component.mjs +1 -1
  191. package/esm2022/core/action/action.model.mjs +1 -1
  192. package/esm2022/core/bootstrap/bootstrap.component.mjs +1 -1
  193. package/esm2022/core/breadcrumb/breadcrumb-item.component.mjs +1 -1
  194. package/esm2022/core/breadcrumb/breadcrumb.model.mjs +1 -1
  195. package/esm2022/core/common/ApplicationOptions.mjs +1 -1
  196. package/esm2022/core/common/empty-state/empty-state.component.mjs +1 -1
  197. package/esm2022/core/common/get-group-icon.pipe.mjs +1 -1
  198. package/esm2022/core/common/group.service.mjs +2 -2
  199. package/esm2022/core/common/icon.directive.mjs +1 -1
  200. package/esm2022/core/common/service-registry.model.mjs +1 -1
  201. package/esm2022/core/data-grid/data-grid.model.mjs +1 -1
  202. package/esm2022/core/docs/docs.models.mjs +1 -1
  203. package/esm2022/core/docs/support-outlet/support-outlet.component.mjs +3 -3
  204. package/esm2022/core/forms/filter-input.component.mjs +22 -7
  205. package/esm2022/core/list-group/list-item-action.component.mjs +1 -1
  206. package/esm2022/core/list-group/list-item-icon.component.mjs +1 -1
  207. package/esm2022/core/login/credentials.component.mjs +2 -2
  208. package/esm2022/core/login/login.service.mjs +18 -7
  209. package/esm2022/core/navigator/navigator-node-data.mjs +1 -1
  210. package/esm2022/core/navigator/navigator-node.component.mjs +11 -2
  211. package/esm2022/core/navigator/navigator-node.mjs +1 -1
  212. package/esm2022/core/plugins/plugins.model.mjs +5 -1
  213. package/esm2022/core/plugins/plugins.service.mjs +6 -2
  214. package/esm2022/core/properties-list/properties-list.component.mjs +1 -1
  215. package/esm2022/core/provider-configuration/model/dynamic-provider-config.model.mjs +1 -1
  216. package/esm2022/core/router/context-route.service.mjs +4 -2
  217. package/esm2022/core/router/router.model.mjs +1 -1
  218. package/esm2022/core/router/scoped-context-route.service.mjs +4 -2
  219. package/esm2022/core/search/search.model.mjs +1 -1
  220. package/esm2022/core/select/select-keyboard.service.mjs +7 -3
  221. package/esm2022/core/select/select.component.mjs +36 -8
  222. package/esm2022/core/select-modal/select-modal.component.mjs +2 -2
  223. package/esm2022/core/shared/core.model.mjs +6 -2
  224. package/esm2022/core/tabs/conditional-tabs-outlet.component.mjs +4 -2
  225. package/esm2022/core/tabs/tab.component.mjs +1 -1
  226. package/esm2022/core/tabs/tab.model.mjs +1 -1
  227. package/esm2022/core/tabs/tabs-outlet.component.mjs +41 -12
  228. package/esm2022/core/user/user-menu-item.component.mjs +1 -1
  229. package/esm2022/core/user/user.model.mjs +1 -1
  230. package/esm2022/core/wizard/wizard.model.mjs +1 -1
  231. package/esm2022/data-grid-columns/asset-type/asset-type.cell-renderer.component.mjs +1 -1
  232. package/esm2022/datapoint-selector/datapoint-attributes-form/datapoint-attributes-form.component.mjs +47 -22
  233. package/esm2022/datapoint-selector/datapoint-attributes-form/datapoint-attributes.model.mjs +1 -1
  234. package/esm2022/datapoint-selector/datapoint-selection.model.mjs +1 -1
  235. package/esm2022/datapoint-selector/datapoint-selector-list-item/datapoint-selector-list-item.component.mjs +3 -3
  236. package/esm2022/datapoints-export-selector/datapoints-export-selector.model.mjs +1 -1
  237. package/esm2022/device-grid/columns/icon.cell-renderer.component.mjs +42 -0
  238. package/esm2022/device-grid/columns/index.mjs +2 -1
  239. package/esm2022/device-grid/device-grid.component.mjs +3 -3
  240. package/esm2022/device-grid/device-grid.service.mjs +7 -25
  241. package/esm2022/device-provisioned-certificates/c8y-ngx-components-device-provisioned-certificates.mjs +5 -0
  242. package/esm2022/device-provisioned-certificates/device-provisioned-certificates.guard.mjs +28 -0
  243. package/esm2022/device-provisioned-certificates/device-provisioned-certificates.module.mjs +51 -0
  244. package/esm2022/device-provisioned-certificates/device-provisioned-certificates.service.mjs +31 -0
  245. package/esm2022/device-provisioned-certificates/device-tab-provisioned-certificates.component.mjs +76 -0
  246. package/esm2022/device-provisioned-certificates/index.mjs +2 -0
  247. package/esm2022/ecosystem/application-plugins/application-plugins.component.mjs +41 -39
  248. package/esm2022/ecosystem/application-plugins/application-plugins.module.mjs +8 -6
  249. package/esm2022/ecosystem/application-plugins/apps-to-update-remotes-select.component.mjs +1 -1
  250. package/esm2022/ecosystem/application-plugins/index.mjs +2 -1
  251. package/esm2022/ecosystem/application-plugins/install-plugin.component.mjs +18 -21
  252. package/esm2022/ecosystem/application-plugins/only-latest-filter/only-latest-filter.component.mjs +26 -0
  253. package/esm2022/ecosystem/application-plugins/plugin-list-item.component.mjs +14 -6
  254. package/esm2022/ecosystem/application-plugins/plugin-list.component.mjs +14 -12
  255. package/esm2022/ecosystem/application-plugins/update-plugin-of-app/update-plugin-of-app.component.mjs +7 -1
  256. package/esm2022/ecosystem/applications/application-list/application-list.component.mjs +1 -1
  257. package/esm2022/ecosystem/applications/install-from-package/install-from-package.component.mjs +6 -1
  258. package/esm2022/ecosystem/archived-confirm/archived-confirm-modal.component.mjs +22 -0
  259. package/esm2022/ecosystem/archived-confirm/archived-confirm.module.mjs +32 -0
  260. package/esm2022/ecosystem/archived-confirm/c8y-ngx-components-ecosystem-archived-confirm.mjs +5 -0
  261. package/esm2022/ecosystem/archived-confirm/index.mjs +3 -0
  262. package/esm2022/ecosystem/ecosystem.module.mjs +20 -16
  263. package/esm2022/ecosystem/features/feature-list.component.mjs +1 -1
  264. package/esm2022/ecosystem/microservices/microservice-list.component.mjs +1 -1
  265. package/esm2022/ecosystem/packages/deploy-application/deploy-application.component.mjs +6 -1
  266. package/esm2022/ecosystem/packages/package-details/package-details.component.mjs +13 -8
  267. package/esm2022/ecosystem/packages/package-list/packages-list.component.mjs +4 -4
  268. package/esm2022/ecosystem/shared/add-application.component.mjs +1 -1
  269. package/esm2022/ecosystem/shared/application-card.component.mjs +3 -3
  270. package/esm2022/ecosystem/shared/archived-filter/archived-filter.component.mjs +27 -0
  271. package/esm2022/ecosystem/shared/ecosystem.constants.mjs +5 -1
  272. package/esm2022/ecosystem/shared/ecosystem.model.mjs +7 -3
  273. package/esm2022/ecosystem/shared/ecosystem.service.mjs +26 -1
  274. package/esm2022/ecosystem/shared/index.mjs +2 -1
  275. package/esm2022/ecosystem/shared/list-filters/list-filters.component.mjs +75 -13
  276. package/esm2022/ecosystem/shared/list-filters/list-filters.model.mjs +1 -1
  277. package/esm2022/ecosystem/shared/shared-ecosystem.module.mjs +10 -5
  278. package/esm2022/ecosystem/shared/translate-package-label.pipe.mjs +3 -3
  279. package/esm2022/files-repository/files-repository.component.mjs +2 -2
  280. package/esm2022/files-repository/files-repository.service.mjs +5 -16
  281. package/esm2022/icon-selector/icon-selector.component.mjs +1 -1
  282. package/esm2022/icon-selector/icons/index.mjs +1 -1
  283. package/esm2022/operations/shared/status-option.model.mjs +1 -1
  284. package/esm2022/protocol-lwm2m/components/configuration/lwm2m-configuration.component.mjs +2 -2
  285. package/esm2022/protocol-opcua/opcua-auto-apply-settings.component.mjs +1 -1
  286. package/esm2022/register-device/bulk/bulk-device-registration-modal.component.mjs +17 -9
  287. package/esm2022/register-device/general/general-device-registration-button.component.mjs +3 -3
  288. package/esm2022/register-device/general/general-device-registration.component.mjs +109 -33
  289. package/esm2022/remote-access/configurations/c8y-ngx-components-remote-access-configurations.mjs +5 -0
  290. package/esm2022/remote-access/configurations/index.mjs +16 -0
  291. package/esm2022/remote-access/configurations/remote-access-configuration-list/remote-access-configuration-list.component.mjs +218 -0
  292. package/esm2022/remote-access/configurations/remote-access-configuration-list/remote-access-connect-button/remote-access-connect-button.component.mjs +60 -0
  293. package/esm2022/remote-access/configurations/remote-access-pick-protocol-modal/remote-access-pick-protocol-modal.component.mjs +36 -0
  294. package/esm2022/remote-access/data/c8y-ngx-components-remote-access-data.mjs +5 -0
  295. package/esm2022/remote-access/data/index.mjs +3 -0
  296. package/esm2022/remote-access/data/remote-access-protocol-provider.mjs +2 -0
  297. package/esm2022/remote-access/data/remote-access.service.mjs +200 -0
  298. package/esm2022/remote-access/passthrough/c8y-ngx-components-remote-access-passthrough.mjs +5 -0
  299. package/esm2022/remote-access/passthrough/index.mjs +36 -0
  300. package/esm2022/remote-access/shared/c8y-ngx-components-remote-access-shared.mjs +5 -0
  301. package/esm2022/remote-access/shared/index.mjs +3 -0
  302. package/esm2022/remote-access/shared/remote-access-basic-endpoint-modal/remote-access-basic-endpoint-modal.component.mjs +49 -0
  303. package/esm2022/remote-access/shared/ssh-key-input/ssh-key-input.component.mjs +87 -0
  304. package/esm2022/remote-access/ssh/c8y-ngx-components-remote-access-ssh.mjs +5 -0
  305. package/esm2022/remote-access/ssh/index.mjs +73 -0
  306. package/esm2022/remote-access/ssh/remote-access-ssh-endpoint-modal/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +5 -0
  307. package/esm2022/remote-access/ssh/remote-access-ssh-endpoint-modal/index.mjs +2 -0
  308. package/esm2022/remote-access/ssh/remote-access-ssh-endpoint-modal/remote-access-ssh-endpoint-modal.component.mjs +104 -0
  309. package/esm2022/remote-access/telnet/c8y-ngx-components-remote-access-telnet.mjs +5 -0
  310. package/esm2022/remote-access/telnet/index.mjs +43 -0
  311. package/esm2022/remote-access/terminal-viewer/c8y-ngx-components-remote-access-terminal-viewer.mjs +5 -0
  312. package/esm2022/remote-access/terminal-viewer/index.mjs +2 -0
  313. package/esm2022/remote-access/terminal-viewer/shell-adapter.mjs +36 -0
  314. package/esm2022/remote-access/terminal-viewer/telnet-negotiator.mjs +96 -0
  315. package/esm2022/remote-access/terminal-viewer/terminal-viewer.component.mjs +101 -0
  316. package/esm2022/remote-access/vnc/c8y-ngx-components-remote-access-vnc.mjs +5 -0
  317. package/esm2022/remote-access/vnc/index.mjs +73 -0
  318. package/esm2022/remote-access/vnc/remote-access-vnc-endpoint-modal/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs +5 -0
  319. package/esm2022/remote-access/vnc/remote-access-vnc-endpoint-modal/index.mjs +2 -0
  320. package/esm2022/remote-access/vnc/remote-access-vnc-endpoint-modal/remote-access-vnc-endpoint-modal.component.mjs +59 -0
  321. package/esm2022/remote-access/vnc/vnc-viewer/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs +5 -0
  322. package/esm2022/remote-access/vnc/vnc-viewer/index.mjs +2 -0
  323. package/esm2022/remote-access/vnc/vnc-viewer/vnc-credentials-prompt/vnc-credentials-prompt.component.mjs +57 -0
  324. package/esm2022/remote-access/vnc/vnc-viewer/vnc-viewer.component.mjs +158 -0
  325. package/esm2022/replace-device/replace-device-wizard/replace-device-wizard.model.mjs +1 -1
  326. package/esm2022/report-dashboard/report-dashboard-list.component.mjs +4 -3
  327. package/esm2022/repository/configuration/device-tab/device-configuration-list.component.mjs +1 -1
  328. package/esm2022/repository/shared/repository.model.mjs +1 -1
  329. package/esm2022/repository/shared/repository.service.mjs +3 -3
  330. package/esm2022/services/status-options/status-options.model.mjs +1 -1
  331. package/esm2022/sub-assets/group-info.component.mjs +1 -1
  332. package/esm2022/translation-editor/data/translation-store.service.mjs +4 -3
  333. package/esm2022/trusted-certificates/list/trusted-certificate-list.component.mjs +35 -9
  334. package/esm2022/upgrade/bridge.service.mjs +16 -2
  335. package/esm2022/widgets/implementations/alarms/severity-icon.pipe.mjs +1 -1
  336. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.component.mjs +3 -2
  337. package/esm2022/widgets/implementations/kpi/kpi-widget.model.mjs +1 -1
  338. package/fesm2022/c8y-ngx-components-alarms.mjs +1 -1
  339. package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
  340. package/fesm2022/c8y-ngx-components-api.mjs +3 -2
  341. package/fesm2022/c8y-ngx-components-api.mjs.map +1 -1
  342. package/fesm2022/c8y-ngx-components-auth-configuration.mjs +12 -7
  343. package/fesm2022/c8y-ngx-components-auth-configuration.mjs.map +1 -1
  344. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +15 -20
  345. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  346. package/fesm2022/c8y-ngx-components-data-grid-columns-asset-type.mjs.map +1 -1
  347. package/fesm2022/c8y-ngx-components-data-grid-columns.mjs.map +1 -1
  348. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +48 -23
  349. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
  350. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  351. package/fesm2022/c8y-ngx-components-device-grid.mjs +48 -28
  352. package/fesm2022/c8y-ngx-components-device-grid.mjs.map +1 -1
  353. package/fesm2022/c8y-ngx-components-device-provisioned-certificates.mjs +174 -0
  354. package/fesm2022/c8y-ngx-components-device-provisioned-certificates.mjs.map +1 -0
  355. package/fesm2022/c8y-ngx-components-ecosystem-application-plugins.mjs +125 -105
  356. package/fesm2022/c8y-ngx-components-ecosystem-application-plugins.mjs.map +1 -1
  357. package/fesm2022/c8y-ngx-components-ecosystem-archived-confirm.mjs +57 -0
  358. package/fesm2022/c8y-ngx-components-ecosystem-archived-confirm.mjs.map +1 -0
  359. package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs +147 -31
  360. package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
  361. package/fesm2022/c8y-ngx-components-ecosystem.mjs +1452 -1414
  362. package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
  363. package/fesm2022/c8y-ngx-components-files-repository.mjs +5 -16
  364. package/fesm2022/c8y-ngx-components-files-repository.mjs.map +1 -1
  365. package/fesm2022/c8y-ngx-components-icon-selector-icons.mjs.map +1 -1
  366. package/fesm2022/c8y-ngx-components-icon-selector.mjs.map +1 -1
  367. package/fesm2022/c8y-ngx-components-protocol-lwm2m-components-configuration.mjs +1 -1
  368. package/fesm2022/c8y-ngx-components-protocol-lwm2m-components-configuration.mjs.map +1 -1
  369. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +1 -1
  370. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
  371. package/fesm2022/c8y-ngx-components-register-device.mjs +269 -188
  372. package/fesm2022/c8y-ngx-components-register-device.mjs.map +1 -1
  373. package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs +314 -0
  374. package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs.map +1 -0
  375. package/fesm2022/c8y-ngx-components-remote-access-data.mjs +206 -0
  376. package/fesm2022/c8y-ngx-components-remote-access-data.mjs.map +1 -0
  377. package/fesm2022/c8y-ngx-components-remote-access-passthrough.mjs +42 -0
  378. package/fesm2022/c8y-ngx-components-remote-access-passthrough.mjs.map +1 -0
  379. package/fesm2022/c8y-ngx-components-remote-access-shared.mjs +138 -0
  380. package/fesm2022/c8y-ngx-components-remote-access-shared.mjs.map +1 -0
  381. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +111 -0
  382. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs.map +1 -0
  383. package/fesm2022/c8y-ngx-components-remote-access-ssh.mjs +79 -0
  384. package/fesm2022/c8y-ngx-components-remote-access-ssh.mjs.map +1 -0
  385. package/fesm2022/c8y-ngx-components-remote-access-telnet.mjs +50 -0
  386. package/fesm2022/c8y-ngx-components-remote-access-telnet.mjs.map +1 -0
  387. package/fesm2022/c8y-ngx-components-remote-access-terminal-viewer.mjs +235 -0
  388. package/fesm2022/c8y-ngx-components-remote-access-terminal-viewer.mjs.map +1 -0
  389. package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs +66 -0
  390. package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs.map +1 -0
  391. package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs +211 -0
  392. package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs.map +1 -0
  393. package/fesm2022/c8y-ngx-components-remote-access-vnc.mjs +79 -0
  394. package/fesm2022/c8y-ngx-components-remote-access-vnc.mjs.map +1 -0
  395. package/fesm2022/c8y-ngx-components-replace-device-replace-device-wizard.mjs.map +1 -1
  396. package/fesm2022/c8y-ngx-components-report-dashboard.mjs +3 -2
  397. package/fesm2022/c8y-ngx-components-report-dashboard.mjs.map +1 -1
  398. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +1 -1
  399. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  400. package/fesm2022/c8y-ngx-components-repository-shared.mjs +2 -2
  401. package/fesm2022/c8y-ngx-components-repository-shared.mjs.map +1 -1
  402. package/fesm2022/c8y-ngx-components-services.mjs.map +1 -1
  403. package/fesm2022/c8y-ngx-components-sub-assets.mjs.map +1 -1
  404. package/fesm2022/c8y-ngx-components-translation-editor-data.mjs +3 -2
  405. package/fesm2022/c8y-ngx-components-translation-editor-data.mjs.map +1 -1
  406. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs +43 -17
  407. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs.map +1 -1
  408. package/fesm2022/c8y-ngx-components-upgrade.mjs +16 -2
  409. package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
  410. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs.map +1 -1
  411. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +2 -1
  412. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
  413. package/fesm2022/c8y-ngx-components.mjs +151 -38
  414. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  415. package/files-repository/files-repository.component.d.ts.map +1 -1
  416. package/files-repository/files-repository.service.d.ts +0 -2
  417. package/files-repository/files-repository.service.d.ts.map +1 -1
  418. package/icon-selector/icon-selector.component.d.ts +3 -2
  419. package/icon-selector/icon-selector.component.d.ts.map +1 -1
  420. package/icon-selector/icons/index.d.ts +1 -0
  421. package/icon-selector/icons/index.d.ts.map +1 -1
  422. package/locales/de.po +157 -5
  423. package/locales/es.po +157 -5
  424. package/locales/fr.po +157 -5
  425. package/locales/ja_JP.po +156 -5
  426. package/locales/ko.po +156 -5
  427. package/locales/locales.pot +156 -4
  428. package/locales/nl.po +157 -5
  429. package/locales/pl.po +157 -5
  430. package/locales/pt_BR.po +157 -5
  431. package/locales/zh_CN.po +156 -5
  432. package/locales/zh_TW.po +156 -5
  433. package/operations/shared/status-option.model.d.ts +2 -1
  434. package/operations/shared/status-option.model.d.ts.map +1 -1
  435. package/package.json +1 -1
  436. package/register-device/bulk/bulk-device-registration-modal.component.d.ts +6 -2
  437. package/register-device/bulk/bulk-device-registration-modal.component.d.ts.map +1 -1
  438. package/register-device/general/general-device-registration-button.component.d.ts +1 -1
  439. package/register-device/general/general-device-registration-button.component.d.ts.map +1 -1
  440. package/register-device/general/general-device-registration.component.d.ts +21 -7
  441. package/register-device/general/general-device-registration.component.d.ts.map +1 -1
  442. package/remote-access/configurations/c8y-ngx-components-remote-access-configurations.d.ts.map +1 -0
  443. package/remote-access/configurations/index.d.ts +3 -0
  444. package/remote-access/configurations/index.d.ts.map +1 -0
  445. package/remote-access/configurations/remote-access-configuration-list/remote-access-configuration-list.component.d.ts +34 -0
  446. package/remote-access/configurations/remote-access-configuration-list/remote-access-configuration-list.component.d.ts.map +1 -0
  447. package/remote-access/configurations/remote-access-configuration-list/remote-access-connect-button/remote-access-connect-button.component.d.ts +17 -0
  448. package/remote-access/configurations/remote-access-configuration-list/remote-access-connect-button/remote-access-connect-button.component.d.ts.map +1 -0
  449. package/remote-access/configurations/remote-access-pick-protocol-modal/remote-access-pick-protocol-modal.component.d.ts +18 -0
  450. package/remote-access/configurations/remote-access-pick-protocol-modal/remote-access-pick-protocol-modal.component.d.ts.map +1 -0
  451. package/remote-access/data/c8y-ngx-components-remote-access-data.d.ts.map +1 -0
  452. package/remote-access/data/index.d.ts +3 -0
  453. package/remote-access/data/index.d.ts.map +1 -0
  454. package/remote-access/data/remote-access-protocol-provider.d.ts +21 -0
  455. package/remote-access/data/remote-access-protocol-provider.d.ts.map +1 -0
  456. package/remote-access/data/remote-access.service.d.ts +94 -0
  457. package/remote-access/data/remote-access.service.d.ts.map +1 -0
  458. package/remote-access/passthrough/c8y-ngx-components-remote-access-passthrough.d.ts.map +1 -0
  459. package/remote-access/passthrough/index.d.ts +17 -0
  460. package/remote-access/passthrough/index.d.ts.map +1 -0
  461. package/remote-access/shared/c8y-ngx-components-remote-access-shared.d.ts.map +1 -0
  462. package/remote-access/shared/index.d.ts +3 -0
  463. package/remote-access/shared/index.d.ts.map +1 -0
  464. package/remote-access/shared/remote-access-basic-endpoint-modal/remote-access-basic-endpoint-modal.component.d.ts +37 -0
  465. package/remote-access/shared/remote-access-basic-endpoint-modal/remote-access-basic-endpoint-modal.component.d.ts.map +1 -0
  466. package/remote-access/shared/ssh-key-input/ssh-key-input.component.d.ts +38 -0
  467. package/remote-access/shared/ssh-key-input/ssh-key-input.component.d.ts.map +1 -0
  468. package/remote-access/ssh/c8y-ngx-components-remote-access-ssh.d.ts.map +1 -0
  469. package/remote-access/ssh/index.d.ts +22 -0
  470. package/remote-access/ssh/index.d.ts.map +1 -0
  471. package/remote-access/ssh/remote-access-ssh-endpoint-modal/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.d.ts.map +1 -0
  472. package/remote-access/ssh/remote-access-ssh-endpoint-modal/index.d.ts +2 -0
  473. package/remote-access/ssh/remote-access-ssh-endpoint-modal/index.d.ts.map +1 -0
  474. package/remote-access/ssh/remote-access-ssh-endpoint-modal/remote-access-ssh-endpoint-modal.component.d.ts +64 -0
  475. package/remote-access/ssh/remote-access-ssh-endpoint-modal/remote-access-ssh-endpoint-modal.component.d.ts.map +1 -0
  476. package/remote-access/telnet/c8y-ngx-components-remote-access-telnet.d.ts.map +1 -0
  477. package/remote-access/telnet/index.d.ts +17 -0
  478. package/remote-access/telnet/index.d.ts.map +1 -0
  479. package/remote-access/terminal-viewer/c8y-ngx-components-remote-access-terminal-viewer.d.ts.map +1 -0
  480. package/remote-access/terminal-viewer/index.d.ts +2 -0
  481. package/remote-access/terminal-viewer/index.d.ts.map +1 -0
  482. package/remote-access/terminal-viewer/shell-adapter.d.ts +14 -0
  483. package/remote-access/terminal-viewer/shell-adapter.d.ts.map +1 -0
  484. package/remote-access/terminal-viewer/telnet-negotiator.d.ts +13 -0
  485. package/remote-access/terminal-viewer/telnet-negotiator.d.ts.map +1 -0
  486. package/remote-access/terminal-viewer/terminal-viewer.component.d.ts +25 -0
  487. package/remote-access/terminal-viewer/terminal-viewer.component.d.ts.map +1 -0
  488. package/remote-access/vnc/c8y-ngx-components-remote-access-vnc.d.ts.map +1 -0
  489. package/remote-access/vnc/index.d.ts +22 -0
  490. package/remote-access/vnc/index.d.ts.map +1 -0
  491. package/remote-access/vnc/remote-access-vnc-endpoint-modal/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.d.ts.map +1 -0
  492. package/remote-access/vnc/remote-access-vnc-endpoint-modal/index.d.ts +2 -0
  493. package/remote-access/vnc/remote-access-vnc-endpoint-modal/index.d.ts.map +1 -0
  494. package/remote-access/vnc/remote-access-vnc-endpoint-modal/remote-access-vnc-endpoint-modal.component.d.ts +46 -0
  495. package/remote-access/vnc/remote-access-vnc-endpoint-modal/remote-access-vnc-endpoint-modal.component.d.ts.map +1 -0
  496. package/remote-access/vnc/vnc-viewer/c8y-ngx-components-remote-access-vnc-vnc-viewer.d.ts.map +1 -0
  497. package/remote-access/vnc/vnc-viewer/index.d.ts +2 -0
  498. package/remote-access/vnc/vnc-viewer/index.d.ts.map +1 -0
  499. package/remote-access/vnc/vnc-viewer/vnc-credentials-prompt/vnc-credentials-prompt.component.d.ts +32 -0
  500. package/remote-access/vnc/vnc-viewer/vnc-credentials-prompt/vnc-credentials-prompt.component.d.ts.map +1 -0
  501. package/remote-access/vnc/vnc-viewer/vnc-viewer.component.d.ts +37 -0
  502. package/remote-access/vnc/vnc-viewer/vnc-viewer.component.d.ts.map +1 -0
  503. package/replace-device/replace-device-wizard/replace-device-wizard.model.d.ts +2 -1
  504. package/replace-device/replace-device-wizard/replace-device-wizard.model.d.ts.map +1 -1
  505. package/report-dashboard/report-dashboard-list.component.d.ts +29 -0
  506. package/report-dashboard/report-dashboard-list.component.d.ts.map +1 -1
  507. package/repository/shared/repository.model.d.ts +2 -1
  508. package/repository/shared/repository.model.d.ts.map +1 -1
  509. package/services/status-options/status-options.model.d.ts +2 -1
  510. package/services/status-options/status-options.model.d.ts.map +1 -1
  511. package/sub-assets/group-info.component.d.ts +2 -1
  512. package/sub-assets/group-info.component.d.ts.map +1 -1
  513. package/translation-editor/data/translation-store.service.d.ts.map +1 -1
  514. package/trusted-certificates/list/trusted-certificate-list.component.d.ts +7 -2
  515. package/trusted-certificates/list/trusted-certificate-list.component.d.ts.map +1 -1
  516. package/upgrade/bridge.service.d.ts +5 -0
  517. package/upgrade/bridge.service.d.ts.map +1 -1
  518. package/widgets/implementations/alarms/severity-icon.pipe.d.ts.map +1 -1
  519. package/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.component.d.ts.map +1 -1
  520. package/widgets/implementations/kpi/kpi-widget.model.d.ts +2 -1
  521. package/widgets/implementations/kpi/kpi-widget.model.d.ts.map +1 -1
  522. package/ecosystem/application-plugins/only-latest-plugin-version.pipe.d.ts +0 -10
  523. package/ecosystem/application-plugins/only-latest-plugin-version.pipe.d.ts.map +0 -1
  524. package/esm2022/ecosystem/application-plugins/only-latest-plugin-version.pipe.mjs +0 -20
@@ -1,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, Input, Pipe, EventEmitter, Output, ViewChild, Injectable, NgModule } from '@angular/core';
3
3
  import * as i2 from '@c8y/ngx-components';
4
- import { gettext, Status, PluginsService, PluginsExportScopes, Permissions, ViewContext, C8yStepper, PackageType, ApplicationPluginStatus, DataGridComponent, CoreModule, hookRoute, FormsModule, hookTab, hookNavigator, hookWizard } from '@c8y/ngx-components';
4
+ import { gettext, Status, PackageType, PluginsService, PluginsExportScopes, Permissions, ViewContext, ApplicationPluginStatus, DataGridComponent, CoreModule, hookRoute, C8yStepper, FormsModule, hookTab, hookNavigator, hookWizard } from '@c8y/ngx-components';
5
5
  import * as i1 from '@c8y/ngx-components/ecosystem/shared';
6
- import { PRODUCT_EXPERIENCE_ECOSYSTEM, packageProperties, defaultPackageAvailabilities, EcosystemWizards, ListFiltersComponent, ApplicationPropertiesFormComponent, ERROR_TYPE, APP_STATE, PACKAGE_TYPE_LABELS, defaultPackageTypes, defaultPackageContents, SharedEcosystemModule } from '@c8y/ngx-components/ecosystem/shared';
6
+ import { PRODUCT_EXPERIENCE_ECOSYSTEM, packageProperties, defaultPackageAvailabilities, EcosystemWizards, ListFiltersComponent, ApplicationPropertiesFormComponent, defaultPackageTypes, SharedEcosystemModule, ERROR_TYPE, APP_STATE, PACKAGE_TYPE_LABELS, defaultPackageContents } from '@c8y/ngx-components/ecosystem/shared';
7
7
  import * as i3 from '@angular/common';
8
- import * as i3$1 from '@angular/forms';
9
- import { Validators, ReactiveFormsModule } from '@angular/forms';
8
+ import * as i2$1 from '@angular/forms';
9
+ import { Validators, FormControl, ReactiveFormsModule } from '@angular/forms';
10
10
  import * as i1$2 from '@angular/router';
11
11
  import { RouterModule } from '@angular/router';
12
12
  import * as i4 from '@c8y/client';
@@ -14,18 +14,19 @@ import { ApplicationType, Isolation, BillingMode } from '@c8y/client';
14
14
  import * as i4$1 from '@ngx-translate/core';
15
15
  import * as i1$1 from 'ngx-bootstrap/modal';
16
16
  import { isEmpty } from 'lodash';
17
- import { Subject, BehaviorSubject, combineLatest, of, firstValueFrom, from } from 'rxjs';
17
+ import { Subject, BehaviorSubject, combineLatest, of, firstValueFrom, from, map as map$1 } from 'rxjs';
18
18
  import { map, takeUntil, tap, switchMap, shareReplay } from 'rxjs/operators';
19
19
  import { pick, uniq } from 'lodash-es';
20
20
  import * as i9 from 'ngx-bootstrap/tooltip';
21
21
  import { TooltipModule } from 'ngx-bootstrap/tooltip';
22
22
  import * as i10 from '@c8y/ngx-components/icon-selector';
23
23
  import { IconSelectorModule } from '@c8y/ngx-components/icon-selector';
24
+ import { A11yModule } from '@angular/cdk/a11y';
25
+ import { ArchivedConfirmModule } from '@c8y/ngx-components/ecosystem/archived-confirm';
26
+ import { LicenseConfirmModule } from '@c8y/ngx-components/ecosystem/license-confirm';
24
27
  import * as i6 from 'ngx-bootstrap/dropdown';
25
28
  import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
26
29
  import { PopoverModule } from 'ngx-bootstrap/popover';
27
- import { LicenseConfirmModule } from '@c8y/ngx-components/ecosystem/license-confirm';
28
- import { A11yModule } from '@angular/cdk/a11y';
29
30
 
30
31
  class ActivityLogComponent {
31
32
  constructor(ecosystemService, alertService) {
@@ -287,7 +288,7 @@ class AppsToUpdateRemotesSelectComponent {
287
288
  return (await this.ecosystemService.getWebApplications()).filter(app => this.ecosystemService.isOwner(app) && app.type !== ApplicationType.EXTERNAL);
288
289
  }
289
290
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AppsToUpdateRemotesSelectComponent, deps: [{ token: i1$1.BsModalRef }, { token: i2.WizardModalService }, { token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
290
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AppsToUpdateRemotesSelectComponent, selector: "c8y-apps-to-update-remotes-select", inputs: { apps: "apps", updateType: "updateType", pluginName: "pluginName", appsDisabled: "appsDisabled" }, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-modules'\"></i>\n <div class=\"modal-title h4\" id=\"modal-title\" translate>Custom applications</div>\n </div>\n <div class=\"inner-scroll\" id=\"modal-body\">\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium\">\n {{ textConfig.header | translate }}\n </p>\n <c8y-filter (onSearch)=\"filterTerm$.next($event)\"></c8y-filter>\n </div>\n <c8y-list-group *ngIf=\"apps.length; else emptyList\">\n <c8y-li\n [ngClass]=\"{ disabled: updateType === 'install' && appsDisabled.has(app.id) }\"\n *ngFor=\"let app of filteredApps$ | async\"\n data-cy=\"apps-to-update-remotes-select--applications-list\"\n >\n <c8y-li-checkbox (onSelect)=\"setSelectedApps($event, app)\" data-cy=\"apps-to-update-remotes-select--app-checkbox\"></c8y-li-checkbox>\n <c8y-li-icon class=\"p-l-0 icon-32\">\n <c8y-app-icon\n class=\"list-group-icon\"\n [app]=\"app\"\n [contextPath]=\"app.contextPath\"\n [name]=\"app.name\"\n ></c8y-app-icon>\n </c8y-li-icon>\n <div class=\"d-flex\">\n <div class=\"p-r-8\">\n <p class=\"text-medium\" [innerText]=\"app | humanizeAppName | async\"></p>\n <p class=\"small text-muted\">{{ app.description }}</p>\n </div>\n <span class=\"label m-l-auto a-s-start\" [ngClass]=\"app | appState: 'class'\">\n {{ app | appState: 'label' | translate }}\n </span>\n </div>\n </c8y-li>\n </c8y-list-group>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ textConfig.applyButton | translate }}\"\n [disabled]=\"appsToUpdateRemotes.length === 0\"\n (click)=\"apply()\"\n >\n {{ textConfig.applyButton | translate }}\n </button>\n </div>\n</div>\n<ng-template #emptyList>\n <c8y-ui-empty-state\n [icon]=\"'c8y-modules'\"\n [title]=\"'No custom applications available.' | translate\"\n *ngIf=\"updateType !== 'install'\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <ng-container *ngIf=\"updateType === 'install'\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-modules'\"\n [title]=\"'No custom applications available.' | translate\"\n [subtitle]=\"'Create a custom application by duplicating an existing one.' | translate\"\n [horizontal]=\"true\"\n >\n <button\n class=\"btn btn-sm btn-default m-t-8\"\n title=\"{{ 'Duplicate' | translate }}\"\n (click)=\"duplicateApp()\"\n >\n {{ 'Duplicate' | translate }}\n </button>\n </c8y-ui-empty-state>\n </ng-container>\n</ng-template>\n", dependencies: [{ kind: "component", type: i2.AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.FilterInputComponent, selector: "c8y-filter", inputs: ["icon"], outputs: ["onSearch"] }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: AppStatePipe, name: "appState" }] }); }
291
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AppsToUpdateRemotesSelectComponent, selector: "c8y-apps-to-update-remotes-select", inputs: { apps: "apps", updateType: "updateType", pluginName: "pluginName", appsDisabled: "appsDisabled" }, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-modules'\"></i>\n <div class=\"modal-title h4\" id=\"modal-title\" translate>Custom applications</div>\n </div>\n <div class=\"inner-scroll\" id=\"modal-body\">\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium\">\n {{ textConfig.header | translate }}\n </p>\n <c8y-filter (onSearch)=\"filterTerm$.next($event)\"></c8y-filter>\n </div>\n <c8y-list-group *ngIf=\"apps.length; else emptyList\">\n <c8y-li\n [ngClass]=\"{ disabled: updateType === 'install' && appsDisabled.has(app.id) }\"\n *ngFor=\"let app of filteredApps$ | async\"\n data-cy=\"apps-to-update-remotes-select--applications-list\"\n >\n <c8y-li-checkbox (onSelect)=\"setSelectedApps($event, app)\" data-cy=\"apps-to-update-remotes-select--app-checkbox\"></c8y-li-checkbox>\n <c8y-li-icon class=\"p-l-0 icon-32\">\n <c8y-app-icon\n class=\"list-group-icon\"\n [app]=\"app\"\n [contextPath]=\"app.contextPath\"\n [name]=\"app.name\"\n ></c8y-app-icon>\n </c8y-li-icon>\n <div class=\"d-flex\">\n <div class=\"p-r-8\">\n <p class=\"text-medium\" [innerText]=\"app | humanizeAppName | async\"></p>\n <p class=\"small text-muted\">{{ app.description }}</p>\n </div>\n <span class=\"label m-l-auto a-s-start\" [ngClass]=\"app | appState: 'class'\">\n {{ app | appState: 'label' | translate }}\n </span>\n </div>\n </c8y-li>\n </c8y-list-group>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ textConfig.applyButton | translate }}\"\n [disabled]=\"appsToUpdateRemotes.length === 0\"\n (click)=\"apply()\"\n >\n {{ textConfig.applyButton | translate }}\n </button>\n </div>\n</div>\n<ng-template #emptyList>\n <c8y-ui-empty-state\n [icon]=\"'c8y-modules'\"\n [title]=\"'No custom applications available.' | translate\"\n *ngIf=\"updateType !== 'install'\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <ng-container *ngIf=\"updateType === 'install'\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-modules'\"\n [title]=\"'No custom applications available.' | translate\"\n [subtitle]=\"'Create a custom application by duplicating an existing one.' | translate\"\n [horizontal]=\"true\"\n >\n <button\n class=\"btn btn-sm btn-default m-t-8\"\n title=\"{{ 'Duplicate' | translate }}\"\n (click)=\"duplicateApp()\"\n >\n {{ 'Duplicate' | translate }}\n </button>\n </c8y-ui-empty-state>\n </ng-container>\n</ng-template>\n", dependencies: [{ kind: "component", type: i2.AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.FilterInputComponent, selector: "c8y-filter", inputs: ["icon", "filterTerm"], outputs: ["onSearch"] }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: AppStatePipe, name: "appState" }] }); }
291
292
  }
292
293
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AppsToUpdateRemotesSelectComponent, decorators: [{
293
294
  type: Component,
@@ -303,21 +304,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
303
304
  }] } });
304
305
 
305
306
  class PluginListItemComponent {
306
- constructor() {
307
+ constructor(pluginService) {
308
+ this.pluginService = pluginService;
307
309
  this.hideSource = false;
308
310
  this.isItemSelected = new EventEmitter();
311
+ this.packageType = PackageType.UNKNOWN;
312
+ this.PACKAGE_TYPE = PackageType;
313
+ }
314
+ ngOnInit() {
315
+ this.packageType = this.pluginService.getPackageType(this.plugin.originApp);
309
316
  }
310
317
  onChange(event) {
311
318
  this.plugin.selected = !this.plugin.selected;
312
319
  this.isItemSelected.next(event);
313
320
  }
314
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PluginListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
315
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PluginListItemComponent, selector: "c8y-plugin-list-item", inputs: { plugin: "plugin", selectable: "selectable", hideSource: "hideSource" }, outputs: { isItemSelected: "isItemSelected" }, ngImport: i0, template: "<c8y-li-checkbox\n class=\"p-r-16 p-l-0\"\n (change)=\"onChange($event.target.checked)\"\n *ngIf=\"selectable\"\n [disabled]=\"plugin.installed\"\n [selected]=\"plugin.selected\"\n></c8y-li-checkbox>\n<c8y-li-icon class=\"p-l-0\">\n <i class=\"c8y-plugin-icon\">\n <span>{{ plugin.name?.substr(0, 2) }}</span>\n </i>\n</c8y-li-icon>\n<div>\n <div [ngClass]=\"{ 'p-r-8': selectable }\">\n <p>\n <span class=\"text-medium\">{{ plugin.name }}</span>\n <em class=\"text-muted small m-l-8\">{{ plugin.version }}</em>\n <span *ngIf=\"plugin.installed\">\n <i\n class=\"text-success\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <em\n class=\"text-muted small\"\n translate\n >\n Installed`plugins`\n </em>\n </span>\n </p>\n <p class=\"small l-h-tight\">{{ plugin.description }}</p>\n </div>\n\n <span\n class=\"label label-info a-s-start m-t-8\"\n *ngIf=\"selectable && !hideSource\"\n >\n {{ plugin.contextPath }}\n </span>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }] }); }
321
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PluginListItemComponent, deps: [{ token: i2.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
322
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PluginListItemComponent, selector: "c8y-plugin-list-item", inputs: { plugin: "plugin", selectable: "selectable", hideSource: "hideSource" }, outputs: { isItemSelected: "isItemSelected" }, ngImport: i0, template: "<c8y-li-checkbox\n class=\"p-r-16 p-l-0\"\n (change)=\"onChange($event.target.checked)\"\n *ngIf=\"selectable\"\n [disabled]=\"plugin.installed\"\n [selected]=\"plugin.selected\"\n></c8y-li-checkbox>\n<c8y-li-icon class=\"p-l-0 text-center\">\n <i class=\"c8y-plugin-icon\">\n <span>{{ plugin.name?.substr(0, 2) }}</span>\n </i>\n</c8y-li-icon>\n<div class=\"p-relative\">\n <div [ngClass]=\"{ 'p-r-8': selectable }\">\n <p>\n <span class=\"text-medium\">{{ plugin.name }}</span>\n <em class=\"text-muted small m-l-8\">{{ plugin.version }}</em>\n <span *ngIf=\"plugin.installed\">\n <i\n class=\"text-success\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <em\n class=\"text-muted small\"\n translate\n >\n Installed`plugins`\n </em>\n </span>\n </p>\n <p class=\"small l-h-tight\">{{ plugin.description }}</p>\n </div>\n\n <span\n class=\"tag tag--info a-s-start m-t-8\"\n *ngIf=\"selectable && !hideSource\"\n >\n {{ plugin.contextPath }}\n </span>\n\n <span\n class=\"tag a-s-start m-t-8 m-l-4\"\n [ngClass]=\"{\n 'tag--default': packageType === PACKAGE_TYPE.COMMUNITY,\n 'tag--primary': packageType === PACKAGE_TYPE.OFFICIAL\n }\"\n >\n {{ plugin.originApp?.label || plugin.originApp?.manifest?.label | translatePackageLabel }}\n </span>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "pipe", type: i1.TranslatePackageLabelPipe, name: "translatePackageLabel" }] }); }
316
323
  }
317
324
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PluginListItemComponent, decorators: [{
318
325
  type: Component,
319
- args: [{ selector: 'c8y-plugin-list-item', template: "<c8y-li-checkbox\n class=\"p-r-16 p-l-0\"\n (change)=\"onChange($event.target.checked)\"\n *ngIf=\"selectable\"\n [disabled]=\"plugin.installed\"\n [selected]=\"plugin.selected\"\n></c8y-li-checkbox>\n<c8y-li-icon class=\"p-l-0\">\n <i class=\"c8y-plugin-icon\">\n <span>{{ plugin.name?.substr(0, 2) }}</span>\n </i>\n</c8y-li-icon>\n<div>\n <div [ngClass]=\"{ 'p-r-8': selectable }\">\n <p>\n <span class=\"text-medium\">{{ plugin.name }}</span>\n <em class=\"text-muted small m-l-8\">{{ plugin.version }}</em>\n <span *ngIf=\"plugin.installed\">\n <i\n class=\"text-success\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <em\n class=\"text-muted small\"\n translate\n >\n Installed`plugins`\n </em>\n </span>\n </p>\n <p class=\"small l-h-tight\">{{ plugin.description }}</p>\n </div>\n\n <span\n class=\"label label-info a-s-start m-t-8\"\n *ngIf=\"selectable && !hideSource\"\n >\n {{ plugin.contextPath }}\n </span>\n</div>\n" }]
320
- }], propDecorators: { plugin: [{
326
+ args: [{ selector: 'c8y-plugin-list-item', template: "<c8y-li-checkbox\n class=\"p-r-16 p-l-0\"\n (change)=\"onChange($event.target.checked)\"\n *ngIf=\"selectable\"\n [disabled]=\"plugin.installed\"\n [selected]=\"plugin.selected\"\n></c8y-li-checkbox>\n<c8y-li-icon class=\"p-l-0 text-center\">\n <i class=\"c8y-plugin-icon\">\n <span>{{ plugin.name?.substr(0, 2) }}</span>\n </i>\n</c8y-li-icon>\n<div class=\"p-relative\">\n <div [ngClass]=\"{ 'p-r-8': selectable }\">\n <p>\n <span class=\"text-medium\">{{ plugin.name }}</span>\n <em class=\"text-muted small m-l-8\">{{ plugin.version }}</em>\n <span *ngIf=\"plugin.installed\">\n <i\n class=\"text-success\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <em\n class=\"text-muted small\"\n translate\n >\n Installed`plugins`\n </em>\n </span>\n </p>\n <p class=\"small l-h-tight\">{{ plugin.description }}</p>\n </div>\n\n <span\n class=\"tag tag--info a-s-start m-t-8\"\n *ngIf=\"selectable && !hideSource\"\n >\n {{ plugin.contextPath }}\n </span>\n\n <span\n class=\"tag a-s-start m-t-8 m-l-4\"\n [ngClass]=\"{\n 'tag--default': packageType === PACKAGE_TYPE.COMMUNITY,\n 'tag--primary': packageType === PACKAGE_TYPE.OFFICIAL\n }\"\n >\n {{ plugin.originApp?.label || plugin.originApp?.manifest?.label | translatePackageLabel }}\n </span>\n</div>\n" }]
327
+ }], ctorParameters: () => [{ type: i2.PluginsService }], propDecorators: { plugin: [{
321
328
  type: Input
322
329
  }], selectable: [{
323
330
  type: Input
@@ -389,6 +396,11 @@ class PluginListComponent {
389
396
  // unreached
390
397
  }
391
398
  if (updateType === 'install') {
399
+ const isArchived = await this.ecosystemService.verifyArchived([plugin]);
400
+ if (!isArchived) {
401
+ this.updatingPluginId[updateType] = '';
402
+ return;
403
+ }
392
404
  const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([plugin]);
393
405
  if (!licensesVerifiedByUser) {
394
406
  this.updatingPluginId[updateType] = '';
@@ -414,17 +426,12 @@ class PluginListComponent {
414
426
  this.onUpdateEventHandleGS(plugin, app, updateType);
415
427
  }
416
428
  catch (error) {
417
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_PLUGINS, {
418
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PLUGIN_LIST,
419
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
420
- url: this.CURRENT_LOCATION,
421
- error
422
- });
429
+ this.onUpdateEventHandleGS(plugin, app, updateType, error);
423
430
  }
424
431
  }
425
432
  this.updatingPluginId[updateType] = '';
426
433
  }
427
- onUpdateEventHandleGS(plugin, app, updateType) {
434
+ onUpdateEventHandleGS(plugin, app, updateType, error) {
428
435
  const pluginCustomEventInfo = pick(plugin, [
429
436
  'name',
430
437
  'contextPath',
@@ -436,14 +443,16 @@ class PluginListComponent {
436
443
  const gsEventResult = updateType === 'install'
437
444
  ? PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_INSTALLED
438
445
  : PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_REMOVED;
439
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_PLUGINS, {
446
+ const eventData = {
440
447
  component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PLUGIN_LIST,
441
- result: gsEventResult,
448
+ result: error || gsEventResult,
442
449
  url: this.CURRENT_LOCATION,
443
450
  ...pluginCustomEventInfo,
444
451
  targetApplicationName: app.name,
445
- targetApplicationContextPath: app.contextPath
446
- });
452
+ targetApplicationContextPath: app.contextPath,
453
+ ...(error && { error })
454
+ };
455
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_PLUGINS, eventData);
447
456
  }
448
457
  async getAppsForUpdate(plugin, updateType) {
449
458
  let apps = (await this.ecosystemService.getWebApplications()).filter(app => this.ecosystemService.isOwner(app) && app.type !== ApplicationType.EXTERNAL);
@@ -966,13 +975,13 @@ class ApplicationPropertiesComponent {
966
975
  this.alertService.warning(gettext('Unable to resolve versions of source package.'));
967
976
  }
968
977
  }
969
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPropertiesComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1.EcosystemService }, { token: i1$2.Router }, { token: i3$1.FormBuilder }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i4.InventoryService }, { token: i2.Permissions }, { token: i2.ModalService }, { token: i4$1.TranslateService }, { token: i1$1.BsModalService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
970
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: ApplicationPropertiesComponent, selector: "c8y-application-properties", ngImport: i0, template: "<c8y-title>{{ application | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb *ngIf=\"!isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n *ngIf=\"isFeature\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-breadcrumb *ngIf=\"isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div [ngClass]=\"{ 'col-md-8': !isActivityLogSupported, 'col-md-12': isActivityLogSupported }\">\n <div\n class=\"card content-fullpage\"\n *ngIf=\"application\"\n [ngClass]=\"{ 'd-grid grid__col--7-5--md': isActivityLogSupported }\"\n >\n <form\n class=\"d-flex d-col content-fullpage\"\n (ngSubmit)=\"formGroup.valid && save(formGroup.value)\"\n [formGroup]=\"formGroup\"\n novalidate\n >\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <div class=\"card-block separator-bottom large-padding flex-no-shrink\">\n <div class=\"d-flex-md a-i-start text-center text-left-md\">\n <c8y-app-icon\n class=\"icon-48\"\n *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n [app]=\"application\"\n [contextPath]=\"application.contextPath\"\n [name]=\"application.name\"\n ></c8y-app-icon>\n <i\n class=\"icon-48\"\n c8yIcon=\"big-parcel\"\n *ngIf=\"isPackage\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"tab\"\n *ngIf=\"isFeature\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"microchip\"\n *ngIf=\"isMicroservice\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"globe1\"\n *ngIf=\"isExternal\"\n ></i>\n\n <div class=\"p-t-md-16 p-l-md-16 p-r-md-32 flex-grow\">\n <p class=\"h4 text-medium m-b-8\">{{ application | humanizeAppName | async }}</p>\n <p *ngIf=\"!isOwner\">\n <em class=\"text-muted\">\n {{\n formGroup?.controls?.description?.value || (noDescriptionLabel | translate)\n }}\n </em>\n </p>\n <div\n class=\"form-group m-b-0\"\n *ngIf=\"isOwner\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{ updated: formGroup?.controls?.description?.dirty }\"\n >\n <textarea\n class=\"form-control no-resize\"\n placeholder=\"{{ noDescriptionLabel | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n formControlName=\"description\"\n ></textarea>\n </label>\n </div>\n </div>\n <div class=\"text-right-md m-t-4\">\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"application.manifest?.version\"\n data-cy=\"application-detail--version\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Version:\n </label>\n <small class=\"p-l-4 text-bold\">{{ application.manifest?.version }}</small>\n </div>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"!isUnpacked\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Creation time:\n </label>\n <small class=\"p-l-4 text-bold\">\n {{ (binaryMo?.creationTime | c8yDate) || '---' }}\n </small>\n </div>\n <div class=\"m-t-8\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"\n 'There\\'s a newer version available, click to update' | translate\n \"\n tooltip=\"{{\n 'There\\'s a newer version available, click to update' | translate\n }}\"\n placement=\"top\"\n type=\"button\"\n *ngIf=\"isUpdateAvailable\"\n (click)=\"updateToLatestVersion()\"\n [delay]=\"300\"\n >\n <i [c8yIcon]=\"'installing-updates'\"></i>\n {{ 'Update available' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Open' | translate }}\"\n type=\"button\"\n (click)=\"openApp(application)\"\n [disabled]=\"disableOpenInBrowser\"\n *ngIf=\"canOpenInBrowser\"\n >\n <i [c8yIcon]=\"'external-link'\"></i>\n {{ 'Open' | translate }}\n </button>\n <div *ngIf=\"canOpenInBrowser && disableOpenInBrowser\">\n <small\n class=\"text-muted\"\n translate\n >\n The application is overwritten by a custom application sharing the same path\n </small>\n </div>\n <span *ngIf=\"isCustomMicroservice\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Subscribe' | translate }}\"\n type=\"button\"\n (click)=\"subscribe()\"\n *ngIf=\"!isSubscribed\"\n >\n <i [c8yIcon]=\"'check-circle-o'\"></i>\n {{ 'Subscribe' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Unsubscribe' | translate }}\"\n type=\"button\"\n (click)=\"unsubscribe()\"\n *ngIf=\"isSubscribed\"\n >\n <i [c8yIcon]=\"'minus-circle'\"></i>\n {{ 'Unsubscribe' | translate }}\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <div class=\"card-block large-padding\">\n <div\n class=\"row p-16\"\n *ngIf=\"isPackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Package details' | translate\"\n [data]=\"application.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div\n class=\"row p-16\"\n *ngIf=\"sourcePackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Source package information' | translate\"\n [data]=\"sourcePackage.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label for=\"appId\">ID</label>\n <input\n class=\"form-control\"\n id=\"appId\"\n name=\"id\"\n type=\"text\"\n autocomplete=\"off\"\n [readonly]=\"true\"\n formControlName=\"id\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-7\">\n <c8y-form-group>\n <label>{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [readonly]=\"!isOwner\"\n formControlName=\"name\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label>{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n name=\"key\"\n type=\"text\"\n required\n [readonly]=\"application.id || !isOwner\"\n formControlName=\"key\"\n />\n </c8y-form-group>\n </div>\n\n <div class=\"col-sm-7\" data-cy=\"application-detail--type\">\n <c8y-form-group>\n <label>{{ 'Type' | translate }}</label>\n <div>\n <div *ngIf=\"application.id\">\n <p class=\"form-control-static\">\n <i [c8yIcon]=\"iconMap[application.type]\"></i>\n <span>\n {{ application.type | translate }}\n </span>\n </p>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n\n <div [ngSwitch]=\"application.type\">\n <div *ngSwitchCase=\"'HOSTED'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/apps/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n </div>\n\n <div *ngSwitchCase=\"'MICROSERVICE'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/service/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-microservice`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n <div class=\"row\">\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.version\"\n data-cy=\"application-detail--version\"\n >\n <label>{{ 'Version' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.version }}\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--isolation\"\n >\n <label>{{ 'Isolation' | translate }}</label>\n <p class=\"form-control-static\">\n <span *ngIf=\"singleTenant\">\n <i\n class=\"c8y-icon-duocolor h4\"\n [c8yIcon]=\"'c8y-enterprise'\"\n ></i>\n {{ 'Single tenant' | translate }}\n </span>\n <span *ngIf=\"!singleTenant\">\n <i\n class=\"c8y-icon-duocolor icon-32\"\n [c8yIcon]=\"'c8y-sub-tenants'\"\n ></i>\n {{ 'Multi tenant' | translate }}\n </span>\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--billing-mode\"\n >\n <label>{{ 'Billing mode' | translate }}</label>\n <p class=\"form-control-static\">\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"subscription\"\n >\n {{ 'Subscription' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Subscriber | translate'\"\n *ngIf=\"!subscription && singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"!subscription && !singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n </p>\n </div>\n </div>\n\n <div\n class=\"legend form-block m-t-40\"\n *ngIf=\"application.manifest.provider\"\n >\n {{ 'Provider' | translate }}\n </div>\n <div\n class=\"list-inline\"\n *ngIf=\"application.manifest.provider\"\n data-cy=\"application-detail--provider\"\n >\n <div *ngIf=\"application.manifest.provider.name\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Name' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.name }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.domain\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Domain' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.domain }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.support\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Support' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.support }}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'EXTERNAL'\">\n <c8y-form-group>\n <label>{{ 'External URL' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://www.example.com/\"\n name=\"externalUrl\"\n type=\"url\"\n required\n [pattern]=\"'^(?!javascript:).+'\"\n [readOnly]=\"!isOwner\"\n formControlName=\"externalUrl\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'pattern'\"\n [text]=\"'Valid URL required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div *ngIf=\"isOwner && !isCustomMicroservice\">\n <label>{{ 'Select icon' | translate }}</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"isCustomMicroservice\">\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <c8y-upload-archive\n [(application)]=\"application\"\n (refresh)=\"onNewArchive()\"\n ></c8y-upload-archive>\n </div>\n </ng-container>\n <div\n class=\"card-footer separator\"\n *ngIf=\"application && !!isOwner && hasAdminPermissions\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-danger\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"delete()\"\n *ngIf=\"canDelete\"\n >\n {{ 'Delete' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"!application.type || formGroup.invalid || formGroup.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"content-fullpage d-flex d-col bg-level-1\"\n *ngIf=\"isActivityLogSupported\"\n >\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Activity log\n </div>\n <div class=\"m-l-auto\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"load()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </div>\n </div>\n <div\n class=\"p-16 text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <c8y-activity-log\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n [hasAdminPermissions]=\"hasAdminPermissions\"\n [application]=\"application\"\n ></c8y-activity-log>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i2.TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i3$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3$1.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: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i2.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i3$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2.PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "directive", type: i9.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "component", type: i1.UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "component", type: i10.IconSelectorWrapperComponent, selector: "c8y-icon-selector-wrapper", inputs: ["canRemoveIcon", "selectedIcon", "iconSize"], outputs: ["onSelect"] }, { kind: "component", type: ActivityLogComponent, selector: "c8y-activity-log", inputs: ["application", "hasAdminPermissions"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: i2.DatePipe, name: "c8yDate" }] }); }
978
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPropertiesComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1.EcosystemService }, { token: i1$2.Router }, { token: i2$1.FormBuilder }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i4.InventoryService }, { token: i2.Permissions }, { token: i2.ModalService }, { token: i4$1.TranslateService }, { token: i1$1.BsModalService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
979
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: ApplicationPropertiesComponent, selector: "c8y-application-properties", ngImport: i0, template: "<c8y-title>{{ application | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb *ngIf=\"!isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n *ngIf=\"isFeature\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-breadcrumb *ngIf=\"isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div [ngClass]=\"{ 'col-md-8': !isActivityLogSupported, 'col-md-12': isActivityLogSupported }\">\n <div\n class=\"card content-fullpage\"\n *ngIf=\"application\"\n [ngClass]=\"{ 'd-grid grid__col--7-5--md': isActivityLogSupported }\"\n >\n <form\n class=\"d-flex d-col content-fullpage\"\n (ngSubmit)=\"formGroup.valid && save(formGroup.value)\"\n [formGroup]=\"formGroup\"\n novalidate\n >\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <div class=\"card-block separator-bottom large-padding flex-no-shrink\">\n <div class=\"d-flex-md a-i-start text-center text-left-md\">\n <c8y-app-icon\n class=\"icon-48\"\n *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n [app]=\"application\"\n [contextPath]=\"application.contextPath\"\n [name]=\"application.name\"\n ></c8y-app-icon>\n <i\n class=\"icon-48\"\n c8yIcon=\"big-parcel\"\n *ngIf=\"isPackage\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"tab\"\n *ngIf=\"isFeature\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"microchip\"\n *ngIf=\"isMicroservice\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"globe1\"\n *ngIf=\"isExternal\"\n ></i>\n\n <div class=\"p-t-md-16 p-l-md-16 p-r-md-32 flex-grow\">\n <p class=\"h4 text-medium m-b-8\">{{ application | humanizeAppName | async }}</p>\n <p *ngIf=\"!isOwner\">\n <em class=\"text-muted\">\n {{\n formGroup?.controls?.description?.value || (noDescriptionLabel | translate)\n }}\n </em>\n </p>\n <div\n class=\"form-group m-b-0\"\n *ngIf=\"isOwner\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{ updated: formGroup?.controls?.description?.dirty }\"\n >\n <textarea\n class=\"form-control no-resize\"\n placeholder=\"{{ noDescriptionLabel | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n formControlName=\"description\"\n ></textarea>\n </label>\n </div>\n </div>\n <div class=\"text-right-md m-t-4\">\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"application.manifest?.version\"\n data-cy=\"application-detail--version\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Version:\n </label>\n <small class=\"p-l-4 text-bold\">{{ application.manifest?.version }}</small>\n </div>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"!isUnpacked\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Creation time:\n </label>\n <small class=\"p-l-4 text-bold\">\n {{ (binaryMo?.creationTime | c8yDate) || '---' }}\n </small>\n </div>\n <div class=\"m-t-8\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"\n 'There\\'s a newer version available, click to update' | translate\n \"\n tooltip=\"{{\n 'There\\'s a newer version available, click to update' | translate\n }}\"\n placement=\"top\"\n type=\"button\"\n *ngIf=\"isUpdateAvailable\"\n (click)=\"updateToLatestVersion()\"\n [delay]=\"300\"\n >\n <i [c8yIcon]=\"'installing-updates'\"></i>\n {{ 'Update available' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Open' | translate }}\"\n type=\"button\"\n (click)=\"openApp(application)\"\n [disabled]=\"disableOpenInBrowser\"\n *ngIf=\"canOpenInBrowser\"\n >\n <i [c8yIcon]=\"'external-link'\"></i>\n {{ 'Open' | translate }}\n </button>\n <div *ngIf=\"canOpenInBrowser && disableOpenInBrowser\">\n <small\n class=\"text-muted\"\n translate\n >\n The application is overwritten by a custom application sharing the same path\n </small>\n </div>\n <span *ngIf=\"isCustomMicroservice\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Subscribe' | translate }}\"\n type=\"button\"\n (click)=\"subscribe()\"\n *ngIf=\"!isSubscribed\"\n >\n <i [c8yIcon]=\"'check-circle-o'\"></i>\n {{ 'Subscribe' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Unsubscribe' | translate }}\"\n type=\"button\"\n (click)=\"unsubscribe()\"\n *ngIf=\"isSubscribed\"\n >\n <i [c8yIcon]=\"'minus-circle'\"></i>\n {{ 'Unsubscribe' | translate }}\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <div class=\"card-block large-padding\">\n <div\n class=\"row p-16\"\n *ngIf=\"isPackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Package details' | translate\"\n [data]=\"application.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div\n class=\"row p-16\"\n *ngIf=\"sourcePackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Source package information' | translate\"\n [data]=\"sourcePackage.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label for=\"appId\">ID</label>\n <input\n class=\"form-control\"\n id=\"appId\"\n name=\"id\"\n type=\"text\"\n autocomplete=\"off\"\n [readonly]=\"true\"\n formControlName=\"id\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-7\">\n <c8y-form-group>\n <label>{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [readonly]=\"!isOwner\"\n formControlName=\"name\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label>{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n name=\"key\"\n type=\"text\"\n required\n [readonly]=\"application.id || !isOwner\"\n formControlName=\"key\"\n />\n </c8y-form-group>\n </div>\n\n <div class=\"col-sm-7\" data-cy=\"application-detail--type\">\n <c8y-form-group>\n <label>{{ 'Type' | translate }}</label>\n <div>\n <div *ngIf=\"application.id\">\n <p class=\"form-control-static\">\n <i [c8yIcon]=\"iconMap[application.type]\"></i>\n <span>\n {{ application.type | translate }}\n </span>\n </p>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n\n <div [ngSwitch]=\"application.type\">\n <div *ngSwitchCase=\"'HOSTED'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/apps/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n </div>\n\n <div *ngSwitchCase=\"'MICROSERVICE'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/service/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-microservice`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n <div class=\"row\">\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.version\"\n data-cy=\"application-detail--version\"\n >\n <label>{{ 'Version' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.version }}\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--isolation\"\n >\n <label>{{ 'Isolation' | translate }}</label>\n <p class=\"form-control-static\">\n <span *ngIf=\"singleTenant\">\n <i\n class=\"c8y-icon-duocolor h4\"\n [c8yIcon]=\"'c8y-enterprise'\"\n ></i>\n {{ 'Single tenant' | translate }}\n </span>\n <span *ngIf=\"!singleTenant\">\n <i\n class=\"c8y-icon-duocolor icon-32\"\n [c8yIcon]=\"'c8y-sub-tenants'\"\n ></i>\n {{ 'Multi tenant' | translate }}\n </span>\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--billing-mode\"\n >\n <label>{{ 'Billing mode' | translate }}</label>\n <p class=\"form-control-static\">\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"subscription\"\n >\n {{ 'Subscription' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Subscriber | translate'\"\n *ngIf=\"!subscription && singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"!subscription && !singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n </p>\n </div>\n </div>\n\n <div\n class=\"legend form-block m-t-40\"\n *ngIf=\"application.manifest.provider\"\n >\n {{ 'Provider' | translate }}\n </div>\n <div\n class=\"list-inline\"\n *ngIf=\"application.manifest.provider\"\n data-cy=\"application-detail--provider\"\n >\n <div *ngIf=\"application.manifest.provider.name\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Name' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.name }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.domain\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Domain' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.domain }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.support\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Support' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.support }}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'EXTERNAL'\">\n <c8y-form-group>\n <label>{{ 'External URL' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://www.example.com/\"\n name=\"externalUrl\"\n type=\"url\"\n required\n [pattern]=\"'^(?!javascript:).+'\"\n [readOnly]=\"!isOwner\"\n formControlName=\"externalUrl\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'pattern'\"\n [text]=\"'Valid URL required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div *ngIf=\"isOwner && !isCustomMicroservice\">\n <label>{{ 'Select icon' | translate }}</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"isCustomMicroservice\">\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <c8y-upload-archive\n [(application)]=\"application\"\n (refresh)=\"onNewArchive()\"\n ></c8y-upload-archive>\n </div>\n </ng-container>\n <div\n class=\"card-footer separator\"\n *ngIf=\"application && !!isOwner && hasAdminPermissions\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-danger\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"delete()\"\n *ngIf=\"canDelete\"\n >\n {{ 'Delete' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"!application.type || formGroup.invalid || formGroup.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"content-fullpage d-flex d-col bg-level-1\"\n *ngIf=\"isActivityLogSupported\"\n >\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Activity log\n </div>\n <div class=\"m-l-auto\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"load()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </div>\n </div>\n <div\n class=\"p-16 text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <c8y-activity-log\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n [hasAdminPermissions]=\"hasAdminPermissions\"\n [application]=\"application\"\n ></c8y-activity-log>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i2.TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i2.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2.PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "directive", type: i9.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "component", type: i1.UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "component", type: i10.IconSelectorWrapperComponent, selector: "c8y-icon-selector-wrapper", inputs: ["canRemoveIcon", "selectedIcon", "iconSize"], outputs: ["onSelect"] }, { kind: "component", type: ActivityLogComponent, selector: "c8y-activity-log", inputs: ["application", "hasAdminPermissions"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: i2.DatePipe, name: "c8yDate" }] }); }
971
980
  }
972
981
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPropertiesComponent, decorators: [{
973
982
  type: Component,
974
983
  args: [{ selector: 'c8y-application-properties', template: "<c8y-title>{{ application | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb *ngIf=\"!isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n *ngIf=\"isFeature\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-breadcrumb *ngIf=\"isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div [ngClass]=\"{ 'col-md-8': !isActivityLogSupported, 'col-md-12': isActivityLogSupported }\">\n <div\n class=\"card content-fullpage\"\n *ngIf=\"application\"\n [ngClass]=\"{ 'd-grid grid__col--7-5--md': isActivityLogSupported }\"\n >\n <form\n class=\"d-flex d-col content-fullpage\"\n (ngSubmit)=\"formGroup.valid && save(formGroup.value)\"\n [formGroup]=\"formGroup\"\n novalidate\n >\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <div class=\"card-block separator-bottom large-padding flex-no-shrink\">\n <div class=\"d-flex-md a-i-start text-center text-left-md\">\n <c8y-app-icon\n class=\"icon-48\"\n *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n [app]=\"application\"\n [contextPath]=\"application.contextPath\"\n [name]=\"application.name\"\n ></c8y-app-icon>\n <i\n class=\"icon-48\"\n c8yIcon=\"big-parcel\"\n *ngIf=\"isPackage\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"tab\"\n *ngIf=\"isFeature\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"microchip\"\n *ngIf=\"isMicroservice\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"globe1\"\n *ngIf=\"isExternal\"\n ></i>\n\n <div class=\"p-t-md-16 p-l-md-16 p-r-md-32 flex-grow\">\n <p class=\"h4 text-medium m-b-8\">{{ application | humanizeAppName | async }}</p>\n <p *ngIf=\"!isOwner\">\n <em class=\"text-muted\">\n {{\n formGroup?.controls?.description?.value || (noDescriptionLabel | translate)\n }}\n </em>\n </p>\n <div\n class=\"form-group m-b-0\"\n *ngIf=\"isOwner\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{ updated: formGroup?.controls?.description?.dirty }\"\n >\n <textarea\n class=\"form-control no-resize\"\n placeholder=\"{{ noDescriptionLabel | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n formControlName=\"description\"\n ></textarea>\n </label>\n </div>\n </div>\n <div class=\"text-right-md m-t-4\">\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"application.manifest?.version\"\n data-cy=\"application-detail--version\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Version:\n </label>\n <small class=\"p-l-4 text-bold\">{{ application.manifest?.version }}</small>\n </div>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"!isUnpacked\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Creation time:\n </label>\n <small class=\"p-l-4 text-bold\">\n {{ (binaryMo?.creationTime | c8yDate) || '---' }}\n </small>\n </div>\n <div class=\"m-t-8\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"\n 'There\\'s a newer version available, click to update' | translate\n \"\n tooltip=\"{{\n 'There\\'s a newer version available, click to update' | translate\n }}\"\n placement=\"top\"\n type=\"button\"\n *ngIf=\"isUpdateAvailable\"\n (click)=\"updateToLatestVersion()\"\n [delay]=\"300\"\n >\n <i [c8yIcon]=\"'installing-updates'\"></i>\n {{ 'Update available' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Open' | translate }}\"\n type=\"button\"\n (click)=\"openApp(application)\"\n [disabled]=\"disableOpenInBrowser\"\n *ngIf=\"canOpenInBrowser\"\n >\n <i [c8yIcon]=\"'external-link'\"></i>\n {{ 'Open' | translate }}\n </button>\n <div *ngIf=\"canOpenInBrowser && disableOpenInBrowser\">\n <small\n class=\"text-muted\"\n translate\n >\n The application is overwritten by a custom application sharing the same path\n </small>\n </div>\n <span *ngIf=\"isCustomMicroservice\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Subscribe' | translate }}\"\n type=\"button\"\n (click)=\"subscribe()\"\n *ngIf=\"!isSubscribed\"\n >\n <i [c8yIcon]=\"'check-circle-o'\"></i>\n {{ 'Subscribe' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Unsubscribe' | translate }}\"\n type=\"button\"\n (click)=\"unsubscribe()\"\n *ngIf=\"isSubscribed\"\n >\n <i [c8yIcon]=\"'minus-circle'\"></i>\n {{ 'Unsubscribe' | translate }}\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <div class=\"card-block large-padding\">\n <div\n class=\"row p-16\"\n *ngIf=\"isPackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Package details' | translate\"\n [data]=\"application.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div\n class=\"row p-16\"\n *ngIf=\"sourcePackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Source package information' | translate\"\n [data]=\"sourcePackage.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label for=\"appId\">ID</label>\n <input\n class=\"form-control\"\n id=\"appId\"\n name=\"id\"\n type=\"text\"\n autocomplete=\"off\"\n [readonly]=\"true\"\n formControlName=\"id\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-7\">\n <c8y-form-group>\n <label>{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [readonly]=\"!isOwner\"\n formControlName=\"name\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label>{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n name=\"key\"\n type=\"text\"\n required\n [readonly]=\"application.id || !isOwner\"\n formControlName=\"key\"\n />\n </c8y-form-group>\n </div>\n\n <div class=\"col-sm-7\" data-cy=\"application-detail--type\">\n <c8y-form-group>\n <label>{{ 'Type' | translate }}</label>\n <div>\n <div *ngIf=\"application.id\">\n <p class=\"form-control-static\">\n <i [c8yIcon]=\"iconMap[application.type]\"></i>\n <span>\n {{ application.type | translate }}\n </span>\n </p>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n\n <div [ngSwitch]=\"application.type\">\n <div *ngSwitchCase=\"'HOSTED'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/apps/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n </div>\n\n <div *ngSwitchCase=\"'MICROSERVICE'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/service/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-microservice`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n <div class=\"row\">\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.version\"\n data-cy=\"application-detail--version\"\n >\n <label>{{ 'Version' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.version }}\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--isolation\"\n >\n <label>{{ 'Isolation' | translate }}</label>\n <p class=\"form-control-static\">\n <span *ngIf=\"singleTenant\">\n <i\n class=\"c8y-icon-duocolor h4\"\n [c8yIcon]=\"'c8y-enterprise'\"\n ></i>\n {{ 'Single tenant' | translate }}\n </span>\n <span *ngIf=\"!singleTenant\">\n <i\n class=\"c8y-icon-duocolor icon-32\"\n [c8yIcon]=\"'c8y-sub-tenants'\"\n ></i>\n {{ 'Multi tenant' | translate }}\n </span>\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--billing-mode\"\n >\n <label>{{ 'Billing mode' | translate }}</label>\n <p class=\"form-control-static\">\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"subscription\"\n >\n {{ 'Subscription' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Subscriber | translate'\"\n *ngIf=\"!subscription && singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"!subscription && !singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n </p>\n </div>\n </div>\n\n <div\n class=\"legend form-block m-t-40\"\n *ngIf=\"application.manifest.provider\"\n >\n {{ 'Provider' | translate }}\n </div>\n <div\n class=\"list-inline\"\n *ngIf=\"application.manifest.provider\"\n data-cy=\"application-detail--provider\"\n >\n <div *ngIf=\"application.manifest.provider.name\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Name' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.name }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.domain\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Domain' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.domain }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.support\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Support' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.support }}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'EXTERNAL'\">\n <c8y-form-group>\n <label>{{ 'External URL' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://www.example.com/\"\n name=\"externalUrl\"\n type=\"url\"\n required\n [pattern]=\"'^(?!javascript:).+'\"\n [readOnly]=\"!isOwner\"\n formControlName=\"externalUrl\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'pattern'\"\n [text]=\"'Valid URL required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div *ngIf=\"isOwner && !isCustomMicroservice\">\n <label>{{ 'Select icon' | translate }}</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"isCustomMicroservice\">\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <c8y-upload-archive\n [(application)]=\"application\"\n (refresh)=\"onNewArchive()\"\n ></c8y-upload-archive>\n </div>\n </ng-container>\n <div\n class=\"card-footer separator\"\n *ngIf=\"application && !!isOwner && hasAdminPermissions\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-danger\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"delete()\"\n *ngIf=\"canDelete\"\n >\n {{ 'Delete' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"!application.type || formGroup.invalid || formGroup.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"content-fullpage d-flex d-col bg-level-1\"\n *ngIf=\"isActivityLogSupported\"\n >\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Activity log\n </div>\n <div class=\"m-l-auto\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"load()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </div>\n </div>\n <div\n class=\"p-16 text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <c8y-activity-log\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n [hasAdminPermissions]=\"hasAdminPermissions\"\n [application]=\"application\"\n ></c8y-activity-log>\n </div>\n </div>\n </div>\n</div>\n" }]
975
- }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1.EcosystemService }, { type: i1$2.Router }, { type: i3$1.FormBuilder }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i4.InventoryService }, { type: i2.Permissions }, { type: i2.ModalService }, { type: i4$1.TranslateService }, { type: i1$1.BsModalService }, { type: i2.GainsightService }] });
984
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1.EcosystemService }, { type: i1$2.Router }, { type: i2$1.FormBuilder }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i4.InventoryService }, { type: i2.Permissions }, { type: i2.ModalService }, { type: i4$1.TranslateService }, { type: i1$1.BsModalService }, { type: i2.GainsightService }] });
976
985
 
977
986
  class ApplicationPropertiesGuard {
978
987
  constructor(ecosystemService) {
@@ -1033,13 +1042,13 @@ class AddExternalApplicationComponent {
1033
1042
  externalUrl: ['', Validators.required]
1034
1043
  });
1035
1044
  }
1036
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddExternalApplicationComponent, deps: [{ token: i4.ApplicationService }, { token: i3$1.FormBuilder }, { token: i2.AlertService }, { token: i2.WizardComponent }], target: i0.ɵɵFactoryTarget.Component }); }
1037
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AddExternalApplicationComponent, selector: "c8y-add-external-application", ngImport: i0, template: "<form *ngIf=\"!createdApp; else appCreated\" [formGroup]=\"formGroup\" novalidate>\n <c8y-wizard-header>\n <i [c8yIcon]=\"'cloud-link'\"></i>\n <h4 translate id=\"modal-title\">Add external application</h4>\n </c8y-wizard-header>\n\n <c8y-wizard-body>\n <p class=\"p-16 text-medium text-center bg-level-0 separator-bottom sticky-top\">\n {{ 'Provide external application details' | translate }}\n </p>\n <div class=\"modal-body p-t-8\" id=\"modal-body\">\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"name\"\n name=\"name\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"key\"\n name=\"key\"\n placeholder=\"{{ 'e.g. my-external-application-key' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'External URL' | translate }}</label>\n <input\n [pattern]=\"'^(?!javascript:).+'\"\n class=\"form-control\"\n formControlName=\"externalUrl\"\n name=\"externalUrl\"\n placeholder=\"{{ 'e.g.' | translate }} https://www.example.com\"\n required\n type=\"url\"\n />\n </c8y-form-group>\n </div>\n </c8y-wizard-body>\n\n <c8y-wizard-footer>\n <button\n (click)=\"back()\"\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n translate\n type=\"button\"\n >\n Back\n </button>\n <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\" translate>\n Cancel\n </button>\n <button\n (click)=\"save(formGroup.value)\"\n [disabled]=\"formGroup.invalid || formGroup.pristine\"\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Add application' | translate }}\"\n type=\"button\"\n >\n {{ 'Add application' | translate }}\n </button>\n </c8y-wizard-footer>\n</form>\n<ng-template #appCreated>\n <c8y-wizard-body>\n <div class=\"d-flex d-col j-c-center a-i-center\" style=\"min-height: 324px\">\n <c8y-operation-result\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </c8y-wizard-body>\n <c8y-wizard-footer>\n <button (click)=\"done()\" class=\"btn btn-default\" title=\"{{ 'Done' | translate }}\" translate>\n Done\n </button>\n <a\n (click)=\"$event.stopPropagation()\"\n [href]=\"formGroup.value.externalUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"btn btn-primary\"\n title=\"{{ 'Open' | translate }}\"\n >\n <i c8yIcon=\"external-link\" class=\"m-r-4\"></i>\n {{ 'Open' | translate }}\n </a>\n </c8y-wizard-footer>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "directive", type: i3$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3$1.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: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i2.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i2.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i2.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "directive", type: i3$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1045
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddExternalApplicationComponent, deps: [{ token: i4.ApplicationService }, { token: i2$1.FormBuilder }, { token: i2.AlertService }, { token: i2.WizardComponent }], target: i0.ɵɵFactoryTarget.Component }); }
1046
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AddExternalApplicationComponent, selector: "c8y-add-external-application", ngImport: i0, template: "<form *ngIf=\"!createdApp; else appCreated\" [formGroup]=\"formGroup\" novalidate>\n <c8y-wizard-header>\n <i [c8yIcon]=\"'cloud-link'\"></i>\n <h4 translate id=\"modal-title\">Add external application</h4>\n </c8y-wizard-header>\n\n <c8y-wizard-body>\n <p class=\"p-16 text-medium text-center bg-level-0 separator-bottom sticky-top\">\n {{ 'Provide external application details' | translate }}\n </p>\n <div class=\"modal-body p-t-8\" id=\"modal-body\">\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"name\"\n name=\"name\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"key\"\n name=\"key\"\n placeholder=\"{{ 'e.g. my-external-application-key' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'External URL' | translate }}</label>\n <input\n [pattern]=\"'^(?!javascript:).+'\"\n class=\"form-control\"\n formControlName=\"externalUrl\"\n name=\"externalUrl\"\n placeholder=\"{{ 'e.g.' | translate }} https://www.example.com\"\n required\n type=\"url\"\n />\n </c8y-form-group>\n </div>\n </c8y-wizard-body>\n\n <c8y-wizard-footer>\n <button\n (click)=\"back()\"\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n translate\n type=\"button\"\n >\n Back\n </button>\n <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\" translate>\n Cancel\n </button>\n <button\n (click)=\"save(formGroup.value)\"\n [disabled]=\"formGroup.invalid || formGroup.pristine\"\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Add application' | translate }}\"\n type=\"button\"\n >\n {{ 'Add application' | translate }}\n </button>\n </c8y-wizard-footer>\n</form>\n<ng-template #appCreated>\n <c8y-wizard-body>\n <div class=\"d-flex d-col j-c-center a-i-center\" style=\"min-height: 324px\">\n <c8y-operation-result\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </c8y-wizard-body>\n <c8y-wizard-footer>\n <button (click)=\"done()\" class=\"btn btn-default\" title=\"{{ 'Done' | translate }}\" translate>\n Done\n </button>\n <a\n (click)=\"$event.stopPropagation()\"\n [href]=\"formGroup.value.externalUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"btn btn-primary\"\n title=\"{{ 'Open' | translate }}\"\n >\n <i c8yIcon=\"external-link\" class=\"m-r-4\"></i>\n {{ 'Open' | translate }}\n </a>\n </c8y-wizard-footer>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i2.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i2.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i2.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1038
1047
  }
1039
1048
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddExternalApplicationComponent, decorators: [{
1040
1049
  type: Component,
1041
1050
  args: [{ selector: 'c8y-add-external-application', template: "<form *ngIf=\"!createdApp; else appCreated\" [formGroup]=\"formGroup\" novalidate>\n <c8y-wizard-header>\n <i [c8yIcon]=\"'cloud-link'\"></i>\n <h4 translate id=\"modal-title\">Add external application</h4>\n </c8y-wizard-header>\n\n <c8y-wizard-body>\n <p class=\"p-16 text-medium text-center bg-level-0 separator-bottom sticky-top\">\n {{ 'Provide external application details' | translate }}\n </p>\n <div class=\"modal-body p-t-8\" id=\"modal-body\">\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"name\"\n name=\"name\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"key\"\n name=\"key\"\n placeholder=\"{{ 'e.g. my-external-application-key' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'External URL' | translate }}</label>\n <input\n [pattern]=\"'^(?!javascript:).+'\"\n class=\"form-control\"\n formControlName=\"externalUrl\"\n name=\"externalUrl\"\n placeholder=\"{{ 'e.g.' | translate }} https://www.example.com\"\n required\n type=\"url\"\n />\n </c8y-form-group>\n </div>\n </c8y-wizard-body>\n\n <c8y-wizard-footer>\n <button\n (click)=\"back()\"\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n translate\n type=\"button\"\n >\n Back\n </button>\n <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\" translate>\n Cancel\n </button>\n <button\n (click)=\"save(formGroup.value)\"\n [disabled]=\"formGroup.invalid || formGroup.pristine\"\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Add application' | translate }}\"\n type=\"button\"\n >\n {{ 'Add application' | translate }}\n </button>\n </c8y-wizard-footer>\n</form>\n<ng-template #appCreated>\n <c8y-wizard-body>\n <div class=\"d-flex d-col j-c-center a-i-center\" style=\"min-height: 324px\">\n <c8y-operation-result\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </c8y-wizard-body>\n <c8y-wizard-footer>\n <button (click)=\"done()\" class=\"btn btn-default\" title=\"{{ 'Done' | translate }}\" translate>\n Done\n </button>\n <a\n (click)=\"$event.stopPropagation()\"\n [href]=\"formGroup.value.externalUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"btn btn-primary\"\n title=\"{{ 'Open' | translate }}\"\n >\n <i c8yIcon=\"external-link\" class=\"m-r-4\"></i>\n {{ 'Open' | translate }}\n </a>\n </c8y-wizard-footer>\n</ng-template>\n" }]
1042
- }], ctorParameters: () => [{ type: i4.ApplicationService }, { type: i3$1.FormBuilder }, { type: i2.AlertService }, { type: i2.WizardComponent }] });
1051
+ }], ctorParameters: () => [{ type: i4.ApplicationService }, { type: i2$1.FormBuilder }, { type: i2.AlertService }, { type: i2.WizardComponent }] });
1043
1052
 
1044
1053
  class AddWebApplicationComponent {
1045
1054
  constructor(ecosystemService) {
@@ -1185,6 +1194,11 @@ class InstallFromPackageComponent {
1185
1194
  type,
1186
1195
  version: this.model.selected.version
1187
1196
  };
1197
+ const isArchived = await this.ecosystemService.verifyArchived([licensedApp]);
1198
+ if (!isArchived) {
1199
+ this.cancel();
1200
+ return;
1201
+ }
1188
1202
  const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([licensedApp]);
1189
1203
  if (!licensesVerifiedByUser) {
1190
1204
  this.cancel();
@@ -1262,7 +1276,7 @@ class InstallFromPackageComponent {
1262
1276
  this.packages = applications.filter(app => this.ecosystemService.isPackageBlueprint(app));
1263
1277
  }
1264
1278
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: InstallFromPackageComponent, deps: [{ token: i1.EcosystemService }, { token: i4.ApplicationService }, { token: i2.WizardComponent }, { token: i2.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
1265
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: InstallFromPackageComponent, selector: "c8y-install-from-package", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <i [c8yIcon]=\"'big-parcel'\"></i>\n <h4\n id=\"modal-title\"\n translate\n >\n Install from extension package\n </h4>\n</c8y-wizard-header>\n<c8y-wizard-body>\n <ng-container *ngIf=\"!selectedPackage\">\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <p class=\"p-16 text-medium text-center separator-bottom sticky-top bg-level-0\">\n {{ 'Select from available extension packages' | translate }}\n </p>\n\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extension packages to display.' | translate\"\n *ngIf=\"!packages?.length\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div\n class=\"c8y-wizard-list-nav\"\n style=\"min-height: 257px\"\n *ngIf=\"packages?.length\"\n >\n <button\n class=\"list-group-item text-truncate\"\n title=\"{{ package.name }}\"\n type=\"button\"\n *ngFor=\"let package of packages\"\n (click)=\"selectPackage(package)\"\n >\n <i\n class=\"list-group-icon\"\n c8yIcon=\"big-parcel\"\n ></i>\n <span [innerText]=\"package.name\"></span>\n </button>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!isDeployed && selectedPackage\">\n <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n {{ 'Provide application details' | translate }}\n </p>\n <div\n class=\"d-flex d-col a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-application-properties-form\n class=\"d-block fit-w\"\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div\n class=\"d-block fit-w bg-gray-white\"\n [ngStyle]=\"{ padding: '0 16px' }\"\n >\n <label\n for=\"packageVersion\"\n translate\n >\n Use extension package version\n </label>\n <c8y-form-group>\n <c8y-typeahead\n placeholder=\"{{ 'Select or enter' | translate }}\"\n name=\"packageVersion\"\n [(ngModel)]=\"model.selected\"\n (onSearch)=\"onInput.next($event)\"\n [displayProperty]=\"'version'\"\n [required]=\"true\"\n [hideNew]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let version of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n (click)=\"onAppVersionSelect(version)\"\n [active]=\"model.selected === version\"\n >\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <span\n [ngStyle]=\"{\n display: 'flex',\n 'flex-direction': 'row',\n 'align-content': 'center',\n 'justify-content': 'space-between',\n 'align-items': 'center'\n }\"\n >\n <c8y-highlight\n [text]=\"version.version || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n\n <span>\n <span\n class=\"label label-info m-l-4\"\n *ngFor=\"let tag of version.tags\"\n >\n {{ tag }}\n </span>\n </span>\n </span>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li\n class=\"bg-gray-lighter p-8\"\n *ngIf=\"(onInput | async)?.length > 0 && (versions$ | async)?.data?.length === 0\"\n >\n <span translate>No match found.</span>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n </ng-container>\n\n <c8y-loading\n class=\"text-center d-block\"\n [message]=\"'Installing\u2026' | translate\"\n *ngIf=\"inProgress\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"success\"\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n <ng-template #failedDeploy>\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"error\"\n text=\"{{ 'Application creation failed' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"!isDeployed\"\n (click)=\"selectedPackage ? clean() : back()\"\n [disabled]=\"inProgress\"\n >\n {{ 'Back' | translate }}\n </button>\n <button\n class=\"btn btn-default\"\n title=\"{{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\n </button>\n\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"deployApp()\"\n [disabled]=\"inProgress || !packages?.length\"\n *ngIf=\"!isDeployed\"\n >\n {{ 'Install' | translate }}\n </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i2.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: i2.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i2.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i2.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i2.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "component", type: i1.ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
1279
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: InstallFromPackageComponent, selector: "c8y-install-from-package", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <i [c8yIcon]=\"'big-parcel'\"></i>\n <h4\n id=\"modal-title\"\n translate\n >\n Install from extension package\n </h4>\n</c8y-wizard-header>\n<c8y-wizard-body>\n <ng-container *ngIf=\"!selectedPackage\">\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <p class=\"p-16 text-medium text-center separator-bottom sticky-top bg-level-0\">\n {{ 'Select from available extension packages' | translate }}\n </p>\n\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extension packages to display.' | translate\"\n *ngIf=\"!packages?.length\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div\n class=\"c8y-wizard-list-nav\"\n style=\"min-height: 257px\"\n *ngIf=\"packages?.length\"\n >\n <button\n class=\"list-group-item text-truncate\"\n title=\"{{ package.name }}\"\n type=\"button\"\n *ngFor=\"let package of packages\"\n (click)=\"selectPackage(package)\"\n >\n <i\n class=\"list-group-icon\"\n c8yIcon=\"big-parcel\"\n ></i>\n <span [innerText]=\"package.name\"></span>\n </button>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!isDeployed && selectedPackage\">\n <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n {{ 'Provide application details' | translate }}\n </p>\n <div\n class=\"d-flex d-col a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-application-properties-form\n class=\"d-block fit-w\"\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div\n class=\"d-block fit-w bg-gray-white\"\n [ngStyle]=\"{ padding: '0 16px' }\"\n >\n <label\n for=\"packageVersion\"\n translate\n >\n Use extension package version\n </label>\n <c8y-form-group>\n <c8y-typeahead\n placeholder=\"{{ 'Select or enter' | translate }}\"\n name=\"packageVersion\"\n [(ngModel)]=\"model.selected\"\n (onSearch)=\"onInput.next($event)\"\n [displayProperty]=\"'version'\"\n [required]=\"true\"\n [hideNew]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let version of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n (click)=\"onAppVersionSelect(version)\"\n [active]=\"model.selected === version\"\n >\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <span\n [ngStyle]=\"{\n display: 'flex',\n 'flex-direction': 'row',\n 'align-content': 'center',\n 'justify-content': 'space-between',\n 'align-items': 'center'\n }\"\n >\n <c8y-highlight\n [text]=\"version.version || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n\n <span>\n <span\n class=\"label label-info m-l-4\"\n *ngFor=\"let tag of version.tags\"\n >\n {{ tag }}\n </span>\n </span>\n </span>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li\n class=\"bg-gray-lighter p-8\"\n *ngIf=\"(onInput | async)?.length > 0 && (versions$ | async)?.data?.length === 0\"\n >\n <span translate>No match found.</span>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n </ng-container>\n\n <c8y-loading\n class=\"text-center d-block\"\n [message]=\"'Installing\u2026' | translate\"\n *ngIf=\"inProgress\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"success\"\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n <ng-template #failedDeploy>\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"error\"\n text=\"{{ 'Application creation failed' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"!isDeployed\"\n (click)=\"selectedPackage ? clean() : back()\"\n [disabled]=\"inProgress\"\n >\n {{ 'Back' | translate }}\n </button>\n <button\n class=\"btn btn-default\"\n title=\"{{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\n </button>\n\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"deployApp()\"\n [disabled]=\"inProgress || !packages?.length\"\n *ngIf=\"!isDeployed\"\n >\n {{ 'Install' | translate }}\n </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i2.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: i2.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i2.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i2.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i2.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "component", type: i1.ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
1266
1280
  }
1267
1281
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: InstallFromPackageComponent, decorators: [{
1268
1282
  type: Component,
@@ -1353,757 +1367,691 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
1353
1367
  type: Injectable
1354
1368
  }], ctorParameters: () => [{ type: i1$2.Router }] });
1355
1369
 
1356
- class FeatureListComponent {
1357
- constructor(ecosystemService) {
1358
- this.ecosystemService = ecosystemService;
1359
- this.reloading = false;
1360
- this.reload$ = new BehaviorSubject(null);
1361
- this.features$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getFeatureApplications()), tap(() => (this.reloading = false)), shareReplay());
1362
- }
1363
- ngOnInit() {
1364
- this.loadFeatures();
1365
- }
1366
- loadFeatures() {
1367
- this.reload$.next();
1368
- }
1369
- setFilterPipe(pipe) {
1370
- this.filteredFeatures$ = this.features$.pipe(src => pipe(src));
1371
- }
1372
- resetFilters() {
1373
- this.filtersComponent?.resetAllFilters();
1370
+ class OnlyLatestFilterComponent {
1371
+ constructor(filterComponent) {
1372
+ this.filterComponent = filterComponent;
1373
+ this.filterLabel = gettext('Only latest versions');
1374
+ this.onlyLatestFormControl = new FormControl(true);
1375
+ this.filterComponent.formGroup.controls.custom.addControl(this.filterLabel, this.onlyLatestFormControl);
1376
+ filterComponent.customFilters.set(this.filterLabel, (plugin, enabled) => {
1377
+ return !enabled || !!plugin.tags?.includes('latest');
1378
+ });
1374
1379
  }
1375
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: FeatureListComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
1376
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: FeatureListComponent, selector: "c8y-feature-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Features' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'tab'\" [label]=\"'Features' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button (click)=\"reload$.next()\" class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\">\n <i [ngClass]=\"{ 'icon-spin': reloading }\" c8yIcon=\"refresh\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"features$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\" itemClass=\"navbar-form hidden-xs\">\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(features$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div *ngIf=\"(features$ | async)?.length === 0\" class=\"c8y-empty-state text-center\">\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No features to display.</h3>\n <p translate>No additional features are subscribed to the tenant.</p>\n</div>\n\n<div [ngClass]=\"listClass\" class=\"card-group\">\n <div class=\"page-sticky-header hidden-xs d-flex\" *ngIf=\"(features$ | async)?.length > 0\">\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Feature' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n </div>\n </div>\n <div *ngFor=\"let feature of filteredFeatures$ | async\" class=\"col-xs-12 col-sm-4 col-md-3\">\n <c8y-application-card\n [app]=\"feature\"\n [canEdit]=\"false\"\n class=\"d-contents\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n *ngIf=\"(features$ | async)?.length > 0 && (filteredFeatures$ | async)?.length === 0\"\n [icon]=\"'search'\"\n [title]=\"'No matching features.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n>\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Reset filters' | translate }}\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i1.ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
1380
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OnlyLatestFilterComponent, deps: [{ token: i1.ListFiltersComponent }], target: i0.ɵɵFactoryTarget.Component }); }
1381
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: OnlyLatestFilterComponent, selector: "c8y-only-latest-filter", ngImport: i0, template: "<label class=\"c8y-switch\">\n <input\n type=\"checkbox\"\n checked=\"checked\"\n [formControl]=\"onlyLatestFormControl\"\n />\n <span></span>\n {{ 'Show only latest version of plugins' | translate }}\n</label>\n", dependencies: [{ kind: "directive", type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1377
1382
  }
1378
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: FeatureListComponent, decorators: [{
1383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OnlyLatestFilterComponent, decorators: [{
1379
1384
  type: Component,
1380
- args: [{ selector: 'c8y-feature-list', template: "<c8y-title>{{ 'Features' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'tab'\" [label]=\"'Features' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button (click)=\"reload$.next()\" class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\">\n <i [ngClass]=\"{ 'icon-spin': reloading }\" c8yIcon=\"refresh\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"features$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\" itemClass=\"navbar-form hidden-xs\">\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(features$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div *ngIf=\"(features$ | async)?.length === 0\" class=\"c8y-empty-state text-center\">\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No features to display.</h3>\n <p translate>No additional features are subscribed to the tenant.</p>\n</div>\n\n<div [ngClass]=\"listClass\" class=\"card-group\">\n <div class=\"page-sticky-header hidden-xs d-flex\" *ngIf=\"(features$ | async)?.length > 0\">\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Feature' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n </div>\n </div>\n <div *ngFor=\"let feature of filteredFeatures$ | async\" class=\"col-xs-12 col-sm-4 col-md-3\">\n <c8y-application-card\n [app]=\"feature\"\n [canEdit]=\"false\"\n class=\"d-contents\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n *ngIf=\"(features$ | async)?.length > 0 && (filteredFeatures$ | async)?.length === 0\"\n [icon]=\"'search'\"\n [title]=\"'No matching features.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n>\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Reset filters' | translate }}\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
1381
- }], ctorParameters: () => [{ type: i1.EcosystemService }], propDecorators: { filtersComponent: [{
1382
- type: ViewChild,
1383
- args: [ListFiltersComponent]
1384
- }] } });
1385
+ args: [{ selector: 'c8y-only-latest-filter', template: "<label class=\"c8y-switch\">\n <input\n type=\"checkbox\"\n checked=\"checked\"\n [formControl]=\"onlyLatestFormControl\"\n />\n <span></span>\n {{ 'Show only latest version of plugins' | translate }}\n</label>\n" }]
1386
+ }], ctorParameters: () => [{ type: i1.ListFiltersComponent }] });
1385
1387
 
1386
- class AddMicroserviceComponent {
1387
- constructor(ecosystemService, modal, tenantService, docs) {
1388
+ class InstallPluginComponent {
1389
+ constructor(bsModalRef, ecosystemService) {
1390
+ this.bsModalRef = bsModalRef;
1388
1391
  this.ecosystemService = ecosystemService;
1389
- this.modal = modal;
1390
- this.tenantService = tenantService;
1391
- this.docs = docs;
1392
- this.slaHref = this.docs.getUserGuideLink('docs/microservice-sdk/microservices-sla');
1393
- this.headerText = gettext('Add microservice');
1394
- this.successText = gettext('Microservice created');
1395
- this.createMicroserviceApplicationHandler = (f) => this.createMicroserviceApplication(f);
1396
- this.uploadMicroserviceHandler = (f, app) => this.uploadMicroservice(f, app);
1397
- }
1398
- async createMicroserviceApplication(file) {
1399
- await this.ecosystemService.isValidAppType(file, ApplicationType.MICROSERVICE);
1400
- return this.ecosystemService.createAppForArchive(file);
1392
+ this.filteredPlugins$ = new BehaviorSubject([]);
1393
+ this.selectedPlugins = [];
1394
+ this.packageTypes = defaultPackageTypes;
1395
+ this.result = new Promise((resolve, reject) => {
1396
+ this._install = resolve;
1397
+ this._cancel = reject;
1398
+ });
1399
+ this.onlyLatestPluginVersion = true;
1401
1400
  }
1402
- async uploadMicroservice(file, microservice) {
1403
- const subscribeToCurrentTenant = await this.askIfActivationAfterUploadNeeded();
1404
- await this.ecosystemService.uploadArchiveToApp(file, microservice);
1405
- await this.subscribeMicroservice(microservice, subscribeToCurrentTenant);
1401
+ setFilterPipe(filterPipe) {
1402
+ this.filteredPlugins$ = this.plugins$.pipe(map$1(plugins => plugins.map(plugin => {
1403
+ plugin.filterProps = this.ecosystemService.getAppFilterProps(plugin.originApp);
1404
+ return plugin;
1405
+ })), src => filterPipe(src));
1406
1406
  }
1407
- async askIfActivationAfterUploadNeeded() {
1408
- try {
1409
- await this.modal.confirm(gettext('Subscribe to microservice'), gettext('You are about to subscribe to the microservice after upload. Do you want to subscribe to it?'), Status.INFO, { ok: gettext('Subscribe'), cancel: gettext("Don't subscribe") });
1410
- return true;
1411
- }
1412
- catch (ex) {
1413
- return false;
1414
- }
1407
+ cancel() {
1408
+ this.bsModalRef.hide();
1409
+ this._cancel();
1415
1410
  }
1416
- async subscribeMicroservice(app, subscribeToCurrentTenant) {
1417
- const tenant = (await this.tenantService.current()).data;
1418
- const applications = tenant.applications.references;
1419
- const isSubscribed = applications.some(({ application }) => application.id === app.id);
1420
- if (!isSubscribed && subscribeToCurrentTenant) {
1421
- try {
1422
- return await this.tenantService.subscribeApplication(tenant, app);
1423
- }
1424
- catch (res) {
1425
- if (res.status === 409) {
1426
- throw Error(ERROR_TYPE.ALREADY_SUBSCRIBED);
1427
- }
1428
- }
1429
- }
1430
- else if (isSubscribed && !subscribeToCurrentTenant) {
1431
- return this.tenantService.unsubscribeApplication(tenant, app);
1432
- }
1411
+ install() {
1412
+ this._install(this.selectedPlugins);
1413
+ this.bsModalRef.hide();
1433
1414
  }
1434
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddMicroserviceComponent, deps: [{ token: i1.EcosystemService }, { token: i2.ModalService }, { token: i4.TenantService }, { token: i2.DocsService }], target: i0.ɵɵFactoryTarget.Component }); }
1435
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AddMicroserviceComponent, selector: "c8y-add-microservice", ngImport: i0, template: `<div class="p-16" translate [translateParams]="{ slaHref: slaHref }" ngNonBindable>
1436
- By uploading a microservice, you agree to the
1437
- <a href="{{ slaHref }}" target="_blank" rel="noopener noreferrer"
1438
- >Microservice Deployment SLA</a
1439
- >
1440
- which outlines our microservices hosting terms, conditions, and performance standards.
1441
- </div>
1442
- <c8y-add-application
1443
- [headerIcon]="'microchip'"
1444
- [headerText]="headerText"
1445
- [successText]="successText"
1446
- [createApplicationHandler]="createMicroserviceApplicationHandler"
1447
- [uploadApplicationHandler]="uploadMicroserviceHandler"
1448
- ></c8y-add-application>`, isInline: true, dependencies: [{ kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i1.AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
1415
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: InstallPluginComponent, deps: [{ token: i1$1.BsModalRef }, { token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
1416
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: InstallPluginComponent, selector: "c8y-install-plugin", inputs: { plugins$: "plugins$" }, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'plugin'\"></i>\n <div\n class=\"modal-title h4\"\n id=\"modal-title\"\n translate\n >\n Available plugins\n </div>\n </div>\n <div class=\"p-t-8 p-16 text-center separator-bottom flex-no-shrink\">\n <p\n class=\"text-medium m-b-8\"\n translate\n >\n Select the compatible plugins to install\n </p>\n <c8y-list-filters\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageTypes]=\"packageTypes\"\n >\n <c8y-archived-filter></c8y-archived-filter>\n <c8y-only-latest-filter></c8y-only-latest-filter>\n </c8y-list-filters>\n </div>\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <c8y-plugin-list\n class=\"m-t-16\"\n (selectedItems)=\"selectedPlugins = $event\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"filteredPlugins$\"\n [selectable]=\"true\"\n ></c8y-plugin-list>\n </div>\n\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n data-cy=\"install-plugin--cancel-button\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"install()\"\n [disabled]=\"selectedPlugins.length === 0\"\n data-cy=\"install-plugin--install-button\"\n >\n {{ 'Install' | translate }}\n <span\n class=\"badge\"\n *ngIf=\"selectedPlugins.length as length\"\n >\n {{ length }}\n </span>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "component", type: i1.ArchivedFilterComponent, selector: "c8y-archived-filter" }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { kind: "component", type: OnlyLatestFilterComponent, selector: "c8y-only-latest-filter" }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1449
1417
  }
1450
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddMicroserviceComponent, decorators: [{
1418
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: InstallPluginComponent, decorators: [{
1451
1419
  type: Component,
1452
- args: [{
1453
- selector: 'c8y-add-microservice',
1454
- template: `<div class="p-16" translate [translateParams]="{ slaHref: slaHref }" ngNonBindable>
1455
- By uploading a microservice, you agree to the
1456
- <a href="{{ slaHref }}" target="_blank" rel="noopener noreferrer"
1457
- >Microservice Deployment SLA</a
1458
- >
1459
- which outlines our microservices hosting terms, conditions, and performance standards.
1460
- </div>
1461
- <c8y-add-application
1462
- [headerIcon]="'microchip'"
1463
- [headerText]="headerText"
1464
- [successText]="successText"
1465
- [createApplicationHandler]="createMicroserviceApplicationHandler"
1466
- [uploadApplicationHandler]="uploadMicroserviceHandler"
1467
- ></c8y-add-application>`
1468
- }]
1469
- }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.ModalService }, { type: i4.TenantService }, { type: i2.DocsService }] });
1420
+ args: [{ selector: 'c8y-install-plugin', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'plugin'\"></i>\n <div\n class=\"modal-title h4\"\n id=\"modal-title\"\n translate\n >\n Available plugins\n </div>\n </div>\n <div class=\"p-t-8 p-16 text-center separator-bottom flex-no-shrink\">\n <p\n class=\"text-medium m-b-8\"\n translate\n >\n Select the compatible plugins to install\n </p>\n <c8y-list-filters\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageTypes]=\"packageTypes\"\n >\n <c8y-archived-filter></c8y-archived-filter>\n <c8y-only-latest-filter></c8y-only-latest-filter>\n </c8y-list-filters>\n </div>\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <c8y-plugin-list\n class=\"m-t-16\"\n (selectedItems)=\"selectedPlugins = $event\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"filteredPlugins$\"\n [selectable]=\"true\"\n ></c8y-plugin-list>\n </div>\n\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n data-cy=\"install-plugin--cancel-button\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"install()\"\n [disabled]=\"selectedPlugins.length === 0\"\n data-cy=\"install-plugin--install-button\"\n >\n {{ 'Install' | translate }}\n <span\n class=\"badge\"\n *ngIf=\"selectedPlugins.length as length\"\n >\n {{ length }}\n </span>\n </button>\n </div>\n</div>\n" }]
1421
+ }], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: i1.EcosystemService }], propDecorators: { plugins$: [{
1422
+ type: Input
1423
+ }] } });
1470
1424
 
1471
- class MicroserviceListComponent {
1472
- constructor(ecosystemService, wizardModalService, cd) {
1473
- this.ecosystemService = ecosystemService;
1474
- this.wizardModalService = wizardModalService;
1475
- this.cd = cd;
1476
- this.reloading = false;
1477
- this.reload$ = new BehaviorSubject(null);
1478
- this.microservices$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getMicroservices()), tap(microservices => {
1479
- microservices.forEach(microservice => {
1480
- microservice.filterProps = this.ecosystemService.getAppFilterProps(microservice);
1481
- });
1482
- }), tap(() => (this.reloading = false)), shareReplay());
1483
- this.isMicroserviceHostingAllowed$ = this.reload$.pipe(switchMap(() => this.ecosystemService.isMicroserviceHostingAllowed()), shareReplay());
1484
- this.packageAvailabilities = [
1485
- APP_STATE.SUBSCRIBED.label,
1486
- APP_STATE.CUSTOM.label
1487
- ];
1488
- }
1489
- ngOnInit() {
1490
- this.loadMicroservices();
1491
- // manually trigger detection to not have ExpressionChangedAfterItHasBeenChecked error in spec file
1492
- this.cd.detectChanges();
1493
- }
1494
- loadMicroservices() {
1495
- this.reload$.next();
1496
- }
1497
- addMicroservice() {
1498
- const initialState = {
1499
- id: EcosystemWizards.MICROSERVICE_UPLOAD
1500
- };
1501
- const modalOptions = { initialState };
1502
- const modalRef = this.wizardModalService.show(modalOptions);
1503
- modalRef.content.onClose.subscribe(() => {
1504
- this.loadMicroservices();
1505
- });
1425
+ class LabelCellRendererComponent {
1426
+ constructor(context) {
1427
+ this.context = context;
1506
1428
  }
1507
- setFilterPipe(pipe) {
1508
- this.filteredMicroservices$ = this.microservices$.pipe(src => pipe(src));
1429
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: LabelCellRendererComponent, deps: [{ token: i2.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
1430
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: LabelCellRendererComponent, selector: "c8y-label-cell-renderer", ngImport: i0, template: "<span class=\"label label-info\">{{ context.value }}</span>\n" }); }
1431
+ }
1432
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: LabelCellRendererComponent, decorators: [{
1433
+ type: Component,
1434
+ args: [{ selector: 'c8y-label-cell-renderer', template: "<span class=\"label label-info\">{{ context.value }}</span>\n" }]
1435
+ }], ctorParameters: () => [{ type: i2.CellRendererContext }] });
1436
+
1437
+ class OrphanedStatusCellRendererComponent {
1438
+ constructor(context) {
1439
+ this.context = context;
1440
+ this.label = this.getLabel(context.value);
1509
1441
  }
1510
- resetFilters() {
1511
- this.filtersComponent?.resetAllFilters();
1442
+ getLabel(statusValue) {
1443
+ switch (statusValue) {
1444
+ case ApplicationPluginStatus.OUTDATED:
1445
+ return {
1446
+ value: statusValue,
1447
+ text: gettext('OUTDATED`plugin status`'),
1448
+ class: 'label-warning'
1449
+ };
1450
+ case ApplicationPluginStatus.ORPHANED:
1451
+ return {
1452
+ value: statusValue,
1453
+ text: gettext('ORPHANED`plugin status`'),
1454
+ class: 'label-danger'
1455
+ };
1456
+ case ApplicationPluginStatus.REVOKED:
1457
+ return {
1458
+ value: statusValue,
1459
+ text: gettext('REVOKED`plugin status`'),
1460
+ class: 'label-danger'
1461
+ };
1462
+ case ApplicationPluginStatus.LATEST:
1463
+ return {
1464
+ value: statusValue,
1465
+ text: gettext('LATEST`plugin status`'),
1466
+ class: 'label-success'
1467
+ };
1468
+ case ApplicationPluginStatus.AUTO:
1469
+ return {
1470
+ value: statusValue,
1471
+ text: gettext('AUTO`plugin status`'),
1472
+ class: 'label-success'
1473
+ };
1474
+ default:
1475
+ return null;
1476
+ }
1512
1477
  }
1513
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: MicroserviceListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1514
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: MicroserviceListComponent, selector: "c8y-microservice-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Microservices' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'microchip'\"\n [label]=\"'Microservices' | translate\"\n [path]=\"'ecosystem/microservice/microservices'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n *ngIf=\"isMicroserviceHostingAllowed$ | async\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add microservice' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-microservices\"></c8y-help>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"microservices$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(microservices$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(microservices$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No microservices to display.</h3>\n <p translate>Add your first microservice by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n {{ 'Add microservice' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(microservices$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Microservice' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let microservice of filteredMicroservices$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadMicroservices()\"\n [app]=\"microservice\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching microservices.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(microservices$ | async)?.length > 0 && (filteredMicroservices$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i1.ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
1478
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OrphanedStatusCellRendererComponent, deps: [{ token: i2.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
1479
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: OrphanedStatusCellRendererComponent, selector: "c8y-orphaned-status-cell-renderer", ngImport: i0, template: "<span\n *ngIf=\"label\"\n class=\"label\"\n [ngClass]=\"label.class\"\n [title]=\"label.text | translate\"\n>\n {{ label.text | translate }}\n</span>\n", dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1515
1480
  }
1516
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: MicroserviceListComponent, decorators: [{
1481
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OrphanedStatusCellRendererComponent, decorators: [{
1517
1482
  type: Component,
1518
- args: [{ selector: 'c8y-microservice-list', template: "<c8y-title>{{ 'Microservices' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'microchip'\"\n [label]=\"'Microservices' | translate\"\n [path]=\"'ecosystem/microservice/microservices'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n *ngIf=\"isMicroserviceHostingAllowed$ | async\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add microservice' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-microservices\"></c8y-help>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"microservices$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(microservices$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(microservices$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No microservices to display.</h3>\n <p translate>Add your first microservice by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n {{ 'Add microservice' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(microservices$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Microservice' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let microservice of filteredMicroservices$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadMicroservices()\"\n [app]=\"microservice\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching microservices.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(microservices$ | async)?.length > 0 && (filteredMicroservices$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
1519
- }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }, { type: i0.ChangeDetectorRef }], propDecorators: { filtersComponent: [{
1520
- type: ViewChild,
1521
- args: [ListFiltersComponent]
1522
- }] } });
1483
+ args: [{ selector: 'c8y-orphaned-status-cell-renderer', template: "<span\n *ngIf=\"label\"\n class=\"label\"\n [ngClass]=\"label.class\"\n [title]=\"label.text | translate\"\n>\n {{ label.text | translate }}\n</span>\n" }]
1484
+ }], ctorParameters: () => [{ type: i2.CellRendererContext }] });
1523
1485
 
1524
- class AddPackageComponent {
1525
- constructor(ecosystemService) {
1486
+ class UpdatePluginOfAppComponent {
1487
+ constructor(bsModalRef, pluginsService, alert, ecosystemService, gainsightService) {
1488
+ this.bsModalRef = bsModalRef;
1489
+ this.pluginsService = pluginsService;
1490
+ this.alert = alert;
1526
1491
  this.ecosystemService = ecosystemService;
1527
- this.headerText = gettext('Add extension package');
1528
- this.successText = gettext('Extension package created');
1529
- this.createPackageAppHandler = (f) => this.createPackageApp(f);
1530
- this.uploadPackageHandler = (f, app) => this.uploadPackage(f, app);
1531
- }
1532
- async createPackageApp(file) {
1533
- await this.ecosystemService.isValidAppType(file, ApplicationType.HOSTED);
1534
- return await this.ecosystemService.createAppForArchive(file, true);
1535
- }
1536
- uploadPackage(file, pckg) {
1537
- return this.ecosystemService.uploadArchiveToApp(file, pckg, true);
1538
- }
1539
- next() {
1540
- this.stepper.next();
1541
- }
1542
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddPackageComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
1543
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AddPackageComponent, selector: "c8y-add-package", viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true, static: true }], ngImport: i0, template: `<c8y-add-application
1544
- [headerIcon]="'big-parcel'"
1545
- [headerText]="headerText"
1546
- [successText]="successText"
1547
- [createApplicationHandler]="createPackageAppHandler"
1548
- [uploadApplicationHandler]="uploadPackageHandler"
1549
- [applicationType]="'package'"
1550
- ></c8y-add-application>`, isInline: true, dependencies: [{ kind: "component", type: i1.AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
1551
- }
1552
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddPackageComponent, decorators: [{
1553
- type: Component,
1554
- args: [{
1555
- selector: 'c8y-add-package',
1556
- template: `<c8y-add-application
1557
- [headerIcon]="'big-parcel'"
1558
- [headerText]="headerText"
1559
- [successText]="successText"
1560
- [createApplicationHandler]="createPackageAppHandler"
1561
- [uploadApplicationHandler]="uploadPackageHandler"
1562
- [applicationType]="'package'"
1563
- ></c8y-add-application>`
1564
- }]
1565
- }], ctorParameters: () => [{ type: i1.EcosystemService }], propDecorators: { stepper: [{
1566
- type: ViewChild,
1567
- args: [C8yStepper, { static: true }]
1568
- }] } });
1569
-
1570
- class DeployApplicationComponent {
1571
- constructor(ecosystemService, wizardComponent, translate, pluginService, gainsightService, router) {
1572
- this.ecosystemService = ecosystemService;
1573
- this.wizardComponent = wizardComponent;
1574
- this.translate = translate;
1575
- this.pluginService = pluginService;
1576
1492
  this.gainsightService = gainsightService;
1577
- this.router = router;
1578
1493
  this.CURRENT_LOCATION = location.href;
1579
- this.inProgress = true;
1580
- this.isDeployed = false;
1581
- this.deployedWithSuccess = false;
1582
- this.model = {
1583
- selected: undefined,
1584
- binary: {
1585
- id: undefined
1586
- }
1587
- };
1588
- this.canDeploy = false;
1589
- this.descriptionTemplate = gettext('Deploy application using "{{ packageName }}" package');
1590
- this.successMessageTemplate = gettext('Application "{{ packageName }}" created');
1591
- this.doneLabel = gettext('Done');
1592
- this.cancelLabel = gettext('Cancel');
1593
- this.package = this.wizardComponent.package;
1594
- }
1595
- async ngOnInit() {
1596
- const apps = await this.ecosystemService.getHostedAndPackageApplications();
1597
- this.newAppConfig = this.ecosystemService.getUniqueAppConfig(this.package, apps);
1598
- this.headerText = this.getHeaderText();
1599
- this.inProgress = false;
1494
+ this.result = new Promise((resolve, reject) => {
1495
+ this._install = resolve;
1496
+ this._cancel = reject;
1497
+ });
1498
+ this.updateAll = true;
1600
1499
  }
1601
- async deployApp() {
1602
- this.inProgress = true;
1603
- const formGroupValue = this.applicationPropertiesForm.formGroup.getRawValue();
1604
- // Verify if selected package version is compatible with current platform versions.
1605
- this.package.manifest.version = this.model.selected.version;
1606
- const verifyVersionCompatibility = await this.ecosystemService.verifyBlueprintVersionsCompatibility(this.package.manifest);
1607
- if (!verifyVersionCompatibility) {
1500
+ async update() {
1501
+ const remotes = this.pluginsService.getMFRemotes(this.app);
1502
+ const oldRemotePath = `${this.plugin.contextPath}@${this.plugin.version}`;
1503
+ const newRemotePath = `${this.plugin.contextPath}@${this.applicationVersion.version}`;
1504
+ let oldRemoteModules = [...(remotes[oldRemotePath] || [])];
1505
+ if (!oldRemoteModules.length) {
1506
+ this.alert.warning(gettext('Could not change the version of plugin.'));
1608
1507
  this.cancel();
1609
1508
  return;
1610
1509
  }
1611
- const { contextPath, license, name, manifest } = this.package;
1612
- const type = this.pluginService.getPackageType(this.package);
1613
- const licensedApp = {
1614
- contextPath,
1615
- license: license || manifest.license,
1616
- name,
1617
- type,
1618
- version: this.model.selected.version
1619
- };
1620
- const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([licensedApp]);
1621
- if (!licensesVerifiedByUser) {
1510
+ const isArchived = await this.ecosystemService.verifyArchived([this.plugin]);
1511
+ if (!isArchived) {
1512
+ this.alert.warning(gettext('Plugin update aborted by user.'));
1513
+ this.cancel();
1514
+ return;
1515
+ }
1516
+ const result = await this.ecosystemService.verifyLicenses([this.plugin]);
1517
+ if (!result) {
1518
+ this.alert.warning(gettext('Plugin update aborted by user.'));
1622
1519
  this.cancel();
1623
1520
  return;
1624
1521
  }
1522
+ let remoteModulesOfNewVersion = [...(remotes[newRemotePath] || [])];
1523
+ let olderVersions = {};
1524
+ if (this.updateAll) {
1525
+ olderVersions = Object.keys(remotes)
1526
+ .filter(key => key.startsWith(`${this.plugin.contextPath}@`))
1527
+ .reduceRight((prev, curr) => {
1528
+ prev[curr] = undefined;
1529
+ return prev;
1530
+ }, {});
1531
+ oldRemoteModules = Object.keys(olderVersions)
1532
+ .map(version => remotes[version])
1533
+ .reduceRight((prev, curr) => {
1534
+ prev.push(...curr);
1535
+ return prev;
1536
+ }, []);
1537
+ remoteModulesOfNewVersion.push(...oldRemoteModules);
1538
+ }
1539
+ else {
1540
+ remoteModulesOfNewVersion.push(this.plugin.module);
1541
+ olderVersions[oldRemotePath] = oldRemoteModules.filter(module => module !== this.plugin.module);
1542
+ if (!olderVersions[oldRemotePath].length) {
1543
+ olderVersions[oldRemotePath] = undefined;
1544
+ }
1545
+ }
1546
+ remoteModulesOfNewVersion = uniq(remoteModulesOfNewVersion);
1547
+ const newRemotes = {
1548
+ ...remotes,
1549
+ ...olderVersions,
1550
+ [newRemotePath]: remoteModulesOfNewVersion
1551
+ };
1625
1552
  try {
1626
- this.deployedApp = await this.ecosystemService.deployApp(this.package, formGroupValue, this.model);
1627
- const applicationCustomEventInfo = pick(this.package, [
1628
- 'id',
1629
- 'name',
1630
- 'contextPath',
1631
- 'label',
1632
- 'key'
1633
- ]);
1634
- this.deployedWithSuccess = true;
1635
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DEPLOY_APPLICATION, {
1636
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DEPLOY_APPLICATION,
1637
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION,
1638
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.DEPLOYED,
1639
- url: this.CURRENT_LOCATION,
1640
- ...applicationCustomEventInfo,
1641
- package: this.deployedApp?.manifest?.package ?? null
1553
+ await this.pluginsService.updateRemotesInAppConfig(this.app, newRemotes);
1554
+ this.alert.success(gettext(`Switched the version of plugin.`));
1555
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
1556
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.UPDATE_PLUGIN_OF_APP,
1557
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.CHANGE_PLUGIN_VERSION,
1558
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_VERSION_CHANGED,
1559
+ url: this.CURRENT_LOCATION
1642
1560
  });
1643
1561
  }
1644
- catch (error) {
1645
- this.ecosystemService.alertError(error);
1646
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DEPLOY_APPLICATION, {
1647
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DEPLOY_APPLICATION,
1648
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION,
1562
+ catch (e) {
1563
+ this.alert.addServerFailure(e);
1564
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
1565
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.UPDATE_PLUGIN_OF_APP,
1566
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.CHANGE_PLUGIN_VERSION,
1649
1567
  result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
1650
- url: this.CURRENT_LOCATION,
1651
- error
1568
+ url: this.CURRENT_LOCATION
1652
1569
  });
1653
1570
  }
1654
- finally {
1655
- this.markAsDeployed();
1656
- }
1571
+ this.bsModalRef.hide();
1572
+ this._install();
1657
1573
  }
1658
1574
  cancel() {
1659
- this.wizardComponent.close();
1660
- }
1661
- onAppVersionSelect(appVersion) {
1662
- Object.assign(this.model, {
1663
- selected: appVersion
1664
- });
1665
- this.canDeploy = true;
1666
- }
1667
- open() {
1668
- this.router.navigateByUrl(ViewContext.Application.replace(':id', `${this.deployedApp.id}`));
1669
- this.cancel();
1670
- }
1671
- markAsDeployed() {
1672
- this.isDeployed = true;
1673
- this.inProgress = false;
1674
- }
1675
- getHeaderText() {
1676
- return this.translate.instant(this.descriptionTemplate, {
1677
- packageName: this.package.name
1678
- });
1575
+ this.bsModalRef.hide();
1576
+ this._cancel();
1679
1577
  }
1680
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DeployApplicationComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardComponent }, { token: i4$1.TranslateService }, { token: i2.PluginsService }, { token: i2.GainsightService }, { token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
1681
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DeployApplicationComponent, selector: "c8y-deploy-application", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"output\"></i>\n <h4 id=\"modal-title\">{{ 'Deploy application' | translate }}</h4>\n </div>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n <ng-container *ngIf=\"!isDeployed\">\n <div class=\"fadeIn animated d-flex a-i-center j-c-center d-col\" style=\"min-height: 309px\">\n <p\n class=\"bg-level-0 fit-w p-16 text-center text-medium sticky-top bg-level-0 separator-bottom\"\n *ngIf=\"!inProgress\"\n >\n {{ headerText | translate }}\n </p>\n <c8y-application-properties-form\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n class=\"d-block fit-w bg-level-1\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div [ngStyle]=\"{ padding: '0 16px' }\" class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [ngModel]=\"model.selected\"\n (ngModelChange)=\"onAppVersionSelect($event)\"\n [packageId]=\"package?.id\"\n [label]=\"'Use extension package version' | translate\"\n ></c8y-package-version-select>\n </div>\n </ng-container>\n\n <c8y-loading\n *ngIf=\"inProgress\"\n [message]=\"'Deploying\u2026' | translate\"\n class=\"text-center\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n class=\"modal-body fadeIn animated\"\n style=\"min-height: 309px\"\n >\n <div class=\"d-flex a-i-center j-c-center d-col\">\n <c8y-operation-result\n type=\"success\"\n [size]=\"84\"\n [vertical]=\"true\"\n [text]=\"successMessageTemplate | translate: { packageName: package.name }\"\n class=\"lead d-block m-b-16\"\n ></c8y-operation-result>\n </div>\n </div>\n <ng-template #failedDeploy>\n <div class=\"modal-body fadeIn animated text-center\" style=\"min-height: 257px\">\n <c8y-operation-result\n type=\"error\"\n [size]=\"84\"\n [vertical]=\"true\"\n text=\"{{ 'Application creation failed' | translate }}\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n data-cy=\"c8y-deploy-application--cancel-blueprint-button\"\n title=\"{{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\"\n >\n {{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\n </button>\n\n <button\n (click)=\"deployApp()\"\n *ngIf=\"!isDeployed\"\n [disabled]=\"inProgress || !canDeploy\"\n [ngClass]=\"{ 'btn-pending': inProgress }\"\n class=\"btn btn-primary\"\n type=\"button\"\n data-cy=\"c8y-deploy-application--deploy-blueprint-button\"\n title=\"{{ 'Deploy' | translate }}\"\n >\n {{ 'Deploy' | translate }}\n </button>\n\n <button\n (click)=\"open()\"\n type=\"button\"\n class=\"btn btn-primary\"\n *ngIf=\"isDeployed && deployedWithSuccess\"\n title=\"{{ 'Open the application details' | translate }}\"\n translate\n >\n Open\n </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i2.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i2.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i2.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "component", type: i1.ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "component", type: i1.PackageVersionSelectComponent, selector: "c8y-package-version-select", inputs: ["label", "packageContextPath", "packageId"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1578
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: UpdatePluginOfAppComponent, deps: [{ token: i1$1.BsModalRef }, { token: i2.PluginsService }, { token: i2.AlertService }, { token: i1.EcosystemService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
1579
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: UpdatePluginOfAppComponent, selector: "c8y-update-plugin-of-app", ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-modules'\"></i>\n <h4 *ngIf=\"!downgrade\" id=\"modal-title\" translate>Update plugin</h4>\n <h4 *ngIf=\"downgrade\" id=\"modal-title\" translate>Downgrade plugin</h4>\n </div>\n <div class=\"inner-scroll\" id=\"modal-body\">\n <div class=\"p-16\">\n <div class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [packageContextPath]=\"plugin?.contextPath\"\n [(ngModel)]=\"applicationVersion\"\n ></c8y-package-version-select>\n <div\n *ngIf=\"plugin?.version && plugin.version === applicationVersion?.version\"\n class=\"alert alert-info\"\n role=\"alert\"\n >\n <span translate ngNonBindable [translateParams]=\"applicationVersion\">\n Select another version, as {{ version }} is currently used.\n </span>\n </div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"c8y-checkbox\">\n <input [(ngModel)]=\"updateAll\" type=\"checkbox\" />\n <span></span>\n <span translate ngNonBindable [translateParams]=\"plugin\">\n Set version for all plugins using the same context path \"{{ contextPath }}\".\n </span>\n </label>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Set version' | translate }}\"\n [disabled]=\"!applicationVersion || plugin?.version === applicationVersion?.version\"\n (click)=\"update()\"\n >\n {{ 'Set version' | translate }}\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1.PackageVersionSelectComponent, selector: "c8y-package-version-select", inputs: ["label", "packageContextPath", "packageId"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1682
1580
  }
1683
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DeployApplicationComponent, decorators: [{
1581
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: UpdatePluginOfAppComponent, decorators: [{
1684
1582
  type: Component,
1685
- args: [{ selector: 'c8y-deploy-application', template: "<c8y-wizard-header>\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"output\"></i>\n <h4 id=\"modal-title\">{{ 'Deploy application' | translate }}</h4>\n </div>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n <ng-container *ngIf=\"!isDeployed\">\n <div class=\"fadeIn animated d-flex a-i-center j-c-center d-col\" style=\"min-height: 309px\">\n <p\n class=\"bg-level-0 fit-w p-16 text-center text-medium sticky-top bg-level-0 separator-bottom\"\n *ngIf=\"!inProgress\"\n >\n {{ headerText | translate }}\n </p>\n <c8y-application-properties-form\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n class=\"d-block fit-w bg-level-1\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div [ngStyle]=\"{ padding: '0 16px' }\" class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [ngModel]=\"model.selected\"\n (ngModelChange)=\"onAppVersionSelect($event)\"\n [packageId]=\"package?.id\"\n [label]=\"'Use extension package version' | translate\"\n ></c8y-package-version-select>\n </div>\n </ng-container>\n\n <c8y-loading\n *ngIf=\"inProgress\"\n [message]=\"'Deploying\u2026' | translate\"\n class=\"text-center\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n class=\"modal-body fadeIn animated\"\n style=\"min-height: 309px\"\n >\n <div class=\"d-flex a-i-center j-c-center d-col\">\n <c8y-operation-result\n type=\"success\"\n [size]=\"84\"\n [vertical]=\"true\"\n [text]=\"successMessageTemplate | translate: { packageName: package.name }\"\n class=\"lead d-block m-b-16\"\n ></c8y-operation-result>\n </div>\n </div>\n <ng-template #failedDeploy>\n <div class=\"modal-body fadeIn animated text-center\" style=\"min-height: 257px\">\n <c8y-operation-result\n type=\"error\"\n [size]=\"84\"\n [vertical]=\"true\"\n text=\"{{ 'Application creation failed' | translate }}\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n data-cy=\"c8y-deploy-application--cancel-blueprint-button\"\n title=\"{{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\"\n >\n {{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\n </button>\n\n <button\n (click)=\"deployApp()\"\n *ngIf=\"!isDeployed\"\n [disabled]=\"inProgress || !canDeploy\"\n [ngClass]=\"{ 'btn-pending': inProgress }\"\n class=\"btn btn-primary\"\n type=\"button\"\n data-cy=\"c8y-deploy-application--deploy-blueprint-button\"\n title=\"{{ 'Deploy' | translate }}\"\n >\n {{ 'Deploy' | translate }}\n </button>\n\n <button\n (click)=\"open()\"\n type=\"button\"\n class=\"btn btn-primary\"\n *ngIf=\"isDeployed && deployedWithSuccess\"\n title=\"{{ 'Open the application details' | translate }}\"\n translate\n >\n Open\n </button>\n</c8y-wizard-footer>\n" }]
1686
- }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardComponent }, { type: i4$1.TranslateService }, { type: i2.PluginsService }, { type: i2.GainsightService }, { type: i1$2.Router }], propDecorators: { applicationPropertiesForm: [{
1687
- type: ViewChild,
1688
- args: [ApplicationPropertiesFormComponent]
1689
- }] } });
1583
+ args: [{ selector: 'c8y-update-plugin-of-app', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-modules'\"></i>\n <h4 *ngIf=\"!downgrade\" id=\"modal-title\" translate>Update plugin</h4>\n <h4 *ngIf=\"downgrade\" id=\"modal-title\" translate>Downgrade plugin</h4>\n </div>\n <div class=\"inner-scroll\" id=\"modal-body\">\n <div class=\"p-16\">\n <div class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [packageContextPath]=\"plugin?.contextPath\"\n [(ngModel)]=\"applicationVersion\"\n ></c8y-package-version-select>\n <div\n *ngIf=\"plugin?.version && plugin.version === applicationVersion?.version\"\n class=\"alert alert-info\"\n role=\"alert\"\n >\n <span translate ngNonBindable [translateParams]=\"applicationVersion\">\n Select another version, as {{ version }} is currently used.\n </span>\n </div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"c8y-checkbox\">\n <input [(ngModel)]=\"updateAll\" type=\"checkbox\" />\n <span></span>\n <span translate ngNonBindable [translateParams]=\"plugin\">\n Set version for all plugins using the same context path \"{{ contextPath }}\".\n </span>\n </label>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Set version' | translate }}\"\n [disabled]=\"!applicationVersion || plugin?.version === applicationVersion?.version\"\n (click)=\"update()\"\n >\n {{ 'Set version' | translate }}\n </button>\n </div>\n</div>\n" }]
1584
+ }], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: i2.PluginsService }, { type: i2.AlertService }, { type: i1.EcosystemService }, { type: i2.GainsightService }] });
1690
1585
 
1691
- class PackageDetailsComponent {
1692
- constructor(activatedRoute, client, wizardModalService, ecosystemService, contextRouteService, pluginsService, packageAvailabilityService, ui, pluginService) {
1586
+ class ApplicationPluginsComponent {
1587
+ constructor(activatedRoute, ecosystemService, bsModalService, pluginsService, alertService, gainsightService) {
1693
1588
  this.activatedRoute = activatedRoute;
1694
- this.client = client;
1695
- this.wizardModalService = wizardModalService;
1696
1589
  this.ecosystemService = ecosystemService;
1697
- this.contextRouteService = contextRouteService;
1590
+ this.bsModalService = bsModalService;
1698
1591
  this.pluginsService = pluginsService;
1699
- this.packageAvailabilityService = packageAvailabilityService;
1700
- this.ui = ui;
1701
- this.pluginService = pluginService;
1702
- this.package = {};
1703
- this.exportedPlugins$ = new BehaviorSubject([]);
1704
- this.isChangingAvailability = false;
1705
- this.isOwnedByCurrentTenant = false;
1706
- this.isAllowedToCreateSubtenants = false;
1707
- this.packageTypeLabels = PACKAGE_TYPE_LABELS;
1708
- this.PACKAGE_TYPE = PackageType;
1709
- this.packageProperties = packageProperties;
1710
- this.headers = { 'Content-Type': 'text/markdown', responseType: 'blob' };
1711
- this.NOT_FOUND_ERROR_CODE = 404;
1712
- }
1713
- async ngOnInit() {
1714
- this.isAllowedToCreateSubtenants = !!this.ui.currentTenant.value?.allowCreateTenants;
1715
- await this.loadData();
1716
- }
1717
- deploy() {
1718
- const initialState = {
1719
- wizardConfig: {},
1720
- id: EcosystemWizards.BLUEPRINT_DEPLOYMENT,
1721
- package: this.package
1722
- };
1723
- const modalOptions = { initialState };
1724
- this.wizardModalService.show(modalOptions);
1725
- }
1726
- async togglePackageAvailability(pckg, newAvailability) {
1727
- this.isChangingAvailability = true;
1728
- pckg = await this.packageAvailabilityService.askIfAvailabilityShouldBeSetTo(pckg, newAvailability);
1729
- const availabilityHasChanged = pckg.availability === newAvailability;
1730
- if (availabilityHasChanged) {
1731
- await this.loadData(pckg);
1732
- this.contextRouteService.setContext(this.activatedRoute, pckg);
1733
- }
1734
- else {
1735
- this.packageAvailability = this.package.availability;
1736
- }
1737
- this.isChangingAvailability = false;
1738
- }
1739
- async loadData(pckg) {
1740
- this.package = pckg
1741
- ? pckg
1742
- : this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
1743
- this.packageAvailability = this.package.availability;
1744
- this.packageContentState = this.ecosystemService.getPackageContentState(this.package);
1745
- this.packageType = this.pluginService.getPackageType(this.package);
1746
- this.name = this.package?.name;
1747
- this.description = this.package?.manifest?.description;
1748
- this.markdown = await this.getReadmeFileContent();
1749
- this.baseUrl = this.getBaseUrl();
1750
- this.appState = this.ecosystemService.getAppState(this.package);
1751
- this.isPackageBlueprint = this.ecosystemService.isPackageBlueprint(this.package);
1752
- this.isOwnedByCurrentTenant =
1753
- this.package?.owner?.tenant?.id === this.ui.currentTenant.value?.name;
1754
- this.extractPackageMFExports();
1755
- }
1756
- extractPackageMFExports() {
1757
- const exports = this.pluginsService.getMFExports(this.package);
1758
- this.exportedPlugins$.next(exports);
1759
- }
1760
- async getReadmeFileContent() {
1761
- const readmeFile = await this.getReadmeFile();
1762
- if (readmeFile.status === 200) {
1763
- return await readmeFile.text();
1764
- }
1765
- return '';
1766
- }
1767
- async getReadmeFile() {
1768
- const baseUrl = this.getBaseUrl();
1769
- let result;
1770
- const options = {
1771
- method: 'GET',
1772
- headers: this.headers
1592
+ this.alertService = alertService;
1593
+ this.gainsightService = gainsightService;
1594
+ this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_ECOSYSTEM;
1595
+ this.CURRENT_LOCATION = location.href;
1596
+ this.remotePlugins$ = new BehaviorSubject({});
1597
+ this.allAvailablePlugins$ = new BehaviorSubject([]);
1598
+ this.selfPlugins$ = new BehaviorSubject([]);
1599
+ this.installedPlugins$ = combineLatest([
1600
+ this.remotePlugins$.pipe(map(remotes => PluginsService.convertInstalledRemotesToIds(remotes))),
1601
+ this.allAvailablePlugins$
1602
+ ]).pipe(map(([remotePlugins, allPlugins]) => this.getInstalledPlugins(allPlugins, remotePlugins)), shareReplay(1));
1603
+ this.orphanedPlugins$ = this.installedPlugins$.pipe(map(plugins => plugins.filter(p => p.status === ApplicationPluginStatus.ORPHANED)));
1604
+ this.isStandard$ = combineLatest([this.installedPlugins$, this.selfPlugins$]).pipe(map(([installedPlugins, selfPlugins]) => {
1605
+ const manifestRemotes = this.app?.manifest?.remotes || {};
1606
+ // ensure that every installed plugin is a self plugin or a plugin from the manifest
1607
+ const allInstalledPluginsAreSelf = installedPlugins.every(p => selfPlugins.some(selfPlugin => selfPlugin.id === p.id) ||
1608
+ (Array.isArray(manifestRemotes[p.contextPath]) &&
1609
+ manifestRemotes[p.contextPath].includes(p.module)));
1610
+ // ensure that every self plugin is installed
1611
+ const allSelfPluginsAreInstalled = selfPlugins.every(selfPlugin => installedPlugins.some(p => p.id === selfPlugin.id));
1612
+ const configRemotes = this.app?.config?.remotes || {};
1613
+ // ensure that every remote from the manifest is in the config
1614
+ // if no config exists we are also all good
1615
+ const everyRemoteFromManifestIsInConfig = !this.app?.config?.remotes ||
1616
+ Object.keys(manifestRemotes).every(contextPath => Array.isArray(configRemotes[contextPath]) &&
1617
+ Array.isArray(manifestRemotes[contextPath]) &&
1618
+ manifestRemotes[contextPath].every(module => configRemotes[contextPath].includes(module)));
1619
+ return (allInstalledPluginsAreSelf &&
1620
+ allSelfPluginsAreInstalled &&
1621
+ everyRemoteFromManifestIsInConfig);
1622
+ }));
1623
+ this.title = gettext('Installed plugins');
1624
+ this.loadMoreItemsLabel = gettext('Load more packages');
1625
+ this.loadingItemsLabel = gettext('Loading packages…');
1626
+ this.actionControls = this.getActionControls();
1627
+ this.bulkActionControls = this.getBulkActionControls();
1628
+ this.headerActionControls = [];
1629
+ this.noResultsMessage = gettext('No plugins to display.');
1630
+ this.noDataMessage = gettext('No plugins installed.');
1631
+ this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.');
1632
+ this.noDataSubtitle = gettext("This application doesn't have any plugin. Click below to install.");
1633
+ this.pagination = {
1634
+ pageSize: 10,
1635
+ currentPage: 1
1773
1636
  };
1774
- result = await this.client.fetch(`${baseUrl}README.md`, options);
1775
- if (result && result.status === this.NOT_FOUND_ERROR_CODE) {
1776
- result = await this.client.fetch(`${baseUrl}readme.md`, options);
1777
- }
1778
- return result;
1779
- }
1780
- getBaseUrl() {
1781
- return `/apps/${this.package.contextPath}/`;
1782
- }
1783
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageDetailsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i4.FetchClient }, { token: i2.WizardModalService }, { token: i1.EcosystemService }, { token: i2.ContextRouteService }, { token: i2.PluginsService }, { token: i1.PackageAvailabilityService }, { token: i2.AppStateService }, { token: i2.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
1784
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageDetailsComponent, selector: "c8y-package-details", ngImport: i0, template: "<c8y-title>{{ name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Extension package' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n placement=\"right\"\n itemClass=\"navbar-form\"\n *ngIf=\"isOwnedByCurrentTenant && isAllowedToCreateSubtenants\"\n>\n <div class=\"form-horizontal\">\n <div class=\"form-group\">\n <label\n for=\"availability\"\n translate\n >\n Availability`of package based on app state`\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"availability\"\n [(ngModel)]=\"packageAvailability\"\n [disabled]=\"isChangingAvailability\"\n (ngModelChange)=\"togglePackageAvailability(package, $event)\"\n >\n <option\n *ngFor=\"let availability of packageAvailabilityService.availabilities\"\n [ngValue]=\"availability.value\"\n >\n {{ availability.label | translate }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-grid grid__col--8-4--md grid__row--fit-auto\">\n <div class=\"bg-level-1 grid__col--fullspan separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <button\n class=\"card__ribbon btn-clean\"\n [attr.aria-label]=\"\n (package.label || package.manifest.label | translatePackageLabel) +\n ': ' +\n (packageTypeLabels[packageType].tooltip | translate)\n \"\n tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n placement=\"bottom\"\n type=\"button\"\n *ngIf=\"packageType !== PACKAGE_TYPE.CUSTOM\"\n [delay]=\"500\"\n >\n <span\n [ngClass]=\"{\n 'bg-info': packageType === PACKAGE_TYPE.COMMUNITY,\n 'bg-primary': packageType === PACKAGE_TYPE.OFFICIAL\n }\"\n >\n {{ package.label || package.manifest.label | translatePackageLabel }}\n </span>\n </button>\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n c8yIcon=\"big-parcel\"\n ></i>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (appState?.label | translate) + ': ' + (appState?.tooltip | translate)\n \"\n [tooltip]=\"appState?.tooltip | translate\"\n placement=\"top\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n </button>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (packageContentState?.label | translate) +\n ': ' +\n (packageContentState?.tooltip | translate)\n \"\n [tooltip]=\"packageContentState?.tooltip | translate\"\n placement=\"bottom\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"packageContentState?.class\"\n >\n {{ packageContentState?.label | translate }}\n </span>\n </button>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-5\">\n <div class=\"card-title text-bold m-b-8\">{{ name | humanizeAppName | async }}</div>\n <p *ngIf=\"description\">{{ description }}</p>\n <p\n class=\"text-muted\"\n *ngIf=\"!description\"\n >\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n </div>\n <div\n class=\"col-3 text-right-md p-r-md-40\"\n *ngIf=\"isPackageBlueprint\"\n >\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"deploy()\"\n data-cy=\"c8y-package-details--deploy-application-button\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"output\"\n ></i>\n {{ 'Deploy application' | translate }}\n </button>\n </div>\n <div class=\"flex-grow\">\n <c8y-properties-list\n [data]=\"package.manifest\"\n [properties]=\"packageProperties\"\n ></c8y-properties-list>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Extension package overview' | translate }}</div>\n </div>\n <div class=\"card-block p-l-16 p-r-16\">\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found' | translate\"\n [subtitle]=\"\n 'To view the contents of &quot;README&quot;, add the file &quot;README.md&quot; to the package.'\n | translate\n \"\n *ngIf=\"!markdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <div\n class=\"markdown-content\"\n [innerHTML]=\"markdown | markdownToHtml: { baseUrl } | async\"\n ></div>\n </div>\n <div class=\"separator-bottom visible-sm visible-xs\"></div>\n </div>\n\n <div class=\"inner-scroll d-flex d-col\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Package plugins' | translate }}</div>\n </div>\n <div class=\"border-left flex-grow\">\n <!-- empty state -->\n <div\n class=\"p-16\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n >\n <c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [installable]=\"true\"\n [package]=\"package\"\n ></c8y-plugin-list>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i3$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "directive", type: i9.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: i2.MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: i1.TranslatePackageLabelPipe, name: "translatePackageLabel" }] }); }
1785
- }
1786
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageDetailsComponent, decorators: [{
1787
- type: Component,
1788
- args: [{ selector: 'c8y-package-details', template: "<c8y-title>{{ name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Extension package' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n placement=\"right\"\n itemClass=\"navbar-form\"\n *ngIf=\"isOwnedByCurrentTenant && isAllowedToCreateSubtenants\"\n>\n <div class=\"form-horizontal\">\n <div class=\"form-group\">\n <label\n for=\"availability\"\n translate\n >\n Availability`of package based on app state`\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"availability\"\n [(ngModel)]=\"packageAvailability\"\n [disabled]=\"isChangingAvailability\"\n (ngModelChange)=\"togglePackageAvailability(package, $event)\"\n >\n <option\n *ngFor=\"let availability of packageAvailabilityService.availabilities\"\n [ngValue]=\"availability.value\"\n >\n {{ availability.label | translate }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-grid grid__col--8-4--md grid__row--fit-auto\">\n <div class=\"bg-level-1 grid__col--fullspan separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <button\n class=\"card__ribbon btn-clean\"\n [attr.aria-label]=\"\n (package.label || package.manifest.label | translatePackageLabel) +\n ': ' +\n (packageTypeLabels[packageType].tooltip | translate)\n \"\n tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n placement=\"bottom\"\n type=\"button\"\n *ngIf=\"packageType !== PACKAGE_TYPE.CUSTOM\"\n [delay]=\"500\"\n >\n <span\n [ngClass]=\"{\n 'bg-info': packageType === PACKAGE_TYPE.COMMUNITY,\n 'bg-primary': packageType === PACKAGE_TYPE.OFFICIAL\n }\"\n >\n {{ package.label || package.manifest.label | translatePackageLabel }}\n </span>\n </button>\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n c8yIcon=\"big-parcel\"\n ></i>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (appState?.label | translate) + ': ' + (appState?.tooltip | translate)\n \"\n [tooltip]=\"appState?.tooltip | translate\"\n placement=\"top\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n </button>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (packageContentState?.label | translate) +\n ': ' +\n (packageContentState?.tooltip | translate)\n \"\n [tooltip]=\"packageContentState?.tooltip | translate\"\n placement=\"bottom\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"packageContentState?.class\"\n >\n {{ packageContentState?.label | translate }}\n </span>\n </button>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-5\">\n <div class=\"card-title text-bold m-b-8\">{{ name | humanizeAppName | async }}</div>\n <p *ngIf=\"description\">{{ description }}</p>\n <p\n class=\"text-muted\"\n *ngIf=\"!description\"\n >\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n </div>\n <div\n class=\"col-3 text-right-md p-r-md-40\"\n *ngIf=\"isPackageBlueprint\"\n >\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"deploy()\"\n data-cy=\"c8y-package-details--deploy-application-button\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"output\"\n ></i>\n {{ 'Deploy application' | translate }}\n </button>\n </div>\n <div class=\"flex-grow\">\n <c8y-properties-list\n [data]=\"package.manifest\"\n [properties]=\"packageProperties\"\n ></c8y-properties-list>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Extension package overview' | translate }}</div>\n </div>\n <div class=\"card-block p-l-16 p-r-16\">\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found' | translate\"\n [subtitle]=\"\n 'To view the contents of &quot;README&quot;, add the file &quot;README.md&quot; to the package.'\n | translate\n \"\n *ngIf=\"!markdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <div\n class=\"markdown-content\"\n [innerHTML]=\"markdown | markdownToHtml: { baseUrl } | async\"\n ></div>\n </div>\n <div class=\"separator-bottom visible-sm visible-xs\"></div>\n </div>\n\n <div class=\"inner-scroll d-flex d-col\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Package plugins' | translate }}</div>\n </div>\n <div class=\"border-left flex-grow\">\n <!-- empty state -->\n <div\n class=\"p-16\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n >\n <c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [installable]=\"true\"\n [package]=\"package\"\n ></c8y-plugin-list>\n </div>\n </div>\n</div>\n" }]
1789
- }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i4.FetchClient }, { type: i2.WizardModalService }, { type: i1.EcosystemService }, { type: i2.ContextRouteService }, { type: i2.PluginsService }, { type: i1.PackageAvailabilityService }, { type: i2.AppStateService }, { type: i2.PluginsService }] });
1790
-
1791
- class PackagesListComponent {
1792
- constructor(ecosystemService, wizardModalService, permissions) {
1793
- this.ecosystemService = ecosystemService;
1794
- this.wizardModalService = wizardModalService;
1795
- this.permissions = permissions;
1796
- this.reloading = false;
1797
- this.reload$ = new BehaviorSubject(null);
1798
- this.hasAdminPermissions = false;
1799
- this.emptyStateSubtitle = gettext('Add your first package by clicking below.');
1800
- this.packageTypes = defaultPackageTypes;
1801
- this.packageAvailabilities = [
1802
- APP_STATE.SUBSCRIBED.label,
1803
- APP_STATE.CUSTOM.label
1637
+ this.displayOptions = {
1638
+ bordered: false,
1639
+ striped: true,
1640
+ filter: true,
1641
+ gridHeader: true,
1642
+ hover: true
1643
+ };
1644
+ this.columns = [
1645
+ {
1646
+ name: 'name',
1647
+ header: gettext('Plugin name'),
1648
+ path: 'name',
1649
+ filterable: true
1650
+ },
1651
+ {
1652
+ name: 'Version',
1653
+ header: gettext('Version'),
1654
+ path: 'version',
1655
+ filterable: false
1656
+ },
1657
+ {
1658
+ name: 'Tag',
1659
+ header: gettext('Tag`noun`'),
1660
+ path: 'installedViaTag',
1661
+ filterable: false,
1662
+ cellRendererComponent: LabelCellRendererComponent
1663
+ },
1664
+ {
1665
+ name: 'description',
1666
+ header: gettext('Description'),
1667
+ path: 'description',
1668
+ filterable: false,
1669
+ cellCSSClassName: 'small'
1670
+ },
1671
+ {
1672
+ name: 'contextPath',
1673
+ header: gettext('Source'),
1674
+ path: 'contextPath',
1675
+ filterable: false,
1676
+ cellRendererComponent: LabelCellRendererComponent
1677
+ },
1678
+ {
1679
+ name: 'scope',
1680
+ header: gettext('Scope'),
1681
+ path: 'scope',
1682
+ filterable: false,
1683
+ visible: false,
1684
+ cellRendererComponent: LabelCellRendererComponent
1685
+ },
1686
+ {
1687
+ name: 'status',
1688
+ header: gettext('Status'),
1689
+ path: 'status',
1690
+ filterable: false,
1691
+ cellRendererComponent: OrphanedStatusCellRendererComponent
1692
+ }
1804
1693
  ];
1805
- this.packageContents = defaultPackageContents;
1806
1694
  this.destroy$ = new Subject();
1807
- this.packages$ = this.reload$.pipe(takeUntil(this.destroy$), tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getPackageApplications()), tap(packages => {
1808
- packages.forEach(pckg => {
1809
- pckg.filterProps = this.ecosystemService.getAppFilterProps(pckg);
1810
- });
1811
- }), tap(() => (this.reloading = false)), shareReplay(1));
1812
1695
  }
1813
1696
  ngOnInit() {
1814
- this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
1815
- this.loadPackages();
1816
- }
1817
- loadPackages() {
1818
- this.reload$.next();
1819
- }
1820
- addPackage() {
1821
- const initialState = {
1822
- id: EcosystemWizards.PACKAGE_UPLOAD
1823
- };
1824
- const modalOptions = { initialState };
1825
- const modalRef = this.wizardModalService.show(modalOptions);
1826
- modalRef.content.onClose.subscribe(() => {
1827
- this.loadPackages();
1828
- });
1829
- }
1830
- ngOnDestroy() {
1831
- this.destroy$.next(true);
1832
- this.destroy$.complete();
1833
- }
1834
- setFilterPipe(pipe) {
1835
- this.filteredPackages$ = this.packages$.pipe(src => pipe(src));
1697
+ this.addInstallButtonToHeaderActionControls();
1698
+ this.loadData();
1836
1699
  }
1837
- resetFilters() {
1838
- this.filtersComponent?.resetAllFilters();
1700
+ async loadData() {
1701
+ this.isLoading = true;
1702
+ await this.getApplicationMO();
1703
+ await this.getApplicationMFRemotes(this.app);
1704
+ await this.getAllApplicationsMFExports(this.app);
1705
+ await this.getAllSelfMFExports(this.app);
1706
+ this.isLoading = false;
1839
1707
  }
1840
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackagesListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }, { token: i2.Permissions }], target: i0.ɵɵFactoryTarget.Component }); }
1841
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackagesListComponent, selector: "c8y-packages-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Extensions' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [path]=\"'ecosystem/extension/extensions'\"\n [label]=\"'Extensions' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"hasAdminPermissions\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n data-cy=\"packages-list--add-extension-package\"\n (click)=\"addPackage()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add extension package' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadPackages()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"p-r-8 p-l-8\"\n>\n <c8y-list-filters\n *ngIf=\"packages$ | async\"\n [packageTypes]=\"packageTypes\"\n [packageAvailabilities]=\"packageAvailabilities\"\n [packageContents]=\"packageContents\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(packages$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#extensions\"></c8y-help>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex m-b-8\"\n *ngIf=\"(filteredPackages$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Package' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredPackages$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadPackages()\"\n (onAppCloned)=\"loadPackages()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extensions to display.' | translate\"\n [subtitle]=\"hasAdminPermissions ? (emptyStateSubtitle | translate) : ''\"\n *ngIf=\"(packages$ | async)?.length === 0\"\n>\n <div *ngIf=\"hasAdminPermissions\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n (click)=\"addPackage()\"\n >\n {{ 'Add extension package' | translate }}\n </button>\n </div>\n</c8y-ui-empty-state>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching extensions.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(packages$ | async)?.length > 0 && (filteredPackages$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i1.ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
1842
- }
1843
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackagesListComponent, decorators: [{
1844
- type: Component,
1845
- args: [{ selector: 'c8y-packages-list', template: "<c8y-title>{{ 'Extensions' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [path]=\"'ecosystem/extension/extensions'\"\n [label]=\"'Extensions' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"hasAdminPermissions\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n data-cy=\"packages-list--add-extension-package\"\n (click)=\"addPackage()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add extension package' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadPackages()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"p-r-8 p-l-8\"\n>\n <c8y-list-filters\n *ngIf=\"packages$ | async\"\n [packageTypes]=\"packageTypes\"\n [packageAvailabilities]=\"packageAvailabilities\"\n [packageContents]=\"packageContents\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(packages$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#extensions\"></c8y-help>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex m-b-8\"\n *ngIf=\"(filteredPackages$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Package' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredPackages$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadPackages()\"\n (onAppCloned)=\"loadPackages()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extensions to display.' | translate\"\n [subtitle]=\"hasAdminPermissions ? (emptyStateSubtitle | translate) : ''\"\n *ngIf=\"(packages$ | async)?.length === 0\"\n>\n <div *ngIf=\"hasAdminPermissions\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n (click)=\"addPackage()\"\n >\n {{ 'Add extension package' | translate }}\n </button>\n </div>\n</c8y-ui-empty-state>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching extensions.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(packages$ | async)?.length > 0 && (filteredPackages$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
1846
- }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }, { type: i2.Permissions }], propDecorators: { filtersComponent: [{
1847
- type: ViewChild,
1848
- args: [ListFiltersComponent]
1849
- }] } });
1850
-
1851
- class PackageVersionsPluginsComponent {
1852
- constructor() {
1853
- this.exportedPlugins$ = new BehaviorSubject([]);
1708
+ async resetToDefault() {
1709
+ this.isLoading = true;
1710
+ await this.pluginsService.resetRemotes(this.app);
1711
+ await this.loadData();
1712
+ this.alertService.success(gettext('The application was reset to its default plugins.'));
1854
1713
  }
1855
- async ngOnChanges() {
1856
- this.exportedPlugins$.next(this.getExportedPlugins());
1714
+ async installPlugins() {
1715
+ let currentPlugin = null;
1716
+ try {
1717
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
1718
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS,
1719
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.INSTALL_PLUGINS_INITIATED,
1720
+ url: this.CURRENT_LOCATION,
1721
+ targetApplicationName: this.app.name,
1722
+ targetApplicationContextPath: this.app.contextPath
1723
+ });
1724
+ const pluginsToAdd = await this.bsModalService.show(InstallPluginComponent, {
1725
+ class: 'modal-md',
1726
+ ariaDescribedby: 'modal-body',
1727
+ ariaLabelledBy: 'modal-title',
1728
+ initialState: this.getInstallModalInitState(),
1729
+ ignoreBackdropClick: true
1730
+ }).content.result;
1731
+ const isArchived = await this.ecosystemService.verifyArchived(pluginsToAdd);
1732
+ if (!isArchived) {
1733
+ return;
1734
+ }
1735
+ const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses(pluginsToAdd);
1736
+ if (!licensesVerifiedByUser) {
1737
+ return;
1738
+ }
1739
+ const verifyVersionCompatibility = await this.ecosystemService.verifyPluginVersionsCompatibility(pluginsToAdd, this.app);
1740
+ if (!verifyVersionCompatibility) {
1741
+ return;
1742
+ }
1743
+ this.isLoading = true;
1744
+ await this.handleRemotesInstallation(pluginsToAdd);
1745
+ this.alertService.success(gettext('Plugins installed.'));
1746
+ pluginsToAdd.forEach(plugin => {
1747
+ currentPlugin = plugin;
1748
+ this.triggerPluginEvent(plugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_INSTALLED);
1749
+ });
1750
+ }
1751
+ catch (ex) {
1752
+ if (ex) {
1753
+ this.alertService.addServerFailure(ex);
1754
+ this.triggerPluginEvent(currentPlugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE);
1755
+ }
1756
+ }
1757
+ finally {
1758
+ this.isLoading = false;
1759
+ }
1857
1760
  }
1858
- getExportedPlugins() {
1859
- return this.selectedVersionManifest?.exports || [];
1761
+ async removePlugins(plugins) {
1762
+ let currentPlugin = null;
1763
+ try {
1764
+ this.isLoading = true;
1765
+ const installedPlugins = await firstValueFrom(this.installedPlugins$);
1766
+ const pluginsToRemove = installedPlugins.filter(p => plugins.includes(p.id));
1767
+ const updatedRemotes = await this.pluginsService.removeRemotes(this.app, plugins.map(id => installedPlugins.find(p => p.id === id)));
1768
+ this.emitRemotes(updatedRemotes);
1769
+ this.isLoading = false;
1770
+ this.dataGrid.cancel();
1771
+ this.alertService.success(gettext('Plugins removed.'));
1772
+ pluginsToRemove.forEach(plugin => {
1773
+ currentPlugin = plugin;
1774
+ this.triggerPluginEvent(plugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_REMOVED);
1775
+ });
1776
+ }
1777
+ catch (ex) {
1778
+ if (ex) {
1779
+ this.alertService.addServerFailure(ex);
1780
+ this.triggerPluginEvent(currentPlugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE);
1781
+ }
1782
+ }
1783
+ finally {
1784
+ this.isLoading = false;
1785
+ }
1860
1786
  }
1861
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsPluginsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1862
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsPluginsComponent, selector: "c8y-contents-plugins", inputs: { selectedVersionManifest: "selectedVersionManifest" }, usesOnChanges: true, ngImport: i0, template: "<p class=\"legend form-block\">\n {{ 'Plugins' | translate }}\n</p>\n<!-- empty state -->\n<c8y-ui-empty-state\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n [icon]=\"'plugin'\"\n [horizontal]=\"true\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n></c8y-ui-empty-state>\n\n<c8y-plugin-list [plugins$]=\"exportedPlugins$\" [selectable]=\"false\"></c8y-plugin-list>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
1863
- }
1864
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsPluginsComponent, decorators: [{
1865
- type: Component,
1866
- args: [{ selector: 'c8y-contents-plugins', template: "<p class=\"legend form-block\">\n {{ 'Plugins' | translate }}\n</p>\n<!-- empty state -->\n<c8y-ui-empty-state\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n [icon]=\"'plugin'\"\n [horizontal]=\"true\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n></c8y-ui-empty-state>\n\n<c8y-plugin-list [plugins$]=\"exportedPlugins$\" [selectable]=\"false\"></c8y-plugin-list>\n" }]
1867
- }], propDecorators: { selectedVersionManifest: [{
1868
- type: Input,
1869
- args: ['selectedVersionManifest']
1870
- }] } });
1871
-
1872
- class PackageVersionsAppsComponent {
1873
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsAppsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1874
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsAppsComponent, selector: "c8y-contents-apps", inputs: { selectedVersionManifest: "selectedVersionManifest" }, ngImport: i0, template: "<p class=\"legend form-block\">\n {{ 'Application' | translate }}\n</p>\n\n<div *ngIf=\"selectedVersionManifest?.name; else emptyApp\">\n <c8y-li>\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <h5 class=\"text-medium text-16 p-b-8\">\n {{ selectedVersionManifest?.name | humanizeAppName | async }}\n <small class=\"m-l-8\" *ngIf=\"selectedVersionManifest?.requiredPlatformVersion\">\n <em>{{ selectedVersionManifest?.requiredPlatformVersion }}</em>\n </small>\n </h5>\n <p *ngIf=\"selectedVersionManifest?.description; else notAvailable\">\n {{ selectedVersionManifest?.description }}\n </p>\n </c8y-li>\n</div>\n\n<ng-template #notAvailable>\n <p class=\"text-muted\">\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n</ng-template>\n\n<ng-template #emptyApp>\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No application.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain an application.' | translate\"\n ></c8y-ui-empty-state>\n</ng-template>", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
1875
- }
1876
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsAppsComponent, decorators: [{
1877
- type: Component,
1878
- args: [{ selector: 'c8y-contents-apps', template: "<p class=\"legend form-block\">\n {{ 'Application' | translate }}\n</p>\n\n<div *ngIf=\"selectedVersionManifest?.name; else emptyApp\">\n <c8y-li>\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <h5 class=\"text-medium text-16 p-b-8\">\n {{ selectedVersionManifest?.name | humanizeAppName | async }}\n <small class=\"m-l-8\" *ngIf=\"selectedVersionManifest?.requiredPlatformVersion\">\n <em>{{ selectedVersionManifest?.requiredPlatformVersion }}</em>\n </small>\n </h5>\n <p *ngIf=\"selectedVersionManifest?.description; else notAvailable\">\n {{ selectedVersionManifest?.description }}\n </p>\n </c8y-li>\n</div>\n\n<ng-template #notAvailable>\n <p class=\"text-muted\">\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n</ng-template>\n\n<ng-template #emptyApp>\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No application.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain an application.' | translate\"\n ></c8y-ui-empty-state>\n</ng-template>" }]
1879
- }], propDecorators: { selectedVersionManifest: [{
1880
- type: Input,
1881
- args: ['selectedVersionManifest']
1882
- }] } });
1883
-
1884
- class PackageContentsComponent {
1885
- constructor(activatedRoute, applicationService, alertService, contextRouteService) {
1886
- this.activatedRoute = activatedRoute;
1887
- this.applicationService = applicationService;
1888
- this.alertService = alertService;
1889
- this.contextRouteService = contextRouteService;
1890
- this.package = {};
1891
- this.isLoading = false;
1892
- this.packageVersionProperties = packageProperties;
1787
+ async cleanupOrphanedPlugins(plugins) {
1788
+ const pluginIds = plugins.map(p => p.id);
1789
+ await this.removePlugins(pluginIds);
1893
1790
  }
1894
- async ngOnChanges(changes) {
1895
- if (changes.selectedVersion.currentValue) {
1896
- this.loadManifest(this.selectedVersion);
1897
- }
1898
- this.selectedVersionManifest = undefined;
1791
+ getActionControls() {
1792
+ return [
1793
+ {
1794
+ type: 'customUpdate',
1795
+ text: gettext('Update'),
1796
+ icon: 'caret-square-o-up',
1797
+ showIf: plugin => {
1798
+ return (plugin.status === ApplicationPluginStatus.OUTDATED ||
1799
+ plugin.status === ApplicationPluginStatus.REVOKED);
1800
+ },
1801
+ callback: plugin => this.updatePlugin(this.app, plugin)
1802
+ },
1803
+ {
1804
+ type: 'customDowngrade',
1805
+ text: gettext('Downgrade'),
1806
+ icon: 'caret-square-o-down',
1807
+ showIf: (plugin) => {
1808
+ if (plugin.scope === PluginsExportScopes.SELF ||
1809
+ plugin.scope === PluginsExportScopes.SELF_OPTIONAL) {
1810
+ return false;
1811
+ }
1812
+ return plugin.status === ApplicationPluginStatus.LATEST;
1813
+ },
1814
+ callback: plugin => this.updatePlugin(this.app, plugin, true)
1815
+ }
1816
+ ];
1899
1817
  }
1900
- async loadManifest(version) {
1901
- this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
1902
- this.isLoading = true;
1903
- this.selectedVersionManifest = await this.getManifest(version);
1904
- this.isLoading = false;
1818
+ getBulkActionControls() {
1819
+ return [
1820
+ {
1821
+ type: 'customDelete',
1822
+ text: gettext('Remove'),
1823
+ icon: 'trash',
1824
+ callback: plugins => this.removePlugins(plugins)
1825
+ }
1826
+ ];
1905
1827
  }
1906
- async getManifest(version) {
1828
+ async updatePlugin(app, plugin, downgrade = false) {
1907
1829
  try {
1908
- return await this.applicationService.getAppManifest(this.package, version);
1830
+ await this.bsModalService.show(UpdatePluginOfAppComponent, {
1831
+ class: 'modal-sm',
1832
+ ariaDescribedby: 'modal-body',
1833
+ ariaLabelledBy: 'modal-title',
1834
+ initialState: {
1835
+ app,
1836
+ plugin,
1837
+ downgrade
1838
+ },
1839
+ ignoreBackdropClick: true
1840
+ }).content.result;
1841
+ this.refresh();
1909
1842
  }
1910
- catch (error) {
1911
- this.alertService.addServerFailure(error);
1843
+ catch (er) {
1844
+ return;
1912
1845
  }
1913
- return undefined;
1914
- }
1915
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageContentsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
1916
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageContentsComponent, selector: "c8y-package-contents", inputs: { selectedVersion: "selectedVersion" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"inner-scroll\">\n <ng-container *ngIf=\"!selectedVersionManifest && !isLoading\">\n <div class=\"p-16\">\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No package selected' | translate\"\n [subtitle]=\"'Select a package from the list to display the package contents.' | translate\"\n ></c8y-ui-empty-state>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-container *ngIf=\"selectedVersionManifest && !isLoading\">\n <!-- DETAILS -->\n <div class=\"card-block p-t-0\">\n <c8y-properties-list\n [data]=\"selectedVersionManifest\"\n [emptyLabel]=\"'--'\"\n [properties]=\"packageVersionProperties\"\n >\n </c8y-properties-list>\n \n <!-- APPS -->\n <c8y-contents-apps\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-apps>\n\n <!-- PLUGINS -->\n <c8y-contents-plugins\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-plugins>\n </div>\n </ng-container>\n</div>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i2.PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "component", type: PackageVersionsPluginsComponent, selector: "c8y-contents-plugins", inputs: ["selectedVersionManifest"] }, { kind: "component", type: PackageVersionsAppsComponent, selector: "c8y-contents-apps", inputs: ["selectedVersionManifest"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
1917
- }
1918
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageContentsComponent, decorators: [{
1919
- type: Component,
1920
- args: [{ selector: 'c8y-package-contents', template: "<div class=\"inner-scroll\">\n <ng-container *ngIf=\"!selectedVersionManifest && !isLoading\">\n <div class=\"p-16\">\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No package selected' | translate\"\n [subtitle]=\"'Select a package from the list to display the package contents.' | translate\"\n ></c8y-ui-empty-state>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-container *ngIf=\"selectedVersionManifest && !isLoading\">\n <!-- DETAILS -->\n <div class=\"card-block p-t-0\">\n <c8y-properties-list\n [data]=\"selectedVersionManifest\"\n [emptyLabel]=\"'--'\"\n [properties]=\"packageVersionProperties\"\n >\n </c8y-properties-list>\n \n <!-- APPS -->\n <c8y-contents-apps\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-apps>\n\n <!-- PLUGINS -->\n <c8y-contents-plugins\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-plugins>\n </div>\n </ng-container>\n</div>\n" }]
1921
- }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i2.ContextRouteService }], propDecorators: { selectedVersion: [{
1922
- type: Input
1923
- }] } });
1924
-
1925
- const DEFAULT_VERSIONS_LIMIT = 20;
1926
- class PackageVersionsListComponent {
1927
- constructor(activatedRoute, pluginsService, ecosystemService, translateService, modal, alertService, optionsService, permissions, gainsightService) {
1928
- this.activatedRoute = activatedRoute;
1929
- this.pluginsService = pluginsService;
1930
- this.ecosystemService = ecosystemService;
1931
- this.translateService = translateService;
1932
- this.modal = modal;
1933
- this.alertService = alertService;
1934
- this.optionsService = optionsService;
1935
- this.permissions = permissions;
1936
- this.gainsightService = gainsightService;
1937
- this.CURRENT_LOCATION = location.href;
1938
- this.isLoading = false;
1939
- this.hasAdminPermissions = false;
1940
- this.isPackageOwnedByCurrentTenant = false;
1941
- this.onVersionSelect = new EventEmitter();
1942
1846
  }
1943
- async ngOnInit() {
1944
- this.isLoading = true;
1945
- this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
1946
- this.package = this.activatedRoute?.snapshot?.parent?.data?.contextData;
1947
- this.isPackageOwnedByCurrentTenant = this.ecosystemService.isOwner(this.package);
1948
- this.versionsLimit = (await this.optionsService.getSystemOption('application', 'versions.limit', DEFAULT_VERSIONS_LIMIT));
1949
- this.sortVersions();
1950
- this.isLoading = false;
1847
+ refresh() {
1848
+ this.loadData();
1951
1849
  }
1952
- async downloadArchive(appVersion) {
1953
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
1954
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
1955
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DOWNLOAD,
1956
- url: this.CURRENT_LOCATION
1957
- });
1958
- const archiveMO = await this.ecosystemService.getArchiveManagedObject(appVersion.binaryId);
1959
- await this.ecosystemService.downloadArchive(this.package, {
1960
- id: appVersion.binaryId,
1961
- name: archiveMO.name
1962
- });
1850
+ ngOnDestroy() {
1851
+ this.destroy$.next();
1852
+ this.destroy$.complete();
1963
1853
  }
1964
- packageVersionUploaded() {
1965
- this.activatedRoute.snapshot.parent.data.contextData = this.package;
1966
- this.sortVersions();
1967
- this.setUploadedVersionAsLatest();
1854
+ addInstallButtonToHeaderActionControls() {
1855
+ if (this.appId) {
1856
+ this.headerActionControls = [
1857
+ {
1858
+ text: gettext('Install plugins'),
1859
+ callback: () => {
1860
+ this.installPlugins();
1861
+ },
1862
+ icon: 'plus-circle',
1863
+ type: 'custom'
1864
+ }
1865
+ ];
1866
+ }
1968
1867
  }
1969
- selectVersion(version) {
1970
- this.selectedVersion = version;
1971
- this.onVersionSelect.emit(version);
1868
+ async handleRemotesInstallation(plugins) {
1869
+ const updatedRemotes = await this.pluginsService.addRemotes(this.app, plugins);
1870
+ return this.emitRemotes(updatedRemotes);
1972
1871
  }
1973
- async removeVersionPackage(version) {
1974
- try {
1975
- await this.ecosystemService.deletePackageVersion(this.package, { version });
1976
- this.alertService.success(this.translateService.instant(gettext('Package version {{version}} has been removed'), {
1977
- version
1978
- }));
1979
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
1980
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
1981
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
1982
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
1983
- url: this.CURRENT_LOCATION
1984
- });
1985
- }
1986
- catch (e) {
1987
- this.alertService.addServerFailure(e);
1988
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
1989
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
1990
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
1991
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
1992
- url: this.CURRENT_LOCATION
1993
- });
1994
- }
1995
- if (version === this.selectedVersion) {
1996
- this.selectVersion(null);
1872
+ emitRemotes(pluginsConfig) {
1873
+ const { remotes, excludedRemotes } = pluginsConfig;
1874
+ // needed for first time adding/removing a plugin
1875
+ if (!this.app.config) {
1876
+ this.app.config = {};
1997
1877
  }
1998
- await this.refreshPackage();
1878
+ this.app.config.remotes = remotes;
1879
+ this.app.config.excludedRemotes = excludedRemotes;
1880
+ const actualRemotes = this.pluginsService.getMFRemotes(this.app);
1881
+ this.remotePlugins$.next(actualRemotes);
1882
+ return { ...this.remotePlugins$.value };
1999
1883
  }
2000
- async setVersionAsLatest(appVersion) {
1884
+ async getApplicationMO() {
1885
+ let id = this.appId;
1886
+ if (!id) {
1887
+ const { id: routeId } = this.activatedRoute.snapshot.parent.data.contextData;
1888
+ id = routeId;
1889
+ }
2001
1890
  try {
2002
- await this.ecosystemService.setPackageVersionTag(this.package, appVersion.version, [
2003
- ...appVersion.tags,
2004
- 'latest'
2005
- ]);
2006
- // TODO added it due to: https://cumulocity.atlassian.net/browse/MTM-48553
2007
- // Remove it when BE fixes issues with activeVersion.
2008
- await this.ecosystemService.setAppActiveVersion(this.package, appVersion.binaryId);
2009
- this.alertService.success(gettext('Tag has been set.'));
2010
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2011
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2012
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_AS_LATEST,
2013
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
2014
- url: this.CURRENT_LOCATION
2015
- });
1891
+ this.app = await this.ecosystemService.getApplication(id);
2016
1892
  }
2017
- catch (e) {
2018
- this.alertService.addServerFailure(e);
2019
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2020
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2021
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_AS_LATEST,
2022
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2023
- url: this.CURRENT_LOCATION
2024
- });
2025
- return;
1893
+ catch (er) {
1894
+ if (er) {
1895
+ this.alertService.addServerFailure(er);
1896
+ }
2026
1897
  }
2027
- await this.refreshPackage();
1898
+ return this.app;
2028
1899
  }
2029
- async acknowledgeLimitReached() {
2030
- await this.modal.acknowledge(gettext('Package limit exceeded'), this.translateService.instant(gettext('You have reached the maximum number of {{ versionsLimit }} package versions. To add another version, first delete one from the list.'), { versionsLimit: this.versionsLimit }), Status.INFO, gettext('Close'));
2031
- throw undefined;
1900
+ async getApplicationMFExports(app) {
1901
+ const exports = this.pluginsService.getMFExports(app, [], true);
1902
+ return exports;
2032
1903
  }
2033
- async refreshPackage() {
2034
- this.isLoading = true;
2035
- this.package = await this.ecosystemService.getApplication(this.package.id);
2036
- this.activatedRoute.snapshot.parent.data.contextData = this.package;
2037
- this.sortVersions();
2038
- this.isLoading = false;
1904
+ async getApplicationMFRemotes(app) {
1905
+ const appConfigRemotes = this.pluginsService.getMFRemotes(app);
1906
+ this.remotePlugins$.next(appConfigRemotes || {});
2039
1907
  }
2040
- sortVersions() {
2041
- this.sortedVersions = this.pluginsService.sortVersions({
2042
- list: this.package.applicationVersions,
2043
- path: ['version']
2044
- }, 'desc');
2045
- this.toggleUploadPossibility();
1908
+ async getAllApplicationsMFExports(app) {
1909
+ const exportedByCurrentApp = await this.getApplicationMFExports(app);
1910
+ const allAppsMFExports = await this.pluginsService.getAllMFExports(true);
1911
+ this.allAvailablePlugins$.next([...allAppsMFExports, ...exportedByCurrentApp]);
2046
1912
  }
2047
- async setUploadedVersionAsLatest() {
2048
- const uploadedVersion = this.package.applicationVersions[this.package.applicationVersions.length - 1];
2049
- try {
2050
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2051
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2052
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.UPLOAD,
2053
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
2054
- url: this.CURRENT_LOCATION
2055
- });
2056
- await this.modal.confirm(gettext('Upload successful'), this.translateService.instant(gettext('Do you want to set version {{version}} as the latest? Deploying a new application will always use this version.'), { version: uploadedVersion.version }), Status.SUCCESS, {
2057
- ok: gettext('Set as latest`version`'),
2058
- cancel: gettext('Keep unchanged`version`')
2059
- });
2060
- }
2061
- catch (e) {
2062
- await this.refreshPackage();
2063
- return;
1913
+ async getAllSelfMFExports(app) {
1914
+ const exportedByCurrentApp = await this.getApplicationMFExports(app);
1915
+ this.selfPlugins$.next(exportedByCurrentApp.filter(({ scope }) => scope === 'self'));
1916
+ }
1917
+ getInstallModalInitState() {
1918
+ return {
1919
+ plugins$: combineLatest([this.allAvailablePlugins$, this.installedPlugins$]).pipe(map(([allPlugins, installedPlugins]) => {
1920
+ // to not mutate the original array and objects contained in it
1921
+ const allPluginsAsNewObjects = allPlugins.map(p => ({ ...p }));
1922
+ for (const plugin of installedPlugins) {
1923
+ let installedPlugin = allPluginsAsNewObjects.find(p => p.id === plugin.id);
1924
+ if (!installedPlugin && plugin.installedViaTag) {
1925
+ installedPlugin = allPluginsAsNewObjects.find(p => p.contextPath === plugin.contextPath &&
1926
+ p.module === plugin.module &&
1927
+ p.tags?.includes(plugin.installedViaTag));
1928
+ }
1929
+ if (installedPlugin) {
1930
+ installedPlugin.installed = true;
1931
+ continue;
1932
+ }
1933
+ }
1934
+ return allPluginsAsNewObjects.map(p => ({ ...p, installed: !!p.installed }));
1935
+ }), shareReplay(1))
1936
+ };
1937
+ }
1938
+ getOrphanedPlugins(orphanedPluginIds, allPlugins) {
1939
+ const orphanedPlugins = orphanedPluginIds.map(p => this.extractDetails(p));
1940
+ const orphanedPluginsUpdated = orphanedPlugins.map(p => {
1941
+ const pluginWithMatchingTag = allPlugins.find(tmp => tmp.contextPath === p.contextPath &&
1942
+ tmp.module === p.module &&
1943
+ tmp.tags?.includes(p.version || 'latest'));
1944
+ if (pluginWithMatchingTag) {
1945
+ return {
1946
+ ...pluginWithMatchingTag,
1947
+ id: p.id,
1948
+ status: ApplicationPluginStatus.AUTO,
1949
+ installedViaTag: p.version || 'latest'
1950
+ };
1951
+ }
1952
+ const pluginInDifferentVersion = allPlugins.find(tmp => tmp.contextPath === p.contextPath && tmp.module === p.module);
1953
+ if (pluginInDifferentVersion) {
1954
+ return {
1955
+ ...pluginInDifferentVersion,
1956
+ version: p.version,
1957
+ id: p.id,
1958
+ status: ApplicationPluginStatus.OUTDATED
1959
+ };
1960
+ }
1961
+ return p;
1962
+ });
1963
+ return orphanedPluginsUpdated;
1964
+ }
1965
+ splitOrphanedPluginsIntoOrphanedAndRevokedPlugins(allPlugins, orphanedPlugins) {
1966
+ const revokedPlugins = new Array();
1967
+ const actuallyOrphanedPlugins = new Array();
1968
+ for (const plugin of orphanedPlugins) {
1969
+ const foundFamiliarPlugin = allPlugins.find(plugin1 => plugin.contextPath === plugin1.contextPath && plugin.module === plugin1.module);
1970
+ if (foundFamiliarPlugin) {
1971
+ revokedPlugins.push(Object.assign({}, foundFamiliarPlugin, plugin, {
1972
+ status: ApplicationPluginStatus.REVOKED
1973
+ }));
1974
+ }
1975
+ else {
1976
+ actuallyOrphanedPlugins.push(plugin);
1977
+ }
2064
1978
  }
2065
- await this.setVersionAsLatest(uploadedVersion);
2066
- }
2067
- toggleUploadPossibility() {
2068
- this.preUploadCallback =
2069
- this.sortedVersions.length < this.versionsLimit
2070
- ? null
2071
- : this.acknowledgeLimitReached.bind(this);
1979
+ return { revokedPlugins, actuallyOrphanedPlugins };
2072
1980
  }
2073
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsListComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.PluginsService }, { token: i1.EcosystemService }, { token: i4$1.TranslateService }, { token: i2.ModalService }, { token: i2.AlertService }, { token: i2.OptionsService }, { token: i2.Permissions }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
2074
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsListComponent, selector: "c8y-package-versions-list", outputs: { onVersionSelect: "onVersionSelect" }, ngImport: i0, template: "<div class=\"inner-scroll split-view__list\">\n <div class=\"card-header separator sticky-top bg-component\">\n <div class=\"card-title\" translate>Versions</div>\n </div>\n\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"p-16\" *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </div>\n <ul class=\"nav c8y-nav-stacked\" *ngIf=\"!isLoading\">\n <li\n class=\"c8y-stacked-item p-t-0 p-b-0 p-r-4\"\n [ngClass]=\"{ active: selectedVersion === applicationVersion.version }\"\n *ngFor=\"let applicationVersion of sortedVersions\"\n >\n <div\n class=\"flex-grow d-flex a-i-center gap-4 p-t-8 p-b-8\"\n (click)=\"selectVersion(applicationVersion.version)\"\n >\n <i c8yIcon=\"big-parcel\" class=\"icon-20\"></i>\n <span class=\"text-label-small\">\n {{ 'Version' | translate }}\n </span>\n <span class=\"text-medium\">{{ applicationVersion.version }}</span>\n <div class=\"text-truncate d-flex j-c-end flex-grow gap-4 flex-wrap m-l-auto\">\n <span *ngFor=\"let tag of applicationVersion.tags\" class=\"label label-info\">\n {{ tag }}\n </span>\n </div>\n </div>\n <div class=\"dropdown\" dropdown *ngIf=\"hasAdminPermissions && isPackageOwnedByCurrentTenant\">\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Settings' | translate }}\"\n dropdownToggle\n >\n <i c8yIcon=\"ellipsis-v\"></i>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu dropdown-menu-right\">\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Set as latest`version`' | translate }}\"\n (click)=\"setVersionAsLatest(applicationVersion)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"collect\" class=\"m-r-4\"></i>\n {{ 'Set as latest`version`' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Download' | translate }}\"\n (click)=\"downloadArchive(applicationVersion)\"\n >\n <i c8yIcon=\"download\" class=\"m-r-4\"></i>\n {{ 'Download' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"removeVersionPackage(applicationVersion.version)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"trash\" class=\"m-r-4\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </li>\n </ul>\n </div>\n\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"!isLoading && isPackageOwnedByCurrentTenant\"\n >\n <div class=\"form-group m-b-0\">\n <label translate>Upload a new version</label>\n <c8y-upload-archive\n [(application)]=\"package\"\n [uploadNewVersion]=\"true\"\n (refresh)=\"packageVersionUploaded()\"\n [preUploadCallback]=\"preUploadCallback\"\n ></c8y-upload-archive>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i6.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i6.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i6.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "component", type: i1.UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
2075
- }
2076
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsListComponent, decorators: [{
2077
- type: Component,
2078
- args: [{ selector: 'c8y-package-versions-list', template: "<div class=\"inner-scroll split-view__list\">\n <div class=\"card-header separator sticky-top bg-component\">\n <div class=\"card-title\" translate>Versions</div>\n </div>\n\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"p-16\" *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </div>\n <ul class=\"nav c8y-nav-stacked\" *ngIf=\"!isLoading\">\n <li\n class=\"c8y-stacked-item p-t-0 p-b-0 p-r-4\"\n [ngClass]=\"{ active: selectedVersion === applicationVersion.version }\"\n *ngFor=\"let applicationVersion of sortedVersions\"\n >\n <div\n class=\"flex-grow d-flex a-i-center gap-4 p-t-8 p-b-8\"\n (click)=\"selectVersion(applicationVersion.version)\"\n >\n <i c8yIcon=\"big-parcel\" class=\"icon-20\"></i>\n <span class=\"text-label-small\">\n {{ 'Version' | translate }}\n </span>\n <span class=\"text-medium\">{{ applicationVersion.version }}</span>\n <div class=\"text-truncate d-flex j-c-end flex-grow gap-4 flex-wrap m-l-auto\">\n <span *ngFor=\"let tag of applicationVersion.tags\" class=\"label label-info\">\n {{ tag }}\n </span>\n </div>\n </div>\n <div class=\"dropdown\" dropdown *ngIf=\"hasAdminPermissions && isPackageOwnedByCurrentTenant\">\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Settings' | translate }}\"\n dropdownToggle\n >\n <i c8yIcon=\"ellipsis-v\"></i>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu dropdown-menu-right\">\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Set as latest`version`' | translate }}\"\n (click)=\"setVersionAsLatest(applicationVersion)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"collect\" class=\"m-r-4\"></i>\n {{ 'Set as latest`version`' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Download' | translate }}\"\n (click)=\"downloadArchive(applicationVersion)\"\n >\n <i c8yIcon=\"download\" class=\"m-r-4\"></i>\n {{ 'Download' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"removeVersionPackage(applicationVersion.version)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"trash\" class=\"m-r-4\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </li>\n </ul>\n </div>\n\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"!isLoading && isPackageOwnedByCurrentTenant\"\n >\n <div class=\"form-group m-b-0\">\n <label translate>Upload a new version</label>\n <c8y-upload-archive\n [(application)]=\"package\"\n [uploadNewVersion]=\"true\"\n (refresh)=\"packageVersionUploaded()\"\n [preUploadCallback]=\"preUploadCallback\"\n ></c8y-upload-archive>\n </div>\n </div>\n</div>\n" }]
2079
- }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.PluginsService }, { type: i1.EcosystemService }, { type: i4$1.TranslateService }, { type: i2.ModalService }, { type: i2.AlertService }, { type: i2.OptionsService }, { type: i2.Permissions }, { type: i2.GainsightService }], propDecorators: { onVersionSelect: [{
2080
- type: Output
2081
- }] } });
2082
-
2083
- class PackageVersionsComponent {
2084
- constructor(activatedRoute, contextRouteService) {
2085
- this.activatedRoute = activatedRoute;
2086
- this.contextRouteService = contextRouteService;
2087
- this.package = {};
1981
+ getInstalledPlugins(allPlugins, remotePlugins) {
1982
+ const availablePlugins = allPlugins
1983
+ .filter(plugin => remotePlugins.includes(plugin.id))
1984
+ .map(plugin => Object.assign(plugin, {
1985
+ status: plugin.tags?.includes('latest')
1986
+ ? ApplicationPluginStatus.LATEST
1987
+ : ApplicationPluginStatus.OUTDATED
1988
+ }));
1989
+ const orphanedPluginIds = remotePlugins.filter(r => !availablePlugins.find(plugin => plugin.id === r));
1990
+ const orphanedPlugins = this.getOrphanedPlugins(orphanedPluginIds, allPlugins);
1991
+ const notActuallyOrphanedPlugins = orphanedPlugins.filter(p => p.status === ApplicationPluginStatus.AUTO);
1992
+ const orphanedOrRevokedPlugins = orphanedPlugins.filter(p => p.status !== ApplicationPluginStatus.AUTO);
1993
+ const { actuallyOrphanedPlugins, revokedPlugins } = this.splitOrphanedPluginsIntoOrphanedAndRevokedPlugins(allPlugins, orphanedOrRevokedPlugins);
1994
+ return [
1995
+ ...availablePlugins,
1996
+ ...notActuallyOrphanedPlugins,
1997
+ ...revokedPlugins,
1998
+ ...actuallyOrphanedPlugins
1999
+ ];
2088
2000
  }
2089
- async ngOnInit() {
2090
- this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
2001
+ extractDetails(pluginId) {
2002
+ const contextPath = this.getStringMatchingRegex(pluginId, /^[^@]*(@|\/)/);
2003
+ const version = this.getStringMatchingRegex(pluginId, /@.*\//);
2004
+ const module = this.getStringMatchingRegex(pluginId, /\/.*$/);
2005
+ const unavailable = gettext('unavailable`plugin`');
2006
+ return {
2007
+ id: pluginId,
2008
+ idLatest: `${contextPath}/${module}`,
2009
+ path: '',
2010
+ module,
2011
+ name: module,
2012
+ status: ApplicationPluginStatus.ORPHANED,
2013
+ contextPath: contextPath,
2014
+ description: unavailable,
2015
+ version: version
2016
+ };
2091
2017
  }
2092
- clearSelectedVersion() {
2093
- this.selectedVersion = null;
2018
+ getStringMatchingRegex(str, regex) {
2019
+ const matches = str.match(regex);
2020
+ const value = matches ? matches[0] : '';
2021
+ return value.replace(/(@|\/)/g, '');
2094
2022
  }
2095
- selectVersion(version) {
2096
- this.selectedVersion = version;
2023
+ triggerPluginEvent(plugin, result) {
2024
+ const pluginInfo = pick(plugin, [
2025
+ 'name',
2026
+ 'contextPath',
2027
+ 'module',
2028
+ 'version',
2029
+ 'type',
2030
+ 'id'
2031
+ ]);
2032
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2033
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS,
2034
+ result,
2035
+ url: this.CURRENT_LOCATION,
2036
+ ...pluginInfo,
2037
+ targetApplicationName: this.app.name,
2038
+ targetApplicationContextPath: this.app.contextPath
2039
+ });
2097
2040
  }
2098
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
2099
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsComponent, selector: "c8y-package-versions", ngImport: i0, template: "<c8y-title>{{ package?.name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Versions' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"card content-fullpage split-view--5-7 grid__row--1\">\n <c8y-package-versions-list\n class=\"d-contents\"\n (onVersionSelect)=\"selectVersion($event)\"\n ></c8y-package-versions-list>\n\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedVersion }\"\n >\n <div class=\"large-padding card-header separator visible-sm visible-xs fit-w sticky-top\">\n <div class=\"d-flex a-i-center\">\n <button\n title=\"{{ 'Back' | translate }}\"\n class=\"btn btn-clean text-primary m-r-8\"\n (click)=\"clearSelectedVersion()\"\n >\n <i c8yIcon=\"chevron-left\"></i>\n <span translate>Back</span>\n </button>\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n </div>\n <div class=\"card-header large-padding separator sticky-top visible-md visible-lg\">\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <c8y-package-contents [selectedVersion]=\"selectedVersion\"></c8y-package-contents>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: PackageContentsComponent, selector: "c8y-package-contents", inputs: ["selectedVersion"] }, { kind: "component", type: PackageVersionsListComponent, selector: "c8y-package-versions-list", outputs: ["onVersionSelect"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
2041
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1.EcosystemService }, { token: i1$1.BsModalService }, { token: i2.PluginsService }, { token: i2.AlertService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
2042
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: ApplicationPluginsComponent, selector: "c8y-app-plugins", inputs: { appId: "appId" }, viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ app | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"app | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Plugins' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"!(isStandard$ | async)\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reset to default plugins' | translate }}\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n (click)=\"resetToDefault()\"\n >\n <i c8yIcon=\"undo\"></i>\n {{ 'Reset to default' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install plugins' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<ng-container *ngIf=\"orphanedPlugins$ | async as orphanedPlugins\">\n <c8y-action-bar-item\n *ngIf=\"orphanedPlugins?.length\"\n [placement]=\"'right'\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Clean up orphaned plugins' | translate }}\"\n (click)=\"cleanupOrphanedPlugins(orphanedPlugins)\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"erase\"></i>\n {{ 'Clean up orphaned plugins' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<div class=\"content-fullpage d-flex d-col border-top\">\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [rows]=\"installedPlugins$ | async\"\n [pagination]=\"pagination\"\n [selectable]=\"true\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n [headerActionControls]=\"headerActionControls\"\n (onReload)=\"refresh()\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'plugin'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n translate\n >\n Install plugins\n </button>\n </p>\n </c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
2100
2043
  }
2101
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsComponent, decorators: [{
2044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsComponent, decorators: [{
2102
2045
  type: Component,
2103
- args: [{ selector: 'c8y-package-versions', template: "<c8y-title>{{ package?.name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Versions' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"card content-fullpage split-view--5-7 grid__row--1\">\n <c8y-package-versions-list\n class=\"d-contents\"\n (onVersionSelect)=\"selectVersion($event)\"\n ></c8y-package-versions-list>\n\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedVersion }\"\n >\n <div class=\"large-padding card-header separator visible-sm visible-xs fit-w sticky-top\">\n <div class=\"d-flex a-i-center\">\n <button\n title=\"{{ 'Back' | translate }}\"\n class=\"btn btn-clean text-primary m-r-8\"\n (click)=\"clearSelectedVersion()\"\n >\n <i c8yIcon=\"chevron-left\"></i>\n <span translate>Back</span>\n </button>\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n </div>\n <div class=\"card-header large-padding separator sticky-top visible-md visible-lg\">\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <c8y-package-contents [selectedVersion]=\"selectedVersion\"></c8y-package-contents>\n </div>\n </div>\n</div>\n" }]
2104
- }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.ContextRouteService }] });
2046
+ args: [{ selector: 'c8y-app-plugins', template: "<c8y-title>{{ app | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"app | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Plugins' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"!(isStandard$ | async)\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reset to default plugins' | translate }}\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n (click)=\"resetToDefault()\"\n >\n <i c8yIcon=\"undo\"></i>\n {{ 'Reset to default' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install plugins' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<ng-container *ngIf=\"orphanedPlugins$ | async as orphanedPlugins\">\n <c8y-action-bar-item\n *ngIf=\"orphanedPlugins?.length\"\n [placement]=\"'right'\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Clean up orphaned plugins' | translate }}\"\n (click)=\"cleanupOrphanedPlugins(orphanedPlugins)\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"erase\"></i>\n {{ 'Clean up orphaned plugins' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<div class=\"content-fullpage d-flex d-col border-top\">\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [rows]=\"installedPlugins$ | async\"\n [pagination]=\"pagination\"\n [selectable]=\"true\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n [headerActionControls]=\"headerActionControls\"\n (onReload)=\"refresh()\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'plugin'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n translate\n >\n Install plugins\n </button>\n </p>\n </c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n" }]
2047
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1.EcosystemService }, { type: i1$1.BsModalService }, { type: i2.PluginsService }, { type: i2.AlertService }, { type: i2.GainsightService }], propDecorators: { appId: [{
2048
+ type: Input
2049
+ }], dataGrid: [{
2050
+ type: ViewChild,
2051
+ args: [DataGridComponent, { static: false }]
2052
+ }] } });
2105
2053
 
2106
- class PackageGuard {
2054
+ class ApplicationPluginsGuard {
2107
2055
  constructor(ecosystemService) {
2108
2056
  this.ecosystemService = ecosystemService;
2109
2057
  }
@@ -2112,703 +2060,877 @@ class PackageGuard {
2112
2060
  if (!app) {
2113
2061
  return false;
2114
2062
  }
2115
- return this.ecosystemService.isPackage(app);
2063
+ const manifest = app.manifest;
2064
+ if (!manifest) {
2065
+ return false;
2066
+ }
2067
+ return (app.type === ApplicationType.HOSTED &&
2068
+ this.ecosystemService.isOwner(app) &&
2069
+ !this.ecosystemService.isPackage(app) &&
2070
+ // apps like e.g. the public-options should not have the plugins tab
2071
+ !manifest.noAppSwitcher);
2116
2072
  }
2117
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageGuard, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2118
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageGuard }); }
2073
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsGuard, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2074
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsGuard }); }
2119
2075
  }
2120
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageGuard, decorators: [{
2076
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsGuard, decorators: [{
2121
2077
  type: Injectable
2122
2078
  }], ctorParameters: () => [{ type: i1.EcosystemService }] });
2123
2079
 
2124
- class PackageVersionsGuard {
2125
- canActivate(route) {
2126
- const app = route.data.contextData || route.parent.data.contextData;
2127
- return !!app?.applicationVersions?.length;
2128
- }
2129
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2130
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsGuard }); }
2080
+ class ApplicationPluginsModule {
2081
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2082
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, declarations: [ApplicationPluginsComponent,
2083
+ PluginListItemComponent,
2084
+ InstallPluginComponent,
2085
+ PluginListComponent,
2086
+ AppsToUpdateRemotesSelectComponent,
2087
+ AppStatePipe,
2088
+ LabelCellRendererComponent,
2089
+ OrphanedStatusCellRendererComponent,
2090
+ UpdatePluginOfAppComponent,
2091
+ OnlyLatestFilterComponent], imports: [CoreModule, SharedEcosystemModule], exports: [ApplicationPluginsComponent,
2092
+ PluginListItemComponent,
2093
+ InstallPluginComponent,
2094
+ PluginListComponent,
2095
+ AppsToUpdateRemotesSelectComponent,
2096
+ AppStatePipe,
2097
+ LabelCellRendererComponent,
2098
+ OrphanedStatusCellRendererComponent,
2099
+ UpdatePluginOfAppComponent,
2100
+ OnlyLatestFilterComponent] }); }
2101
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, providers: [
2102
+ ApplicationPluginsGuard,
2103
+ hookRoute([
2104
+ {
2105
+ path: 'plugins',
2106
+ component: ApplicationPluginsComponent,
2107
+ icon: 'plugin',
2108
+ label: gettext('Plugins'),
2109
+ context: ViewContext.Application,
2110
+ priority: 3,
2111
+ canActivate: [ApplicationPluginsGuard]
2112
+ }
2113
+ ])
2114
+ ], imports: [CoreModule, SharedEcosystemModule] }); }
2131
2115
  }
2132
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsGuard, decorators: [{
2133
- type: Injectable
2116
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, decorators: [{
2117
+ type: NgModule,
2118
+ args: [{
2119
+ imports: [CoreModule, SharedEcosystemModule],
2120
+ declarations: [
2121
+ ApplicationPluginsComponent,
2122
+ PluginListItemComponent,
2123
+ InstallPluginComponent,
2124
+ PluginListComponent,
2125
+ AppsToUpdateRemotesSelectComponent,
2126
+ AppStatePipe,
2127
+ LabelCellRendererComponent,
2128
+ OrphanedStatusCellRendererComponent,
2129
+ UpdatePluginOfAppComponent,
2130
+ OnlyLatestFilterComponent
2131
+ ],
2132
+ exports: [
2133
+ ApplicationPluginsComponent,
2134
+ PluginListItemComponent,
2135
+ InstallPluginComponent,
2136
+ PluginListComponent,
2137
+ AppsToUpdateRemotesSelectComponent,
2138
+ AppStatePipe,
2139
+ LabelCellRendererComponent,
2140
+ OrphanedStatusCellRendererComponent,
2141
+ UpdatePluginOfAppComponent,
2142
+ OnlyLatestFilterComponent
2143
+ ],
2144
+ providers: [
2145
+ ApplicationPluginsGuard,
2146
+ hookRoute([
2147
+ {
2148
+ path: 'plugins',
2149
+ component: ApplicationPluginsComponent,
2150
+ icon: 'plugin',
2151
+ label: gettext('Plugins'),
2152
+ context: ViewContext.Application,
2153
+ priority: 3,
2154
+ canActivate: [ApplicationPluginsGuard]
2155
+ }
2156
+ ])
2157
+ ]
2158
+ }]
2134
2159
  }] });
2135
2160
 
2136
- class OnlyLatestPluginVersionPipe {
2137
- transform(value, disabled) {
2138
- if (disabled) {
2139
- return value;
2161
+ class FeatureListComponent {
2162
+ constructor(ecosystemService) {
2163
+ this.ecosystemService = ecosystemService;
2164
+ this.reloading = false;
2165
+ this.reload$ = new BehaviorSubject(null);
2166
+ this.features$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getFeatureApplications()), tap(() => (this.reloading = false)), shareReplay());
2167
+ }
2168
+ ngOnInit() {
2169
+ this.loadFeatures();
2170
+ }
2171
+ loadFeatures() {
2172
+ this.reload$.next();
2173
+ }
2174
+ setFilterPipe(pipe) {
2175
+ this.filteredFeatures$ = this.features$.pipe(src => pipe(src));
2176
+ }
2177
+ resetFilters() {
2178
+ this.filtersComponent?.resetAllFilters();
2179
+ }
2180
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: FeatureListComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
2181
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: FeatureListComponent, selector: "c8y-feature-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Features' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'tab'\" [label]=\"'Features' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button (click)=\"reload$.next()\" class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\">\n <i [ngClass]=\"{ 'icon-spin': reloading }\" c8yIcon=\"refresh\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"features$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\" itemClass=\"navbar-form hidden-xs\">\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(features$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div *ngIf=\"(features$ | async)?.length === 0\" class=\"c8y-empty-state text-center\">\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No features to display.</h3>\n <p translate>No additional features are subscribed to the tenant.</p>\n</div>\n\n<div [ngClass]=\"listClass\" class=\"card-group\">\n <div class=\"page-sticky-header hidden-xs d-flex\" *ngIf=\"(features$ | async)?.length > 0\">\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Feature' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n </div>\n </div>\n <div *ngFor=\"let feature of filteredFeatures$ | async\" class=\"col-xs-12 col-sm-4 col-md-3\">\n <c8y-application-card\n [app]=\"feature\"\n [canEdit]=\"false\"\n class=\"d-contents\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n *ngIf=\"(features$ | async)?.length > 0 && (filteredFeatures$ | async)?.length === 0\"\n [icon]=\"'search'\"\n [title]=\"'No matching features.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n>\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Reset filters' | translate }}\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i1.ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
2182
+ }
2183
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: FeatureListComponent, decorators: [{
2184
+ type: Component,
2185
+ args: [{ selector: 'c8y-feature-list', template: "<c8y-title>{{ 'Features' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'tab'\" [label]=\"'Features' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button (click)=\"reload$.next()\" class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\">\n <i [ngClass]=\"{ 'icon-spin': reloading }\" c8yIcon=\"refresh\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"features$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\" itemClass=\"navbar-form hidden-xs\">\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(features$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div *ngIf=\"(features$ | async)?.length === 0\" class=\"c8y-empty-state text-center\">\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No features to display.</h3>\n <p translate>No additional features are subscribed to the tenant.</p>\n</div>\n\n<div [ngClass]=\"listClass\" class=\"card-group\">\n <div class=\"page-sticky-header hidden-xs d-flex\" *ngIf=\"(features$ | async)?.length > 0\">\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Feature' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n </div>\n </div>\n <div *ngFor=\"let feature of filteredFeatures$ | async\" class=\"col-xs-12 col-sm-4 col-md-3\">\n <c8y-application-card\n [app]=\"feature\"\n [canEdit]=\"false\"\n class=\"d-contents\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n *ngIf=\"(features$ | async)?.length > 0 && (filteredFeatures$ | async)?.length === 0\"\n [icon]=\"'search'\"\n [title]=\"'No matching features.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n>\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Reset filters' | translate }}\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
2186
+ }], ctorParameters: () => [{ type: i1.EcosystemService }], propDecorators: { filtersComponent: [{
2187
+ type: ViewChild,
2188
+ args: [ListFiltersComponent]
2189
+ }] } });
2190
+
2191
+ class AddMicroserviceComponent {
2192
+ constructor(ecosystemService, modal, tenantService, docs) {
2193
+ this.ecosystemService = ecosystemService;
2194
+ this.modal = modal;
2195
+ this.tenantService = tenantService;
2196
+ this.docs = docs;
2197
+ this.slaHref = this.docs.getUserGuideLink('docs/microservice-sdk/microservices-sla');
2198
+ this.headerText = gettext('Add microservice');
2199
+ this.successText = gettext('Microservice created');
2200
+ this.createMicroserviceApplicationHandler = (f) => this.createMicroserviceApplication(f);
2201
+ this.uploadMicroserviceHandler = (f, app) => this.uploadMicroservice(f, app);
2202
+ }
2203
+ async createMicroserviceApplication(file) {
2204
+ await this.ecosystemService.isValidAppType(file, ApplicationType.MICROSERVICE);
2205
+ return this.ecosystemService.createAppForArchive(file);
2206
+ }
2207
+ async uploadMicroservice(file, microservice) {
2208
+ const subscribeToCurrentTenant = await this.askIfActivationAfterUploadNeeded();
2209
+ await this.ecosystemService.uploadArchiveToApp(file, microservice);
2210
+ await this.subscribeMicroservice(microservice, subscribeToCurrentTenant);
2211
+ }
2212
+ async askIfActivationAfterUploadNeeded() {
2213
+ try {
2214
+ await this.modal.confirm(gettext('Subscribe to microservice'), gettext('You are about to subscribe to the microservice after upload. Do you want to subscribe to it?'), Status.INFO, { ok: gettext('Subscribe'), cancel: gettext("Don't subscribe") });
2215
+ return true;
2216
+ }
2217
+ catch (ex) {
2218
+ return false;
2219
+ }
2220
+ }
2221
+ async subscribeMicroservice(app, subscribeToCurrentTenant) {
2222
+ const tenant = (await this.tenantService.current()).data;
2223
+ const applications = tenant.applications.references;
2224
+ const isSubscribed = applications.some(({ application }) => application.id === app.id);
2225
+ if (!isSubscribed && subscribeToCurrentTenant) {
2226
+ try {
2227
+ return await this.tenantService.subscribeApplication(tenant, app);
2228
+ }
2229
+ catch (res) {
2230
+ if (res.status === 409) {
2231
+ throw Error(ERROR_TYPE.ALREADY_SUBSCRIBED);
2232
+ }
2233
+ }
2234
+ }
2235
+ else if (isSubscribed && !subscribeToCurrentTenant) {
2236
+ return this.tenantService.unsubscribeApplication(tenant, app);
2140
2237
  }
2141
- return value.pipe(map(list => list.filter(plugin => !!plugin.tags?.includes('latest'))));
2142
2238
  }
2143
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OnlyLatestPluginVersionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
2144
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.9", ngImport: i0, type: OnlyLatestPluginVersionPipe, name: "onlyLatestPluginVersion" }); }
2239
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddMicroserviceComponent, deps: [{ token: i1.EcosystemService }, { token: i2.ModalService }, { token: i4.TenantService }, { token: i2.DocsService }], target: i0.ɵɵFactoryTarget.Component }); }
2240
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AddMicroserviceComponent, selector: "c8y-add-microservice", ngImport: i0, template: `<div class="p-16" translate [translateParams]="{ slaHref: slaHref }" ngNonBindable>
2241
+ By uploading a microservice, you agree to the
2242
+ <a href="{{ slaHref }}" target="_blank" rel="noopener noreferrer"
2243
+ >Microservice Deployment SLA</a
2244
+ >
2245
+ which outlines our microservices hosting terms, conditions, and performance standards.
2246
+ </div>
2247
+ <c8y-add-application
2248
+ [headerIcon]="'microchip'"
2249
+ [headerText]="headerText"
2250
+ [successText]="successText"
2251
+ [createApplicationHandler]="createMicroserviceApplicationHandler"
2252
+ [uploadApplicationHandler]="uploadMicroserviceHandler"
2253
+ ></c8y-add-application>`, isInline: true, dependencies: [{ kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i1.AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
2145
2254
  }
2146
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OnlyLatestPluginVersionPipe, decorators: [{
2147
- type: Pipe,
2255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddMicroserviceComponent, decorators: [{
2256
+ type: Component,
2148
2257
  args: [{
2149
- name: 'onlyLatestPluginVersion'
2258
+ selector: 'c8y-add-microservice',
2259
+ template: `<div class="p-16" translate [translateParams]="{ slaHref: slaHref }" ngNonBindable>
2260
+ By uploading a microservice, you agree to the
2261
+ <a href="{{ slaHref }}" target="_blank" rel="noopener noreferrer"
2262
+ >Microservice Deployment SLA</a
2263
+ >
2264
+ which outlines our microservices hosting terms, conditions, and performance standards.
2265
+ </div>
2266
+ <c8y-add-application
2267
+ [headerIcon]="'microchip'"
2268
+ [headerText]="headerText"
2269
+ [successText]="successText"
2270
+ [createApplicationHandler]="createMicroserviceApplicationHandler"
2271
+ [uploadApplicationHandler]="uploadMicroserviceHandler"
2272
+ ></c8y-add-application>`
2150
2273
  }]
2151
- }] });
2274
+ }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.ModalService }, { type: i4.TenantService }, { type: i2.DocsService }] });
2152
2275
 
2153
- class InstallPluginComponent {
2154
- constructor(bsModalRef, modal, ecosystemService) {
2155
- this.bsModalRef = bsModalRef;
2156
- this.modal = modal;
2276
+ class MicroserviceListComponent {
2277
+ constructor(ecosystemService, wizardModalService, cd) {
2157
2278
  this.ecosystemService = ecosystemService;
2158
- this.filterTerm$ = new BehaviorSubject('');
2159
- this.filteredPlugins$ = new BehaviorSubject([]);
2160
- this.selectedPlugins = [];
2161
- this.result = new Promise((resolve, reject) => {
2162
- this._install = resolve;
2163
- this._cancel = reject;
2164
- });
2165
- this.onlyLatestPluginVersion = true;
2279
+ this.wizardModalService = wizardModalService;
2280
+ this.cd = cd;
2281
+ this.reloading = false;
2282
+ this.reload$ = new BehaviorSubject(null);
2283
+ this.microservices$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getMicroservices()), tap(microservices => {
2284
+ microservices.forEach(microservice => {
2285
+ microservice.filterProps = this.ecosystemService.getAppFilterProps(microservice);
2286
+ });
2287
+ }), tap(() => (this.reloading = false)), shareReplay());
2288
+ this.isMicroserviceHostingAllowed$ = this.reload$.pipe(switchMap(() => this.ecosystemService.isMicroserviceHostingAllowed()), shareReplay());
2289
+ this.packageAvailabilities = [
2290
+ APP_STATE.SUBSCRIBED.label,
2291
+ APP_STATE.CUSTOM.label
2292
+ ];
2166
2293
  }
2167
2294
  ngOnInit() {
2168
- this.filteredPlugins$ = combineLatest([this.plugins$, this.filterTerm$]).pipe(map(([plugins, filterTerm]) => filterTerm.trim().length === 0
2169
- ? plugins
2170
- : plugins.filter((plugin) => this.ecosystemService.filterContainString(plugin.name, filterTerm))));
2171
- }
2172
- cancel() {
2173
- this.bsModalRef.hide();
2174
- this._cancel();
2295
+ this.loadMicroservices();
2296
+ // manually trigger detection to not have ExpressionChangedAfterItHasBeenChecked error in spec file
2297
+ this.cd.detectChanges();
2175
2298
  }
2176
- install() {
2177
- this._install(this.selectedPlugins);
2178
- this.bsModalRef.hide();
2299
+ loadMicroservices() {
2300
+ this.reload$.next();
2179
2301
  }
2180
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: InstallPluginComponent, deps: [{ token: i1$1.BsModalRef }, { token: i2.ModalService }, { token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
2181
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: InstallPluginComponent, selector: "c8y-install-plugin", inputs: { plugins$: "plugins$" }, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'plugin'\"></i>\n <div id=\"modal-title\" class=\"modal-title h4\" translate>Available plugins</div>\n </div>\n <div class=\"p-t-8 p-16 text-center separator-bottom flex-no-shrink\">\n <p class=\"text-medium m-b-8\" translate>Select the compatible plugins to install</p>\n <label class=\"c8y-switch\">\n <input type=\"checkbox\" [(ngModel)]=\"onlyLatestPluginVersion\" />\n <span></span>\n <span translate>Only latest version of plugins</span>\n </label>\n <c8y-filter (onSearch)=\"this.filterTerm$.next($event)\"></c8y-filter>\n </div>\n <div class=\"modal-inner-scroll\" id=\"modal-body\">\n <c8y-plugin-list\n (selectedItems)=\"selectedPlugins = $event\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"filteredPlugins$ | onlyLatestPluginVersion: !onlyLatestPluginVersion\"\n [selectable]=\"true\"\n class=\"m-t-16\"\n ></c8y-plugin-list>\n </div>\n\n <div class=\"modal-footer\">\n <button\n (click)=\"cancel()\"\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n data-cy=\"install-plugin--cancel-button\"\n type=\"button\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n (click)=\"install()\"\n [disabled]=\"selectedPlugins.length === 0\"\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n data-cy=\"install-plugin--install-button\"\n type=\"button\"\n >\n {{ 'Install' | translate }}\n <span class=\"badge\" *ngIf=\"selectedPlugins.length as length\">{{ length }}</span>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.FilterInputComponent, selector: "c8y-filter", inputs: ["icon"], outputs: ["onSearch"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: OnlyLatestPluginVersionPipe, name: "onlyLatestPluginVersion" }] }); }
2182
- }
2183
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: InstallPluginComponent, decorators: [{
2184
- type: Component,
2185
- args: [{ selector: 'c8y-install-plugin', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'plugin'\"></i>\n <div id=\"modal-title\" class=\"modal-title h4\" translate>Available plugins</div>\n </div>\n <div class=\"p-t-8 p-16 text-center separator-bottom flex-no-shrink\">\n <p class=\"text-medium m-b-8\" translate>Select the compatible plugins to install</p>\n <label class=\"c8y-switch\">\n <input type=\"checkbox\" [(ngModel)]=\"onlyLatestPluginVersion\" />\n <span></span>\n <span translate>Only latest version of plugins</span>\n </label>\n <c8y-filter (onSearch)=\"this.filterTerm$.next($event)\"></c8y-filter>\n </div>\n <div class=\"modal-inner-scroll\" id=\"modal-body\">\n <c8y-plugin-list\n (selectedItems)=\"selectedPlugins = $event\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"filteredPlugins$ | onlyLatestPluginVersion: !onlyLatestPluginVersion\"\n [selectable]=\"true\"\n class=\"m-t-16\"\n ></c8y-plugin-list>\n </div>\n\n <div class=\"modal-footer\">\n <button\n (click)=\"cancel()\"\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n data-cy=\"install-plugin--cancel-button\"\n type=\"button\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n (click)=\"install()\"\n [disabled]=\"selectedPlugins.length === 0\"\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n data-cy=\"install-plugin--install-button\"\n type=\"button\"\n >\n {{ 'Install' | translate }}\n <span class=\"badge\" *ngIf=\"selectedPlugins.length as length\">{{ length }}</span>\n </button>\n </div>\n</div>\n" }]
2186
- }], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: i2.ModalService }, { type: i1.EcosystemService }], propDecorators: { plugins$: [{
2187
- type: Input
2188
- }] } });
2189
-
2190
- class LabelCellRendererComponent {
2191
- constructor(context) {
2192
- this.context = context;
2302
+ addMicroservice() {
2303
+ const initialState = {
2304
+ id: EcosystemWizards.MICROSERVICE_UPLOAD
2305
+ };
2306
+ const modalOptions = { initialState };
2307
+ const modalRef = this.wizardModalService.show(modalOptions);
2308
+ modalRef.content.onClose.subscribe(() => {
2309
+ this.loadMicroservices();
2310
+ });
2193
2311
  }
2194
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: LabelCellRendererComponent, deps: [{ token: i2.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
2195
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: LabelCellRendererComponent, selector: "c8y-label-cell-renderer", ngImport: i0, template: "<span class=\"label label-info\">{{ context.value }}</span>\n" }); }
2196
- }
2197
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: LabelCellRendererComponent, decorators: [{
2198
- type: Component,
2199
- args: [{ selector: 'c8y-label-cell-renderer', template: "<span class=\"label label-info\">{{ context.value }}</span>\n" }]
2200
- }], ctorParameters: () => [{ type: i2.CellRendererContext }] });
2201
-
2202
- class OrphanedStatusCellRendererComponent {
2203
- constructor(context) {
2204
- this.context = context;
2205
- this.label = this.getLabel(context.value);
2312
+ setFilterPipe(pipe) {
2313
+ this.filteredMicroservices$ = this.microservices$.pipe(src => pipe(src));
2206
2314
  }
2207
- getLabel(statusValue) {
2208
- switch (statusValue) {
2209
- case ApplicationPluginStatus.OUTDATED:
2210
- return {
2211
- value: statusValue,
2212
- text: gettext('OUTDATED`plugin status`'),
2213
- class: 'label-warning'
2214
- };
2215
- case ApplicationPluginStatus.ORPHANED:
2216
- return {
2217
- value: statusValue,
2218
- text: gettext('ORPHANED`plugin status`'),
2219
- class: 'label-danger'
2220
- };
2221
- case ApplicationPluginStatus.REVOKED:
2222
- return {
2223
- value: statusValue,
2224
- text: gettext('REVOKED`plugin status`'),
2225
- class: 'label-danger'
2226
- };
2227
- case ApplicationPluginStatus.LATEST:
2228
- return {
2229
- value: statusValue,
2230
- text: gettext('LATEST`plugin status`'),
2231
- class: 'label-success'
2232
- };
2233
- case ApplicationPluginStatus.AUTO:
2234
- return {
2235
- value: statusValue,
2236
- text: gettext('AUTO`plugin status`'),
2237
- class: 'label-success'
2238
- };
2239
- default:
2240
- return null;
2241
- }
2315
+ resetFilters() {
2316
+ this.filtersComponent?.resetAllFilters();
2242
2317
  }
2243
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OrphanedStatusCellRendererComponent, deps: [{ token: i2.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
2244
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: OrphanedStatusCellRendererComponent, selector: "c8y-orphaned-status-cell-renderer", ngImport: i0, template: "<span\n *ngIf=\"label\"\n class=\"label\"\n [ngClass]=\"label.class\"\n [title]=\"label.text | translate\"\n>\n {{ label.text | translate }}\n</span>\n", dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
2318
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: MicroserviceListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2319
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: MicroserviceListComponent, selector: "c8y-microservice-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Microservices' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'microchip'\"\n [label]=\"'Microservices' | translate\"\n [path]=\"'ecosystem/microservice/microservices'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n *ngIf=\"isMicroserviceHostingAllowed$ | async\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add microservice' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-microservices\"></c8y-help>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"microservices$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(microservices$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(microservices$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No microservices to display.</h3>\n <p translate>Add your first microservice by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n {{ 'Add microservice' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(microservices$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Microservice' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let microservice of filteredMicroservices$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadMicroservices()\"\n [app]=\"microservice\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching microservices.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(microservices$ | async)?.length > 0 && (filteredMicroservices$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i1.ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
2245
2320
  }
2246
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: OrphanedStatusCellRendererComponent, decorators: [{
2321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: MicroserviceListComponent, decorators: [{
2247
2322
  type: Component,
2248
- args: [{ selector: 'c8y-orphaned-status-cell-renderer', template: "<span\n *ngIf=\"label\"\n class=\"label\"\n [ngClass]=\"label.class\"\n [title]=\"label.text | translate\"\n>\n {{ label.text | translate }}\n</span>\n" }]
2249
- }], ctorParameters: () => [{ type: i2.CellRendererContext }] });
2323
+ args: [{ selector: 'c8y-microservice-list', template: "<c8y-title>{{ 'Microservices' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'microchip'\"\n [label]=\"'Microservices' | translate\"\n [path]=\"'ecosystem/microservice/microservices'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n *ngIf=\"isMicroserviceHostingAllowed$ | async\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add microservice' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-microservices\"></c8y-help>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"microservices$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(microservices$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(microservices$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No microservices to display.</h3>\n <p translate>Add your first microservice by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n {{ 'Add microservice' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(microservices$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Microservice' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let microservice of filteredMicroservices$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadMicroservices()\"\n [app]=\"microservice\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching microservices.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(microservices$ | async)?.length > 0 && (filteredMicroservices$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
2324
+ }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }, { type: i0.ChangeDetectorRef }], propDecorators: { filtersComponent: [{
2325
+ type: ViewChild,
2326
+ args: [ListFiltersComponent]
2327
+ }] } });
2250
2328
 
2251
- class UpdatePluginOfAppComponent {
2252
- constructor(bsModalRef, pluginsService, alert, ecosystemService, gainsightService) {
2253
- this.bsModalRef = bsModalRef;
2254
- this.pluginsService = pluginsService;
2255
- this.alert = alert;
2256
- this.ecosystemService = ecosystemService;
2257
- this.gainsightService = gainsightService;
2258
- this.CURRENT_LOCATION = location.href;
2259
- this.result = new Promise((resolve, reject) => {
2260
- this._install = resolve;
2261
- this._cancel = reject;
2262
- });
2263
- this.updateAll = true;
2264
- }
2265
- async update() {
2266
- const remotes = this.pluginsService.getMFRemotes(this.app);
2267
- const oldRemotePath = `${this.plugin.contextPath}@${this.plugin.version}`;
2268
- const newRemotePath = `${this.plugin.contextPath}@${this.applicationVersion.version}`;
2269
- let oldRemoteModules = [...(remotes[oldRemotePath] || [])];
2270
- if (!oldRemoteModules.length) {
2271
- this.alert.warning(gettext('Could not change the version of plugin.'));
2272
- this.cancel();
2273
- return;
2274
- }
2275
- const result = await this.ecosystemService.verifyLicenses([this.plugin]);
2276
- if (!result) {
2277
- this.alert.warning(gettext('Plugin update aborted by user.'));
2278
- this.cancel();
2279
- return;
2280
- }
2281
- let remoteModulesOfNewVersion = [...(remotes[newRemotePath] || [])];
2282
- let olderVersions = {};
2283
- if (this.updateAll) {
2284
- olderVersions = Object.keys(remotes)
2285
- .filter(key => key.startsWith(`${this.plugin.contextPath}@`))
2286
- .reduceRight((prev, curr) => {
2287
- prev[curr] = undefined;
2288
- return prev;
2289
- }, {});
2290
- oldRemoteModules = Object.keys(olderVersions)
2291
- .map(version => remotes[version])
2292
- .reduceRight((prev, curr) => {
2293
- prev.push(...curr);
2294
- return prev;
2295
- }, []);
2296
- remoteModulesOfNewVersion.push(...oldRemoteModules);
2297
- }
2298
- else {
2299
- remoteModulesOfNewVersion.push(this.plugin.module);
2300
- olderVersions[oldRemotePath] = oldRemoteModules.filter(module => module !== this.plugin.module);
2301
- if (!olderVersions[oldRemotePath].length) {
2302
- olderVersions[oldRemotePath] = undefined;
2303
- }
2304
- }
2305
- remoteModulesOfNewVersion = uniq(remoteModulesOfNewVersion);
2306
- const newRemotes = {
2307
- ...remotes,
2308
- ...olderVersions,
2309
- [newRemotePath]: remoteModulesOfNewVersion
2310
- };
2311
- try {
2312
- await this.pluginsService.updateRemotesInAppConfig(this.app, newRemotes);
2313
- this.alert.success(gettext(`Switched the version of plugin.`));
2314
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2315
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.UPDATE_PLUGIN_OF_APP,
2316
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.CHANGE_PLUGIN_VERSION,
2317
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_VERSION_CHANGED,
2318
- url: this.CURRENT_LOCATION
2319
- });
2320
- }
2321
- catch (e) {
2322
- this.alert.addServerFailure(e);
2323
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2324
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.UPDATE_PLUGIN_OF_APP,
2325
- action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.CHANGE_PLUGIN_VERSION,
2326
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2327
- url: this.CURRENT_LOCATION
2328
- });
2329
- }
2330
- this.bsModalRef.hide();
2331
- this._install();
2329
+ class AddPackageComponent {
2330
+ constructor(ecosystemService) {
2331
+ this.ecosystemService = ecosystemService;
2332
+ this.headerText = gettext('Add extension package');
2333
+ this.successText = gettext('Extension package created');
2334
+ this.createPackageAppHandler = (f) => this.createPackageApp(f);
2335
+ this.uploadPackageHandler = (f, app) => this.uploadPackage(f, app);
2332
2336
  }
2333
- cancel() {
2334
- this.bsModalRef.hide();
2335
- this._cancel();
2337
+ async createPackageApp(file) {
2338
+ await this.ecosystemService.isValidAppType(file, ApplicationType.HOSTED);
2339
+ return await this.ecosystemService.createAppForArchive(file, true);
2336
2340
  }
2337
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: UpdatePluginOfAppComponent, deps: [{ token: i1$1.BsModalRef }, { token: i2.PluginsService }, { token: i2.AlertService }, { token: i1.EcosystemService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
2338
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: UpdatePluginOfAppComponent, selector: "c8y-update-plugin-of-app", ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-modules'\"></i>\n <h4 *ngIf=\"!downgrade\" id=\"modal-title\" translate>Update plugin</h4>\n <h4 *ngIf=\"downgrade\" id=\"modal-title\" translate>Downgrade plugin</h4>\n </div>\n <div class=\"inner-scroll\" id=\"modal-body\">\n <div class=\"p-16\">\n <div class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [packageContextPath]=\"plugin?.contextPath\"\n [(ngModel)]=\"applicationVersion\"\n ></c8y-package-version-select>\n <div\n *ngIf=\"plugin?.version && plugin.version === applicationVersion?.version\"\n class=\"alert alert-info\"\n role=\"alert\"\n >\n <span translate ngNonBindable [translateParams]=\"applicationVersion\">\n Select another version, as {{ version }} is currently used.\n </span>\n </div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"c8y-checkbox\">\n <input [(ngModel)]=\"updateAll\" type=\"checkbox\" />\n <span></span>\n <span translate ngNonBindable [translateParams]=\"plugin\">\n Set version for all plugins using the same context path \"{{ contextPath }}\".\n </span>\n </label>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Set version' | translate }}\"\n [disabled]=\"!applicationVersion || plugin?.version === applicationVersion?.version\"\n (click)=\"update()\"\n >\n {{ 'Set version' | translate }}\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1.PackageVersionSelectComponent, selector: "c8y-package-version-select", inputs: ["label", "packageContextPath", "packageId"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
2341
+ uploadPackage(file, pckg) {
2342
+ return this.ecosystemService.uploadArchiveToApp(file, pckg, true);
2343
+ }
2344
+ next() {
2345
+ this.stepper.next();
2346
+ }
2347
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddPackageComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
2348
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: AddPackageComponent, selector: "c8y-add-package", viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true, static: true }], ngImport: i0, template: `<c8y-add-application
2349
+ [headerIcon]="'big-parcel'"
2350
+ [headerText]="headerText"
2351
+ [successText]="successText"
2352
+ [createApplicationHandler]="createPackageAppHandler"
2353
+ [uploadApplicationHandler]="uploadPackageHandler"
2354
+ [applicationType]="'package'"
2355
+ ></c8y-add-application>`, isInline: true, dependencies: [{ kind: "component", type: i1.AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
2339
2356
  }
2340
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: UpdatePluginOfAppComponent, decorators: [{
2357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: AddPackageComponent, decorators: [{
2341
2358
  type: Component,
2342
- args: [{ selector: 'c8y-update-plugin-of-app', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-modules'\"></i>\n <h4 *ngIf=\"!downgrade\" id=\"modal-title\" translate>Update plugin</h4>\n <h4 *ngIf=\"downgrade\" id=\"modal-title\" translate>Downgrade plugin</h4>\n </div>\n <div class=\"inner-scroll\" id=\"modal-body\">\n <div class=\"p-16\">\n <div class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [packageContextPath]=\"plugin?.contextPath\"\n [(ngModel)]=\"applicationVersion\"\n ></c8y-package-version-select>\n <div\n *ngIf=\"plugin?.version && plugin.version === applicationVersion?.version\"\n class=\"alert alert-info\"\n role=\"alert\"\n >\n <span translate ngNonBindable [translateParams]=\"applicationVersion\">\n Select another version, as {{ version }} is currently used.\n </span>\n </div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"c8y-checkbox\">\n <input [(ngModel)]=\"updateAll\" type=\"checkbox\" />\n <span></span>\n <span translate ngNonBindable [translateParams]=\"plugin\">\n Set version for all plugins using the same context path \"{{ contextPath }}\".\n </span>\n </label>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Set version' | translate }}\"\n [disabled]=\"!applicationVersion || plugin?.version === applicationVersion?.version\"\n (click)=\"update()\"\n >\n {{ 'Set version' | translate }}\n </button>\n </div>\n</div>\n" }]
2343
- }], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: i2.PluginsService }, { type: i2.AlertService }, { type: i1.EcosystemService }, { type: i2.GainsightService }] });
2359
+ args: [{
2360
+ selector: 'c8y-add-package',
2361
+ template: `<c8y-add-application
2362
+ [headerIcon]="'big-parcel'"
2363
+ [headerText]="headerText"
2364
+ [successText]="successText"
2365
+ [createApplicationHandler]="createPackageAppHandler"
2366
+ [uploadApplicationHandler]="uploadPackageHandler"
2367
+ [applicationType]="'package'"
2368
+ ></c8y-add-application>`
2369
+ }]
2370
+ }], ctorParameters: () => [{ type: i1.EcosystemService }], propDecorators: { stepper: [{
2371
+ type: ViewChild,
2372
+ args: [C8yStepper, { static: true }]
2373
+ }] } });
2344
2374
 
2345
- class ApplicationPluginsComponent {
2346
- constructor(activatedRoute, ecosystemService, bsModalService, pluginsService, alertService, gainsightService) {
2347
- this.activatedRoute = activatedRoute;
2375
+ class DeployApplicationComponent {
2376
+ constructor(ecosystemService, wizardComponent, translate, pluginService, gainsightService, router) {
2348
2377
  this.ecosystemService = ecosystemService;
2349
- this.bsModalService = bsModalService;
2350
- this.pluginsService = pluginsService;
2351
- this.alertService = alertService;
2378
+ this.wizardComponent = wizardComponent;
2379
+ this.translate = translate;
2380
+ this.pluginService = pluginService;
2352
2381
  this.gainsightService = gainsightService;
2353
- this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_ECOSYSTEM;
2382
+ this.router = router;
2354
2383
  this.CURRENT_LOCATION = location.href;
2355
- this.remotePlugins$ = new BehaviorSubject({});
2356
- this.allAvailablePlugins$ = new BehaviorSubject([]);
2357
- this.selfPlugins$ = new BehaviorSubject([]);
2358
- this.installedPlugins$ = combineLatest([
2359
- this.remotePlugins$.pipe(map(remotes => PluginsService.convertInstalledRemotesToIds(remotes))),
2360
- this.allAvailablePlugins$
2361
- ]).pipe(map(([remotePlugins, allPlugins]) => this.getInstalledPlugins(allPlugins, remotePlugins)), shareReplay(1));
2362
- this.orphanedPlugins$ = this.installedPlugins$.pipe(map(plugins => plugins.filter(p => p.status === ApplicationPluginStatus.ORPHANED)));
2363
- this.isStandard$ = combineLatest([this.installedPlugins$, this.selfPlugins$]).pipe(map(([installedPlugins, selfPlugins]) => {
2364
- const manifestRemotes = this.app?.manifest?.remotes || {};
2365
- // ensure that every installed plugin is a self plugin or a plugin from the manifest
2366
- const allInstalledPluginsAreSelf = installedPlugins.every(p => selfPlugins.some(selfPlugin => selfPlugin.id === p.id) ||
2367
- (Array.isArray(manifestRemotes[p.contextPath]) &&
2368
- manifestRemotes[p.contextPath].includes(p.module)));
2369
- // ensure that every self plugin is installed
2370
- const allSelfPluginsAreInstalled = selfPlugins.every(selfPlugin => installedPlugins.some(p => p.id === selfPlugin.id));
2371
- const configRemotes = this.app?.config?.remotes || {};
2372
- // ensure that every remote from the manifest is in the config
2373
- // if no config exists we are also all good
2374
- const everyRemoteFromManifestIsInConfig = !this.app?.config?.remotes ||
2375
- Object.keys(manifestRemotes).every(contextPath => Array.isArray(configRemotes[contextPath]) &&
2376
- Array.isArray(manifestRemotes[contextPath]) &&
2377
- manifestRemotes[contextPath].every(module => configRemotes[contextPath].includes(module)));
2378
- return (allInstalledPluginsAreSelf &&
2379
- allSelfPluginsAreInstalled &&
2380
- everyRemoteFromManifestIsInConfig);
2381
- }));
2382
- this.title = gettext('Installed plugins');
2383
- this.loadMoreItemsLabel = gettext('Load more packages');
2384
- this.loadingItemsLabel = gettext('Loading packages…');
2385
- this.actionControls = this.getActionControls();
2386
- this.bulkActionControls = this.getBulkActionControls();
2387
- this.headerActionControls = [];
2388
- this.noResultsMessage = gettext('No plugins to display.');
2389
- this.noDataMessage = gettext('No plugins installed.');
2390
- this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.');
2391
- this.noDataSubtitle = gettext("This application doesn't have any plugin. Click below to install.");
2392
- this.pagination = {
2393
- pageSize: 10,
2394
- currentPage: 1
2395
- };
2396
- this.displayOptions = {
2397
- bordered: false,
2398
- striped: true,
2399
- filter: true,
2400
- gridHeader: true,
2401
- hover: true
2402
- };
2403
- this.columns = [
2404
- {
2405
- name: 'name',
2406
- header: gettext('Plugin name'),
2407
- path: 'name',
2408
- filterable: true
2409
- },
2410
- {
2411
- name: 'Version',
2412
- header: gettext('Version'),
2413
- path: 'version',
2414
- filterable: false
2415
- },
2416
- {
2417
- name: 'Tag',
2418
- header: gettext('Tag`noun`'),
2419
- path: 'installedViaTag',
2420
- filterable: false,
2421
- cellRendererComponent: LabelCellRendererComponent
2422
- },
2423
- {
2424
- name: 'description',
2425
- header: gettext('Description'),
2426
- path: 'description',
2427
- filterable: false,
2428
- cellCSSClassName: 'small'
2429
- },
2430
- {
2431
- name: 'contextPath',
2432
- header: gettext('Source'),
2433
- path: 'contextPath',
2434
- filterable: false,
2435
- cellRendererComponent: LabelCellRendererComponent
2436
- },
2437
- {
2438
- name: 'scope',
2439
- header: gettext('Scope'),
2440
- path: 'scope',
2441
- filterable: false,
2442
- visible: false,
2443
- cellRendererComponent: LabelCellRendererComponent
2444
- },
2445
- {
2446
- name: 'status',
2447
- header: gettext('Status'),
2448
- path: 'status',
2449
- filterable: false,
2450
- cellRendererComponent: OrphanedStatusCellRendererComponent
2384
+ this.inProgress = true;
2385
+ this.isDeployed = false;
2386
+ this.deployedWithSuccess = false;
2387
+ this.model = {
2388
+ selected: undefined,
2389
+ binary: {
2390
+ id: undefined
2451
2391
  }
2452
- ];
2453
- this.destroy$ = new Subject();
2454
- }
2455
- ngOnInit() {
2456
- this.addInstallButtonToHeaderActionControls();
2457
- this.loadData();
2458
- }
2459
- async loadData() {
2460
- this.isLoading = true;
2461
- await this.getApplicationMO();
2462
- await this.getApplicationMFRemotes(this.app);
2463
- await this.getAllApplicationsMFExports(this.app);
2464
- await this.getAllSelfMFExports(this.app);
2465
- this.isLoading = false;
2392
+ };
2393
+ this.canDeploy = false;
2394
+ this.descriptionTemplate = gettext('Deploy application using "{{ packageName }}" package');
2395
+ this.successMessageTemplate = gettext('Application "{{ packageName }}" created');
2396
+ this.doneLabel = gettext('Done');
2397
+ this.cancelLabel = gettext('Cancel');
2398
+ this.package = this.wizardComponent.package;
2466
2399
  }
2467
- async resetToDefault() {
2468
- this.isLoading = true;
2469
- await this.pluginsService.resetRemotes(this.app);
2470
- await this.loadData();
2471
- this.alertService.success(gettext('The application was reset to its default plugins.'));
2400
+ async ngOnInit() {
2401
+ const apps = await this.ecosystemService.getHostedAndPackageApplications();
2402
+ this.newAppConfig = this.ecosystemService.getUniqueAppConfig(this.package, apps);
2403
+ this.headerText = this.getHeaderText();
2404
+ this.inProgress = false;
2472
2405
  }
2473
- async installPlugins() {
2406
+ async deployApp() {
2407
+ this.inProgress = true;
2408
+ const formGroupValue = this.applicationPropertiesForm.formGroup.getRawValue();
2409
+ // Verify if selected package version is compatible with current platform versions.
2410
+ this.package.manifest.version = this.model.selected.version;
2411
+ const verifyVersionCompatibility = await this.ecosystemService.verifyBlueprintVersionsCompatibility(this.package.manifest);
2412
+ if (!verifyVersionCompatibility) {
2413
+ this.cancel();
2414
+ return;
2415
+ }
2416
+ const { contextPath, license, name, manifest } = this.package;
2417
+ const type = this.pluginService.getPackageType(this.package);
2418
+ const licensedApp = {
2419
+ contextPath,
2420
+ license: license || manifest.license,
2421
+ name,
2422
+ type,
2423
+ version: this.model.selected.version
2424
+ };
2425
+ const isArchived = await this.ecosystemService.verifyArchived([licensedApp]);
2426
+ if (!isArchived) {
2427
+ this.cancel();
2428
+ return;
2429
+ }
2430
+ const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([licensedApp]);
2431
+ if (!licensesVerifiedByUser) {
2432
+ this.cancel();
2433
+ return;
2434
+ }
2474
2435
  try {
2475
- const pluginsToAdd = await this.bsModalService.show(InstallPluginComponent, {
2476
- class: 'modal-sm',
2477
- ariaDescribedby: 'modal-body',
2478
- ariaLabelledBy: 'modal-title',
2479
- initialState: this.getInstallModalInitState(),
2480
- ignoreBackdropClick: true
2481
- }).content.result;
2482
- const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses(pluginsToAdd);
2483
- if (!licensesVerifiedByUser) {
2484
- return;
2485
- }
2486
- const verifyVersionCompatibility = await this.ecosystemService.verifyPluginVersionsCompatibility(pluginsToAdd, this.app);
2487
- if (!verifyVersionCompatibility) {
2488
- return;
2489
- }
2490
- this.isLoading = true;
2491
- await this.handleRemotesInstallation(pluginsToAdd);
2492
- this.alertService.success(gettext('Plugins installed.'));
2493
- pluginsToAdd.forEach(plugin => {
2494
- const pluginCustomEventInfo = pick(plugin, [
2495
- 'name',
2496
- 'contextPath',
2497
- 'module',
2498
- 'version',
2499
- 'type',
2500
- 'id'
2501
- ]);
2502
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2503
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS,
2504
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_INSTALLED,
2505
- url: this.CURRENT_LOCATION,
2506
- ...pluginCustomEventInfo,
2507
- targetApplicationName: this.app.name,
2508
- targetApplicationContextPath: this.app.contextPath
2509
- });
2436
+ this.deployedApp = await this.ecosystemService.deployApp(this.package, formGroupValue, this.model);
2437
+ const applicationCustomEventInfo = pick(this.package, [
2438
+ 'id',
2439
+ 'name',
2440
+ 'contextPath',
2441
+ 'label',
2442
+ 'key'
2443
+ ]);
2444
+ this.deployedWithSuccess = true;
2445
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DEPLOY_APPLICATION, {
2446
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DEPLOY_APPLICATION,
2447
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION,
2448
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.DEPLOYED,
2449
+ url: this.CURRENT_LOCATION,
2450
+ ...applicationCustomEventInfo,
2451
+ package: this.deployedApp?.manifest?.package ?? null
2510
2452
  });
2511
2453
  }
2512
- catch (ex) {
2513
- if (ex) {
2514
- this.alertService.addServerFailure(ex);
2515
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2516
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS,
2517
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2518
- url: this.CURRENT_LOCATION,
2519
- error: ex
2520
- });
2521
- }
2454
+ catch (error) {
2455
+ this.ecosystemService.alertError(error);
2456
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DEPLOY_APPLICATION, {
2457
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DEPLOY_APPLICATION,
2458
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION,
2459
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2460
+ url: this.CURRENT_LOCATION,
2461
+ error
2462
+ });
2522
2463
  }
2523
2464
  finally {
2524
- this.isLoading = false;
2465
+ this.markAsDeployed();
2525
2466
  }
2526
2467
  }
2527
- async removePlugins(plugins) {
2528
- try {
2529
- this.isLoading = true;
2530
- const installedPlugins = await firstValueFrom(this.installedPlugins$);
2531
- const updatedRemotes = await this.pluginsService.removeRemotes(this.app, plugins.map(id => installedPlugins.find(p => p.id === id)));
2532
- this.emitRemotes(updatedRemotes);
2533
- this.isLoading = false;
2534
- this.dataGrid.cancel();
2535
- this.alertService.success(gettext('Plugins removed.'));
2536
- plugins.forEach(plugin => {
2537
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2538
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS,
2539
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_REMOVED,
2540
- url: this.CURRENT_LOCATION,
2541
- id: plugin,
2542
- targetApplicationName: this.app.name,
2543
- targetApplicationContextPath: this.app.contextPath
2544
- });
2545
- });
2468
+ cancel() {
2469
+ this.wizardComponent.close();
2470
+ }
2471
+ onAppVersionSelect(appVersion) {
2472
+ Object.assign(this.model, {
2473
+ selected: appVersion
2474
+ });
2475
+ this.canDeploy = true;
2476
+ }
2477
+ open() {
2478
+ this.router.navigateByUrl(ViewContext.Application.replace(':id', `${this.deployedApp.id}`));
2479
+ this.cancel();
2480
+ }
2481
+ markAsDeployed() {
2482
+ this.isDeployed = true;
2483
+ this.inProgress = false;
2484
+ }
2485
+ getHeaderText() {
2486
+ return this.translate.instant(this.descriptionTemplate, {
2487
+ packageName: this.package.name
2488
+ });
2489
+ }
2490
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DeployApplicationComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardComponent }, { token: i4$1.TranslateService }, { token: i2.PluginsService }, { token: i2.GainsightService }, { token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
2491
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DeployApplicationComponent, selector: "c8y-deploy-application", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"output\"></i>\n <h4 id=\"modal-title\">{{ 'Deploy application' | translate }}</h4>\n </div>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n <ng-container *ngIf=\"!isDeployed\">\n <div class=\"fadeIn animated d-flex a-i-center j-c-center d-col\" style=\"min-height: 309px\">\n <p\n class=\"bg-level-0 fit-w p-16 text-center text-medium sticky-top bg-level-0 separator-bottom\"\n *ngIf=\"!inProgress\"\n >\n {{ headerText | translate }}\n </p>\n <c8y-application-properties-form\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n class=\"d-block fit-w bg-level-1\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div [ngStyle]=\"{ padding: '0 16px' }\" class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [ngModel]=\"model.selected\"\n (ngModelChange)=\"onAppVersionSelect($event)\"\n [packageId]=\"package?.id\"\n [label]=\"'Use extension package version' | translate\"\n ></c8y-package-version-select>\n </div>\n </ng-container>\n\n <c8y-loading\n *ngIf=\"inProgress\"\n [message]=\"'Deploying\u2026' | translate\"\n class=\"text-center\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n class=\"modal-body fadeIn animated\"\n style=\"min-height: 309px\"\n >\n <div class=\"d-flex a-i-center j-c-center d-col\">\n <c8y-operation-result\n type=\"success\"\n [size]=\"84\"\n [vertical]=\"true\"\n [text]=\"successMessageTemplate | translate: { packageName: package.name }\"\n class=\"lead d-block m-b-16\"\n ></c8y-operation-result>\n </div>\n </div>\n <ng-template #failedDeploy>\n <div class=\"modal-body fadeIn animated text-center\" style=\"min-height: 257px\">\n <c8y-operation-result\n type=\"error\"\n [size]=\"84\"\n [vertical]=\"true\"\n text=\"{{ 'Application creation failed' | translate }}\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n data-cy=\"c8y-deploy-application--cancel-blueprint-button\"\n title=\"{{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\"\n >\n {{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\n </button>\n\n <button\n (click)=\"deployApp()\"\n *ngIf=\"!isDeployed\"\n [disabled]=\"inProgress || !canDeploy\"\n [ngClass]=\"{ 'btn-pending': inProgress }\"\n class=\"btn btn-primary\"\n type=\"button\"\n data-cy=\"c8y-deploy-application--deploy-blueprint-button\"\n title=\"{{ 'Deploy' | translate }}\"\n >\n {{ 'Deploy' | translate }}\n </button>\n\n <button\n (click)=\"open()\"\n type=\"button\"\n class=\"btn btn-primary\"\n *ngIf=\"isDeployed && deployedWithSuccess\"\n title=\"{{ 'Open the application details' | translate }}\"\n translate\n >\n Open\n </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i2.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i2.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i2.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "component", type: i1.ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "component", type: i1.PackageVersionSelectComponent, selector: "c8y-package-version-select", inputs: ["label", "packageContextPath", "packageId"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
2492
+ }
2493
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DeployApplicationComponent, decorators: [{
2494
+ type: Component,
2495
+ args: [{ selector: 'c8y-deploy-application', template: "<c8y-wizard-header>\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"output\"></i>\n <h4 id=\"modal-title\">{{ 'Deploy application' | translate }}</h4>\n </div>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n <ng-container *ngIf=\"!isDeployed\">\n <div class=\"fadeIn animated d-flex a-i-center j-c-center d-col\" style=\"min-height: 309px\">\n <p\n class=\"bg-level-0 fit-w p-16 text-center text-medium sticky-top bg-level-0 separator-bottom\"\n *ngIf=\"!inProgress\"\n >\n {{ headerText | translate }}\n </p>\n <c8y-application-properties-form\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n class=\"d-block fit-w bg-level-1\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div [ngStyle]=\"{ padding: '0 16px' }\" class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [ngModel]=\"model.selected\"\n (ngModelChange)=\"onAppVersionSelect($event)\"\n [packageId]=\"package?.id\"\n [label]=\"'Use extension package version' | translate\"\n ></c8y-package-version-select>\n </div>\n </ng-container>\n\n <c8y-loading\n *ngIf=\"inProgress\"\n [message]=\"'Deploying\u2026' | translate\"\n class=\"text-center\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n class=\"modal-body fadeIn animated\"\n style=\"min-height: 309px\"\n >\n <div class=\"d-flex a-i-center j-c-center d-col\">\n <c8y-operation-result\n type=\"success\"\n [size]=\"84\"\n [vertical]=\"true\"\n [text]=\"successMessageTemplate | translate: { packageName: package.name }\"\n class=\"lead d-block m-b-16\"\n ></c8y-operation-result>\n </div>\n </div>\n <ng-template #failedDeploy>\n <div class=\"modal-body fadeIn animated text-center\" style=\"min-height: 257px\">\n <c8y-operation-result\n type=\"error\"\n [size]=\"84\"\n [vertical]=\"true\"\n text=\"{{ 'Application creation failed' | translate }}\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n data-cy=\"c8y-deploy-application--cancel-blueprint-button\"\n title=\"{{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\"\n >\n {{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\n </button>\n\n <button\n (click)=\"deployApp()\"\n *ngIf=\"!isDeployed\"\n [disabled]=\"inProgress || !canDeploy\"\n [ngClass]=\"{ 'btn-pending': inProgress }\"\n class=\"btn btn-primary\"\n type=\"button\"\n data-cy=\"c8y-deploy-application--deploy-blueprint-button\"\n title=\"{{ 'Deploy' | translate }}\"\n >\n {{ 'Deploy' | translate }}\n </button>\n\n <button\n (click)=\"open()\"\n type=\"button\"\n class=\"btn btn-primary\"\n *ngIf=\"isDeployed && deployedWithSuccess\"\n title=\"{{ 'Open the application details' | translate }}\"\n translate\n >\n Open\n </button>\n</c8y-wizard-footer>\n" }]
2496
+ }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardComponent }, { type: i4$1.TranslateService }, { type: i2.PluginsService }, { type: i2.GainsightService }, { type: i1$2.Router }], propDecorators: { applicationPropertiesForm: [{
2497
+ type: ViewChild,
2498
+ args: [ApplicationPropertiesFormComponent]
2499
+ }] } });
2500
+
2501
+ class PackageDetailsComponent {
2502
+ constructor(activatedRoute, client, wizardModalService, ecosystemService, contextRouteService, pluginsService, packageAvailabilityService, ui, pluginService, gainsightService) {
2503
+ this.activatedRoute = activatedRoute;
2504
+ this.client = client;
2505
+ this.wizardModalService = wizardModalService;
2506
+ this.ecosystemService = ecosystemService;
2507
+ this.contextRouteService = contextRouteService;
2508
+ this.pluginsService = pluginsService;
2509
+ this.packageAvailabilityService = packageAvailabilityService;
2510
+ this.ui = ui;
2511
+ this.pluginService = pluginService;
2512
+ this.gainsightService = gainsightService;
2513
+ this.package = {};
2514
+ this.exportedPlugins$ = new BehaviorSubject([]);
2515
+ this.isChangingAvailability = false;
2516
+ this.isOwnedByCurrentTenant = false;
2517
+ this.isAllowedToCreateSubtenants = false;
2518
+ this.packageTypeLabels = PACKAGE_TYPE_LABELS;
2519
+ this.PACKAGE_TYPE = PackageType;
2520
+ this.packageProperties = packageProperties;
2521
+ this.headers = { 'Content-Type': 'text/markdown', responseType: 'blob' };
2522
+ this.NOT_FOUND_ERROR_CODE = 404;
2523
+ }
2524
+ async ngOnInit() {
2525
+ this.isAllowedToCreateSubtenants = !!this.ui.currentTenant.value?.allowCreateTenants;
2526
+ await this.loadData();
2527
+ }
2528
+ deploy() {
2529
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_PLUGINS, {
2530
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_DETAILS,
2531
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION_INITIATED
2532
+ });
2533
+ const initialState = {
2534
+ wizardConfig: {},
2535
+ id: EcosystemWizards.BLUEPRINT_DEPLOYMENT,
2536
+ package: this.package
2537
+ };
2538
+ const modalOptions = { initialState };
2539
+ this.wizardModalService.show(modalOptions);
2540
+ }
2541
+ async togglePackageAvailability(pckg, newAvailability) {
2542
+ this.isChangingAvailability = true;
2543
+ pckg = await this.packageAvailabilityService.askIfAvailabilityShouldBeSetTo(pckg, newAvailability);
2544
+ const availabilityHasChanged = pckg.availability === newAvailability;
2545
+ if (availabilityHasChanged) {
2546
+ await this.loadData(pckg);
2547
+ this.contextRouteService.setContext(this.activatedRoute, pckg);
2546
2548
  }
2547
- catch (ex) {
2548
- if (ex) {
2549
- this.alertService.addServerFailure(ex);
2550
- this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, {
2551
- component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS,
2552
- result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2553
- url: this.CURRENT_LOCATION,
2554
- error: ex
2555
- });
2556
- }
2549
+ else {
2550
+ this.packageAvailability = this.package.availability;
2557
2551
  }
2558
- finally {
2559
- this.isLoading = false;
2552
+ this.isChangingAvailability = false;
2553
+ }
2554
+ async loadData(pckg) {
2555
+ this.package = pckg
2556
+ ? pckg
2557
+ : this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
2558
+ this.packageAvailability = this.package.availability;
2559
+ this.packageContentState = this.ecosystemService.getPackageContentState(this.package);
2560
+ this.packageType = this.pluginService.getPackageType(this.package);
2561
+ this.name = this.package?.name;
2562
+ this.description = this.package?.manifest?.description;
2563
+ this.markdown = await this.getReadmeFileContent();
2564
+ this.baseUrl = this.getBaseUrl();
2565
+ this.appState = this.ecosystemService.getAppState(this.package);
2566
+ this.isPackageBlueprint = this.ecosystemService.isPackageBlueprint(this.package);
2567
+ this.isOwnedByCurrentTenant =
2568
+ this.package?.owner?.tenant?.id === this.ui.currentTenant.value?.name;
2569
+ this.extractPackageMFExports();
2570
+ }
2571
+ extractPackageMFExports() {
2572
+ const exports = this.pluginsService.getMFExports(this.package);
2573
+ this.exportedPlugins$.next(exports);
2574
+ }
2575
+ async getReadmeFileContent() {
2576
+ const readmeFile = await this.getReadmeFile();
2577
+ if (readmeFile.status === 200) {
2578
+ return await readmeFile.text();
2560
2579
  }
2580
+ return '';
2561
2581
  }
2562
- async cleanupOrphanedPlugins(plugins) {
2563
- const pluginIds = plugins.map(p => p.id);
2564
- await this.removePlugins(pluginIds);
2582
+ async getReadmeFile() {
2583
+ const baseUrl = this.getBaseUrl();
2584
+ let result;
2585
+ const options = {
2586
+ method: 'GET',
2587
+ headers: this.headers
2588
+ };
2589
+ result = await this.client.fetch(`${baseUrl}README.md`, options);
2590
+ if (result && result.status === this.NOT_FOUND_ERROR_CODE) {
2591
+ result = await this.client.fetch(`${baseUrl}readme.md`, options);
2592
+ }
2593
+ return result;
2565
2594
  }
2566
- getActionControls() {
2567
- return [
2568
- {
2569
- type: 'customUpdate',
2570
- text: gettext('Update'),
2571
- icon: 'caret-square-o-up',
2572
- showIf: plugin => {
2573
- return (plugin.status === ApplicationPluginStatus.OUTDATED ||
2574
- plugin.status === ApplicationPluginStatus.REVOKED);
2575
- },
2576
- callback: plugin => this.updatePlugin(this.app, plugin)
2577
- },
2578
- {
2579
- type: 'customDowngrade',
2580
- text: gettext('Downgrade'),
2581
- icon: 'caret-square-o-down',
2582
- showIf: (plugin) => {
2583
- if (plugin.scope === PluginsExportScopes.SELF ||
2584
- plugin.scope === PluginsExportScopes.SELF_OPTIONAL) {
2585
- return false;
2586
- }
2587
- return plugin.status === ApplicationPluginStatus.LATEST;
2588
- },
2589
- callback: plugin => this.updatePlugin(this.app, plugin, true)
2590
- }
2591
- ];
2595
+ getBaseUrl() {
2596
+ return `/apps/${this.package.contextPath}/`;
2592
2597
  }
2593
- getBulkActionControls() {
2594
- return [
2595
- {
2596
- type: 'customDelete',
2597
- text: gettext('Remove'),
2598
- icon: 'trash',
2599
- callback: plugins => this.removePlugins(plugins)
2600
- }
2598
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageDetailsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i4.FetchClient }, { token: i2.WizardModalService }, { token: i1.EcosystemService }, { token: i2.ContextRouteService }, { token: i2.PluginsService }, { token: i1.PackageAvailabilityService }, { token: i2.AppStateService }, { token: i2.PluginsService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
2599
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageDetailsComponent, selector: "c8y-package-details", ngImport: i0, template: "<c8y-title>{{ name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Extension package' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n placement=\"right\"\n itemClass=\"navbar-form\"\n *ngIf=\"isOwnedByCurrentTenant && isAllowedToCreateSubtenants\"\n>\n <div class=\"form-horizontal\">\n <div class=\"form-group\">\n <label\n for=\"availability\"\n translate\n >\n Availability`of package based on app state`\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"availability\"\n [(ngModel)]=\"packageAvailability\"\n [disabled]=\"isChangingAvailability\"\n (ngModelChange)=\"togglePackageAvailability(package, $event)\"\n >\n <option\n *ngFor=\"let availability of packageAvailabilityService.availabilities\"\n [ngValue]=\"availability.value\"\n >\n {{ availability.label | translate }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-grid grid__col--8-4--md grid__row--fit-auto\">\n <div class=\"bg-level-1 grid__col--fullspan separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <button\n class=\"card__ribbon btn-clean\"\n [attr.aria-label]=\"\n (package.label || package.manifest.label | translatePackageLabel) +\n ': ' +\n (packageTypeLabels[packageType].tooltip | translate)\n \"\n tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n placement=\"bottom\"\n type=\"button\"\n *ngIf=\"packageType !== PACKAGE_TYPE.CUSTOM\"\n [delay]=\"500\"\n >\n <span\n [ngClass]=\"{\n 'bg-info': packageType === PACKAGE_TYPE.COMMUNITY,\n 'bg-primary': packageType === PACKAGE_TYPE.OFFICIAL,\n 'bg-warning': packageType === PACKAGE_TYPE.ARCHIVED\n }\"\n >\n {{ package.label || package.manifest.label | translatePackageLabel }}\n </span>\n </button>\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n c8yIcon=\"big-parcel\"\n ></i>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (appState?.label | translate) + ': ' + (appState?.tooltip | translate)\n \"\n [tooltip]=\"appState?.tooltip | translate\"\n placement=\"top\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n </button>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (packageContentState?.label | translate) +\n ': ' +\n (packageContentState?.tooltip | translate)\n \"\n [tooltip]=\"packageContentState?.tooltip | translate\"\n placement=\"bottom\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"packageContentState?.class\"\n >\n {{ packageContentState?.label | translate }}\n </span>\n </button>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-5\">\n <div class=\"card-title text-bold m-b-8\">{{ name | humanizeAppName | async }}</div>\n <p *ngIf=\"description\">{{ description }}</p>\n <p\n class=\"text-muted\"\n *ngIf=\"!description\"\n >\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n </div>\n <div\n class=\"col-3 text-right-md p-r-md-40\"\n *ngIf=\"isPackageBlueprint\"\n >\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"deploy()\"\n data-cy=\"c8y-package-details--deploy-application-button\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"output\"\n ></i>\n {{ 'Deploy application' | translate }}\n </button>\n </div>\n <div class=\"flex-grow\">\n <c8y-properties-list\n [data]=\"package.manifest\"\n [properties]=\"packageProperties\"\n ></c8y-properties-list>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Extension package overview' | translate }}</div>\n </div>\n <div class=\"card-block p-l-16 p-r-16\">\n <div\n class=\"alert alert-warning m-b-16\"\n style=\"margin: auto\"\n *ngIf=\"packageType === PACKAGE_TYPE.ARCHIVED\"\n translate\n >\n The package was archived by the owner marking it as out of maintenance. It is not\n recommended to install the package.\n </div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found' | translate\"\n [subtitle]=\"\n 'To view the contents of &quot;README&quot;, add the file &quot;README.md&quot; to the package.'\n | translate\n \"\n *ngIf=\"!markdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <div\n class=\"markdown-content\"\n [innerHTML]=\"markdown | markdownToHtml: { baseUrl } | async\"\n ></div>\n </div>\n <div class=\"separator-bottom visible-sm visible-xs\"></div>\n </div>\n\n <div class=\"inner-scroll d-flex d-col\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Package plugins' | translate }}</div>\n </div>\n <div class=\"border-left flex-grow\">\n <!-- empty state -->\n <div\n class=\"p-16\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n >\n <c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [installable]=\"true\"\n [package]=\"package\"\n ></c8y-plugin-list>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "directive", type: i9.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: i2.MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: i1.TranslatePackageLabelPipe, name: "translatePackageLabel" }] }); }
2600
+ }
2601
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageDetailsComponent, decorators: [{
2602
+ type: Component,
2603
+ args: [{ selector: 'c8y-package-details', template: "<c8y-title>{{ name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Extension package' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n placement=\"right\"\n itemClass=\"navbar-form\"\n *ngIf=\"isOwnedByCurrentTenant && isAllowedToCreateSubtenants\"\n>\n <div class=\"form-horizontal\">\n <div class=\"form-group\">\n <label\n for=\"availability\"\n translate\n >\n Availability`of package based on app state`\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"availability\"\n [(ngModel)]=\"packageAvailability\"\n [disabled]=\"isChangingAvailability\"\n (ngModelChange)=\"togglePackageAvailability(package, $event)\"\n >\n <option\n *ngFor=\"let availability of packageAvailabilityService.availabilities\"\n [ngValue]=\"availability.value\"\n >\n {{ availability.label | translate }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-grid grid__col--8-4--md grid__row--fit-auto\">\n <div class=\"bg-level-1 grid__col--fullspan separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <button\n class=\"card__ribbon btn-clean\"\n [attr.aria-label]=\"\n (package.label || package.manifest.label | translatePackageLabel) +\n ': ' +\n (packageTypeLabels[packageType].tooltip | translate)\n \"\n tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n placement=\"bottom\"\n type=\"button\"\n *ngIf=\"packageType !== PACKAGE_TYPE.CUSTOM\"\n [delay]=\"500\"\n >\n <span\n [ngClass]=\"{\n 'bg-info': packageType === PACKAGE_TYPE.COMMUNITY,\n 'bg-primary': packageType === PACKAGE_TYPE.OFFICIAL,\n 'bg-warning': packageType === PACKAGE_TYPE.ARCHIVED\n }\"\n >\n {{ package.label || package.manifest.label | translatePackageLabel }}\n </span>\n </button>\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n c8yIcon=\"big-parcel\"\n ></i>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (appState?.label | translate) + ': ' + (appState?.tooltip | translate)\n \"\n [tooltip]=\"appState?.tooltip | translate\"\n placement=\"top\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n </button>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (packageContentState?.label | translate) +\n ': ' +\n (packageContentState?.tooltip | translate)\n \"\n [tooltip]=\"packageContentState?.tooltip | translate\"\n placement=\"bottom\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"packageContentState?.class\"\n >\n {{ packageContentState?.label | translate }}\n </span>\n </button>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-5\">\n <div class=\"card-title text-bold m-b-8\">{{ name | humanizeAppName | async }}</div>\n <p *ngIf=\"description\">{{ description }}</p>\n <p\n class=\"text-muted\"\n *ngIf=\"!description\"\n >\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n </div>\n <div\n class=\"col-3 text-right-md p-r-md-40\"\n *ngIf=\"isPackageBlueprint\"\n >\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"deploy()\"\n data-cy=\"c8y-package-details--deploy-application-button\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"output\"\n ></i>\n {{ 'Deploy application' | translate }}\n </button>\n </div>\n <div class=\"flex-grow\">\n <c8y-properties-list\n [data]=\"package.manifest\"\n [properties]=\"packageProperties\"\n ></c8y-properties-list>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Extension package overview' | translate }}</div>\n </div>\n <div class=\"card-block p-l-16 p-r-16\">\n <div\n class=\"alert alert-warning m-b-16\"\n style=\"margin: auto\"\n *ngIf=\"packageType === PACKAGE_TYPE.ARCHIVED\"\n translate\n >\n The package was archived by the owner marking it as out of maintenance. It is not\n recommended to install the package.\n </div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found' | translate\"\n [subtitle]=\"\n 'To view the contents of &quot;README&quot;, add the file &quot;README.md&quot; to the package.'\n | translate\n \"\n *ngIf=\"!markdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <div\n class=\"markdown-content\"\n [innerHTML]=\"markdown | markdownToHtml: { baseUrl } | async\"\n ></div>\n </div>\n <div class=\"separator-bottom visible-sm visible-xs\"></div>\n </div>\n\n <div class=\"inner-scroll d-flex d-col\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Package plugins' | translate }}</div>\n </div>\n <div class=\"border-left flex-grow\">\n <!-- empty state -->\n <div\n class=\"p-16\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n >\n <c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [installable]=\"true\"\n [package]=\"package\"\n ></c8y-plugin-list>\n </div>\n </div>\n</div>\n" }]
2604
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i4.FetchClient }, { type: i2.WizardModalService }, { type: i1.EcosystemService }, { type: i2.ContextRouteService }, { type: i2.PluginsService }, { type: i1.PackageAvailabilityService }, { type: i2.AppStateService }, { type: i2.PluginsService }, { type: i2.GainsightService }] });
2605
+
2606
+ class PackagesListComponent {
2607
+ constructor(ecosystemService, wizardModalService, permissions) {
2608
+ this.ecosystemService = ecosystemService;
2609
+ this.wizardModalService = wizardModalService;
2610
+ this.permissions = permissions;
2611
+ this.reloading = false;
2612
+ this.reload$ = new BehaviorSubject(null);
2613
+ this.hasAdminPermissions = false;
2614
+ this.emptyStateSubtitle = gettext('Add your first package by clicking below.');
2615
+ this.packageTypes = defaultPackageTypes;
2616
+ this.packageAvailabilities = [
2617
+ APP_STATE.SUBSCRIBED.label,
2618
+ APP_STATE.CUSTOM.label
2601
2619
  ];
2620
+ this.packageContents = defaultPackageContents;
2621
+ this.destroy$ = new Subject();
2622
+ this.packages$ = this.reload$.pipe(takeUntil(this.destroy$), tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getPackageApplications()), tap(packages => {
2623
+ packages.forEach(pckg => {
2624
+ pckg.filterProps = this.ecosystemService.getAppFilterProps(pckg);
2625
+ });
2626
+ }), tap(() => (this.reloading = false)), shareReplay(1));
2602
2627
  }
2603
- async updatePlugin(app, plugin, downgrade = false) {
2604
- try {
2605
- await this.bsModalService.show(UpdatePluginOfAppComponent, {
2606
- class: 'modal-sm',
2607
- ariaDescribedby: 'modal-body',
2608
- ariaLabelledBy: 'modal-title',
2609
- initialState: {
2610
- app,
2611
- plugin,
2612
- downgrade
2613
- },
2614
- ignoreBackdropClick: true
2615
- }).content.result;
2616
- this.refresh();
2617
- }
2618
- catch (er) {
2619
- return;
2620
- }
2628
+ ngOnInit() {
2629
+ this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
2630
+ this.loadPackages();
2631
+ }
2632
+ loadPackages() {
2633
+ this.reload$.next();
2634
+ }
2635
+ addPackage() {
2636
+ const initialState = {
2637
+ id: EcosystemWizards.PACKAGE_UPLOAD
2638
+ };
2639
+ const modalOptions = { initialState };
2640
+ const modalRef = this.wizardModalService.show(modalOptions);
2641
+ modalRef.content.onClose.subscribe(() => {
2642
+ this.loadPackages();
2643
+ });
2644
+ }
2645
+ ngOnDestroy() {
2646
+ this.destroy$.next(true);
2647
+ this.destroy$.complete();
2648
+ }
2649
+ setFilterPipe(pipe) {
2650
+ this.filteredPackages$ = this.packages$.pipe(src => pipe(src));
2621
2651
  }
2622
- refresh() {
2623
- this.loadData();
2652
+ resetFilters() {
2653
+ this.filtersComponent?.resetAllFilters();
2624
2654
  }
2625
- ngOnDestroy() {
2626
- this.destroy$.next();
2627
- this.destroy$.complete();
2655
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackagesListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }, { token: i2.Permissions }], target: i0.ɵɵFactoryTarget.Component }); }
2656
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackagesListComponent, selector: "c8y-packages-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Extensions' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [path]=\"'ecosystem/extension/extensions'\"\n [label]=\"'Extensions' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"hasAdminPermissions\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n data-cy=\"packages-list--add-extension-package\"\n (click)=\"addPackage()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add extension package' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadPackages()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"p-r-8 p-l-8\"\n>\n <c8y-list-filters\n *ngIf=\"packages$ | async\"\n [packageTypes]=\"packageTypes\"\n [packageAvailabilities]=\"packageAvailabilities\"\n [packageContents]=\"packageContents\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n >\n <c8y-archived-filter></c8y-archived-filter>\n </c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(packages$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#extensions\"></c8y-help>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex m-b-8\"\n *ngIf=\"(filteredPackages$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Package' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredPackages$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadPackages()\"\n (onAppCloned)=\"loadPackages()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extensions to display.' | translate\"\n [subtitle]=\"hasAdminPermissions ? (emptyStateSubtitle | translate) : ''\"\n *ngIf=\"(packages$ | async)?.length === 0\"\n>\n <div *ngIf=\"hasAdminPermissions\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n (click)=\"addPackage()\"\n >\n {{ 'Add extension package' | translate }}\n </button>\n </div>\n</c8y-ui-empty-state>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching extensions.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(packages$ | async)?.length > 0 && (filteredPackages$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i1.ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: i1.ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "component", type: i1.ArchivedFilterComponent, selector: "c8y-archived-filter" }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
2657
+ }
2658
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackagesListComponent, decorators: [{
2659
+ type: Component,
2660
+ args: [{ selector: 'c8y-packages-list', template: "<c8y-title>{{ 'Extensions' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [path]=\"'ecosystem/extension/extensions'\"\n [label]=\"'Extensions' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"hasAdminPermissions\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n data-cy=\"packages-list--add-extension-package\"\n (click)=\"addPackage()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add extension package' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadPackages()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"p-r-8 p-l-8\"\n>\n <c8y-list-filters\n *ngIf=\"packages$ | async\"\n [packageTypes]=\"packageTypes\"\n [packageAvailabilities]=\"packageAvailabilities\"\n [packageContents]=\"packageContents\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n >\n <c8y-archived-filter></c8y-archived-filter>\n </c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(packages$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#extensions\"></c8y-help>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex m-b-8\"\n *ngIf=\"(filteredPackages$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Package' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredPackages$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadPackages()\"\n (onAppCloned)=\"loadPackages()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extensions to display.' | translate\"\n [subtitle]=\"hasAdminPermissions ? (emptyStateSubtitle | translate) : ''\"\n *ngIf=\"(packages$ | async)?.length === 0\"\n>\n <div *ngIf=\"hasAdminPermissions\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n (click)=\"addPackage()\"\n >\n {{ 'Add extension package' | translate }}\n </button>\n </div>\n</c8y-ui-empty-state>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching extensions.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(packages$ | async)?.length > 0 && (filteredPackages$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
2661
+ }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }, { type: i2.Permissions }], propDecorators: { filtersComponent: [{
2662
+ type: ViewChild,
2663
+ args: [ListFiltersComponent]
2664
+ }] } });
2665
+
2666
+ class PackageVersionsGuard {
2667
+ canActivate(route) {
2668
+ const app = route.data.contextData || route.parent.data.contextData;
2669
+ return !!app?.applicationVersions?.length;
2628
2670
  }
2629
- addInstallButtonToHeaderActionControls() {
2630
- if (this.appId) {
2631
- this.headerActionControls = [
2632
- {
2633
- text: gettext('Install plugins'),
2634
- callback: () => {
2635
- this.installPlugins();
2636
- },
2637
- icon: 'plus-circle',
2638
- type: 'custom'
2639
- }
2640
- ];
2641
- }
2671
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2672
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsGuard }); }
2673
+ }
2674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsGuard, decorators: [{
2675
+ type: Injectable
2676
+ }] });
2677
+
2678
+ class PackageVersionsAppsComponent {
2679
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsAppsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2680
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsAppsComponent, selector: "c8y-contents-apps", inputs: { selectedVersionManifest: "selectedVersionManifest" }, ngImport: i0, template: "<p class=\"legend form-block\">\n {{ 'Application' | translate }}\n</p>\n\n<div *ngIf=\"selectedVersionManifest?.name; else emptyApp\">\n <c8y-li>\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <h5 class=\"text-medium text-16 p-b-8\">\n {{ selectedVersionManifest?.name | humanizeAppName | async }}\n <small class=\"m-l-8\" *ngIf=\"selectedVersionManifest?.requiredPlatformVersion\">\n <em>{{ selectedVersionManifest?.requiredPlatformVersion }}</em>\n </small>\n </h5>\n <p *ngIf=\"selectedVersionManifest?.description; else notAvailable\">\n {{ selectedVersionManifest?.description }}\n </p>\n </c8y-li>\n</div>\n\n<ng-template #notAvailable>\n <p class=\"text-muted\">\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n</ng-template>\n\n<ng-template #emptyApp>\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No application.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain an application.' | translate\"\n ></c8y-ui-empty-state>\n</ng-template>", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
2681
+ }
2682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsAppsComponent, decorators: [{
2683
+ type: Component,
2684
+ args: [{ selector: 'c8y-contents-apps', template: "<p class=\"legend form-block\">\n {{ 'Application' | translate }}\n</p>\n\n<div *ngIf=\"selectedVersionManifest?.name; else emptyApp\">\n <c8y-li>\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <h5 class=\"text-medium text-16 p-b-8\">\n {{ selectedVersionManifest?.name | humanizeAppName | async }}\n <small class=\"m-l-8\" *ngIf=\"selectedVersionManifest?.requiredPlatformVersion\">\n <em>{{ selectedVersionManifest?.requiredPlatformVersion }}</em>\n </small>\n </h5>\n <p *ngIf=\"selectedVersionManifest?.description; else notAvailable\">\n {{ selectedVersionManifest?.description }}\n </p>\n </c8y-li>\n</div>\n\n<ng-template #notAvailable>\n <p class=\"text-muted\">\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n</ng-template>\n\n<ng-template #emptyApp>\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No application.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain an application.' | translate\"\n ></c8y-ui-empty-state>\n</ng-template>" }]
2685
+ }], propDecorators: { selectedVersionManifest: [{
2686
+ type: Input,
2687
+ args: ['selectedVersionManifest']
2688
+ }] } });
2689
+
2690
+ class PackageVersionsPluginsComponent {
2691
+ constructor() {
2692
+ this.exportedPlugins$ = new BehaviorSubject([]);
2642
2693
  }
2643
- async handleRemotesInstallation(plugins) {
2644
- const updatedRemotes = await this.pluginsService.addRemotes(this.app, plugins);
2645
- return this.emitRemotes(updatedRemotes);
2694
+ async ngOnChanges() {
2695
+ this.exportedPlugins$.next(this.getExportedPlugins());
2646
2696
  }
2647
- emitRemotes(pluginsConfig) {
2648
- const { remotes, excludedRemotes } = pluginsConfig;
2649
- // needed for first time adding/removing a plugin
2650
- if (!this.app.config) {
2651
- this.app.config = {};
2652
- }
2653
- this.app.config.remotes = remotes;
2654
- this.app.config.excludedRemotes = excludedRemotes;
2655
- const actualRemotes = this.pluginsService.getMFRemotes(this.app);
2656
- this.remotePlugins$.next(actualRemotes);
2657
- return { ...this.remotePlugins$.value };
2697
+ getExportedPlugins() {
2698
+ return this.selectedVersionManifest?.exports || [];
2658
2699
  }
2659
- async getApplicationMO() {
2660
- let id = this.appId;
2661
- if (!id) {
2662
- const { id: routeId } = this.activatedRoute.snapshot.parent.data.contextData;
2663
- id = routeId;
2700
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsPluginsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2701
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsPluginsComponent, selector: "c8y-contents-plugins", inputs: { selectedVersionManifest: "selectedVersionManifest" }, usesOnChanges: true, ngImport: i0, template: "<p class=\"legend form-block\">\n {{ 'Plugins' | translate }}\n</p>\n<!-- empty state -->\n<c8y-ui-empty-state\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n [icon]=\"'plugin'\"\n [horizontal]=\"true\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n></c8y-ui-empty-state>\n\n<c8y-plugin-list [plugins$]=\"exportedPlugins$\" [selectable]=\"false\"></c8y-plugin-list>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
2702
+ }
2703
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsPluginsComponent, decorators: [{
2704
+ type: Component,
2705
+ args: [{ selector: 'c8y-contents-plugins', template: "<p class=\"legend form-block\">\n {{ 'Plugins' | translate }}\n</p>\n<!-- empty state -->\n<c8y-ui-empty-state\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n [icon]=\"'plugin'\"\n [horizontal]=\"true\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n></c8y-ui-empty-state>\n\n<c8y-plugin-list [plugins$]=\"exportedPlugins$\" [selectable]=\"false\"></c8y-plugin-list>\n" }]
2706
+ }], propDecorators: { selectedVersionManifest: [{
2707
+ type: Input,
2708
+ args: ['selectedVersionManifest']
2709
+ }] } });
2710
+
2711
+ class PackageContentsComponent {
2712
+ constructor(activatedRoute, applicationService, alertService, contextRouteService) {
2713
+ this.activatedRoute = activatedRoute;
2714
+ this.applicationService = applicationService;
2715
+ this.alertService = alertService;
2716
+ this.contextRouteService = contextRouteService;
2717
+ this.package = {};
2718
+ this.isLoading = false;
2719
+ this.packageVersionProperties = packageProperties;
2720
+ }
2721
+ async ngOnChanges(changes) {
2722
+ if (changes.selectedVersion.currentValue) {
2723
+ this.loadManifest(this.selectedVersion);
2664
2724
  }
2725
+ this.selectedVersionManifest = undefined;
2726
+ }
2727
+ async loadManifest(version) {
2728
+ this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
2729
+ this.isLoading = true;
2730
+ this.selectedVersionManifest = await this.getManifest(version);
2731
+ this.isLoading = false;
2732
+ }
2733
+ async getManifest(version) {
2665
2734
  try {
2666
- this.app = await this.ecosystemService.getApplication(id);
2735
+ return await this.applicationService.getAppManifest(this.package, version);
2667
2736
  }
2668
- catch (er) {
2669
- if (er) {
2670
- this.alertService.addServerFailure(er);
2671
- }
2737
+ catch (error) {
2738
+ this.alertService.addServerFailure(error);
2672
2739
  }
2673
- return this.app;
2740
+ return undefined;
2674
2741
  }
2675
- async getApplicationMFExports(app) {
2676
- const exports = this.pluginsService.getMFExports(app, [], true);
2677
- return exports;
2742
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageContentsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
2743
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageContentsComponent, selector: "c8y-package-contents", inputs: { selectedVersion: "selectedVersion" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"inner-scroll\">\n <ng-container *ngIf=\"!selectedVersionManifest && !isLoading\">\n <div class=\"p-16\">\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No package selected' | translate\"\n [subtitle]=\"'Select a package from the list to display the package contents.' | translate\"\n ></c8y-ui-empty-state>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-container *ngIf=\"selectedVersionManifest && !isLoading\">\n <!-- DETAILS -->\n <div class=\"card-block p-t-0\">\n <c8y-properties-list\n [data]=\"selectedVersionManifest\"\n [emptyLabel]=\"'--'\"\n [properties]=\"packageVersionProperties\"\n >\n </c8y-properties-list>\n \n <!-- APPS -->\n <c8y-contents-apps\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-apps>\n\n <!-- PLUGINS -->\n <c8y-contents-plugins\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-plugins>\n </div>\n </ng-container>\n</div>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i2.PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "component", type: PackageVersionsPluginsComponent, selector: "c8y-contents-plugins", inputs: ["selectedVersionManifest"] }, { kind: "component", type: PackageVersionsAppsComponent, selector: "c8y-contents-apps", inputs: ["selectedVersionManifest"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
2744
+ }
2745
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageContentsComponent, decorators: [{
2746
+ type: Component,
2747
+ args: [{ selector: 'c8y-package-contents', template: "<div class=\"inner-scroll\">\n <ng-container *ngIf=\"!selectedVersionManifest && !isLoading\">\n <div class=\"p-16\">\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No package selected' | translate\"\n [subtitle]=\"'Select a package from the list to display the package contents.' | translate\"\n ></c8y-ui-empty-state>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-container *ngIf=\"selectedVersionManifest && !isLoading\">\n <!-- DETAILS -->\n <div class=\"card-block p-t-0\">\n <c8y-properties-list\n [data]=\"selectedVersionManifest\"\n [emptyLabel]=\"'--'\"\n [properties]=\"packageVersionProperties\"\n >\n </c8y-properties-list>\n \n <!-- APPS -->\n <c8y-contents-apps\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-apps>\n\n <!-- PLUGINS -->\n <c8y-contents-plugins\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-plugins>\n </div>\n </ng-container>\n</div>\n" }]
2748
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i2.ContextRouteService }], propDecorators: { selectedVersion: [{
2749
+ type: Input
2750
+ }] } });
2751
+
2752
+ const DEFAULT_VERSIONS_LIMIT = 20;
2753
+ class PackageVersionsListComponent {
2754
+ constructor(activatedRoute, pluginsService, ecosystemService, translateService, modal, alertService, optionsService, permissions, gainsightService) {
2755
+ this.activatedRoute = activatedRoute;
2756
+ this.pluginsService = pluginsService;
2757
+ this.ecosystemService = ecosystemService;
2758
+ this.translateService = translateService;
2759
+ this.modal = modal;
2760
+ this.alertService = alertService;
2761
+ this.optionsService = optionsService;
2762
+ this.permissions = permissions;
2763
+ this.gainsightService = gainsightService;
2764
+ this.CURRENT_LOCATION = location.href;
2765
+ this.isLoading = false;
2766
+ this.hasAdminPermissions = false;
2767
+ this.isPackageOwnedByCurrentTenant = false;
2768
+ this.onVersionSelect = new EventEmitter();
2678
2769
  }
2679
- async getApplicationMFRemotes(app) {
2680
- const appConfigRemotes = this.pluginsService.getMFRemotes(app);
2681
- this.remotePlugins$.next(appConfigRemotes || {});
2770
+ async ngOnInit() {
2771
+ this.isLoading = true;
2772
+ this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
2773
+ this.package = this.activatedRoute?.snapshot?.parent?.data?.contextData;
2774
+ this.isPackageOwnedByCurrentTenant = this.ecosystemService.isOwner(this.package);
2775
+ this.versionsLimit = (await this.optionsService.getSystemOption('application', 'versions.limit', DEFAULT_VERSIONS_LIMIT));
2776
+ this.sortVersions();
2777
+ this.isLoading = false;
2682
2778
  }
2683
- async getAllApplicationsMFExports(app) {
2684
- const exportedByCurrentApp = await this.getApplicationMFExports(app);
2685
- const allAppsMFExports = await this.pluginsService.getAllMFExports(true);
2686
- this.allAvailablePlugins$.next([...allAppsMFExports, ...exportedByCurrentApp]);
2779
+ async downloadArchive(appVersion) {
2780
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2781
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2782
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DOWNLOAD,
2783
+ url: this.CURRENT_LOCATION
2784
+ });
2785
+ const archiveMO = await this.ecosystemService.getArchiveManagedObject(appVersion.binaryId);
2786
+ await this.ecosystemService.downloadArchive(this.package, {
2787
+ id: appVersion.binaryId,
2788
+ name: archiveMO.name
2789
+ });
2687
2790
  }
2688
- async getAllSelfMFExports(app) {
2689
- const exportedByCurrentApp = await this.getApplicationMFExports(app);
2690
- this.selfPlugins$.next(exportedByCurrentApp.filter(({ scope }) => scope === 'self'));
2791
+ packageVersionUploaded() {
2792
+ this.activatedRoute.snapshot.parent.data.contextData = this.package;
2793
+ this.sortVersions();
2794
+ this.setUploadedVersionAsLatest();
2691
2795
  }
2692
- getInstallModalInitState() {
2693
- return {
2694
- plugins$: combineLatest([this.allAvailablePlugins$, this.installedPlugins$]).pipe(map(([allPlugins, installedPlugins]) => {
2695
- // to not mutate the original array and objects contained in it
2696
- const allPluginsAsNewObjects = allPlugins.map(p => ({ ...p }));
2697
- for (const plugin of installedPlugins) {
2698
- let installedPlugin = allPluginsAsNewObjects.find(p => p.id === plugin.id);
2699
- if (!installedPlugin && plugin.installedViaTag) {
2700
- installedPlugin = allPluginsAsNewObjects.find(p => p.contextPath === plugin.contextPath &&
2701
- p.module === plugin.module &&
2702
- p.tags?.includes(plugin.installedViaTag));
2703
- }
2704
- if (installedPlugin) {
2705
- installedPlugin.installed = true;
2706
- continue;
2707
- }
2708
- }
2709
- return allPluginsAsNewObjects.map(p => ({ ...p, installed: !!p.installed }));
2710
- }), shareReplay(1))
2711
- };
2796
+ selectVersion(version) {
2797
+ this.selectedVersion = version;
2798
+ this.onVersionSelect.emit(version);
2712
2799
  }
2713
- getOrphanedPlugins(orphanedPluginIds, allPlugins) {
2714
- const orphanedPlugins = orphanedPluginIds.map(p => this.extractDetails(p));
2715
- const orphanedPluginsUpdated = orphanedPlugins.map(p => {
2716
- const pluginWithMatchingTag = allPlugins.find(tmp => tmp.contextPath === p.contextPath &&
2717
- tmp.module === p.module &&
2718
- tmp.tags?.includes(p.version || 'latest'));
2719
- if (pluginWithMatchingTag) {
2720
- return {
2721
- ...pluginWithMatchingTag,
2722
- id: p.id,
2723
- status: ApplicationPluginStatus.AUTO,
2724
- installedViaTag: p.version || 'latest'
2725
- };
2726
- }
2727
- const pluginInDifferentVersion = allPlugins.find(tmp => tmp.contextPath === p.contextPath && tmp.module === p.module);
2728
- if (pluginInDifferentVersion) {
2729
- return {
2730
- ...pluginInDifferentVersion,
2731
- version: p.version,
2732
- id: p.id,
2733
- status: ApplicationPluginStatus.OUTDATED
2734
- };
2735
- }
2736
- return p;
2737
- });
2738
- return orphanedPluginsUpdated;
2800
+ async removeVersionPackage(version) {
2801
+ try {
2802
+ await this.ecosystemService.deletePackageVersion(this.package, { version });
2803
+ this.alertService.success(this.translateService.instant(gettext('Package version {{version}} has been removed'), {
2804
+ version
2805
+ }));
2806
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2807
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2808
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
2809
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
2810
+ url: this.CURRENT_LOCATION
2811
+ });
2812
+ }
2813
+ catch (e) {
2814
+ this.alertService.addServerFailure(e);
2815
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2816
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2817
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
2818
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2819
+ url: this.CURRENT_LOCATION
2820
+ });
2821
+ }
2822
+ if (version === this.selectedVersion) {
2823
+ this.selectVersion(null);
2824
+ }
2825
+ await this.refreshPackage();
2739
2826
  }
2740
- splitOrphanedPluginsIntoOrphanedAndRevokedPlugins(allPlugins, orphanedPlugins) {
2741
- const revokedPlugins = new Array();
2742
- const actuallyOrphanedPlugins = new Array();
2743
- for (const plugin of orphanedPlugins) {
2744
- const foundFamiliarPlugin = allPlugins.find(plugin1 => plugin.contextPath === plugin1.contextPath && plugin.module === plugin1.module);
2745
- if (foundFamiliarPlugin) {
2746
- revokedPlugins.push(Object.assign({}, foundFamiliarPlugin, plugin, {
2747
- status: ApplicationPluginStatus.REVOKED
2748
- }));
2749
- }
2750
- else {
2751
- actuallyOrphanedPlugins.push(plugin);
2752
- }
2827
+ async setVersionAsLatest(appVersion) {
2828
+ try {
2829
+ await this.ecosystemService.setPackageVersionTag(this.package, appVersion.version, [
2830
+ ...appVersion.tags,
2831
+ 'latest'
2832
+ ]);
2833
+ // TODO added it due to: https://cumulocity.atlassian.net/browse/MTM-48553
2834
+ // Remove it when BE fixes issues with activeVersion.
2835
+ await this.ecosystemService.setAppActiveVersion(this.package, appVersion.binaryId);
2836
+ this.alertService.success(gettext('Tag has been set.'));
2837
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2838
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2839
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_AS_LATEST,
2840
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
2841
+ url: this.CURRENT_LOCATION
2842
+ });
2753
2843
  }
2754
- return { revokedPlugins, actuallyOrphanedPlugins };
2844
+ catch (e) {
2845
+ this.alertService.addServerFailure(e);
2846
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2847
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2848
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_AS_LATEST,
2849
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
2850
+ url: this.CURRENT_LOCATION
2851
+ });
2852
+ return;
2853
+ }
2854
+ await this.refreshPackage();
2755
2855
  }
2756
- getInstalledPlugins(allPlugins, remotePlugins) {
2757
- const availablePlugins = allPlugins
2758
- .filter(plugin => remotePlugins.includes(plugin.id))
2759
- .map(plugin => Object.assign(plugin, {
2760
- status: plugin.tags?.includes('latest')
2761
- ? ApplicationPluginStatus.LATEST
2762
- : ApplicationPluginStatus.OUTDATED
2763
- }));
2764
- const orphanedPluginIds = remotePlugins.filter(r => !availablePlugins.find(plugin => plugin.id === r));
2765
- const orphanedPlugins = this.getOrphanedPlugins(orphanedPluginIds, allPlugins);
2766
- const notActuallyOrphanedPlugins = orphanedPlugins.filter(p => p.status === ApplicationPluginStatus.AUTO);
2767
- const orphanedOrRevokedPlugins = orphanedPlugins.filter(p => p.status !== ApplicationPluginStatus.AUTO);
2768
- const { actuallyOrphanedPlugins, revokedPlugins } = this.splitOrphanedPluginsIntoOrphanedAndRevokedPlugins(allPlugins, orphanedOrRevokedPlugins);
2769
- return [
2770
- ...availablePlugins,
2771
- ...notActuallyOrphanedPlugins,
2772
- ...revokedPlugins,
2773
- ...actuallyOrphanedPlugins
2774
- ];
2856
+ async acknowledgeLimitReached() {
2857
+ await this.modal.acknowledge(gettext('Package limit exceeded'), this.translateService.instant(gettext('You have reached the maximum number of {{ versionsLimit }} package versions. To add another version, first delete one from the list.'), { versionsLimit: this.versionsLimit }), Status.INFO, gettext('Close'));
2858
+ throw undefined;
2775
2859
  }
2776
- extractDetails(pluginId) {
2777
- const contextPath = this.getStringMatchingRegex(pluginId, /^[^@]*(@|\/)/);
2778
- const version = this.getStringMatchingRegex(pluginId, /@.*\//);
2779
- const module = this.getStringMatchingRegex(pluginId, /\/.*$/);
2780
- const unavailable = gettext('unavailable`plugin`');
2781
- return {
2782
- id: pluginId,
2783
- idLatest: `${contextPath}/${module}`,
2784
- path: '',
2785
- module,
2786
- name: module,
2787
- status: ApplicationPluginStatus.ORPHANED,
2788
- contextPath: contextPath,
2789
- description: unavailable,
2790
- version: version
2791
- };
2860
+ async refreshPackage() {
2861
+ this.isLoading = true;
2862
+ this.package = await this.ecosystemService.getApplication(this.package.id);
2863
+ this.activatedRoute.snapshot.parent.data.contextData = this.package;
2864
+ this.sortVersions();
2865
+ this.isLoading = false;
2792
2866
  }
2793
- getStringMatchingRegex(str, regex) {
2794
- const matches = str.match(regex);
2795
- const value = matches ? matches[0] : '';
2796
- return value.replace(/(@|\/)/g, '');
2867
+ sortVersions() {
2868
+ this.sortedVersions = this.pluginsService.sortVersions({
2869
+ list: this.package.applicationVersions,
2870
+ path: ['version']
2871
+ }, 'desc');
2872
+ this.toggleUploadPossibility();
2797
2873
  }
2798
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1.EcosystemService }, { token: i1$1.BsModalService }, { token: i2.PluginsService }, { token: i2.AlertService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
2799
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: ApplicationPluginsComponent, selector: "c8y-app-plugins", inputs: { appId: "appId" }, viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ app | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"app | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Plugins' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"!(isStandard$ | async)\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reset to default plugins' | translate }}\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n (click)=\"resetToDefault()\"\n >\n <i c8yIcon=\"undo\"></i>\n {{ 'Reset to default' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install plugins' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<ng-container *ngIf=\"orphanedPlugins$ | async as orphanedPlugins\">\n <c8y-action-bar-item\n *ngIf=\"orphanedPlugins?.length\"\n [placement]=\"'right'\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Clean up orphaned plugins' | translate }}\"\n (click)=\"cleanupOrphanedPlugins(orphanedPlugins)\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"erase\"></i>\n {{ 'Clean up orphaned plugins' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<div class=\"content-fullpage d-flex d-col border-top\">\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [rows]=\"installedPlugins$ | async\"\n [pagination]=\"pagination\"\n [selectable]=\"true\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n [headerActionControls]=\"headerActionControls\"\n (onReload)=\"refresh()\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'plugin'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n translate\n >\n Install plugins\n </button>\n </p>\n </c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
2874
+ async setUploadedVersionAsLatest() {
2875
+ const uploadedVersion = this.package.applicationVersions[this.package.applicationVersions.length - 1];
2876
+ try {
2877
+ this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
2878
+ component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
2879
+ action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.UPLOAD,
2880
+ result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
2881
+ url: this.CURRENT_LOCATION
2882
+ });
2883
+ await this.modal.confirm(gettext('Upload successful'), this.translateService.instant(gettext('Do you want to set version {{version}} as the latest? Deploying a new application will always use this version.'), { version: uploadedVersion.version }), Status.SUCCESS, {
2884
+ ok: gettext('Set as latest`version`'),
2885
+ cancel: gettext('Keep unchanged`version`')
2886
+ });
2887
+ }
2888
+ catch (e) {
2889
+ await this.refreshPackage();
2890
+ return;
2891
+ }
2892
+ await this.setVersionAsLatest(uploadedVersion);
2893
+ }
2894
+ toggleUploadPossibility() {
2895
+ this.preUploadCallback =
2896
+ this.sortedVersions.length < this.versionsLimit
2897
+ ? null
2898
+ : this.acknowledgeLimitReached.bind(this);
2899
+ }
2900
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsListComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.PluginsService }, { token: i1.EcosystemService }, { token: i4$1.TranslateService }, { token: i2.ModalService }, { token: i2.AlertService }, { token: i2.OptionsService }, { token: i2.Permissions }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
2901
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsListComponent, selector: "c8y-package-versions-list", outputs: { onVersionSelect: "onVersionSelect" }, ngImport: i0, template: "<div class=\"inner-scroll split-view__list\">\n <div class=\"card-header separator sticky-top bg-component\">\n <div class=\"card-title\" translate>Versions</div>\n </div>\n\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"p-16\" *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </div>\n <ul class=\"nav c8y-nav-stacked\" *ngIf=\"!isLoading\">\n <li\n class=\"c8y-stacked-item p-t-0 p-b-0 p-r-4\"\n [ngClass]=\"{ active: selectedVersion === applicationVersion.version }\"\n *ngFor=\"let applicationVersion of sortedVersions\"\n >\n <div\n class=\"flex-grow d-flex a-i-center gap-4 p-t-8 p-b-8\"\n (click)=\"selectVersion(applicationVersion.version)\"\n >\n <i c8yIcon=\"big-parcel\" class=\"icon-20\"></i>\n <span class=\"text-label-small\">\n {{ 'Version' | translate }}\n </span>\n <span class=\"text-medium\">{{ applicationVersion.version }}</span>\n <div class=\"text-truncate d-flex j-c-end flex-grow gap-4 flex-wrap m-l-auto\">\n <span *ngFor=\"let tag of applicationVersion.tags\" class=\"label label-info\">\n {{ tag }}\n </span>\n </div>\n </div>\n <div class=\"dropdown\" dropdown *ngIf=\"hasAdminPermissions && isPackageOwnedByCurrentTenant\">\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Settings' | translate }}\"\n dropdownToggle\n >\n <i c8yIcon=\"ellipsis-v\"></i>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu dropdown-menu-right\">\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Set as latest`version`' | translate }}\"\n (click)=\"setVersionAsLatest(applicationVersion)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"collect\" class=\"m-r-4\"></i>\n {{ 'Set as latest`version`' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Download' | translate }}\"\n (click)=\"downloadArchive(applicationVersion)\"\n >\n <i c8yIcon=\"download\" class=\"m-r-4\"></i>\n {{ 'Download' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"removeVersionPackage(applicationVersion.version)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"trash\" class=\"m-r-4\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </li>\n </ul>\n </div>\n\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"!isLoading && isPackageOwnedByCurrentTenant\"\n >\n <div class=\"form-group m-b-0\">\n <label translate>Upload a new version</label>\n <c8y-upload-archive\n [(application)]=\"package\"\n [uploadNewVersion]=\"true\"\n (refresh)=\"packageVersionUploaded()\"\n [preUploadCallback]=\"preUploadCallback\"\n ></c8y-upload-archive>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i6.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i6.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i6.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "component", type: i1.UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
2800
2902
  }
2801
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsComponent, decorators: [{
2903
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsListComponent, decorators: [{
2802
2904
  type: Component,
2803
- args: [{ selector: 'c8y-app-plugins', template: "<c8y-title>{{ app | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"app | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Plugins' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"!(isStandard$ | async)\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reset to default plugins' | translate }}\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n (click)=\"resetToDefault()\"\n >\n <i c8yIcon=\"undo\"></i>\n {{ 'Reset to default' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install plugins' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<ng-container *ngIf=\"orphanedPlugins$ | async as orphanedPlugins\">\n <c8y-action-bar-item\n *ngIf=\"orphanedPlugins?.length\"\n [placement]=\"'right'\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Clean up orphaned plugins' | translate }}\"\n (click)=\"cleanupOrphanedPlugins(orphanedPlugins)\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"erase\"></i>\n {{ 'Clean up orphaned plugins' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<div class=\"content-fullpage d-flex d-col border-top\">\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [rows]=\"installedPlugins$ | async\"\n [pagination]=\"pagination\"\n [selectable]=\"true\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n [headerActionControls]=\"headerActionControls\"\n (onReload)=\"refresh()\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'plugin'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n translate\n >\n Install plugins\n </button>\n </p>\n </c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n" }]
2804
- }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1.EcosystemService }, { type: i1$1.BsModalService }, { type: i2.PluginsService }, { type: i2.AlertService }, { type: i2.GainsightService }], propDecorators: { appId: [{
2805
- type: Input
2806
- }], dataGrid: [{
2807
- type: ViewChild,
2808
- args: [DataGridComponent, { static: false }]
2905
+ args: [{ selector: 'c8y-package-versions-list', template: "<div class=\"inner-scroll split-view__list\">\n <div class=\"card-header separator sticky-top bg-component\">\n <div class=\"card-title\" translate>Versions</div>\n </div>\n\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"p-16\" *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </div>\n <ul class=\"nav c8y-nav-stacked\" *ngIf=\"!isLoading\">\n <li\n class=\"c8y-stacked-item p-t-0 p-b-0 p-r-4\"\n [ngClass]=\"{ active: selectedVersion === applicationVersion.version }\"\n *ngFor=\"let applicationVersion of sortedVersions\"\n >\n <div\n class=\"flex-grow d-flex a-i-center gap-4 p-t-8 p-b-8\"\n (click)=\"selectVersion(applicationVersion.version)\"\n >\n <i c8yIcon=\"big-parcel\" class=\"icon-20\"></i>\n <span class=\"text-label-small\">\n {{ 'Version' | translate }}\n </span>\n <span class=\"text-medium\">{{ applicationVersion.version }}</span>\n <div class=\"text-truncate d-flex j-c-end flex-grow gap-4 flex-wrap m-l-auto\">\n <span *ngFor=\"let tag of applicationVersion.tags\" class=\"label label-info\">\n {{ tag }}\n </span>\n </div>\n </div>\n <div class=\"dropdown\" dropdown *ngIf=\"hasAdminPermissions && isPackageOwnedByCurrentTenant\">\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Settings' | translate }}\"\n dropdownToggle\n >\n <i c8yIcon=\"ellipsis-v\"></i>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu dropdown-menu-right\">\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Set as latest`version`' | translate }}\"\n (click)=\"setVersionAsLatest(applicationVersion)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"collect\" class=\"m-r-4\"></i>\n {{ 'Set as latest`version`' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Download' | translate }}\"\n (click)=\"downloadArchive(applicationVersion)\"\n >\n <i c8yIcon=\"download\" class=\"m-r-4\"></i>\n {{ 'Download' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"removeVersionPackage(applicationVersion.version)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"trash\" class=\"m-r-4\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </li>\n </ul>\n </div>\n\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"!isLoading && isPackageOwnedByCurrentTenant\"\n >\n <div class=\"form-group m-b-0\">\n <label translate>Upload a new version</label>\n <c8y-upload-archive\n [(application)]=\"package\"\n [uploadNewVersion]=\"true\"\n (refresh)=\"packageVersionUploaded()\"\n [preUploadCallback]=\"preUploadCallback\"\n ></c8y-upload-archive>\n </div>\n </div>\n</div>\n" }]
2906
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.PluginsService }, { type: i1.EcosystemService }, { type: i4$1.TranslateService }, { type: i2.ModalService }, { type: i2.AlertService }, { type: i2.OptionsService }, { type: i2.Permissions }, { type: i2.GainsightService }], propDecorators: { onVersionSelect: [{
2907
+ type: Output
2809
2908
  }] } });
2810
2909
 
2811
- class ApplicationPluginsGuard {
2910
+ class PackageVersionsComponent {
2911
+ constructor(activatedRoute, contextRouteService) {
2912
+ this.activatedRoute = activatedRoute;
2913
+ this.contextRouteService = contextRouteService;
2914
+ this.package = {};
2915
+ }
2916
+ async ngOnInit() {
2917
+ this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
2918
+ }
2919
+ clearSelectedVersion() {
2920
+ this.selectedVersion = null;
2921
+ }
2922
+ selectVersion(version) {
2923
+ this.selectedVersion = version;
2924
+ }
2925
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
2926
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: PackageVersionsComponent, selector: "c8y-package-versions", ngImport: i0, template: "<c8y-title>{{ package?.name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Versions' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"card content-fullpage split-view--5-7 grid__row--1\">\n <c8y-package-versions-list\n class=\"d-contents\"\n (onVersionSelect)=\"selectVersion($event)\"\n ></c8y-package-versions-list>\n\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedVersion }\"\n >\n <div class=\"large-padding card-header separator visible-sm visible-xs fit-w sticky-top\">\n <div class=\"d-flex a-i-center\">\n <button\n title=\"{{ 'Back' | translate }}\"\n class=\"btn btn-clean text-primary m-r-8\"\n (click)=\"clearSelectedVersion()\"\n >\n <i c8yIcon=\"chevron-left\"></i>\n <span translate>Back</span>\n </button>\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n </div>\n <div class=\"card-header large-padding separator sticky-top visible-md visible-lg\">\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <c8y-package-contents [selectedVersion]=\"selectedVersion\"></c8y-package-contents>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: PackageContentsComponent, selector: "c8y-package-contents", inputs: ["selectedVersion"] }, { kind: "component", type: PackageVersionsListComponent, selector: "c8y-package-versions-list", outputs: ["onVersionSelect"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
2927
+ }
2928
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageVersionsComponent, decorators: [{
2929
+ type: Component,
2930
+ args: [{ selector: 'c8y-package-versions', template: "<c8y-title>{{ package?.name | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Versions' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"card content-fullpage split-view--5-7 grid__row--1\">\n <c8y-package-versions-list\n class=\"d-contents\"\n (onVersionSelect)=\"selectVersion($event)\"\n ></c8y-package-versions-list>\n\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedVersion }\"\n >\n <div class=\"large-padding card-header separator visible-sm visible-xs fit-w sticky-top\">\n <div class=\"d-flex a-i-center\">\n <button\n title=\"{{ 'Back' | translate }}\"\n class=\"btn btn-clean text-primary m-r-8\"\n (click)=\"clearSelectedVersion()\"\n >\n <i c8yIcon=\"chevron-left\"></i>\n <span translate>Back</span>\n </button>\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n </div>\n <div class=\"card-header large-padding separator sticky-top visible-md visible-lg\">\n <div class=\"card-title\" translate>Package contents</div>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <c8y-package-contents [selectedVersion]=\"selectedVersion\"></c8y-package-contents>\n </div>\n </div>\n</div>\n" }]
2931
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.ContextRouteService }] });
2932
+
2933
+ class PackageGuard {
2812
2934
  constructor(ecosystemService) {
2813
2935
  this.ecosystemService = ecosystemService;
2814
2936
  }
@@ -2817,102 +2939,15 @@ class ApplicationPluginsGuard {
2817
2939
  if (!app) {
2818
2940
  return false;
2819
2941
  }
2820
- const manifest = app.manifest;
2821
- if (!manifest) {
2822
- return false;
2823
- }
2824
- return (app.type === ApplicationType.HOSTED &&
2825
- this.ecosystemService.isOwner(app) &&
2826
- !this.ecosystemService.isPackage(app) &&
2827
- // apps like e.g. the public-options should not have the plugins tab
2828
- !manifest.noAppSwitcher);
2942
+ return this.ecosystemService.isPackage(app);
2829
2943
  }
2830
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsGuard, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2831
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsGuard }); }
2944
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageGuard, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2945
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageGuard }); }
2832
2946
  }
2833
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsGuard, decorators: [{
2947
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: PackageGuard, decorators: [{
2834
2948
  type: Injectable
2835
2949
  }], ctorParameters: () => [{ type: i1.EcosystemService }] });
2836
2950
 
2837
- class ApplicationPluginsModule {
2838
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2839
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, declarations: [ApplicationPluginsComponent,
2840
- PluginListItemComponent,
2841
- InstallPluginComponent,
2842
- PluginListComponent,
2843
- AppsToUpdateRemotesSelectComponent,
2844
- AppStatePipe,
2845
- LabelCellRendererComponent,
2846
- OrphanedStatusCellRendererComponent,
2847
- UpdatePluginOfAppComponent,
2848
- OnlyLatestPluginVersionPipe], imports: [CoreModule, SharedEcosystemModule], exports: [ApplicationPluginsComponent,
2849
- PluginListItemComponent,
2850
- InstallPluginComponent,
2851
- PluginListComponent,
2852
- AppsToUpdateRemotesSelectComponent,
2853
- AppStatePipe,
2854
- LabelCellRendererComponent,
2855
- OrphanedStatusCellRendererComponent,
2856
- UpdatePluginOfAppComponent] }); }
2857
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, providers: [
2858
- ApplicationPluginsGuard,
2859
- hookRoute([
2860
- {
2861
- path: 'plugins',
2862
- component: ApplicationPluginsComponent,
2863
- icon: 'plugin',
2864
- label: gettext('Plugins'),
2865
- context: ViewContext.Application,
2866
- priority: 3,
2867
- canActivate: [ApplicationPluginsGuard]
2868
- }
2869
- ])
2870
- ], imports: [CoreModule, SharedEcosystemModule] }); }
2871
- }
2872
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: ApplicationPluginsModule, decorators: [{
2873
- type: NgModule,
2874
- args: [{
2875
- imports: [CoreModule, SharedEcosystemModule],
2876
- declarations: [
2877
- ApplicationPluginsComponent,
2878
- PluginListItemComponent,
2879
- InstallPluginComponent,
2880
- PluginListComponent,
2881
- AppsToUpdateRemotesSelectComponent,
2882
- AppStatePipe,
2883
- LabelCellRendererComponent,
2884
- OrphanedStatusCellRendererComponent,
2885
- UpdatePluginOfAppComponent,
2886
- OnlyLatestPluginVersionPipe
2887
- ],
2888
- exports: [
2889
- ApplicationPluginsComponent,
2890
- PluginListItemComponent,
2891
- InstallPluginComponent,
2892
- PluginListComponent,
2893
- AppsToUpdateRemotesSelectComponent,
2894
- AppStatePipe,
2895
- LabelCellRendererComponent,
2896
- OrphanedStatusCellRendererComponent,
2897
- UpdatePluginOfAppComponent
2898
- ],
2899
- providers: [
2900
- ApplicationPluginsGuard,
2901
- hookRoute([
2902
- {
2903
- path: 'plugins',
2904
- component: ApplicationPluginsComponent,
2905
- icon: 'plugin',
2906
- label: gettext('Plugins'),
2907
- context: ViewContext.Application,
2908
- priority: 3,
2909
- canActivate: [ApplicationPluginsGuard]
2910
- }
2911
- ])
2912
- ]
2913
- }]
2914
- }] });
2915
-
2916
2951
  const ecosystemMainRoutes = [
2917
2952
  {
2918
2953
  path: 'ecosystem/application',
@@ -3028,7 +3063,8 @@ class EcosystemModule {
3028
3063
  SharedEcosystemModule,
3029
3064
  LicenseConfirmModule,
3030
3065
  IconSelectorModule,
3031
- A11yModule], exports: [ApplicationPropertiesComponent, UpdateApplicationModalComponent] }); }
3066
+ A11yModule,
3067
+ ArchivedConfirmModule], exports: [ApplicationPropertiesComponent, UpdateApplicationModalComponent] }); }
3032
3068
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: EcosystemModule, providers: [
3033
3069
  hookTab(EcosystemTabs),
3034
3070
  hookNavigator(EcosystemNavigationFactory),
@@ -3081,7 +3117,8 @@ class EcosystemModule {
3081
3117
  SharedEcosystemModule,
3082
3118
  LicenseConfirmModule,
3083
3119
  IconSelectorModule,
3084
- A11yModule] }); }
3120
+ A11yModule,
3121
+ ArchivedConfirmModule] }); }
3085
3122
  }
3086
3123
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: EcosystemModule, decorators: [{
3087
3124
  type: NgModule,
@@ -3120,7 +3157,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
3120
3157
  SharedEcosystemModule,
3121
3158
  LicenseConfirmModule,
3122
3159
  IconSelectorModule,
3123
- A11yModule
3160
+ A11yModule,
3161
+ ArchivedConfirmModule
3124
3162
  ],
3125
3163
  exports: [ApplicationPropertiesComponent, UpdateApplicationModalComponent],
3126
3164
  providers: [