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

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 (323) 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/SortableTable/index.vue +1 -0
  82. package/components/Tabbed/__tests__/index.test.ts +86 -0
  83. package/components/{nav/WindowManager → Window}/ContainerLogs.vue +1 -1
  84. package/components/{nav/WindowManager → Window}/ContainerLogsActions.vue +1 -0
  85. package/components/{nav/WindowManager → Window}/__tests__/ContainerLogs.test.ts +1 -1
  86. package/components/{nav/WindowManager → Window}/__tests__/ContainerShell.test.ts +2 -2
  87. package/components/__tests__/AutoscalerCard.test.ts +154 -0
  88. package/components/__tests__/AutoscalerTab.test.ts +125 -0
  89. package/components/__tests__/PopoverCard.test.ts +204 -0
  90. package/components/auth/SelectPrincipal.vue +24 -6
  91. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  92. package/components/formatter/Autoscaler.vue +97 -0
  93. package/components/formatter/InternalExternalIP.vue +198 -24
  94. package/components/formatter/__tests__/Autoscaler.test.ts +156 -0
  95. package/components/formatter/__tests__/InternalExternalIP.test.ts +133 -0
  96. package/components/google/util/__tests__/formatter.test.ts +47 -0
  97. package/components/google/util/formatter.ts +5 -2
  98. package/components/nav/Group.vue +12 -3
  99. package/components/nav/Header.vue +36 -16
  100. package/components/nav/NamespaceFilter.vue +13 -1
  101. package/components/nav/NotificationCenter/index.vue +2 -1
  102. package/components/nav/TopLevelMenu.helper.ts +16 -6
  103. package/components/nav/TopLevelMenu.vue +4 -2
  104. package/components/{DraggableZone.vue → nav/WindowManager/PinArea.vue} +47 -80
  105. package/components/nav/WindowManager/composables/useComponentsMount.ts +70 -0
  106. package/components/nav/WindowManager/composables/useDimensionsHandler.ts +105 -0
  107. package/components/nav/WindowManager/composables/useDragHandler.ts +99 -0
  108. package/components/nav/WindowManager/composables/usePanelHandler.ts +72 -0
  109. package/components/nav/WindowManager/composables/usePanelsHandler.ts +14 -0
  110. package/components/nav/WindowManager/composables/useResizeHandler.ts +167 -0
  111. package/components/nav/WindowManager/composables/useTabsHandler.ts +51 -0
  112. package/components/nav/WindowManager/constants.ts +23 -0
  113. package/components/nav/WindowManager/index.vue +61 -575
  114. package/components/nav/WindowManager/panels/HorizontalPanel.vue +265 -0
  115. package/components/nav/WindowManager/panels/TabBodyContainer.vue +39 -0
  116. package/components/nav/WindowManager/panels/VerticalPanel.vue +308 -0
  117. package/components/templates/default.vue +4 -40
  118. package/components/templates/home.vue +31 -5
  119. package/components/templates/plain.vue +30 -4
  120. package/components/templates/standalone.vue +1 -1
  121. package/composables/useI18n.ts +10 -1
  122. package/composables/useInterval.ts +15 -0
  123. package/config/__test__/uiplugins.test.ts +309 -0
  124. package/config/labels-annotations.js +9 -1
  125. package/config/product/explorer.js +3 -1
  126. package/config/product/manager.js +20 -9
  127. package/config/router/routes.js +10 -2
  128. package/config/settings.ts +2 -1
  129. package/config/store.js +4 -2
  130. package/config/table-headers.js +8 -0
  131. package/config/types.js +9 -0
  132. package/config/uiplugins.js +46 -2
  133. package/config/version.js +1 -1
  134. package/core/__test__/extension-manager-impl.test.js +236 -0
  135. package/core/extension-manager-impl.js +23 -6
  136. package/core/plugin-helpers.ts +2 -0
  137. package/core/types-provisioning.ts +4 -1
  138. package/detail/pod.vue +1 -0
  139. package/detail/provisioning.cattle.io.cluster.vue +13 -1
  140. package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
  141. package/dialog/RollbackWorkloadDialog.vue +2 -5
  142. package/directives/ui-context.ts +103 -0
  143. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
  144. package/edit/auth/__tests__/oidc.test.ts +26 -0
  145. package/edit/auth/github.vue +5 -0
  146. package/edit/auth/oidc.vue +5 -1
  147. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  148. package/edit/cloudcredential.vue +1 -1
  149. package/edit/configmap.vue +1 -0
  150. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  151. package/edit/fleet.cattle.io.gitrepo.vue +0 -10
  152. package/edit/fleet.cattle.io.helmop.vue +6 -6
  153. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  154. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  155. package/edit/logging-flow/index.vue +1 -0
  156. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  157. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  158. package/edit/management.cattle.io.project.vue +1 -0
  159. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  160. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  161. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  162. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  163. package/edit/monitoring.coreos.com.route.vue +1 -1
  164. package/edit/namespace.vue +1 -0
  165. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  166. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  167. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  168. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  169. package/edit/node.vue +1 -0
  170. package/edit/persistentvolume/index.vue +27 -22
  171. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  172. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  173. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  174. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  175. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  176. package/edit/persistentvolume/plugins/csi.vue +18 -16
  177. package/edit/persistentvolume/plugins/fc.vue +13 -14
  178. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  179. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  180. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  181. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  182. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  183. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  184. package/edit/persistentvolume/plugins/local.vue +1 -3
  185. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  186. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  187. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  188. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  189. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  190. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  191. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  192. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  193. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  194. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +32 -5
  195. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +35 -0
  196. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +155 -0
  197. package/edit/provisioning.cattle.io.cluster/index.vue +25 -15
  198. package/edit/provisioning.cattle.io.cluster/rke2.vue +42 -8
  199. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +107 -5
  200. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +92 -4
  201. package/edit/secret/index.vue +1 -1
  202. package/edit/service.vue +9 -4
  203. package/edit/serviceaccount.vue +1 -0
  204. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  205. package/edit/workload/index.vue +2 -1
  206. package/edit/workload/mixins/workload.js +1 -1
  207. package/initialize/App.vue +4 -4
  208. package/initialize/install-directives.js +2 -0
  209. package/initialize/install-plugins.js +19 -2
  210. package/list/provisioning.cattle.io.cluster.vue +15 -2
  211. package/machine-config/amazonec2.vue +42 -135
  212. package/machine-config/components/EC2Networking.vue +490 -0
  213. package/machine-config/components/__tests__/EC2Networking.test.ts +148 -0
  214. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +294 -0
  215. package/machine-config/digitalocean.vue +11 -0
  216. package/machine-config/google.vue +1 -1
  217. package/mixins/__tests__/brand.spec.ts +2 -2
  218. package/mixins/__tests__/chart.test.ts +21 -0
  219. package/mixins/brand.js +1 -7
  220. package/mixins/chart.js +7 -1
  221. package/mixins/create-edit-view/index.js +5 -0
  222. package/models/__tests__/chart.test.ts +33 -4
  223. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
  224. package/models/chart.js +25 -13
  225. package/models/cluster/node.js +13 -6
  226. package/models/cluster.x-k8s.io.machine.js +10 -20
  227. package/models/cluster.x-k8s.io.machinedeployment.js +5 -1
  228. package/models/management.cattle.io.cluster.js +21 -3
  229. package/models/management.cattle.io.kontainerdriver.js +1 -0
  230. package/models/provisioning.cattle.io.cluster.js +249 -33
  231. package/package.json +6 -5
  232. package/pages/auth/login.vue +38 -2
  233. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  234. package/pages/c/_cluster/apps/charts/chart.vue +33 -15
  235. package/pages/c/_cluster/apps/charts/index.vue +11 -13
  236. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  237. package/pages/c/_cluster/explorer/index.vue +8 -6
  238. package/pages/c/_cluster/manager/hostedprovider/index.vue +220 -0
  239. package/pages/c/_cluster/settings/brand.vue +1 -1
  240. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  241. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  242. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  243. package/pages/home.vue +14 -4
  244. package/pkg/dynamic-importer.lib.js +4 -0
  245. package/plugins/dashboard-client-init.js +3 -0
  246. package/plugins/dashboard-store/getters.js +18 -1
  247. package/plugins/dashboard-store/resource-class.js +4 -4
  248. package/plugins/dynamic-content.js +13 -0
  249. package/plugins/i18n.js +8 -0
  250. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
  251. package/plugins/steve/steve-pagination-utils.ts +39 -20
  252. package/plugins/steve/subscribe.js +17 -9
  253. package/plugins/subscribe-events.ts +4 -2
  254. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  255. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -34
  256. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  257. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  258. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  259. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  260. package/rancher-components/Pill/types.ts +0 -1
  261. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -0
  262. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +5 -1
  263. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  264. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  265. package/rancher-components/RcIcon/index.ts +1 -0
  266. package/rancher-components/RcIcon/types.ts +160 -0
  267. package/rancher-components/utils/status.test.ts +67 -0
  268. package/rancher-components/utils/status.ts +77 -0
  269. package/scripts/typegen.sh +1 -0
  270. package/store/action-menu.js +8 -0
  271. package/store/auth.js +3 -3
  272. package/store/catalog.js +6 -0
  273. package/store/features.js +1 -0
  274. package/store/index.js +36 -17
  275. package/store/notifications.ts +51 -4
  276. package/store/plugins.js +7 -3
  277. package/store/prefs.js +6 -6
  278. package/store/type-map.js +3 -3
  279. package/store/ui-context.ts +86 -0
  280. package/store/wm.ts +244 -0
  281. package/types/notifications/index.ts +27 -3
  282. package/types/shell/index.d.ts +79 -4
  283. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  284. package/types/store/pagination.types.ts +157 -9
  285. package/types/store/subscribe-events.types.ts +8 -1
  286. package/types/store/subscribe.types.ts +1 -0
  287. package/types/window-manager.ts +24 -0
  288. package/utils/__tests__/object.test.ts +19 -0
  289. package/utils/__tests__/provider.test.ts +98 -0
  290. package/utils/__tests__/selector-typed.test.ts +263 -0
  291. package/utils/__tests__/version.test.ts +19 -1
  292. package/utils/autoscaler-utils.ts +7 -0
  293. package/utils/back-off.ts +3 -3
  294. package/utils/brand.ts +29 -0
  295. package/utils/chart.js +18 -0
  296. package/utils/color.js +1 -1
  297. package/utils/dynamic-content/__tests__/announcement.test.ts +498 -0
  298. package/utils/dynamic-content/__tests__/info.test.ts +21 -9
  299. package/utils/dynamic-content/announcement.ts +142 -0
  300. package/utils/dynamic-content/example.json +40 -0
  301. package/utils/dynamic-content/index.ts +6 -2
  302. package/utils/dynamic-content/info.ts +44 -2
  303. package/utils/dynamic-content/new-release.ts +1 -1
  304. package/utils/dynamic-content/notification-handler.ts +48 -0
  305. package/utils/dynamic-content/types.d.ts +53 -1
  306. package/utils/dynamic-importer.js +2 -2
  307. package/utils/favicon.js +4 -4
  308. package/utils/object.js +20 -2
  309. package/utils/pagination-wrapper.ts +12 -8
  310. package/utils/provider.ts +14 -0
  311. package/utils/scroll.js +7 -0
  312. package/utils/selector-typed.ts +6 -2
  313. package/utils/settings.ts +15 -0
  314. package/utils/validators/machine-pool.ts +13 -3
  315. package/utils/version.js +15 -0
  316. package/assets/images/icons/document.svg +0 -3
  317. package/plugins/nuxt-client-init.js +0 -3
  318. package/store/wm.js +0 -95
  319. /package/components/{nav/WindowManager → Window}/ChartReadme.vue +0 -0
  320. /package/components/{nav/WindowManager → Window}/ContainerShell.vue +0 -0
  321. /package/components/{nav/WindowManager → Window}/KubectlShell.vue +0 -0
  322. /package/components/{nav/WindowManager → Window}/MachineSsh.vue +0 -0
  323. /package/components/{nav/WindowManager → Window}/Window.vue +0 -0
