@rancher/shell 3.0.8-rc.1 → 3.0.8-rc.12

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 (345) hide show
  1. package/assets/brand/suse/banner.svg +1 -0
  2. package/assets/brand/suse/dark/banner.svg +1 -0
  3. package/assets/brand/suse/dark/login-landscape.svg +1 -0
  4. package/assets/brand/suse/dark/rancher-logo.svg +1 -1
  5. package/assets/brand/suse/favicon.png +0 -0
  6. package/assets/brand/suse/login-landscape.svg +1 -0
  7. package/assets/brand/suse/metadata.json +11 -1
  8. package/assets/brand/suse/rancher-logo.svg +1 -1
  9. package/assets/fonts/suse/suse-v2-latin-300.woff +0 -0
  10. package/assets/fonts/suse/suse-v2-latin-300.woff2 +0 -0
  11. package/assets/fonts/suse/suse-v2-latin-600.woff +0 -0
  12. package/assets/fonts/suse/suse-v2-latin-600.woff2 +0 -0
  13. package/assets/fonts/suse/suse-v2-latin-700.woff +0 -0
  14. package/assets/fonts/suse/suse-v2-latin-700.woff2 +0 -0
  15. package/assets/fonts/suse/suse-v2-latin-800.woff +0 -0
  16. package/assets/fonts/suse/suse-v2-latin-800.woff2 +0 -0
  17. package/assets/fonts/suse/suse-v2-latin-regular.woff +0 -0
  18. package/assets/fonts/suse/suse-v2-latin-regular.woff2 +0 -0
  19. package/assets/images/content/README.md +5 -0
  20. package/assets/images/content/cloud-native.svg +84 -0
  21. package/assets/images/content/dark/cloud-native.svg +21 -0
  22. package/assets/images/content/dark/shield.svg +59 -0
  23. package/assets/images/content/dark/suse.svg +10 -0
  24. package/assets/images/content/shield.svg +59 -0
  25. package/assets/images/content/suse.svg +10 -0
  26. package/assets/styles/base/_typography.scss +1 -0
  27. package/assets/styles/fonts/_fontstack.scss +53 -1
  28. package/assets/styles/global/_cards.scss +0 -3
  29. package/assets/styles/global/_layout.scss +21 -35
  30. package/assets/styles/themes/_dark.scss +1 -1
  31. package/assets/styles/themes/_light.scss +1 -1
  32. package/assets/styles/themes/_modern.scss +11 -3
  33. package/assets/styles/themes/_suse.scss +116 -24
  34. package/assets/translations/en-us.yaml +94 -10
  35. package/components/AutoscalerCard.vue +113 -0
  36. package/components/AutoscalerTab.vue +94 -0
  37. package/components/BackLink.vue +8 -0
  38. package/components/BannerGraphic.vue +36 -21
  39. package/components/BrandImage.vue +17 -6
  40. package/components/ClusterIconMenu.vue +1 -1
  41. package/components/ClusterProviderIcon.vue +1 -1
  42. package/components/Cron/CronExpressionEditor.vue +1 -1
  43. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  44. package/components/Drawer/Chrome.vue +2 -6
  45. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
  46. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
  47. package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
  48. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
  49. package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
  50. package/components/Drawer/types.ts +3 -0
  51. package/components/DynamicContent/DynamicContentBanner.vue +102 -0
  52. package/components/DynamicContent/DynamicContentCloseButton.vue +42 -0
  53. package/components/DynamicContent/DynamicContentIcon.vue +132 -0
  54. package/components/DynamicContent/DynamicContentPanel.vue +112 -0
  55. package/components/DynamicContent/content.ts +78 -0
  56. package/components/EmberPage.vue +1 -1
  57. package/components/IconOrSvg.vue +2 -2
  58. package/components/PaginatedResourceTable.vue +2 -6
  59. package/components/PopoverCard.vue +192 -0
  60. package/components/Questions/__tests__/index.test.ts +159 -0
  61. package/components/Resource/Detail/CopyToClipboard.vue +4 -1
  62. package/components/Resource/Detail/FetchLoader/composables.ts +18 -4
  63. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  64. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +1 -1
  65. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +4 -0
  66. package/components/Resource/Detail/Metadata/KeyValueRow.vue +1 -1
  67. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  68. package/components/Resource/Detail/Metadata/composables.ts +9 -9
  69. package/components/Resource/Detail/Metadata/index.vue +3 -3
  70. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -19
  71. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +0 -29
  72. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +132 -150
  73. package/components/Resource/Detail/ResourcePopover/index.vue +54 -159
  74. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +0 -2
  75. package/components/Resource/Detail/TitleBar/composables.ts +2 -1
  76. package/components/Resource/Detail/TitleBar/index.vue +10 -6
  77. package/components/Resource/Detail/composables.ts +12 -0
  78. package/components/ResourceDetail/Masthead/latest.vue +29 -0
  79. package/components/ResourceDetail/index.vue +4 -1
  80. package/components/ResourceList/Masthead.vue +1 -1
  81. package/components/ResourceTable.vue +1 -1
  82. package/components/SortableTable/index.vue +2 -1
  83. package/components/Tabbed/__tests__/index.test.ts +86 -0
  84. package/components/{nav/WindowManager → Window}/ContainerLogs.vue +1 -1
  85. package/components/{nav/WindowManager → Window}/ContainerLogsActions.vue +1 -0
  86. package/components/{nav/WindowManager → Window}/__tests__/ContainerLogs.test.ts +1 -1
  87. package/components/{nav/WindowManager → Window}/__tests__/ContainerShell.test.ts +2 -2
  88. package/components/__tests__/AutoscalerCard.test.ts +154 -0
  89. package/components/__tests__/AutoscalerTab.test.ts +125 -0
  90. package/components/__tests__/PopoverCard.test.ts +204 -0
  91. package/components/auth/SelectPrincipal.vue +24 -6
  92. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  93. package/components/auth/login/ldap.vue +3 -3
  94. package/components/form/NodeScheduling.vue +2 -2
  95. package/components/formatter/Autoscaler.vue +97 -0
  96. package/components/formatter/InternalExternalIP.vue +198 -24
  97. package/components/formatter/__tests__/Autoscaler.test.ts +156 -0
  98. package/components/formatter/__tests__/InternalExternalIP.test.ts +133 -0
  99. package/components/google/util/__tests__/formatter.test.ts +47 -0
  100. package/components/google/util/formatter.ts +5 -2
  101. package/components/nav/Group.vue +21 -5
  102. package/components/nav/Header.vue +37 -17
  103. package/components/nav/NamespaceFilter.vue +13 -1
  104. package/components/nav/NotificationCenter/index.vue +2 -1
  105. package/components/nav/TopLevelMenu.helper.ts +16 -6
  106. package/components/nav/TopLevelMenu.vue +4 -2
  107. package/components/nav/Type.vue +8 -3
  108. package/components/{DraggableZone.vue → nav/WindowManager/PinArea.vue} +47 -80
  109. package/components/nav/WindowManager/composables/useComponentsMount.ts +70 -0
  110. package/components/nav/WindowManager/composables/useDimensionsHandler.ts +105 -0
  111. package/components/nav/WindowManager/composables/useDragHandler.ts +99 -0
  112. package/components/nav/WindowManager/composables/usePanelHandler.ts +72 -0
  113. package/components/nav/WindowManager/composables/usePanelsHandler.ts +14 -0
  114. package/components/nav/WindowManager/composables/useResizeHandler.ts +167 -0
  115. package/components/nav/WindowManager/composables/useTabsHandler.ts +51 -0
  116. package/components/nav/WindowManager/constants.ts +23 -0
  117. package/components/nav/WindowManager/index.vue +61 -575
  118. package/components/nav/WindowManager/panels/HorizontalPanel.vue +265 -0
  119. package/components/nav/WindowManager/panels/TabBodyContainer.vue +39 -0
  120. package/components/nav/WindowManager/panels/VerticalPanel.vue +308 -0
  121. package/components/nav/__tests__/Type.test.ts +59 -0
  122. package/components/templates/default.vue +4 -40
  123. package/components/templates/home.vue +31 -5
  124. package/components/templates/plain.vue +30 -4
  125. package/components/templates/standalone.vue +1 -1
  126. package/composables/useI18n.ts +10 -1
  127. package/composables/useInterval.ts +15 -0
  128. package/config/__test__/uiplugins.test.ts +309 -0
  129. package/config/labels-annotations.js +9 -1
  130. package/config/product/explorer.js +3 -1
  131. package/config/product/manager.js +20 -9
  132. package/config/router/navigation-guards/clusters.js +3 -3
  133. package/config/router/navigation-guards/products.js +1 -1
  134. package/config/router/routes.js +10 -2
  135. package/config/settings.ts +2 -1
  136. package/config/store.js +4 -2
  137. package/config/table-headers.js +8 -0
  138. package/config/types.js +9 -0
  139. package/config/uiplugins.js +46 -2
  140. package/config/version.js +1 -1
  141. package/core/__test__/extension-manager-impl.test.js +236 -0
  142. package/core/extension-manager-impl.js +21 -4
  143. package/core/plugin-helpers.ts +4 -2
  144. package/core/plugins-loader.js +2 -2
  145. package/core/types-provisioning.ts +8 -1
  146. package/detail/pod.vue +1 -0
  147. package/detail/provisioning.cattle.io.cluster.vue +19 -7
  148. package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
  149. package/dialog/RollbackWorkloadDialog.vue +2 -5
  150. package/dialog/SearchDialog.vue +1 -0
  151. package/directives/ui-context.ts +103 -0
  152. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
  153. package/edit/auth/__tests__/oidc.test.ts +26 -0
  154. package/edit/auth/github.vue +5 -0
  155. package/edit/auth/oidc.vue +5 -1
  156. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  157. package/edit/cloudcredential.vue +1 -1
  158. package/edit/configmap.vue +1 -0
  159. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  160. package/edit/fleet.cattle.io.gitrepo.vue +0 -10
  161. package/edit/fleet.cattle.io.helmop.vue +6 -6
  162. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  163. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  164. package/edit/logging-flow/index.vue +1 -0
  165. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  166. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  167. package/edit/management.cattle.io.project.vue +1 -0
  168. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  169. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  170. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  171. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  172. package/edit/monitoring.coreos.com.route.vue +1 -1
  173. package/edit/namespace.vue +1 -0
  174. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  175. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  176. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  177. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  178. package/edit/node.vue +1 -0
  179. package/edit/persistentvolume/index.vue +27 -22
  180. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  181. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  182. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  183. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  184. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  185. package/edit/persistentvolume/plugins/csi.vue +18 -16
  186. package/edit/persistentvolume/plugins/fc.vue +13 -14
  187. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  188. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  189. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  190. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  191. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  192. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  193. package/edit/persistentvolume/plugins/local.vue +1 -3
  194. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  195. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  196. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  197. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  198. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  199. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  200. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  201. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  202. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  203. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +32 -5
  204. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +35 -0
  205. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +155 -0
  206. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  207. package/edit/provisioning.cattle.io.cluster/index.vue +28 -18
  208. package/edit/provisioning.cattle.io.cluster/rke2.vue +50 -16
  209. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +107 -5
  210. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +92 -4
  211. package/edit/secret/index.vue +1 -1
  212. package/edit/service.vue +9 -4
  213. package/edit/serviceaccount.vue +1 -0
  214. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  215. package/edit/workload/index.vue +2 -1
  216. package/edit/workload/mixins/workload.js +1 -1
  217. package/initialize/App.vue +4 -4
  218. package/initialize/install-directives.js +2 -0
  219. package/initialize/install-plugins.js +19 -2
  220. package/list/provisioning.cattle.io.cluster.vue +15 -2
  221. package/machine-config/amazonec2.vue +42 -135
  222. package/machine-config/components/EC2Networking.vue +490 -0
  223. package/machine-config/components/__tests__/EC2Networking.test.ts +148 -0
  224. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +294 -0
  225. package/machine-config/digitalocean.vue +11 -0
  226. package/machine-config/google.vue +1 -1
  227. package/mixins/__tests__/brand.spec.ts +2 -2
  228. package/mixins/__tests__/chart.test.ts +21 -0
  229. package/mixins/brand.js +1 -7
  230. package/mixins/chart.js +7 -1
  231. package/mixins/create-edit-view/index.js +5 -0
  232. package/models/__tests__/chart.test.ts +33 -4
  233. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
  234. package/models/chart.js +25 -13
  235. package/models/cluster/node.js +13 -6
  236. package/models/cluster.x-k8s.io.machine.js +10 -20
  237. package/models/cluster.x-k8s.io.machinedeployment.js +5 -1
  238. package/models/management.cattle.io.cluster.js +21 -3
  239. package/models/management.cattle.io.kontainerdriver.js +1 -0
  240. package/models/provisioning.cattle.io.cluster.js +249 -33
  241. package/package.json +8 -7
  242. package/pages/auth/login.vue +41 -5
  243. package/pages/auth/setup.vue +1 -1
  244. package/pages/auth/verify.vue +3 -3
  245. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  246. package/pages/c/_cluster/apps/charts/chart.vue +33 -15
  247. package/pages/c/_cluster/apps/charts/index.vue +11 -13
  248. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  249. package/pages/c/_cluster/explorer/index.vue +8 -6
  250. package/pages/c/_cluster/manager/hostedprovider/index.vue +220 -0
  251. package/pages/c/_cluster/settings/brand.vue +1 -1
  252. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  253. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  254. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  255. package/pages/home.vue +14 -4
  256. package/pkg/auto-import.js +3 -3
  257. package/pkg/dynamic-importer.lib.js +5 -1
  258. package/pkg/import.js +1 -1
  259. package/plugins/dashboard-client-init.js +3 -0
  260. package/plugins/dashboard-store/getters.js +19 -2
  261. package/plugins/dashboard-store/model-loader.js +1 -1
  262. package/plugins/dashboard-store/resource-class.js +10 -6
  263. package/plugins/dynamic-content.js +13 -0
  264. package/plugins/i18n.js +8 -0
  265. package/plugins/plugin.js +2 -2
  266. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
  267. package/plugins/steve/steve-class.js +1 -1
  268. package/plugins/steve/steve-pagination-utils.ts +39 -20
  269. package/plugins/steve/subscribe.js +17 -9
  270. package/plugins/subscribe-events.ts +4 -2
  271. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  272. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -34
  273. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  274. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  275. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  276. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  277. package/rancher-components/Pill/types.ts +0 -1
  278. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -0
  279. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +5 -1
  280. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  281. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  282. package/rancher-components/RcIcon/index.ts +1 -0
  283. package/rancher-components/RcIcon/types.ts +160 -0
  284. package/rancher-components/utils/status.test.ts +67 -0
  285. package/rancher-components/utils/status.ts +77 -0
  286. package/scripts/typegen.sh +1 -0
  287. package/store/__tests__/catalog.test.ts +1 -1
  288. package/store/action-menu.js +8 -0
  289. package/store/auth.js +4 -4
  290. package/store/catalog.js +6 -0
  291. package/store/features.js +1 -0
  292. package/store/i18n.js +3 -3
  293. package/store/index.js +40 -19
  294. package/store/notifications.ts +51 -4
  295. package/store/plugins.js +7 -3
  296. package/store/prefs.js +6 -6
  297. package/store/type-map.js +7 -7
  298. package/store/ui-context.ts +86 -0
  299. package/store/wm.ts +244 -0
  300. package/types/notifications/index.ts +27 -3
  301. package/types/shell/index.d.ts +80 -4
  302. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  303. package/types/store/pagination.types.ts +157 -9
  304. package/types/store/subscribe-events.types.ts +8 -1
  305. package/types/store/subscribe.types.ts +1 -0
  306. package/types/window-manager.ts +24 -0
  307. package/utils/__tests__/object.test.ts +19 -0
  308. package/utils/__tests__/provider.test.ts +98 -0
  309. package/utils/__tests__/selector-typed.test.ts +263 -0
  310. package/utils/__tests__/version.test.ts +19 -1
  311. package/utils/autoscaler-utils.ts +7 -0
  312. package/utils/back-off.ts +3 -3
  313. package/utils/brand.ts +29 -0
  314. package/utils/chart.js +18 -0
  315. package/utils/color.js +1 -1
  316. package/utils/dynamic-content/__tests__/announcement.test.ts +498 -0
  317. package/utils/dynamic-content/__tests__/info.test.ts +21 -9
  318. package/utils/dynamic-content/announcement.ts +142 -0
  319. package/utils/dynamic-content/example.json +40 -0
  320. package/utils/dynamic-content/index.ts +6 -2
  321. package/utils/dynamic-content/info.ts +44 -2
  322. package/utils/dynamic-content/new-release.ts +1 -1
  323. package/utils/dynamic-content/notification-handler.ts +48 -0
  324. package/utils/dynamic-content/types.d.ts +53 -1
  325. package/utils/dynamic-importer.js +2 -2
  326. package/utils/favicon.js +4 -4
  327. package/utils/object.js +20 -2
  328. package/utils/pagination-utils.ts +2 -2
  329. package/utils/pagination-wrapper.ts +13 -9
  330. package/utils/provider.ts +14 -0
  331. package/utils/scroll.js +7 -0
  332. package/utils/selector-typed.ts +6 -2
  333. package/utils/settings.ts +15 -0
  334. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  335. package/utils/validators/machine-pool.ts +13 -3
  336. package/utils/version.js +15 -0
  337. package/vue.config.js +3 -3
  338. package/assets/images/icons/document.svg +0 -3
  339. package/plugins/nuxt-client-init.js +0 -3
  340. package/store/wm.js +0 -95
  341. /package/components/{nav/WindowManager → Window}/ChartReadme.vue +0 -0
  342. /package/components/{nav/WindowManager → Window}/ContainerShell.vue +0 -0
  343. /package/components/{nav/WindowManager → Window}/KubectlShell.vue +0 -0
  344. /package/components/{nav/WindowManager → Window}/MachineSsh.vue +0 -0
  345. /package/components/{nav/WindowManager → Window}/Window.vue +0 -0
