@rancher/shell 3.0.7 → 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 (375) 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/images/vendor/githubapp.svg +13 -0
  27. package/assets/styles/base/_typography.scss +2 -1
  28. package/assets/styles/fonts/_fontstack.scss +53 -1
  29. package/assets/styles/global/_cards.scss +0 -3
  30. package/assets/styles/global/_layout.scss +21 -35
  31. package/assets/styles/themes/_dark.scss +1 -1
  32. package/assets/styles/themes/_light.scss +1 -1
  33. package/assets/styles/themes/_modern.scss +16 -8
  34. package/assets/styles/themes/_suse.scss +116 -24
  35. package/assets/translations/en-us.yaml +185 -21
  36. package/assets/translations/zh-hans.yaml +0 -4
  37. package/components/AutoscalerCard.vue +113 -0
  38. package/components/AutoscalerTab.vue +94 -0
  39. package/components/BackLink.vue +8 -0
  40. package/components/BannerGraphic.vue +36 -21
  41. package/components/BrandImage.vue +17 -6
  42. package/components/ClusterIconMenu.vue +1 -1
  43. package/components/ClusterProviderIcon.vue +1 -1
  44. package/components/Cron/CronExpressionEditor.vue +1 -1
  45. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  46. package/components/Drawer/Chrome.vue +2 -6
  47. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
  48. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
  49. package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
  50. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
  51. package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
  52. package/components/Drawer/types.ts +3 -0
  53. package/components/DynamicContent/DynamicContentBanner.vue +102 -0
  54. package/components/DynamicContent/DynamicContentCloseButton.vue +42 -0
  55. package/components/DynamicContent/DynamicContentIcon.vue +132 -0
  56. package/components/DynamicContent/DynamicContentPanel.vue +112 -0
  57. package/components/DynamicContent/content.ts +78 -0
  58. package/components/EmberPage.vue +1 -1
  59. package/components/IconOrSvg.vue +2 -2
  60. package/components/Inactivity.vue +222 -106
  61. package/components/InstallHelmCharts.vue +2 -2
  62. package/components/PaginatedResourceTable.vue +2 -6
  63. package/components/PopoverCard.vue +192 -0
  64. package/components/Questions/__tests__/index.test.ts +159 -0
  65. package/components/Resource/Detail/CopyToClipboard.vue +4 -1
  66. package/components/Resource/Detail/FetchLoader/composables.ts +18 -4
  67. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  68. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +1 -1
  69. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +4 -0
  70. package/components/Resource/Detail/Metadata/KeyValueRow.vue +1 -1
  71. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  72. package/components/Resource/Detail/Metadata/composables.ts +9 -9
  73. package/components/Resource/Detail/Metadata/index.vue +3 -3
  74. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -19
  75. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +0 -29
  76. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +132 -150
  77. package/components/Resource/Detail/ResourcePopover/index.vue +54 -159
  78. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +0 -2
  79. package/components/Resource/Detail/TitleBar/composables.ts +2 -1
  80. package/components/Resource/Detail/TitleBar/index.vue +10 -6
  81. package/components/Resource/Detail/composables.ts +12 -0
  82. package/components/ResourceDetail/Masthead/latest.vue +29 -0
  83. package/components/ResourceDetail/index.vue +5 -2
  84. package/components/ResourceList/Masthead.vue +1 -1
  85. package/components/SortableTable/index.vue +18 -2
  86. package/components/Tabbed/__tests__/index.test.ts +86 -0
  87. package/components/{nav/WindowManager → Window}/ContainerLogs.vue +1 -1
  88. package/components/{nav/WindowManager → Window}/ContainerLogsActions.vue +1 -0
  89. package/components/{nav/WindowManager → Window}/__tests__/ContainerLogs.test.ts +1 -1
  90. package/components/{nav/WindowManager → Window}/__tests__/ContainerShell.test.ts +2 -2
  91. package/components/__tests__/AutoscalerCard.test.ts +154 -0
  92. package/components/__tests__/AutoscalerTab.test.ts +125 -0
  93. package/components/__tests__/PopoverCard.test.ts +204 -0
  94. package/components/auth/SelectPrincipal.vue +24 -6
  95. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  96. package/components/fleet/FleetConfigMapSelector.vue +117 -0
  97. package/components/fleet/FleetSecretSelector.vue +127 -0
  98. package/components/fleet/__tests__/FleetConfigMapSelector.test.ts +125 -0
  99. package/components/fleet/__tests__/FleetSecretSelector.test.ts +82 -0
  100. package/components/form/FileImageSelector.vue +13 -4
  101. package/components/form/FileSelector.vue +11 -2
  102. package/components/form/ResourceLabeledSelect.vue +1 -0
  103. package/components/form/__tests__/ResourceLabeledSelect.test.ts +90 -0
  104. package/components/formatter/Autoscaler.vue +97 -0
  105. package/components/formatter/InternalExternalIP.vue +198 -24
  106. package/components/formatter/__tests__/Autoscaler.test.ts +156 -0
  107. package/components/formatter/__tests__/InternalExternalIP.test.ts +133 -0
  108. package/components/google/util/__tests__/formatter.test.ts +47 -0
  109. package/components/google/util/formatter.ts +5 -2
  110. package/components/nav/Group.vue +12 -3
  111. package/components/nav/Header.vue +37 -16
  112. package/components/nav/NamespaceFilter.vue +13 -1
  113. package/components/nav/NotificationCenter/index.vue +2 -1
  114. package/components/nav/TopLevelMenu.helper.ts +16 -6
  115. package/components/nav/TopLevelMenu.vue +4 -2
  116. package/components/{DraggableZone.vue → nav/WindowManager/PinArea.vue} +47 -80
  117. package/components/nav/WindowManager/composables/useComponentsMount.ts +70 -0
  118. package/components/nav/WindowManager/composables/useDimensionsHandler.ts +105 -0
  119. package/components/nav/WindowManager/composables/useDragHandler.ts +99 -0
  120. package/components/nav/WindowManager/composables/usePanelHandler.ts +72 -0
  121. package/components/nav/WindowManager/composables/usePanelsHandler.ts +14 -0
  122. package/components/nav/WindowManager/composables/useResizeHandler.ts +167 -0
  123. package/components/nav/WindowManager/composables/useTabsHandler.ts +51 -0
  124. package/components/nav/WindowManager/constants.ts +23 -0
  125. package/components/nav/WindowManager/index.vue +61 -575
  126. package/components/nav/WindowManager/panels/HorizontalPanel.vue +265 -0
  127. package/components/nav/WindowManager/panels/TabBodyContainer.vue +39 -0
  128. package/components/nav/WindowManager/panels/VerticalPanel.vue +308 -0
  129. package/components/templates/default.vue +4 -40
  130. package/components/templates/home.vue +31 -5
  131. package/components/templates/plain.vue +30 -4
  132. package/components/templates/standalone.vue +1 -1
  133. package/composables/useI18n.ts +10 -1
  134. package/composables/useInterval.ts +15 -0
  135. package/config/__test__/uiplugins.test.ts +309 -0
  136. package/config/labels-annotations.js +9 -1
  137. package/config/product/auth.js +1 -0
  138. package/config/product/explorer.js +3 -1
  139. package/config/product/manager.js +20 -9
  140. package/config/query-params.js +1 -0
  141. package/config/router/routes.js +10 -2
  142. package/config/settings.ts +10 -2
  143. package/config/store.js +4 -2
  144. package/config/table-headers.js +8 -0
  145. package/config/types.js +11 -0
  146. package/config/uiplugins.js +46 -2
  147. package/config/version.js +1 -1
  148. package/core/__test__/extension-manager-impl.test.js +236 -0
  149. package/core/extension-manager-impl.js +23 -6
  150. package/core/plugin-helpers.ts +2 -0
  151. package/core/types-provisioning.ts +4 -1
  152. package/detail/pod.vue +1 -0
  153. package/detail/provisioning.cattle.io.cluster.vue +13 -1
  154. package/dialog/AddonConfigConfirmationDialog.vue +45 -1
  155. package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
  156. package/dialog/RollbackWorkloadDialog.vue +2 -5
  157. package/directives/ui-context.ts +103 -0
  158. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +52 -11
  159. package/edit/auth/AuthProviderWarningBanners.vue +14 -1
  160. package/edit/auth/__tests__/oidc.test.ts +26 -0
  161. package/edit/auth/github-app-steps.vue +97 -0
  162. package/edit/auth/github-steps.vue +75 -0
  163. package/edit/auth/github.vue +99 -65
  164. package/edit/auth/oidc.vue +5 -1
  165. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  166. package/edit/cloudcredential.vue +1 -1
  167. package/edit/configmap.vue +1 -0
  168. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  169. package/edit/fleet.cattle.io.gitrepo.vue +0 -10
  170. package/edit/fleet.cattle.io.helmop.vue +51 -2
  171. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  172. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  173. package/edit/logging-flow/index.vue +1 -0
  174. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  175. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  176. package/edit/management.cattle.io.project.vue +1 -0
  177. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  178. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  179. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  180. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  181. package/edit/monitoring.coreos.com.route.vue +1 -1
  182. package/edit/namespace.vue +1 -0
  183. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  184. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  185. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +15 -5
  186. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  187. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  188. package/edit/node.vue +1 -0
  189. package/edit/persistentvolume/index.vue +27 -22
  190. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  191. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  192. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  193. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  194. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  195. package/edit/persistentvolume/plugins/csi.vue +18 -16
  196. package/edit/persistentvolume/plugins/fc.vue +13 -14
  197. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  198. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  199. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  200. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  201. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  202. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  203. package/edit/persistentvolume/plugins/local.vue +1 -3
  204. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  205. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  206. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  207. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  208. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  209. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  210. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  211. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  212. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  213. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +32 -5
  214. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +35 -0
  215. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +155 -0
  216. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +11 -9
  217. package/edit/provisioning.cattle.io.cluster/index.vue +25 -15
  218. package/edit/provisioning.cattle.io.cluster/rke2.vue +98 -17
  219. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +28 -2
  220. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +107 -5
  221. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +92 -4
  222. package/edit/secret/index.vue +1 -1
  223. package/edit/service.vue +9 -4
  224. package/edit/serviceaccount.vue +1 -0
  225. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  226. package/edit/workload/index.vue +2 -1
  227. package/edit/workload/mixins/workload.js +1 -1
  228. package/initialize/App.vue +4 -4
  229. package/initialize/install-directives.js +2 -0
  230. package/initialize/install-plugins.js +19 -2
  231. package/list/projectsecret.vue +1 -1
  232. package/list/provisioning.cattle.io.cluster.vue +15 -2
  233. package/machine-config/amazonec2.vue +42 -135
  234. package/machine-config/azure.vue +1 -1
  235. package/machine-config/components/EC2Networking.vue +490 -0
  236. package/machine-config/components/__tests__/EC2Networking.test.ts +148 -0
  237. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +294 -0
  238. package/machine-config/digitalocean.vue +11 -0
  239. package/machine-config/google.vue +1 -1
  240. package/mixins/__tests__/brand.spec.ts +2 -2
  241. package/mixins/__tests__/chart.test.ts +21 -0
  242. package/mixins/brand.js +1 -7
  243. package/mixins/chart.js +8 -2
  244. package/mixins/create-edit-view/index.js +5 -0
  245. package/models/__tests__/chart.test.ts +49 -12
  246. package/models/__tests__/compliance.cattle.io.clusterscanprofile.spec.js +30 -0
  247. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
  248. package/models/catalog.cattle.io.app.js +1 -1
  249. package/models/chart.js +28 -14
  250. package/models/cluster/node.js +13 -6
  251. package/models/cluster.x-k8s.io.machine.js +10 -20
  252. package/models/cluster.x-k8s.io.machinedeployment.js +5 -1
  253. package/models/compliance.cattle.io.clusterscanprofile.js +1 -1
  254. package/models/management.cattle.io.authconfig.js +1 -0
  255. package/models/management.cattle.io.cluster.js +21 -3
  256. package/models/management.cattle.io.kontainerdriver.js +1 -0
  257. package/models/provisioning.cattle.io.cluster.js +249 -33
  258. package/package.json +6 -5
  259. package/pages/auth/login.vue +43 -4
  260. package/pages/auth/verify.vue +1 -1
  261. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +3 -2
  262. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  263. package/pages/c/_cluster/apps/charts/chart.vue +35 -17
  264. package/pages/c/_cluster/apps/charts/index.vue +11 -13
  265. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  266. package/pages/c/_cluster/explorer/EventsTable.vue +89 -3
  267. package/pages/c/_cluster/explorer/index.vue +8 -6
  268. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  269. package/pages/c/_cluster/manager/hostedprovider/index.vue +220 -0
  270. package/pages/c/_cluster/settings/brand.vue +1 -1
  271. package/pages/c/_cluster/settings/performance.vue +12 -25
  272. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  273. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  274. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  275. package/pages/home.vue +327 -16
  276. package/pkg/dynamic-importer.lib.js +4 -0
  277. package/plugins/axios.js +2 -1
  278. package/plugins/dashboard-client-init.js +3 -0
  279. package/plugins/dashboard-store/actions.js +1 -1
  280. package/plugins/dashboard-store/getters.js +18 -1
  281. package/plugins/dashboard-store/resource-class.js +21 -6
  282. package/plugins/dynamic-content.js +13 -0
  283. package/plugins/i18n.js +8 -0
  284. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
  285. package/plugins/steve/steve-pagination-utils.ts +41 -22
  286. package/plugins/steve/subscribe.js +17 -9
  287. package/plugins/subscribe-events.ts +4 -2
  288. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  289. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -34
  290. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  291. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  292. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  293. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  294. package/rancher-components/Pill/types.ts +0 -1
  295. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -0
  296. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +5 -1
  297. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  298. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  299. package/rancher-components/RcIcon/index.ts +1 -0
  300. package/rancher-components/RcIcon/types.ts +160 -0
  301. package/rancher-components/utils/status.test.ts +67 -0
  302. package/rancher-components/utils/status.ts +77 -0
  303. package/scripts/extension/publish +1 -1
  304. package/scripts/typegen.sh +1 -0
  305. package/store/action-menu.js +8 -0
  306. package/store/auth.js +11 -6
  307. package/store/aws.js +8 -6
  308. package/store/catalog.js +6 -0
  309. package/store/features.js +2 -0
  310. package/store/index.js +45 -20
  311. package/store/notifications.ts +51 -4
  312. package/store/plugins.js +7 -3
  313. package/store/prefs.js +12 -6
  314. package/store/type-map.js +3 -3
  315. package/store/ui-context.ts +86 -0
  316. package/store/wm.ts +244 -0
  317. package/types/kube/kube-api.ts +2 -1
  318. package/types/notifications/index.ts +27 -3
  319. package/types/rancher/index.d.ts +1 -0
  320. package/types/resources/settings.d.ts +29 -7
  321. package/types/shell/index.d.ts +138 -4
  322. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  323. package/types/store/pagination.types.ts +157 -9
  324. package/types/store/subscribe-events.types.ts +8 -1
  325. package/types/store/subscribe.types.ts +1 -0
  326. package/types/window-manager.ts +24 -0
  327. package/utils/__tests__/cluster.test.ts +379 -1
  328. package/utils/__tests__/object.test.ts +19 -0
  329. package/utils/__tests__/provider.test.ts +98 -0
  330. package/utils/__tests__/selector-typed.test.ts +263 -0
  331. package/utils/__tests__/version.test.ts +19 -1
  332. package/utils/autoscaler-utils.ts +7 -0
  333. package/utils/back-off.ts +3 -3
  334. package/utils/brand.ts +29 -0
  335. package/utils/chart.js +18 -0
  336. package/utils/cluster.js +157 -3
  337. package/utils/color.js +1 -1
  338. package/utils/dynamic-content/__tests__/announcement.test.ts +498 -0
  339. package/utils/dynamic-content/__tests__/config.test.ts +187 -0
  340. package/utils/dynamic-content/__tests__/index.test.ts +390 -0
  341. package/utils/dynamic-content/__tests__/info.test.ts +275 -0
  342. package/utils/dynamic-content/__tests__/new-release.test.ts +216 -0
  343. package/utils/dynamic-content/__tests__/support-notice.test.ts +262 -0
  344. package/utils/dynamic-content/__tests__/util.test.ts +235 -0
  345. package/utils/dynamic-content/announcement.ts +142 -0
  346. package/utils/dynamic-content/config.ts +55 -0
  347. package/utils/dynamic-content/example.json +40 -0
  348. package/utils/dynamic-content/index.ts +277 -0
  349. package/utils/dynamic-content/info.ts +261 -0
  350. package/utils/dynamic-content/new-release.ts +126 -0
  351. package/utils/dynamic-content/notification-handler.ts +48 -0
  352. package/utils/dynamic-content/support-notice.ts +169 -0
  353. package/utils/dynamic-content/types.d.ts +153 -0
  354. package/utils/dynamic-content/util.ts +122 -0
  355. package/utils/dynamic-importer.js +2 -2
  356. package/utils/favicon.js +4 -4
  357. package/utils/inactivity.ts +104 -0
  358. package/utils/object.js +20 -2
  359. package/utils/pagination-utils.ts +19 -4
  360. package/utils/pagination-wrapper.ts +12 -8
  361. package/utils/provider.ts +14 -0
  362. package/utils/release-notes.ts +1 -1
  363. package/utils/scroll.js +7 -0
  364. package/utils/selector-typed.ts +6 -2
  365. package/utils/settings.ts +15 -0
  366. package/utils/validators/machine-pool.ts +13 -3
  367. package/utils/version.js +15 -0
  368. package/assets/images/icons/document.svg +0 -3
  369. package/plugins/nuxt-client-init.js +0 -3
  370. package/store/wm.js +0 -95
  371. /package/components/{nav/WindowManager → Window}/ChartReadme.vue +0 -0
  372. /package/components/{nav/WindowManager → Window}/ContainerShell.vue +0 -0
  373. /package/components/{nav/WindowManager → Window}/KubectlShell.vue +0 -0
  374. /package/components/{nav/WindowManager → Window}/MachineSsh.vue +0 -0
  375. /package/components/{nav/WindowManager → Window}/Window.vue +0 -0