@@ -182,6 +182,25 @@ describe('fx: diff', () => {
182
182
 
183
183
  expect(result).toStrictEqual(expected);
184
184
  });
185
+ it('should return an object with property "baz" different than "null" if using the flag "preventNull" as true', () => {
186
+ const from = {
187
+ foo: 'bar',
188
+ baz: 'bang',
189
+ };
190
+ const to = {
191
+ foo: 'bar',
192
+ bang: 'baz'
193
+ };
194
+
195
+ const result = diff(from, to, true);
196
+ const expected = {
197
+ // the property "baz" having value !== null covers test case for https://github.com/rancher/dashboard/issues/15710
198
+ baz: 'bang',
199
+ bang: 'baz'
200
+ };
201
+
202
+ expect(result).toStrictEqual(expected);
203
+ });
185
204
  it('should return an object and dot characters in object should still be respected', () => {
186
205
  const from = {};
187
206
  const to = { foo: { 'bar.baz': 'bang' } };
@@ -0,0 +1,98 @@
1
+ import { getHostedProviders, isHostedProvider } from '../provider';
2
+ import { ClusterProvisionerContext, IClusterProvisioner } from '@shell/core/types';
3
+
4
+ const DEFAULT_CONTEXT = {
5
+ dispatch: {},
6
+ getters: {},
7
+ axios: {},
8
+ t: (args: any) => args.join(' '),
9
+ };
10
+
11
+ const MOCK_PROVIDERS: IClusterProvisioner[] = [
12
+ { id: 'AKS', group: 'hosted' } as IClusterProvisioner,
13
+ { id: 'EKS', group: 'hosted' } as IClusterProvisioner,
14
+ { id: 'GKE', group: 'hosted' } as IClusterProvisioner,
15
+ { id: 'alibaba', group: 'hosted' } as IClusterProvisioner,
16
+ { id: 'other', group: 'other' } as IClusterProvisioner,
17
+ ];
18
+
19
+ describe('utils/provider', () => {
20
+ describe('getHostedProviders', () => {
21
+ it('should return an empty array when context.$extension is undefined', () => {
22
+ const context = { ...DEFAULT_CONTEXT } as ClusterProvisionerContext;
23
+ const result = getHostedProviders(context);
24
+
25
+ expect(result).toStrictEqual([]);
26
+ });
27
+
28
+ it('should return hosted providers when context.$extension is defined', () => {
29
+ const context = {
30
+ ...DEFAULT_CONTEXT,
31
+ $extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
32
+ } as unknown as ClusterProvisionerContext;
33
+
34
+ const result = getHostedProviders(context);
35
+
36
+ expect(result).toStrictEqual([
37
+ { id: 'AKS', group: 'hosted' },
38
+ { id: 'EKS', group: 'hosted' },
39
+ { id: 'GKE', group: 'hosted' },
40
+ { id: 'alibaba', group: 'hosted' },
41
+ ]);
42
+ expect(context.$extension.getProviders).toHaveBeenCalledWith(context);
43
+ });
44
+
45
+ it('should return an empty array if getProviders returns null', () => {
46
+ const context = {
47
+ ...DEFAULT_CONTEXT,
48
+ $extension: { getProviders: jest.fn().mockReturnValue(null) }
49
+ } as unknown as ClusterProvisionerContext;
50
+
51
+ const result = getHostedProviders(context);
52
+
53
+ expect(result).toStrictEqual([]);
54
+ });
55
+
56
+ it('should return an empty array if getProviders returns undefined', () => {
57
+ const context = {
58
+ ...DEFAULT_CONTEXT,
59
+ $extension: { getProviders: jest.fn().mockReturnValue(undefined) }
60
+ } as unknown as ClusterProvisionerContext;
61
+
62
+ const result = getHostedProviders(context);
63
+
64
+ expect(result).toStrictEqual([]);
65
+ });
66
+ });
67
+
68
+ describe('isHostedProvider', () => {
69
+ it('should return false if provisioner is not provided', () => {
70
+ const context = {
71
+ ...DEFAULT_CONTEXT,
72
+ $extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
73
+ } as ClusterProvisionerContext;
74
+
75
+ expect(isHostedProvider(context, '')).toBe(false);
76
+ expect(isHostedProvider(context, undefined as any)).toBe(false);
77
+ expect(isHostedProvider(context, null as any)).toBe(false);
78
+ });
79
+
80
+ it('should return true only if provisioner is in the list of hosted providers', () => {
81
+ const context = {
82
+ ...DEFAULT_CONTEXT,
83
+ $extension: { getProviders: jest.fn().mockReturnValue(MOCK_PROVIDERS) }
84
+ } as ClusterProvisionerContext;
85
+
86
+ expect(isHostedProvider(context, 'AKS')).toBe(true);
87
+ expect(isHostedProvider(context, 'eks')).toBe(true);
88
+ expect(isHostedProvider(context, 'different')).toBe(false); // case-insensitive check
89
+ expect(isHostedProvider(context, 'other')).toBe(false); // case-insensitive check
90
+ });
91
+
92
+ it('should return false if there are no hosted providers', () => {
93
+ const context = { ...DEFAULT_CONTEXT, $extension: { getProviders: jest.fn().mockReturnValue([]) } } as ClusterProvisionerContext;
94
+
95
+ expect(isHostedProvider(context, 'prov1')).toBe(false);
96
+ });
97
+ });
98
+ });
@@ -0,0 +1,263 @@
1
+ import { labelSelectorToSelector } from '@shell/utils/selector-typed';
2
+ import { KubeLabelSelector } from '@shell/types/kube/kube-api';
3
+
4
+ describe('selector-typed', () => {
5
+ describe('labelSelectorToSelector', () => {
6
+ describe('empty label selectors', () => {
7
+ it('should return empty string for undefined label selector', () => {
8
+ const result = labelSelectorToSelector(undefined);
9
+
10
+ expect(result).toBe('');
11
+ });
12
+
13
+ it('should return empty string for label selector with no matchLabels and no matchExpressions', () => {
14
+ const labelSelector: KubeLabelSelector = {};
15
+ const result = labelSelectorToSelector(labelSelector);
16
+
17
+ expect(result).toBe('');
18
+ });
19
+
20
+ it('should return empty string for label selector with empty matchLabels', () => {
21
+ const labelSelector: KubeLabelSelector = { matchLabels: {} };
22
+ const result = labelSelectorToSelector(labelSelector);
23
+
24
+ expect(result).toBe('');
25
+ });
26
+
27
+ it('should return empty string for label selector with empty matchExpressions', () => {
28
+ const labelSelector: KubeLabelSelector = { matchExpressions: [] };
29
+ const result = labelSelectorToSelector(labelSelector);
30
+
31
+ expect(result).toBe('');
32
+ });
33
+
34
+ it('should return empty string for label selector with both empty matchLabels and matchExpressions', () => {
35
+ const labelSelector: KubeLabelSelector = {
36
+ matchLabels: {},
37
+ matchExpressions: []
38
+ };
39
+ const result = labelSelectorToSelector(labelSelector);
40
+
41
+ expect(result).toBe('');
42
+ });
43
+ });
44
+
45
+ describe('matchLabels conversion', () => {
46
+ it('should convert single matchLabel to selector string', () => {
47
+ const labelSelector: KubeLabelSelector = { matchLabels: { app: 'nginx' } };
48
+ const result = labelSelectorToSelector(labelSelector);
49
+
50
+ expect(result).toBe('app=nginx');
51
+ });
52
+
53
+ it('should convert multiple matchLabels to comma-separated selector string', () => {
54
+ const labelSelector: KubeLabelSelector = {
55
+ matchLabels: {
56
+ app: 'nginx',
57
+ version: 'v1.0',
58
+ env: 'production'
59
+ }
60
+ };
61
+ const result = labelSelectorToSelector(labelSelector);
62
+
63
+ expect(result).toBe('app=nginx,version=v1.0,env=production');
64
+ });
65
+
66
+ it('should handle matchLabels with special characters', () => {
67
+ const labelSelector: KubeLabelSelector = { matchLabels: { 'app.kubernetes.io/name': 'my-app' } };
68
+ const result = labelSelectorToSelector(labelSelector);
69
+
70
+ expect(result).toBe('app.kubernetes.io/name=my-app');
71
+ });
72
+
73
+ it('should handle matchLabels with numeric values', () => {
74
+ const labelSelector: KubeLabelSelector = { matchLabels: { tier: '3' } };
75
+ const result = labelSelectorToSelector(labelSelector);
76
+
77
+ expect(result).toBe('tier=3');
78
+ });
79
+ });
80
+
81
+ describe('matchExpressions conversion with In operator', () => {
82
+ it('should convert matchExpression with In operator and single value to equality selector', () => {
83
+ const labelSelector: KubeLabelSelector = {
84
+ matchExpressions: [
85
+ {
86
+ key: 'app',
87
+ operator: 'In',
88
+ values: ['nginx']
89
+ }
90
+ ]
91
+ };
92
+ const result = labelSelectorToSelector(labelSelector);
93
+
94
+ expect(result).toBe('app=nginx');
95
+ });
96
+
97
+ it('should convert matchExpression with In operator and multiple values to in() selector', () => {
98
+ const labelSelector: KubeLabelSelector = {
99
+ matchExpressions: [
100
+ {
101
+ key: 'env',
102
+ operator: 'In',
103
+ values: ['dev', 'staging', 'prod']
104
+ }
105
+ ]
106
+ };
107
+ const result = labelSelectorToSelector(labelSelector);
108
+
109
+ expect(result).toBe('env in (dev,staging,prod)');
110
+ });
111
+
112
+ it('should convert multiple matchExpressions with In operator', () => {
113
+ const labelSelector: KubeLabelSelector = {
114
+ matchExpressions: [
115
+ {
116
+ key: 'app',
117
+ operator: 'In',
118
+ values: ['nginx']
119
+ },
120
+ {
121
+ key: 'env',
122
+ operator: 'In',
123
+ values: ['dev', 'staging']
124
+ }
125
+ ]
126
+ };
127
+ const result = labelSelectorToSelector(labelSelector);
128
+
129
+ expect(result).toBe('app=nginx,env in (dev,staging)');
130
+ });
131
+
132
+ it('should handle matchExpression with empty values array for In operator', () => {
133
+ const labelSelector: KubeLabelSelector = {
134
+ matchExpressions: [
135
+ {
136
+ key: 'app',
137
+ operator: 'In',
138
+ values: []
139
+ }
140
+ ]
141
+ };
142
+ const result = labelSelectorToSelector(labelSelector);
143
+
144
+ // With empty values array, it should create an in() with no values
145
+ expect(result).toBe('app in ()');
146
+ });
147
+ });
148
+
149
+ describe('combined matchLabels and matchExpressions', () => {
150
+ it('should combine matchLabels and matchExpressions with single values', () => {
151
+ const labelSelector: KubeLabelSelector = {
152
+ matchLabels: { tier: 'frontend' },
153
+ matchExpressions: [
154
+ {
155
+ key: 'env',
156
+ operator: 'In',
157
+ values: ['prod']
158
+ }
159
+ ]
160
+ };
161
+ const result = labelSelectorToSelector(labelSelector);
162
+
163
+ expect(result).toBe('tier=frontend,env=prod');
164
+ });
165
+
166
+ it('should combine multiple matchLabels and matchExpressions', () => {
167
+ const labelSelector: KubeLabelSelector = {
168
+ matchLabels: {
169
+ tier: 'frontend',
170
+ version: 'v2'
171
+ },
172
+ matchExpressions: [
173
+ {
174
+ key: 'env',
175
+ operator: 'In',
176
+ values: ['dev', 'staging']
177
+ },
178
+ {
179
+ key: 'region',
180
+ operator: 'In',
181
+ values: ['us-west-1']
182
+ }
183
+ ]
184
+ };
185
+ const result = labelSelectorToSelector(labelSelector);
186
+
187
+ expect(result).toBe('tier=frontend,version=v2,env in (dev,staging),region=us-west-1');
188
+ });
189
+
190
+ it('should combine matchLabels with multiple matchExpressions using in() notation', () => {
191
+ const labelSelector: KubeLabelSelector = {
192
+ matchLabels: { 'app.kubernetes.io/name': 'myapp' },
193
+ matchExpressions: [
194
+ {
195
+ key: 'env',
196
+ operator: 'In',
197
+ values: ['dev', 'test', 'prod']
198
+ }
199
+ ]
200
+ };
201
+ const result = labelSelectorToSelector(labelSelector);
202
+
203
+ expect(result).toBe('app.kubernetes.io/name=myapp,env in (dev,test,prod)');
204
+ });
205
+ });
206
+
207
+ describe('unsupported operators', () => {
208
+ it('should throw error for NotIn operator', () => {
209
+ const labelSelector: KubeLabelSelector = {
210
+ matchExpressions: [
211
+ {
212
+ key: 'env',
213
+ operator: 'NotIn',
214
+ values: ['prod']
215
+ }
216
+ ]
217
+ };
218
+
219
+ expect(() => labelSelectorToSelector(labelSelector)).toThrow('Unsupported matchExpression found when converting to selector string.');
220
+ });
221
+ });
222
+
223
+ describe('edge cases', () => {
224
+ it('should handle matchExpression with In operator but undefined values', () => {
225
+ const labelSelector: KubeLabelSelector = {
226
+ matchExpressions: [
227
+ {
228
+ key: 'app',
229
+ operator: 'In',
230
+ values: undefined
231
+ }
232
+ ]
233
+ };
234
+
235
+ // When values is undefined, the function throws an error
236
+ expect(() => labelSelectorToSelector(labelSelector)).toThrow('Unsupported matchExpression found when converting to selector string.');
237
+ });
238
+
239
+ it('should preserve order of matchLabels and matchExpressions', () => {
240
+ const labelSelector: KubeLabelSelector = {
241
+ matchLabels: {
242
+ first: 'value1',
243
+ second: 'value2'
244
+ },
245
+ matchExpressions: [
246
+ {
247
+ key: 'third',
248
+ operator: 'In',
249
+ values: ['value3']
250
+ }
251
+ ]
252
+ };
253
+ const result = labelSelectorToSelector(labelSelector);
254
+
255
+ // matchLabels come before matchExpressions
256
+ expect(result).toContain('first=value1');
257
+ expect(result).toContain('second=value2');
258
+ expect(result).toContain('third=value3');
259
+ expect(result.indexOf('first')).toBeLessThan(result.indexOf('third'));
260
+ });
261
+ });
262
+ });
263
+ });
@@ -1,4 +1,4 @@
1
- import { isDevBuild } from '@shell/utils/version';
1
+ import { isDevBuild, isUpgradeFromPreToStable } from '@shell/utils/version';
2
2
 
3
3
  describe('fx: isDevBuild', () => {
4
4
  it.each([
@@ -16,3 +16,21 @@ describe('fx: isDevBuild', () => {
16
16
  }
17
17
  );
18
18
  });
19
+
20
+ describe('fx: isUpgradeFromPreToStable', () => {
21
+ it('should be true when going from pre-release to stable of same version', () => {
22
+ expect(isUpgradeFromPreToStable('1.0.0-rc1', '1.0.0')).toBe(true);
23
+ });
24
+
25
+ it('should be false when going from stable to pre-release', () => {
26
+ expect(isUpgradeFromPreToStable('1.0.0', '1.0.0-rc1')).toBe(false );
27
+ });
28
+
29
+ it('should be false for stable to stable', () => {
30
+ expect(isUpgradeFromPreToStable('1.0.0', '1.1.0')).toBe(false);
31
+ });
32
+
33
+ it('should be false for pre-release to pre-release', () => {
34
+ expect(isUpgradeFromPreToStable('1.0.0-rc1', '1.0.0-rc2')).toBe(false);
35
+ });
36
+ });
@@ -0,0 +1,7 @@
1
+ import { AUTOSCALER } from '@shell/store/features';
2
+
3
+ export function isAutoscalerFeatureFlagEnabled(store: any): boolean {
4
+ const rootGetters = store.rootGetters || store.getters;
5
+
6
+ return rootGetters['features/get'](AUTOSCALER);
7
+ }
package/utils/back-off.ts CHANGED
@@ -137,9 +137,9 @@ class BackOff {
137
137
 
138
138
  // First step is immediate (0.001s)
139
139
  // Second and others are exponential
140
- // 1, 2, 3, 4, 5, 6, 7, 8, 9
141
- // 1, 4, 9, 16, 25, 36, 49, 64, 81
142
- // 0.25s, 1s, 2.25s, 4s, 6.25s, 9s, 12.25s, 16s, 20.25s
140
+ // Try: 1, 2, 3, 4, 5, 6, 7, 8, 9
141
+ // Multiple: 1, 4, 9, 16, 25, 36, 49, 64, 81
142
+ // Actual Time: 0.25s, 1s, 2.25s, 4s, 6.25s, 9s, 12.25s, 16s, 20.25s
143
143
  const delay = backOffTry === 0 ? 1 : Math.pow(backOffTry, 2) * 250;
144
144
 
145
145
  this.log('info', id, `Delaying call (attempt ${ backOffTry + 1 }, delayed by ${ delay }ms)`, description);
package/utils/brand.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Brand/Theme metadata
3
+ */
4
+ export interface BrandMeta {
5
+ // Does the banner have a stylesheet?
6
+ hasStylesheet?: string;
7
+ banner?: {
8
+ // Text alignment for the banner text overlayed on the banner image
9
+ textAlign?: string;
10
+ }
11
+ }
12
+
13
+ /**
14
+ * Get the brand/theme meta information for the specified brand
15
+ *
16
+ * @param brand - The brand identifier
17
+ * @returns Brand meta information or empty object if none available
18
+ */
19
+ export function getBrandMeta(brand: string): BrandMeta {
20
+ let brandMeta: BrandMeta = {};
21
+
22
+ if (brand) {
23
+ try {
24
+ brandMeta = require(`~shell/assets/brand/${ brand }/metadata.json`);
25
+ } catch {}
26
+ }
27
+
28
+ return brandMeta;
29
+ }
package/utils/chart.js ADDED
@@ -0,0 +1,18 @@
1
+ import { compatibleVersionsFor } from '@shell/store/catalog';
2
+
3
+ /**
4
+ * Get the latest chart version that is compatible with the cluster's OS and user's pre-release preference.
5
+ * @param {Object} chart - The chart object.
6
+ * @param {Array<string>} workerOSs - The list of worker OSs for the cluster.
7
+ * @param {boolean} showPrerelease - Whether to include pre-release versions.
8
+ * @returns {Object} The latest compatible chart version object.
9
+ */
10
+ export function getLatestCompatibleVersion(chart, workerOSs, showPrerelease) {
11
+ if (!chart?.versions?.length) {
12
+ return {};
13
+ }
14
+
15
+ const compatible = compatibleVersionsFor(chart, workerOSs, showPrerelease);
16
+
17
+ return (compatible.length ? compatible[0] : chart.versions[0]) || {};
18
+ }
package/utils/color.js CHANGED
@@ -13,7 +13,7 @@ Primary color classes from _light.scss
13
13
 
14
14
  */
15
15
 
16
- const Color = require('color');
16
+ import Color from 'color';
17
17
 
18
18
  export function createCssVars(color, theme = 'light', name = 'primary') {
19
19
  const contrastOpts = theme === 'light' ? LIGHT_CONTRAST_COLORS : DARK_CONTRAST_COLORS;