@@ -6,12 +6,12 @@ import {
6
6
  HCI,
7
7
  MANAGEMENT,
8
8
  SNAPSHOT,
9
- VIRTUAL_TYPES
9
+ VIRTUAL_TYPES,
10
+ HOSTED_PROVIDER
10
11
  } from '@shell/config/types';
11
12
  import { MULTI_CLUSTER } from '@shell/store/features';
12
13
  import { DSL } from '@shell/store/type-map';
13
14
  import { BLANK_CLUSTER } from '@shell/store/store-types.js';
14
-
15
15
  export const NAME = 'manager';
16
16
 
17
17
  export function init(store) {
@@ -63,7 +63,7 @@ export function init(store) {
63
63
  basicType([
64
64
  CAPI.RANCHER_CLUSTER,
65
65
  'cloud-credentials',
66
- 'drivers',
66
+ 'providers',
67
67
  ]);
68
68
 
69
69
  configureType(SNAPSHOT, { depaginate: true });
@@ -73,12 +73,22 @@ export function init(store) {
73
73
  });
74
74
  weightType(CAPI.RANCHER_CLUSTER, 100, true);
75
75
  weightType('cloud-credentials', 99, true);
76
- weightType('drivers', 98, true);
76
+ weightType('providers', 98, true);
77
77
  weightType(CATALOG.CLUSTER_REPO, 97, true);
78
+ virtualType({
79
+ labelKey: 'providers.hosted.title',
80
+ name: HOSTED_PROVIDER,
81
+ group: 'Root',
82
+ weight: 1,
83
+ namespaced: false,
84
+ icon: 'globe',
85
+ route: { name: 'c-cluster-manager-hostedprovider' },
86
+ exact: true
87
+ });
78
88
 
79
89
  virtualType({
80
90
  labelKey: 'drivers.kontainer.title',
81
- name: 'rke-kontainer-drivers',
91
+ name: 'rke-kontainer-providers',
82
92
  group: 'Root',
83
93
  namespaced: false,
84
94
  icon: 'globe',
@@ -87,7 +97,7 @@ export function init(store) {
87
97
  });
88
98
  virtualType({
89
99
  labelKey: 'drivers.node.title',
90
- name: 'rke-node-drivers',
100
+ name: 'rke-node-providers',
91
101
  group: 'Root',
92
102
  namespaced: false,
93
103
  icon: 'globe',
@@ -107,9 +117,10 @@ export function init(store) {
107
117
  });
108
118
 
109
119
  basicType([
110
- 'rke-kontainer-drivers',
111
- 'rke-node-drivers',
112
- ], 'drivers');
120
+ HOSTED_PROVIDER,
121
+ 'rke-kontainer-providers',
122
+ 'rke-node-providers',
123
+ ], 'providers');
113
124
 
114
125
  weightType(CAPI.MACHINE_DEPLOYMENT, 4, true);
115
126
  weightType(CAPI.MACHINE_SET, 3, true);
@@ -30,12 +30,12 @@ export async function loadClusters(to, from, next, { store }) {
30
30
  const oldPkg = getPackageFromRoute(from);
31
31
  const oldProduct = getProductFromRoute(from);
32
32
 
33
- // TODO: Replace all references to store.$plugin.
33
+ // TODO: Replace all references to store.$extension.
34
34
  // Unfortunately the initialization code has circular dependencies between creating
35
35
  // the router and creating the store that will need to be untangled before this can be tackled.
36
36
 
37
37
  // Leave an old pkg where we weren't before?
38
- const oldPkgPlugin = oldPkg ? Object.values(store.$plugin.getPlugins()).find((p) => p.name === oldPkg) : null;
38
+ const oldPkgPlugin = oldPkg ? Object.values(store.$extension.getPlugins()).find((p) => p.name === oldPkg) : null;
39
39
 
40
40
  if (oldPkg && oldPkg !== pkg ) {
41
41
  // Execute anything optional the plugin wants to. For example resetting it's store to remove data
@@ -53,7 +53,7 @@ export async function loadClusters(to, from, next, { store }) {
53
53
  ];
54
54
 
55
55
  // Entering a new package where we weren't before?
56
- const newPkgPlugin = pkg ? Object.values(store.$plugin.getPlugins()).find((p) => p.name === pkg) : null;
56
+ const newPkgPlugin = pkg ? Object.values(store.$extension.getPlugins()).find((p) => p.name === pkg) : null;
57
57
 
58
58
  // Note - We can't block on oldPkg !== newPkg because on a fresh load the `from` route equals the `to` route
59
59
  if (pkg && (oldPkg !== pkg || from.fullPath === to.fullPath)) {
@@ -9,7 +9,7 @@ export async function loadProducts(to, from, next, { store }) {
9
9
  // GC should be notified of route change before any find/get request is made that might be used for that page
10
10
  store.dispatch('gcRouteChanged', to);
11
11
 
12
- await applyProducts(store, store.$plugin);
12
+ await applyProducts(store, store.$extension);
13
13
  setProduct(store, to);
14
14
  next();
15
15
  }
@@ -81,9 +81,13 @@ export default [
81
81
  {
82
82
  path: '/c/:cluster/uiplugins',
83
83
  name: 'c-cluster-uiplugins',
84
- component: () => interopDefault(import('@shell/pages/c/_cluster/uiplugins/index.vue')),
84
+ component: () => interopDefault(import('@shell/pages/c/_cluster/uiplugins/index.vue'))
85
+ },
86
+ {
87
+ path: '/c/:cluster/uiplugins/catalogs',
88
+ component: () => interopDefault(import('@shell/pages/c/_cluster/uiplugins/catalogs.vue')),
89
+ name: 'c-cluster-uiplugins-catalogs'
85
90
  },
86
-
87
91
  {
88
92
  path: '/diagnostic',
89
93
  component: () => interopDefault(import('@shell/pages/diagnostic.vue')),
@@ -363,6 +367,10 @@ export default [
363
367
  path: '/c/:cluster/manager/nodeDriver',
364
368
  component: () => interopDefault(import('@shell/pages/c/_cluster/manager/drivers/nodeDriver/index.vue')),
365
369
  name: 'c-cluster-manager-driver-nodedriver'
370
+ }, {
371
+ path: '/c/:cluster/manager/hostedprovider',
372
+ component: () => interopDefault(import('@shell/pages/c/_cluster/manager/hostedprovider/index.vue')),
373
+ name: 'c-cluster-manager-hostedprovider'
366
374
  }, {
367
375
  path: '/c/:cluster/monitoring/alertmanagerconfig',
368
376
  component: () => interopDefault(import('@shell/pages/c/_cluster/monitoring/alertmanagerconfig/index.vue')),
@@ -111,6 +111,7 @@ export const SETTING = {
111
111
  IMPORTED_CLUSTER_VERSION_MANAGEMENT: 'imported-cluster-version-management',
112
112
  CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS: 'cluster-agent-default-priority-class',
113
113
  CLUSTER_AGENT_DEFAULT_POD_DISTRIBUTION_BUDGET: 'cluster-agent-default-pod-disruption-budget',
114
+ KEV2_OPERATORS: 'kev2-operators',
114
115
  /**
115
116
  * Dynamic Content settings
116
117
  */
@@ -193,7 +194,7 @@ export const PROVISIONING_SETTINGS = [
193
194
  SETTING.K3S_UPGRADER_UNINSTALL_CONCURRENCY,
194
195
  SETTING.IMPORTED_CLUSTER_VERSION_MANAGEMENT,
195
196
  SETTING.CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS,
196
- SETTING.CLUSTER_AGENT_DEFAULT_POD_DISTRIBUTION_BUDGET
197
+ SETTING.CLUSTER_AGENT_DEFAULT_POD_DISTRIBUTION_BUDGET,
197
198
  ];
198
199
 
199
200
  /**
package/config/store.js CHANGED
@@ -35,11 +35,12 @@ let store = {};
35
35
  resolveStoreModules(require('../store/slideInPanel.ts'), 'slideInPanel.ts');
36
36
  resolveStoreModules(require('../store/type-map.js'), 'type-map.js');
37
37
  resolveStoreModules(require('../store/uiplugins.ts'), 'uiplugins.ts');
38
- resolveStoreModules(require('../store/wm.js'), 'wm.js');
38
+ resolveStoreModules(require('../store/wm.ts'), 'wm.ts');
39
39
  resolveStoreModules(require('../store/customisation.js'), 'customisation.js');
40
40
  resolveStoreModules(require('../store/cru-resource.ts'), 'cru-resource.ts');
41
41
  resolveStoreModules(require('../store/notifications.ts'), 'notifications.ts');
42
42
  resolveStoreModules(require('../store/cookies.ts'), 'cookies.ts');
43
+ resolveStoreModules(require('../store/ui-context.ts'), 'ui-context.ts');
43
44
 
44
45
  // If the environment supports hot reloading...
45
46
 
@@ -66,11 +67,12 @@ let store = {};
66
67
  '../store/slideInPanel.ts',
67
68
  '../store/type-map.js',
68
69
  '../store/uiplugins.ts',
69
- '../store/wm.js',
70
+ '../store/wm.ts',
70
71
  '../store/customisation.js',
71
72
  '../store/cru-resource.ts',
72
73
  '../store/notifications.ts',
73
74
  '../store/cookies.ts',
75
+ '../store/ui-context.ts',
74
76
  ], () => {
75
77
  // Update `root.modules` with the latest definitions.
76
78
  updateModules();
@@ -1183,3 +1183,11 @@ export const PROJECT = {
1183
1183
  name: 'project',
1184
1184
  labelKey: 'tableHeaders.project',
1185
1185
  };
1186
+
1187
+ export const AUTOSCALER_ENABLED = {
1188
+ name: 'autoscaler',
1189
+ labelKey: 'tableHeaders.autoscaler',
1190
+ value: 'isAutoscalerEnabled',
1191
+ sort: ['autoscaler'],
1192
+ formatter: 'Autoscaler',
1193
+ };
package/config/types.js CHANGED
@@ -222,6 +222,13 @@ export const MANAGEMENT = {
222
222
  OIDC_CLIENT: 'management.cattle.io.oidcclient'
223
223
  };
224
224
 
225
+ export const BRAND = {
226
+ SUSE: 'suse',
227
+ CSP: 'csp',
228
+ FEDERAL: 'federal',
229
+ RGS: 'rgs',
230
+ };
231
+
225
232
  export const EXT = { USER_ACTIVITY: 'ext.cattle.io.useractivity' };
226
233
 
227
234
  export const CAPI = {
@@ -364,3 +371,5 @@ export const DEFAULT_GRAFANA_STORAGE_SIZE = '10Gi';
364
371
 
365
372
  export const DEPRECATED = 'Deprecated';
366
373
  export const EXPERIMENTAL = 'Experimental';
374
+ export const AUTOSCALER_CONFIG_MAP_ID = 'kube-system/cluster-autoscaler-status';
375
+ export const HOSTED_PROVIDER = 'hostedprovider';
@@ -1,4 +1,5 @@
1
1
  import semver from 'semver';
2
+ import { isRancherPrime } from '@shell/config/version';
2
3
 
3
4
  // Version of the plugin API supported
4
5
  // here we inject the current shell version that we read in vue.config
@@ -43,6 +44,7 @@ export const UI_PLUGIN_CHART_ANNOTATIONS = {
43
44
  EXTENSIONS_HOST: 'catalog.cattle.io/ui-extensions-host',
44
45
  DISPLAY_NAME: 'catalog.cattle.io/display-name',
45
46
  HIDDEN_BUILTIN: 'catalog.cattle.io/ui-hidden-builtin',
47
+ PRIME_ONLY: 'catalog.cattle.io/prime-only'
46
48
  };
47
49
 
48
50
  // Extension catalog labels
@@ -58,6 +60,7 @@ export const EXTENSIONS_INCOMPATIBILITY_TYPES = {
58
60
  EXTENSIONS_API: 'extensionsApiVersion',
59
61
  KUBE: 'kubeVersion',
60
62
  HOST: 'host',
63
+ PRIME_ONLY: 'primeOnly',
61
64
  };
62
65
 
63
66
  export const EXTENSIONS_INCOMPATIBILITY_DATA = {
@@ -87,6 +90,11 @@ export const EXTENSIONS_INCOMPATIBILITY_DATA = {
87
90
  tooltipKey: 'plugins.info.requiresHost',
88
91
  mainHost: UI_PLUGIN_HOST_APP,
89
92
  },
93
+ PRIME_ONLY: {
94
+ type: EXTENSIONS_INCOMPATIBILITY_TYPES.PRIME_ONLY,
95
+ cardMessageKey: 'plugins.incompatiblePrimeOnly',
96
+ tooltipKey: 'plugins.info.requiresRancherPrime',
97
+ },
90
98
  };
91
99
 
92
100
  export function isUIPlugin(chart) {
@@ -124,10 +132,29 @@ export function parseRancherVersion(v) {
124
132
  * Check if a version is incompatible with the current environment
125
133
  */
126
134
  function checkIncompatibility(currentVersion, requiredVersion, incompatibilityData, returnObj, versionObj) {
127
- if ((incompatibilityData.type === EXTENSIONS_INCOMPATIBILITY_TYPES.EXTENSIONS_API_MISSING && !requiredVersion) || (requiredVersion && !semver.satisfies(currentVersion, requiredVersion))) {
135
+ let passed = true;
136
+
137
+ switch (incompatibilityData.type) {
138
+ case EXTENSIONS_INCOMPATIBILITY_TYPES.PRIME_ONLY:
139
+ if (requiredVersion && !currentVersion) {
140
+ passed = false;
141
+ }
142
+ break;
143
+ case EXTENSIONS_INCOMPATIBILITY_TYPES.EXTENSIONS_API_MISSING:
144
+ !requiredVersion ? passed = false : passed = true;
145
+ break;
146
+ default:
147
+ if (requiredVersion && !semver.satisfies(currentVersion, requiredVersion)) {
148
+ passed = false;
149
+ }
150
+ break;
151
+ }
152
+
153
+ if (!passed) {
128
154
  if (!returnObj) {
129
155
  return false;
130
156
  }
157
+
131
158
  versionObj.isVersionCompatible = false;
132
159
  versionObj.versionIncompatibilityData = { ...incompatibilityData, required: requiredVersion };
133
160
 
@@ -137,7 +164,7 @@ function checkIncompatibility(currentVersion, requiredVersion, incompatibilityDa
137
164
  return true;
138
165
  }
139
166
 
140
- // i18n-uses plugins.error.generic, plugins.error.api, plugins.error.host, plugins.error.kubeVersion, plugins.error.version, plugins.error.developerPkg, plugins.error.apiAnnotationMissing
167
+ // i18n-uses plugins.error.generic, plugins.error.api, plugins.error.host, plugins.error.kubeVersion, plugins.error.version, plugins.error.developerPkg, plugins.error.apiAnnotationMissing, plugins.error.primeOnly
141
168
 
142
169
  /**
143
170
  * Whether an extension should be loaded based on the metadata returned by the backend in the UIPlugins resource instance
@@ -148,6 +175,8 @@ function checkIncompatibility(currentVersion, requiredVersion, incompatibilityDa
148
175
  * @returns String | Boolean
149
176
  */
150
177
  export function shouldNotLoadPlugin(UIPluginResource, { rancherVersion, kubeVersion }, loadedPlugins) {
178
+ const isCurrRancherPrime = isRancherPrime();
179
+
151
180
  const {
152
181
  name, version, endpoint, compressedEndpoint
153
182
  } = UIPluginResource;
@@ -171,6 +200,13 @@ export function shouldNotLoadPlugin(UIPluginResource, { rancherVersion, kubeVers
171
200
  return 'plugins.error.api';
172
201
  }
173
202
 
203
+ // Prime only
204
+ const primeOnlyAnnotation = UIPluginResource.metadata?.[UI_PLUGIN_CHART_ANNOTATIONS.PRIME_ONLY] === 'true';
205
+
206
+ if (!isCurrRancherPrime && primeOnlyAnnotation) {
207
+ return 'plugins.error.primeOnly';
208
+ }
209
+
174
210
  // Host application
175
211
  const requiredHost = UIPluginResource.metadata?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST];
176
212
 
@@ -220,10 +256,13 @@ export function shouldNotLoadPlugin(UIPluginResource, { rancherVersion, kubeVers
220
256
  * @returns Boolean | Object
221
257
  */
222
258
  export function isSupportedChartVersion(versionData, returnObj = false) {
259
+ const isCurrRancherPrime = isRancherPrime();
260
+
223
261
  const { version, rancherVersion, kubeVersion } = versionData;
224
262
  const versionObj = {
225
263
  ...version, isVersionCompatible: true, versionIncompatibilityData: {}
226
264
  };
265
+
227
266
  const parsedRancherVersion = rancherVersion ? parseRancherVersion(rancherVersion) : '';
228
267
  const parsedUiExtensionsApiVersion = semver.coerce(UI_EXTENSIONS_API_VERSION)?.version;
229
268
 
@@ -258,6 +297,11 @@ export function isSupportedChartVersion(versionData, returnObj = false) {
258
297
  requiredVersion: version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST],
259
298
  incompatibilityData: EXTENSIONS_INCOMPATIBILITY_DATA.HOST,
260
299
  },
300
+ {
301
+ currentVersion: isCurrRancherPrime,
302
+ requiredVersion: version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.PRIME_ONLY] === 'true',
303
+ incompatibilityData: EXTENSIONS_INCOMPATIBILITY_DATA.PRIME_ONLY,
304
+ }
261
305
  ];
262
306
 
263
307
  for (const { currentVersion, requiredVersion, incompatibilityData } of checks) {
package/config/version.js CHANGED
@@ -30,4 +30,4 @@ export function setKubeVersionData(v) {
30
30
  _kubeVersionData = JSON.parse(JSON.stringify(v));
31
31
  }
32
32
 
33
- export const CURRENT_RANCHER_VERSION = '2.12';
33
+ export const CURRENT_RANCHER_VERSION = '2.13';
@@ -0,0 +1,236 @@
1
+ import { DEVELOPER_LOAD_NAME_SUFFIX } from '@shell/core/extension-manager-impl';
2
+
3
+ // Mock external dependencies
4
+ jest.mock('@shell/store/type-map', () => ({ productsLoaded: jest.fn().mockReturnValue(true) }));
5
+
6
+ jest.mock('@shell/plugins/dashboard-store/model-loader', () => ({ clearModelCache: jest.fn() }));
7
+
8
+ jest.mock('@shell/config/uiplugins', () => ({ UI_PLUGIN_BASE_URL: '/api/v1/uiplugins' }));
9
+
10
+ jest.mock('@shell/plugins/clean-html', () => ({
11
+ addLinkInterceptor: jest.fn(),
12
+ removeLinkInterceptor: jest.fn(),
13
+ }));
14
+
15
+ // Mock the Plugin class
16
+ jest.mock('@shell/core/plugin', () => {
17
+ return {
18
+ Plugin: jest.fn().mockImplementation((id) => ({
19
+ id,
20
+ name: id,
21
+ types: {},
22
+ uiConfig: {},
23
+ l10n: {},
24
+ modelExtensions: {},
25
+ stores: [],
26
+ locales: [],
27
+ routes: [],
28
+ validators: {},
29
+ uninstallHooks: [],
30
+ productNames: [],
31
+ })),
32
+ EXT_IDS: {
33
+ MODELS: 'models',
34
+ MODEL_EXTENSION: 'model-extension'
35
+ },
36
+ ExtensionPoint: { EDIT_YAML: 'edit-yaml' }
37
+ };
38
+ });
39
+
40
+ // Mock PluginRoutes
41
+ jest.mock('@shell/core/plugin-routes', () => {
42
+ return { PluginRoutes: jest.fn().mockImplementation(() => ({ addRoutes: jest.fn() })) };
43
+ });
44
+
45
+ describe('extension Manager', () => {
46
+ let mockStore;
47
+ let mockApp;
48
+ let context;
49
+
50
+ // These variables will be assigned the fresh functions inside beforeEach
51
+ let initExtensionManager;
52
+ let getExtensionManager;
53
+
54
+ beforeEach(() => {
55
+ // singleton instance for every test run, preventing mock store leaks.
56
+ jest.resetModules();
57
+
58
+ // Re-require the System Under Test (SUT)
59
+ const extensionManagerModule = require('../extension-manager-impl');
60
+
61
+ initExtensionManager = extensionManagerModule.initExtensionManager;
62
+ getExtensionManager = extensionManagerModule.getExtensionManager;
63
+
64
+ jest.clearAllMocks();
65
+
66
+ // Setup Mock Context
67
+ mockStore = {
68
+ getters: { 'i18n/t': jest.fn() },
69
+ dispatch: jest.fn(),
70
+ commit: jest.fn(),
71
+ };
72
+
73
+ mockApp = { router: {} };
74
+
75
+ context = {
76
+ app: mockApp,
77
+ store: mockStore,
78
+ $axios: {},
79
+ redirect: jest.fn(),
80
+ };
81
+
82
+ // Clean up DOM from previous tests
83
+ document.head.innerHTML = '';
84
+ });
85
+
86
+ describe('singleton Pattern', () => {
87
+ it('initializes and returns the same instance', () => {
88
+ const instance1 = initExtensionManager(context);
89
+ const instance2 = getExtensionManager();
90
+ const instance3 = initExtensionManager(context);
91
+
92
+ expect(instance1).toBeDefined();
93
+ expect(instance1).toBe(instance2);
94
+ expect(instance1).toBe(instance3);
95
+ });
96
+ });
97
+
98
+ describe('registration (Dynamic)', () => {
99
+ it('registers and retrieves a dynamic component', () => {
100
+ const manager = initExtensionManager(context);
101
+ const mockFn = jest.fn();
102
+
103
+ manager.register('component', 'my-component', mockFn);
104
+
105
+ const retrieved = manager.getDynamic('component', 'my-component');
106
+
107
+ expect(retrieved).toBe(mockFn);
108
+ });
109
+
110
+ it('unregisters a dynamic component', () => {
111
+ const manager = initExtensionManager(context);
112
+ const mockFn = jest.fn();
113
+
114
+ manager.register('component', 'my-component', mockFn);
115
+ manager.unregister('component', 'my-component');
116
+
117
+ const retrieved = manager.getDynamic('component', 'my-component');
118
+
119
+ expect(retrieved).toBeUndefined();
120
+ });
121
+ });
122
+
123
+ describe('loadPluginAsync (URL Generation)', () => {
124
+ let manager;
125
+
126
+ beforeEach(() => {
127
+ manager = initExtensionManager(context);
128
+ // Mock the internal loadAsync so we only test URL generation here
129
+ jest.spyOn(manager, 'loadAsync').mockImplementation().mockResolvedValue();
130
+ });
131
+
132
+ it('generates correct URL for standard plugin', async() => {
133
+ const pluginData = { name: 'elemental', version: '1.0.0' };
134
+ const expectedId = 'elemental-1.0.0';
135
+ const expectedUrl = `/api/v1/uiplugins/elemental/1.0.0/plugin/elemental-1.0.0.umd.min.js`;
136
+
137
+ await manager.loadPluginAsync(pluginData);
138
+
139
+ expect(manager.loadAsync).toHaveBeenCalledWith(expectedId, expectedUrl);
140
+ });
141
+
142
+ it('handles "direct" metadata plugins', async() => {
143
+ const pluginData = {
144
+ name: 'direct-plugin',
145
+ version: '1.0.0',
146
+ endpoint: 'http://localhost:8000/plugin.js',
147
+ metadata: { direct: 'true' }
148
+ };
149
+
150
+ await manager.loadPluginAsync(pluginData);
151
+
152
+ expect(manager.loadAsync).toHaveBeenCalledWith('direct-plugin-1.0.0', 'http://localhost:8000/plugin.js');
153
+ });
154
+
155
+ it('removes developer suffix from ID but keeps it for internal logic', async() => {
156
+ const pluginData = {
157
+ name: `my-plugin${ DEVELOPER_LOAD_NAME_SUFFIX }`,
158
+ version: `1.0.0`
159
+ };
160
+
161
+ await manager.loadPluginAsync(pluginData);
162
+
163
+ // Expected ID passed to loadAsync should NOT have the suffix
164
+ const expectedIdWithoutSuffix = 'my-plugin-1.0.0';
165
+
166
+ expect(manager.loadAsync).toHaveBeenCalledWith(
167
+ expectedIdWithoutSuffix,
168
+ expect.any(String)
169
+ );
170
+ });
171
+ });
172
+
173
+ describe('loadAsync (Script Injection)', () => {
174
+ let manager;
175
+
176
+ beforeEach(() => {
177
+ manager = initExtensionManager(context);
178
+ });
179
+
180
+ it('resolves immediately if element already exists', async() => {
181
+ const id = 'existing-plugin';
182
+ const script = document.createElement('script');
183
+
184
+ script.id = id;
185
+ document.body.appendChild(script);
186
+
187
+ await expect(manager.loadAsync(id, 'url.js')).resolves.toBeUndefined();
188
+
189
+ document.body.removeChild(script);
190
+ });
191
+
192
+ it('injects script tag and initializes plugin on load', async() => {
193
+ const pluginId = 'test-plugin';
194
+ const pluginUrl = 'http://test.com/plugin.js';
195
+
196
+ // Mock the window object to simulate the plugin loading into global scope
197
+ const mockPluginInit = jest.fn();
198
+
199
+ window[pluginId] = { default: mockPluginInit };
200
+
201
+ // Start the load
202
+ const loadPromise = manager.loadAsync(pluginId, pluginUrl);
203
+
204
+ // Find the injected script tag in the DOM
205
+ const script = document.head.querySelector(`script[id="${ pluginId }"]`);
206
+
207
+ expect(script).toBeTruthy();
208
+ expect(script.src).toBe(pluginUrl);
209
+
210
+ // Manually trigger the onload event
211
+ script.onload();
212
+
213
+ // Await the promise
214
+ await loadPromise;
215
+
216
+ // Assertions
217
+ expect(mockPluginInit).toHaveBeenCalledWith(expect.objectContaining({ id: pluginId }), expect.objectContaining({ ...context }));
218
+ expect(mockStore.dispatch).toHaveBeenCalledWith('uiplugins/addPlugin', expect.objectContaining({ id: pluginId }));
219
+
220
+ // Cleanup
221
+ delete window[pluginId];
222
+ });
223
+
224
+ it('rejects if script load fails', async() => {
225
+ const pluginId = 'fail-plugin';
226
+ const loadPromise = manager.loadAsync(pluginId, 'bad-url.js');
227
+
228
+ const script = document.head.querySelector(`script[id="${ pluginId }"]`);
229
+
230
+ // Trigger error
231
+ script.onerror({ target: { src: 'bad-url.js' } });
232
+
233
+ await expect(loadPromise).rejects.toThrow('Failed to load script');
234
+ });
235
+ });
236
+ });
@@ -6,6 +6,8 @@ import { UI_PLUGIN_BASE_URL } from '@shell/config/uiplugins';
6
6
  import { ExtensionPoint } from './types';
7
7
  import { addLinkInterceptor, removeLinkInterceptor } from '@shell/plugins/clean-html';
8
8
 
9
+ export const DEVELOPER_LOAD_NAME_SUFFIX = '-developer-load';
10
+
9
11
  let extensionManagerInstance;
10
12
 
11
13
  const createExtensionManager = (context) => {
@@ -33,13 +35,13 @@ const createExtensionManager = (context) => {
33
35
  /**
34
36
  * When an extension adds a model extension, it provides the class - we will instantiate that class and store and use that
35
37
  */
36
- function instantiateModelExtension($plugin, clz) {
38
+ function instantiateModelExtension($extension, clz) {
37
39
  const context = {
38
40
  dispatch: store.dispatch,
39
41
  getters: store.getters,
40
42
  t: store.getters['i18n/t'],
41
43
  $axios,
42
- $plugin,
44
+ $extension,
43
45
  };
44
46
 
45
47
  return new clz(context);
@@ -63,9 +65,18 @@ const createExtensionManager = (context) => {
63
65
  // Load a plugin from a UI package
64
66
  loadPluginAsync(plugin) {
65
67
  const { name, version } = plugin;
66
- const id = `${ name }-${ version }`;
68
+ let id = `${ name }-${ version }`;
67
69
  let url;
68
70
 
71
+ // for a developer load, we need to remove the suffix applied
72
+ // otherwise the extension won't load correctly
73
+ // but with this at least we won't hit developer loaded cards find charts
74
+ // when they aren't supposed to
75
+ if (id.includes(DEVELOPER_LOAD_NAME_SUFFIX)) {
76
+ id = id.replace(DEVELOPER_LOAD_NAME_SUFFIX, '');
77
+ }
78
+
79
+ // this is where a developer load hits (direct=true, developer=true)
69
80
  if (plugin?.metadata?.direct === 'true') {
70
81
  url = plugin.endpoint;
71
82
  } else {
@@ -455,7 +466,13 @@ const createExtensionManager = (context) => {
455
466
  try {
456
467
  const provisioner = context.$extension.getDynamic('provisioner', name);
457
468
 
458
- return new provisioner({ ...context });
469
+ const defaults = {
470
+ isCreate: false,
471
+ isEdit: false,
472
+ isView: false
473
+ };
474
+
475
+ return new provisioner({ ...defaults, ...context });
459
476
  } catch (e) {
460
477
  console.error('Error loading provisioner(s) from extensions', e); // eslint-disable-line no-console
461
478
  }
@@ -147,8 +147,8 @@ export function getApplicableExtensionEnhancements<T>(
147
147
  const extensionEnhancements: T[] = [];
148
148
 
149
149
  // gate it so that we prevent errors on older versions of dashboard
150
- if (pluginCtx.$plugin?.getUIConfig) {
151
- const actions = pluginCtx.$plugin.getUIConfig(actionType, uiArea);
150
+ if (pluginCtx.$extension?.getUIConfig) {
151
+ const actions = pluginCtx.$extension.getUIConfig(actionType, uiArea);
152
152
 
153
153
  actions.forEach((action: any, i: number) => {
154
154
  if (checkExtensionRouteBinding(currRoute, action.locationConfig, context || {})) {
@@ -195,6 +195,8 @@ export function getApplicableExtensionEnhancements<T>(
195
195
  if (i < keyboardCombo.length - 1) {
196
196
  if (key === 'meta') {
197
197
  key = '\u2318';
198
+ } else if (isMac && key === 'alt') {
199
+ key = '⌥';
198
200
  } else {
199
201
  key = ucFirst(key);
200
202
  }
@@ -13,10 +13,10 @@ export default function({
13
13
  store,
14
14
  $axios,
15
15
  redirect,
16
- $plugin,
16
+ $extension,
17
17
  }, inject) {
18
18
  if (dynamicLoader) {
19
- dynamicLoader.default($plugin);
19
+ dynamicLoader.default($extension);
20
20
  }
21
21
 
22
22
  // The libraries we build have Vue externalised, so we need to expose Vue as a global for