@@ -32,8 +32,6 @@ export interface TitleBarProps {
32
32
  actionMenuResource?: any;
33
33
  onShowConfiguration?: (returnFocusSelector: string) => void;
34
34
  }
35
-
36
- const showConfigurationIcon = require(`@shell/assets/images/icons/document.svg`);
37
35
  </script>
38
36
 
39
37
  <script setup lang="ts">
@@ -84,6 +82,7 @@ watch(
84
82
  </span>
85
83
  <BadgeState
86
84
  v-if="badge"
85
+ v-ui-context="{ store: store, icon: 'icon-folder', hookable: true, value: resource, tag: '__details-state', description: 'Details' }"
87
86
  class="badge-state"
88
87
  :color="badge.color"
89
88
  :label="badge.label"
@@ -99,11 +98,10 @@ watch(
99
98
  :aria-label="i18n.t('component.resource.detail.titleBar.ariaLabel.showConfiguration', { resource: resourceName })"
100
99
  @click="() => emit('show-configuration', showConfigurationReturnFocusSelector)"
101
100
  >
102
- <img
103
- :src="showConfigurationIcon"
104
- class="mmr-3"
101
+ <i
102
+ class="icon icon-document"
105
103
  aria-hidden="true"
106
- >
104
+ />
107
105
  {{ i18n.t('component.resource.detail.titleBar.showConfiguration') }}
108
106
  </RcButton>
109
107
  <ActionMenu
@@ -139,6 +137,12 @@ watch(
139
137
  position: relative;
140
138
  }
141
139
 
140
+ .icon-document {
141
+ width: 15px;
142
+ font-size: 16px;
143
+ margin-right: 10px;
144
+ }
145
+
142
146
  .show-configuration {
143
147
  margin-left: 16px;
144
148
  }
@@ -2,6 +2,7 @@ import { computed, Ref, toValue } from 'vue';
2
2
  import { useStore } from 'vuex';
3
3
  import { Props as BannerProps } from '@components/Banner/Banner.vue';
4
4
  import { useI18n } from '@shell/composables/useI18n';
5
+ import ResourceClass from '@shell/plugins/dashboard-store/resource-class';
5
6
 
6
7
  export const useResourceDetailBannerProps = (resource: any): Ref<BannerProps | undefined> => {
7
8
  const store = useStore();
@@ -43,3 +44,14 @@ export const useResourceDetailBannerProps = (resource: any): Ref<BannerProps | u
43
44
  return undefined;
44
45
  });
45
46
  };
47
+
48
+ export const useOnShowConfiguration = (resource: any) => {
49
+ return (returnFocusSelector?: string, defaultTab?: string) => {
50
+ const resourceValue = toValue(resource);
51
+ // Because extensions can make a copy of the resource-class it's possible that an extension will have a resource-class which predates the inclusion of showConfiguration
52
+ // to still the rest of shell to consume
53
+ const showConfiguration = resourceValue.showConfiguration ? resourceValue.showConfiguration.bind(resourceValue) : ResourceClass.prototype.showConfiguration.bind(resourceValue);
54
+
55
+ showConfiguration(returnFocusSelector, defaultTab);
56
+ };
57
+ };
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable */
2
3
  import { Banner } from '@components/Banner';
3
4
  import TitleBar from '@shell/components/Resource/Detail/TitleBar/index.vue';
4
5
  import { useDefaultTitleBarProps } from '@shell/components/Resource/Detail/TitleBar/composables';
@@ -7,6 +8,7 @@ import { useDefaultMetadataForLegacyPagesProps } from '@shell/components/Resourc
7
8
  import { useResourceDetailBannerProps } from '@shell/components/Resource/Detail/composables';
8
9
  import { computed } from 'vue';
9
10
 
11
+ // We are disabling eslint for this script to allow the use of the Props interface
10
12
  export interface Props {
11
13
  value?: Object;
12
14
  resourceSubtype?: string;
@@ -15,18 +17,45 @@ export interface Props {
15
17
  </script>
16
18
 
17
19
  <script lang="ts" setup>
20
+ import { useStore } from 'vuex';
21
+
18
22
  const props = withDefaults(defineProps<Props>(), { value: () => ({}), resourceSubtype: undefined });
19
23
 
24
+ const uiCtxResource = computed(() => {
25
+ const {
26
+ name, metadata, kind, state
27
+ } = (props.value || {}) as any;
28
+
29
+ return {
30
+ name,
31
+ namespace: metadata?.namespace,
32
+ kind,
33
+ state,
34
+ };
35
+ });
20
36
  const resourceSubtype = computed(() => props.resourceSubtype);
21
37
  const titleBarProps = useDefaultTitleBarProps(props.value, resourceSubtype);
22
38
  const metadataProps = useDefaultMetadataForLegacyPagesProps(props.value);
23
39
  const bannerProps = useResourceDetailBannerProps(props.value);
40
+
41
+ const store = useStore();
24
42
  </script>
25
43
 
26
44
  <template>
27
45
  <TitleBar v-bind="titleBarProps" />
28
46
  <Banner
29
47
  v-if="bannerProps"
48
+ v-ui-context="{
49
+ store: store,
50
+ icon: 'icon-info',
51
+ hookable: true,
52
+ value: {
53
+ bannerProps,
54
+ resource: uiCtxResource
55
+ },
56
+ tag: '__details-state-banner',
57
+ description: 'Status Message'
58
+ }"
30
59
  class="new state-banner"
31
60
  v-bind="bannerProps"
32
61
  />
@@ -310,7 +310,7 @@ export default {
310
310
  }), {});
311
311
  },
312
312
  isFullPageOverride() {
313
- return this.isView && this.value.fullDetailPageOverride;
313
+ return this.isView && this.value.fullDetailPageOverride && !this.isYaml;
314
314
  }
315
315
  },
316
316
 
@@ -430,6 +430,7 @@ export default {
430
430
  :is="showComponent"
431
431
  v-else-if="isFullPageOverride"
432
432
  v-model:value="value"
433
+ v-ui-context="{ icon: 'icon-folder', value: value.name, tag: value.kind?.toLowerCase(), description: value.kind }"
433
434
  v-bind="$data"
434
435
  :done-params="doneParams"
435
436
  :done-route="doneRoute"
@@ -446,6 +447,7 @@ export default {
446
447
  <div v-else>
447
448
  <Masthead
448
449
  v-if="showMasthead"
450
+ v-ui-context="{ icon: 'icon-folder', value: liveModel.name, tag: liveModel.kind?.toLowerCase(), description: liveModel.kind }"
449
451
  :resource="resourceType"
450
452
  :value="liveModel"
451
453
  :mode="mode"
@@ -481,7 +483,7 @@ export default {
481
483
  </div>
482
484
 
483
485
  <ResourceYaml
484
- v-else-if="isYaml"
486
+ v-if="isYaml"
485
487
  ref="resourceyaml"
486
488
  :value="value"
487
489
  :mode="mode"
@@ -499,6 +501,7 @@ export default {
499
501
  v-else
500
502
  ref="comp"
501
503
  v-model:value="value"
504
+ v-ui-context="{ icon: 'icon-folder', value: value.name, tag: value.kind?.toLowerCase(), description: value.kind }"
502
505
  v-bind="$data"
503
506
  :done-params="doneParams"
504
507
  :done-route="doneRoute"
@@ -141,7 +141,7 @@ export default {
141
141
  }
142
142
 
143
143
  // blocked-post means you can post through norman, but not through steve.
144
- if ( this.schema && !this.schema?.collectionMethods.find((x) => ['blocked-post', 'post'].includes(x.toLowerCase())) ) {
144
+ if ( this.schema && this.schema?.collectionMethods && !this.schema?.collectionMethods.find((x) => ['blocked-post', 'post'].includes(x.toLowerCase())) ) {
145
145
  return false;
146
146
  }
147
147
 
@@ -1090,7 +1090,7 @@ export default {
1090
1090
  <div
1091
1091
  v-if="showHeaderRow"
1092
1092
  class="fixed-header-actions"
1093
- :class="{button: !!$slots['header-button'], 'advanced-filtering': hasAdvancedFiltering}"
1093
+ :class="{button: !!$slots['header-button'], 'with-sub-header': !!$slots['sub-header-row'], 'advanced-filtering': hasAdvancedFiltering}"
1094
1094
  >
1095
1095
  <div
1096
1096
  :class="bulkActionsClass"
@@ -1296,6 +1296,12 @@ export default {
1296
1296
  <slot name="header-button" />
1297
1297
  </div>
1298
1298
  </div>
1299
+ <div
1300
+ v-if="!!$slots['sub-header-row']"
1301
+ class="sub-header-row"
1302
+ >
1303
+ <slot name="sub-header-row" />
1304
+ </div>
1299
1305
  </div>
1300
1306
  <table
1301
1307
  ref="table"
@@ -1468,6 +1474,7 @@ export default {
1468
1474
  <td
1469
1475
  v-show="!hasAdvancedFiltering || (hasAdvancedFiltering && col.col.isColVisible)"
1470
1476
  :key="col.col.name"
1477
+ v-ui-context="col.col.name === 'state' ? { icon: 'icon-folder', hookable: true, value: row.row, tag: '__sortable-table-row', description: 'Row' } : undefined"
1471
1478
  :data-title="col.col.label"
1472
1479
  :data-testid="`sortable-cell-${ i }-${ j }`"
1473
1480
  :align="col.col.align || 'left'"
@@ -2047,8 +2054,17 @@ export default {
2047
2054
  grid-template-columns: [bulk] auto [middle] min-content [search] minmax(min-content, 350px);
2048
2055
  }
2049
2056
 
2057
+ $header-padding: 20px;
2058
+ .sub-header-row {
2059
+ padding: 0 0 $header-padding / 2 0;
2060
+ }
2061
+
2050
2062
  .fixed-header-actions {
2051
- padding: 0 0 20px 0;
2063
+ padding: 0 0 $header-padding 0;
2064
+ &.with-sub-header {
2065
+ padding: 0 0 $header-padding / 4 0;
2066
+ }
2067
+
2052
2068
  width: 100%;
2053
2069
  z-index: z-index('fixedTableHeader');
2054
2070
  background: transparent;
@@ -0,0 +1,86 @@
1
+ import { mount, VueWrapper } from '@vue/test-utils';
2
+ import Tabbed from '@shell/components/Tabbed/index.vue';
3
+ import Tab from '@shell/components/Tabbed/Tab.vue';
4
+
5
+ jest.mock('@shell/components/form/ResourceTabs/composable', () => ({ useTabCountWatcher: () => ({}) }));
6
+
7
+ const mockT = (key: string) => key;
8
+
9
+ const defaultGlobalMountOptions = {
10
+ components: { Tab },
11
+ mocks: {
12
+ $router: {
13
+ replace: jest.fn(),
14
+ currentRoute: { _value: { hash: '' } }
15
+ },
16
+ $route: { hash: '' },
17
+ t: mockT,
18
+ store: { getters: { 'i18n/t': mockT } }
19
+ }
20
+ };
21
+
22
+ describe('component: Tabbed', () => {
23
+ const findTabNav = (wrapper: VueWrapper<any>) => wrapper.find('[data-testid="tabbed-block"]');
24
+
25
+ it('should display tab navigation for a single tab when hideSingleTab is false (default)', async() => {
26
+ const wrapper = mount(Tabbed, {
27
+ slots: { default: { components: { Tab }, template: '<Tab name="tab1" label="Tab 1" />' } },
28
+ global: { ...defaultGlobalMountOptions },
29
+ });
30
+
31
+ await wrapper.vm.$nextTick();
32
+
33
+ expect(findTabNav(wrapper).exists()).toBe(true);
34
+ });
35
+
36
+ it('should display tab navigation for multiple tabs when hideSingleTab is false (default)', async() => {
37
+ const wrapper = mount(Tabbed, {
38
+ slots: {
39
+ default: {
40
+ components: { Tab },
41
+ template: `
42
+ <Tab name="tab1" label="Tab 1" />
43
+ <Tab name="tab2" label="Tab 2" />
44
+ `,
45
+ },
46
+ },
47
+ global: { ...defaultGlobalMountOptions },
48
+ });
49
+
50
+ await wrapper.vm.$nextTick();
51
+
52
+ expect(findTabNav(wrapper).exists()).toBe(true);
53
+ });
54
+
55
+ it('should NOT display tab navigation for a single tab when hideSingleTab is true', async() => {
56
+ const wrapper = mount(Tabbed, {
57
+ props: { hideSingleTab: true },
58
+ slots: { default: { components: { Tab }, template: '<Tab name="tab1" label="Tab 1" />' } },
59
+ global: { ...defaultGlobalMountOptions },
60
+ });
61
+
62
+ await wrapper.vm.$nextTick();
63
+
64
+ expect(findTabNav(wrapper).exists()).toBe(false);
65
+ });
66
+
67
+ it('should display tab navigation for multiple tabs when hideSingleTab is true', async() => {
68
+ const wrapper = mount(Tabbed, {
69
+ props: { hideSingleTab: true },
70
+ slots: {
71
+ default: {
72
+ components: { Tab },
73
+ template: `
74
+ <Tab name="tab1" label="Tab 1" />
75
+ <Tab name="tab2" label="Tab 2" />
76
+ `,
77
+ },
78
+ },
79
+ global: { ...defaultGlobalMountOptions },
80
+ });
81
+
82
+ await wrapper.vm.$nextTick();
83
+
84
+ expect(findTabNav(wrapper).exists()).toBe(true);
85
+ });
86
+ });
@@ -10,7 +10,7 @@ import AsyncButton from '@shell/components/AsyncButton';
10
10
  import Select from '@shell/components/form/Select';
11
11
  import VirtualList from 'vue3-virtual-scroll-list';
12
12
  import LogItem from '@shell/components/LogItem';
13
- import ContainerLogsActions from '@shell/components/nav/WindowManager/ContainerLogsActions.vue';
13
+ import ContainerLogsActions from '@shell/components/Window/ContainerLogsActions.vue';
14
14
  import { shallowRef } from 'vue';
15
15
  import { useStore } from 'vuex';
16
16
  import { debounce } from 'lodash';
@@ -49,6 +49,7 @@ defineEmits([
49
49
  <rc-dropdown-item-select
50
50
  :model-value="range"
51
51
  :options="rangeOptions"
52
+ :label="t('wm.containerLogs.range.label')"
52
53
  @select="$emit('toggleRange', $event)"
53
54
  />
54
55
  <rc-dropdown-item-checkbox
@@ -1,6 +1,6 @@
1
1
  import { nextTick } from 'vue';
2
2
  import { shallowMount } from '@vue/test-utils';
3
- import ContainerLogs from '@shell/components/nav/WindowManager/ContainerLogs.vue';
3
+ import ContainerLogs from '@shell/components/Window/ContainerLogs.vue';
4
4
  import { base64Encode } from '@shell/utils/crypto';
5
5
  import { Buffer } from 'buffer';
6
6
  import { addEventListener } from '@shell/utils/socket';
@@ -1,9 +1,9 @@
1
1
  import { flushPromises, mount, Wrapper } from '@vue/test-utils';
2
- import ContainerShell from '@shell/components/nav/WindowManager/ContainerShell.vue';
2
+ import ContainerShell from '@shell/components/Window/ContainerShell.vue';
3
3
  import Socket, {
4
4
  addEventListener, EVENT_CONNECTED, EVENT_CONNECTING, EVENT_DISCONNECTED, EVENT_MESSAGE, EVENT_CONNECT_ERROR
5
5
  } from '@shell/utils/socket';
6
- import Window from '@shell/components/nav/WindowManager/Window.vue';
6
+ import Window from '@shell/components/Window/Window.vue';
7
7
 
8
8
  jest.mock('@shell/utils/socket');
9
9
  jest.mock('@shell/utils/crypto', () => {
@@ -0,0 +1,154 @@
1
+
2
+ import { mount } from '@vue/test-utils';
3
+ import AutoscalerCard from '@shell/components/AutoscalerCard.vue';
4
+ import { ref } from 'vue';
5
+ import { createStore } from 'vuex';
6
+
7
+ const mockUseFetch = jest.fn();
8
+
9
+ jest.mock('@shell/components/Resource/Detail/FetchLoader/composables', () => ({ useFetch: (...args: any[]) => mockUseFetch(...args) }));
10
+
11
+ const mockUseInterval = jest.fn();
12
+
13
+ jest.mock('@shell/composables/useInterval', () => ({ useInterval: (...args: any[]) => mockUseInterval(...args) }));
14
+
15
+ describe('component: AutoscalerCard.vue', () => {
16
+ const mockLoadDetails = jest.fn();
17
+ const mockRefresh = jest.fn();
18
+
19
+ const createWrapper = (props: any, useFetchState: any) => {
20
+ // Reset and configure the useFetch mock for each test
21
+ mockUseFetch.mockImplementation(() => {
22
+ return ref({
23
+ loading: false,
24
+ refreshing: false,
25
+ data: null,
26
+ refresh: mockRefresh,
27
+ ...useFetchState,
28
+ });
29
+ });
30
+
31
+ return mount(AutoscalerCard, {
32
+ props: {
33
+ value: { loadAutoscalerDetails: mockLoadDetails },
34
+ ...props,
35
+ },
36
+ global: { plugins: [createStore({})] },
37
+ // Shallow mount to avoid rendering child components like the dynamic ones
38
+ shallow: true,
39
+ });
40
+ };
41
+
42
+ beforeEach(() => {
43
+ jest.clearAllMocks();
44
+ });
45
+
46
+ it('should call useFetch with the correct loader function', () => {
47
+ createWrapper({}, {});
48
+ // The first argument to useFetch is the loader function
49
+ expect(mockUseFetch).toHaveBeenCalledWith(expect.any(Function));
50
+ // We can invoke the loader to ensure it calls the prop method
51
+ const loader = mockUseFetch.mock.calls[0][0];
52
+
53
+ loader();
54
+ expect(mockLoadDetails).toHaveBeenCalledWith();
55
+ });
56
+
57
+ it('should setup a polling interval to refresh data', () => {
58
+ createWrapper({}, {});
59
+ expect(mockUseInterval).toHaveBeenCalledWith(expect.any(Function), 10000);
60
+
61
+ // Invoke the interval function to ensure it calls refresh
62
+ const intervalFn = mockUseInterval.mock.calls[0][0];
63
+
64
+ intervalFn();
65
+ expect(mockRefresh).toHaveBeenCalledWith();
66
+ });
67
+
68
+ describe('uI States', () => {
69
+ it('should display a loading spinner on initial load', () => {
70
+ const wrapper = createWrapper({}, { loading: true, refreshing: false });
71
+
72
+ expect(wrapper.find('.loading').exists()).toBe(true);
73
+ expect(wrapper.find('.icon-spinner').exists()).toBe(true);
74
+ expect(wrapper.find('.details').exists()).toBe(false);
75
+ expect(wrapper.find('.text-warning').exists()).toBe(false);
76
+ });
77
+
78
+ it('should NOT display the main loading spinner during a background refresh', () => {
79
+ const wrapper = createWrapper({}, {
80
+ loading: true, refreshing: true, data: []
81
+ });
82
+
83
+ expect(wrapper.find('.loading').exists()).toBe(false);
84
+ // Data should still be visible
85
+ expect(wrapper.find('.details').exists()).toBe(true);
86
+ });
87
+
88
+ it('should display an error message if loading fails', () => {
89
+ const wrapper = createWrapper({}, { loading: false, data: null });
90
+
91
+ expect(wrapper.find('.text-warning').exists()).toBe(true);
92
+ expect(wrapper.find('.text-warning').text()).toBe('autoscaler.card.loadingError');
93
+ expect(wrapper.find('.loading').exists()).toBe(false);
94
+ expect(wrapper.find('.details').exists()).toBe(false);
95
+ });
96
+
97
+ it('should display details when data is loaded', () => {
98
+ const mockData = [
99
+ { label: 'Status', value: 'Active' },
100
+ { label: 'Nodes', value: '3' },
101
+ ];
102
+ const wrapper = createWrapper({}, { loading: false, data: mockData });
103
+
104
+ expect(wrapper.find('.details').exists()).toBe(true);
105
+ const details = wrapper.findAll('.detail');
106
+
107
+ expect(details).toHaveLength(2);
108
+ expect(details[0].text()).toContain('Status');
109
+ expect(details[0].text()).toContain('Active');
110
+ expect(details[1].text()).toContain('Nodes');
111
+ expect(details[1].text()).toContain('3');
112
+ });
113
+ });
114
+
115
+ describe('detail Rendering', () => {
116
+ it('should render a string value', () => {
117
+ const mockData = [{ label: 'My Label', value: 'My Value' }];
118
+ const wrapper = createWrapper({}, { data: mockData });
119
+ const valueDiv = wrapper.find('.value');
120
+
121
+ expect(valueDiv.find('span').exists()).toBe(true);
122
+ expect(valueDiv.text()).toBe('My Value');
123
+ });
124
+
125
+ it('should render a dynamic component value', () => {
126
+ const DynamicComponent = {
127
+ name: 'DynamicComponent',
128
+ props: ['text'],
129
+ template: '<div>{{ text }}</div>'
130
+ };
131
+ const mockData = [{
132
+ label: 'My Component',
133
+ value: { component: DynamicComponent, props: { text: 'Dynamic Text' } }
134
+ }];
135
+ const wrapper = createWrapper({}, { data: mockData });
136
+ const valueDiv = wrapper.find('.value');
137
+ const renderedComponent = valueDiv.findComponent(DynamicComponent);
138
+
139
+ expect(renderedComponent.exists()).toBe(true);
140
+ expect(renderedComponent.props('text')).toBe('Dynamic Text');
141
+ });
142
+
143
+ it('should render a heading for details without a value', () => {
144
+ const mockData = [{ label: 'Section Header' }];
145
+ const wrapper = createWrapper({}, { data: mockData });
146
+
147
+ expect(wrapper.find('h5').exists()).toBe(true);
148
+ expect(wrapper.find('h5').text()).toBe('Section Header');
149
+ // Label and value should not be rendered
150
+ expect(wrapper.find('label').exists()).toBe(false);
151
+ expect(wrapper.find('.value').exists()).toBe(false);
152
+ });
153
+ });
154
+ });
@@ -0,0 +1,125 @@
1
+
2
+ import { mount } from '@vue/test-utils';
3
+ import AutoscalerTab from '@shell/components/AutoscalerTab.vue';
4
+ import { ref } from 'vue';
5
+ import { createStore } from 'vuex';
6
+
7
+ const mockUseFetch = jest.fn();
8
+
9
+ jest.mock('@shell/components/Resource/Detail/FetchLoader/composables', () => ({ useFetch: (...args: any[]) => mockUseFetch(...args) }));
10
+
11
+ const mockUseInterval = jest.fn();
12
+
13
+ jest.mock('@shell/composables/useInterval', () => ({ useInterval: (...args: any[]) => mockUseInterval(...args) }));
14
+
15
+ describe('component: AutoscalerTab.vue', () => {
16
+ const mockLoadEvents = jest.fn();
17
+ const mockRefresh = jest.fn();
18
+ const mockChangeSort = jest.fn();
19
+
20
+ const SortableTableStub = {
21
+ name: 'SortableTable',
22
+ template: '<div></div>',
23
+ setup() {
24
+ return { changeSort: mockChangeSort };
25
+ },
26
+ props: ['namespaced', 'rowActions', 'defaultSortBy', 'headers', 'rows']
27
+ };
28
+
29
+ const createWrapper = (props: any, useFetchState: any) => {
30
+ mockUseFetch.mockImplementation(() => {
31
+ return ref({
32
+ data: null,
33
+ refresh: mockRefresh,
34
+ ...useFetchState,
35
+ });
36
+ });
37
+
38
+ return mount(AutoscalerTab, {
39
+ props: {
40
+ value: { loadAutoscalerEvents: mockLoadEvents },
41
+ ...props,
42
+ },
43
+ global: {
44
+ plugins: [createStore({})],
45
+ stubs: {
46
+ Tab: {
47
+ name: 'Tab',
48
+ template: '<div><slot/></div>',
49
+ props: ['label']
50
+ },
51
+ SortableTable: SortableTableStub,
52
+ },
53
+ }
54
+ });
55
+ };
56
+
57
+ beforeEach(() => {
58
+ jest.clearAllMocks();
59
+ });
60
+
61
+ describe('initialization and Data Fetching', () => {
62
+ it('should call useFetch with the correct loader function', () => {
63
+ createWrapper({}, {});
64
+ expect(mockUseFetch).toHaveBeenCalledWith(expect.any(Function));
65
+
66
+ const loader = mockUseFetch.mock.calls[0][0];
67
+
68
+ loader();
69
+ expect(mockLoadEvents).toHaveBeenCalledWith();
70
+ });
71
+
72
+ it('should setup a polling interval to refresh data', () => {
73
+ createWrapper({}, {});
74
+ expect(mockUseInterval).toHaveBeenCalledWith(expect.any(Function), 20000);
75
+
76
+ const intervalFn = mockUseInterval.mock.calls[0][0];
77
+
78
+ intervalFn();
79
+ expect(mockRefresh).toHaveBeenCalledWith();
80
+ });
81
+
82
+ it('should call changeSort on the table on mounted', () => {
83
+ createWrapper({}, {});
84
+ expect(mockChangeSort).toHaveBeenCalledWith('date', true);
85
+ });
86
+ });
87
+
88
+ describe('sortableTable props', () => {
89
+ it('should pass static props to the table', () => {
90
+ const wrapper = createWrapper({}, {});
91
+ const table = wrapper.findComponent(SortableTableStub);
92
+
93
+ expect(table.props('namespaced')).toBe(false);
94
+ expect(table.props('rowActions')).toBe(false);
95
+ expect(table.props('defaultSortBy')).toBe('date');
96
+ expect(table.props('headers')).toHaveLength(4);
97
+ expect(table.props('headers')[0].name).toBe('type');
98
+ });
99
+
100
+ it('should pass an empty array to rows when data is null', () => {
101
+ const wrapper = createWrapper({}, { data: null });
102
+ const table = wrapper.findComponent(SortableTableStub);
103
+
104
+ expect(table.props('rows')).toStrictEqual([]);
105
+ });
106
+
107
+ it('should pass fetched data to the rows prop', () => {
108
+ const mockEvents = [
109
+ { id: 1, message: 'Event 1' },
110
+ { id: 2, message: 'Event 2' },
111
+ ];
112
+ const wrapper = createWrapper({}, { data: mockEvents });
113
+ const table = wrapper.findComponent(SortableTableStub);
114
+
115
+ expect(table.props('rows')).toStrictEqual(mockEvents);
116
+ });
117
+ });
118
+
119
+ it('should pass correct label to Tab component', () => {
120
+ const wrapper = createWrapper({}, {});
121
+ const tab = wrapper.findComponent({ name: 'Tab' });
122
+
123
+ expect(tab.props('label')).toBe('autoscaler.tab.title');
124
+ });
125
+ });