@rancher/shell 3.0.12-rc.2 → 3.0.12-rc.4

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 (473) hide show
  1. package/apis/impl/apis.ts +6 -0
  2. package/apis/index.ts +26 -0
  3. package/apis/intf/resources-api/cluster-api.ts +18 -0
  4. package/apis/intf/resources-api/mgmt-api.ts +15 -0
  5. package/apis/intf/resources-api/resource-base.ts +107 -0
  6. package/apis/intf/resources-api/resource-constants.ts +147 -0
  7. package/apis/intf/resources-api/resources-api.ts +143 -0
  8. package/apis/intf/resources.ts +49 -0
  9. package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
  10. package/apis/intf/shell-api/proxy.ts +216 -0
  11. package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
  12. package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
  13. package/apis/intf/shell.ts +12 -6
  14. package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
  15. package/apis/resources/index.ts +22 -0
  16. package/apis/resources/resources-api-class.ts +187 -0
  17. package/apis/shell/__tests__/proxy.test.ts +369 -0
  18. package/apis/shell/index.ts +8 -1
  19. package/apis/shell/modal.ts +4 -1
  20. package/apis/shell/notifications.ts +9 -6
  21. package/apis/shell/proxy.ts +256 -0
  22. package/apis/shell/slide-in.ts +4 -1
  23. package/apis/vue-shim.d.ts +2 -1
  24. package/assets/data/aws-regions.json +4 -0
  25. package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
  26. package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
  27. package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
  28. package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
  29. package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
  30. package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
  31. package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
  32. package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
  33. package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
  34. package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
  35. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
  36. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
  37. package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
  38. package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
  39. package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
  40. package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
  41. package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
  42. package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
  43. package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
  44. package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
  45. package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
  46. package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
  47. package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
  48. package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
  49. package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
  50. package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
  51. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
  52. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
  53. package/assets/styles/base/_variables.scss +2 -0
  54. package/assets/styles/fonts/_fontstack.scss +132 -8
  55. package/assets/styles/global/_layout.scss +4 -0
  56. package/assets/translations/en-us.yaml +165 -45
  57. package/assets/translations/zh-hans.yaml +1 -7
  58. package/chart/monitoring/ClusterSelector.vue +0 -21
  59. package/chart/monitoring/index.vue +10 -1
  60. package/chart/monitoring/prometheus/index.vue +6 -3
  61. package/components/ActionDropdownShell.vue +2 -1
  62. package/components/CruResource.vue +161 -14
  63. package/components/CruResourceFooter.vue +9 -5
  64. package/components/ExplorerMembers.vue +8 -4
  65. package/components/ExplorerProjectsNamespaces.vue +11 -7
  66. package/components/GrowlManager.vue +4 -0
  67. package/components/InstallHelmCharts.vue +2 -2
  68. package/components/LandingPagePreference.vue +14 -5
  69. package/components/MgmtNodeList.vue +184 -0
  70. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
  71. package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
  72. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
  73. package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
  74. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +17 -1
  75. package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
  76. package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
  77. package/components/Resource/Detail/Metadata/index.vue +6 -0
  78. package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
  79. package/components/Resource/Detail/SpacedRow.vue +3 -1
  80. package/components/Resource/Detail/TitleBar/index.vue +10 -11
  81. package/components/ResourceDetail/index.vue +1 -1
  82. package/components/ResourceList/Masthead.vue +19 -9
  83. package/components/ResourceList/index.vue +82 -1
  84. package/components/RichTranslation.vue +5 -2
  85. package/components/SelectIconGrid.vue +0 -10
  86. package/components/Setting.vue +1 -0
  87. package/components/SingleClusterInfo.vue +1 -0
  88. package/components/SortableTable/__tests__/sorting.test.ts +126 -0
  89. package/components/SortableTable/index.vue +6 -9
  90. package/components/SortableTable/selection.js +23 -5
  91. package/components/SortableTable/sorting.js +6 -3
  92. package/components/SubtleLink.vue +31 -6
  93. package/components/Tabbed/Tab.vue +29 -3
  94. package/components/Tabbed/index.vue +25 -3
  95. package/components/TableOfContents/TableOfContents.vue +109 -0
  96. package/components/TableOfContents/composables.ts +258 -0
  97. package/components/Window/ContainerShell.vue +21 -11
  98. package/components/Window/__tests__/ContainerShell.test.ts +107 -37
  99. package/components/Wizard.vue +23 -17
  100. package/components/fleet/AppCoChartGrid.vue +401 -0
  101. package/components/fleet/AppCoEmptyState.vue +127 -0
  102. package/components/fleet/AppCoPageHeader.vue +119 -0
  103. package/components/fleet/AppCoVersionSelect.vue +70 -0
  104. package/components/fleet/FleetBundles.vue +100 -12
  105. package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
  106. package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
  107. package/components/fleet/FleetClusterTargets/index.vue +226 -161
  108. package/components/fleet/FleetIntro.vue +7 -3
  109. package/components/fleet/FleetNoWorkspaces.vue +7 -3
  110. package/components/fleet/FleetSecretSelector.vue +5 -3
  111. package/components/fleet/FleetValuesFrom.vue +8 -2
  112. package/components/fleet/GitRepoTargetTab.vue +0 -2
  113. package/components/fleet/HelmOpAdvancedTab.vue +19 -53
  114. package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
  115. package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
  116. package/components/fleet/HelmOpResourcesSection.vue +82 -0
  117. package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
  118. package/components/fleet/HelmOpTargetTab.vue +64 -60
  119. package/components/fleet/HelmOpValuesTab.vue +129 -105
  120. package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
  121. package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
  122. package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
  123. package/components/fleet/__tests__/FleetClusterTargets.test.ts +402 -115
  124. package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
  125. package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
  126. package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
  127. package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
  128. package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
  129. package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
  130. package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
  131. package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
  132. package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
  133. package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
  134. package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
  135. package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
  136. package/components/fleet/dashboard/Empty.vue +8 -4
  137. package/components/fleet/dashboard/ResourceCard.vue +28 -0
  138. package/components/fleet/dashboard/ResourceDetails.vue +28 -0
  139. package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
  140. package/components/form/ArrayList.vue +61 -4
  141. package/components/form/KeyValue.vue +23 -2
  142. package/components/form/LabeledSelect.vue +59 -4
  143. package/components/form/Labels.vue +22 -3
  144. package/components/form/NameNsDescription.vue +24 -5
  145. package/components/form/ResourceTabs/index.vue +1 -0
  146. package/components/form/Security.vue +6 -2
  147. package/components/form/WorkloadPorts.vue +2 -7
  148. package/components/form/__tests__/NameNsDescription.test.ts +75 -0
  149. package/components/form/__tests__/Security.test.ts +76 -0
  150. package/components/formatter/Autoscaler.vue +4 -4
  151. package/components/formatter/ClusterKubeVersion.vue +27 -0
  152. package/components/formatter/ClusterLink.vue +1 -7
  153. package/components/formatter/ClusterProvider.vue +6 -10
  154. package/components/formatter/FleetSummaryGraph.vue +0 -3
  155. package/components/formatter/InternalExternalIP.vue +10 -4
  156. package/components/formatter/MachineSummaryGraph.vue +1 -1
  157. package/components/formatter/PodsUsage.vue +2 -2
  158. package/components/formatter/ServiceTargets.vue +26 -7
  159. package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
  160. package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
  161. package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
  162. package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
  163. package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
  164. package/components/nav/Header.vue +4 -0
  165. package/components/nav/NamespaceFilter.vue +2 -2
  166. package/components/nav/TopLevelMenu.helper.ts +15 -3
  167. package/components/nav/TopLevelMenu.vue +22 -6
  168. package/components/nav/__tests__/Header.test.ts +15 -0
  169. package/components/nav/__tests__/TopLevelMenu.test.ts +263 -21
  170. package/components/templates/default.vue +9 -4
  171. package/components/templates/home.vue +23 -0
  172. package/components/templates/plain.vue +23 -0
  173. package/components/templates/standalone.vue +17 -0
  174. package/composables/useFormValidation.ts +93 -0
  175. package/composables/useHelmOpResources.test.ts +56 -0
  176. package/composables/useHelmOpResources.ts +32 -0
  177. package/composables/useStateColor.test.ts +325 -0
  178. package/composables/useStateColor.ts +128 -0
  179. package/composables/useVeeValidateField.test.ts +159 -0
  180. package/composables/useVeeValidateField.ts +67 -0
  181. package/config/home-links.js +1 -1
  182. package/config/labels-annotations.js +1 -0
  183. package/config/pagination-table-headers.js +18 -1
  184. package/config/product/explorer.js +17 -4
  185. package/config/product/manager.js +84 -21
  186. package/config/router/index.js +16 -0
  187. package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
  188. package/config/router/navigation-guards/authentication.js +10 -4
  189. package/config/router/routes.js +26 -6
  190. package/config/settings.ts +0 -2
  191. package/config/table-headers.js +23 -5
  192. package/config/types.js +11 -1
  193. package/core/__tests__/plugin-products.test.ts +904 -20
  194. package/core/plugin-products-base.ts +110 -10
  195. package/core/plugin-products.ts +4 -0
  196. package/core/plugin-types.ts +194 -31
  197. package/core/plugin.ts +18 -7
  198. package/core/productDebugger.js +9 -4
  199. package/core/types-provisioning.ts +77 -31
  200. package/core/types.ts +72 -22
  201. package/detail/__tests__/pod.test.ts +41 -0
  202. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
  203. package/detail/__tests__/workload.test.ts +3 -152
  204. package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
  205. package/detail/harvesterhci.io.management.cluster.vue +6 -2
  206. package/detail/pod.vue +1 -1
  207. package/detail/provisioning.cattle.io.cluster.vue +34 -14
  208. package/detail/workload/index.vue +12 -55
  209. package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
  210. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
  211. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  212. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
  213. package/edit/auth/__tests__/azuread.test.ts +247 -39
  214. package/edit/auth/__tests__/github.test.ts +234 -0
  215. package/edit/auth/__tests__/oidc.test.ts +26 -6
  216. package/edit/auth/__tests__/saml.test.ts +196 -0
  217. package/edit/auth/azuread.vue +197 -56
  218. package/edit/auth/github.vue +72 -13
  219. package/edit/auth/ldap/__tests__/index.test.ts +206 -0
  220. package/edit/auth/ldap/config.vue +8 -0
  221. package/edit/auth/ldap/index.vue +75 -1
  222. package/edit/auth/oidc.vue +119 -73
  223. package/edit/auth/saml.vue +76 -12
  224. package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
  225. package/edit/fleet.cattle.io.helmop.vue +491 -136
  226. package/edit/management.cattle.io.user.vue +5 -2
  227. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
  228. package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
  229. package/edit/networking.k8s.io.ingress/index.vue +75 -20
  230. package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
  231. package/edit/provisioning.cattle.io.cluster/index.vue +11 -7
  232. package/edit/provisioning.cattle.io.cluster/rke2.vue +92 -14
  233. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +22 -0
  234. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
  235. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
  236. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
  237. package/edit/secret/__tests__/ssh.test.ts +5 -6
  238. package/edit/secret/basic.vue +31 -0
  239. package/edit/secret/index.vue +68 -17
  240. package/edit/secret/registry.vue +38 -0
  241. package/edit/secret/ssh.vue +29 -0
  242. package/edit/secret/tls.vue +30 -0
  243. package/edit/service.vue +4 -4
  244. package/edit/workload/Upgrading.vue +3 -3
  245. package/edit/workload/__tests__/Upgrading.test.ts +6 -9
  246. package/edit/workload/mixins/workload.js +2 -1
  247. package/list/fleet.cattle.io.bundle.vue +7 -104
  248. package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
  249. package/list/group.principal.vue +5 -4
  250. package/list/harvesterhci.io.management.cluster.vue +8 -9
  251. package/list/management.cattle.io.user.vue +12 -9
  252. package/list/provisioning.cattle.io.cluster.vue +268 -180
  253. package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
  254. package/mixins/__tests__/auth-config.test.ts +90 -0
  255. package/mixins/__tests__/chart.test.ts +206 -0
  256. package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
  257. package/mixins/auth-config.js +7 -0
  258. package/mixins/brand.js +2 -1
  259. package/mixins/chart.js +22 -9
  260. package/mixins/child-hook.js +12 -6
  261. package/mixins/create-edit-view/impl.js +5 -3
  262. package/mixins/resource-fetch-api-pagination.js +62 -6
  263. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
  264. package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
  265. package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
  266. package/models/__tests__/fleet-application.test.ts +175 -0
  267. package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
  268. package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
  269. package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
  270. package/models/__tests__/management.cattle.io.node.ts +28 -5
  271. package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
  272. package/models/__tests__/namespace.test.ts +36 -0
  273. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +81 -11
  274. package/models/__tests__/workload.test.ts +401 -26
  275. package/models/base-cluster.x-k8s.io.js +26 -0
  276. package/models/catalog.cattle.io.clusterrepo.js +28 -4
  277. package/models/cluster.js +1 -1
  278. package/models/cluster.x-k8s.io.machine.js +4 -22
  279. package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
  280. package/models/cluster.x-k8s.io.machineset.js +2 -20
  281. package/models/compliance.cattle.io.clusterscan.js +165 -2
  282. package/models/ext.cattle.io.kubeconfig.ts +4 -7
  283. package/models/fleet-application.js +7 -1
  284. package/models/fleet.cattle.io.helmop.js +20 -1
  285. package/models/management.cattle.io.cluster.js +434 -41
  286. package/models/management.cattle.io.node.js +50 -7
  287. package/models/management.cattle.io.nodepool.js +1 -1
  288. package/models/namespace.js +1 -1
  289. package/models/networking.k8s.io.ingress.js +12 -4
  290. package/models/pod.js +33 -1
  291. package/models/provisioning.cattle.io.cluster.js +51 -334
  292. package/models/rke.cattle.io.etcdsnapshot.js +1 -2
  293. package/models/workload.js +108 -13
  294. package/models/workload.service.js +5 -0
  295. package/package.json +22 -39
  296. package/pages/__tests__/readme.test.ts +49 -0
  297. package/pages/about.vue +5 -6
  298. package/pages/auth/login.vue +0 -35
  299. package/pages/auth/setup.vue +13 -3
  300. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
  301. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
  302. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +76 -0
  303. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
  304. package/pages/c/_cluster/apps/charts/chart.vue +62 -9
  305. package/pages/c/_cluster/apps/charts/index.vue +48 -10
  306. package/pages/c/_cluster/apps/charts/install.vue +122 -113
  307. package/pages/c/_cluster/auth/roles/index.vue +5 -4
  308. package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
  309. package/pages/c/_cluster/explorer/index.vue +5 -49
  310. package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
  311. package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
  312. package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
  313. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
  314. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
  315. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
  316. package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
  317. package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
  318. package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
  319. package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
  320. package/pages/c/_cluster/fleet/application/create.vue +187 -136
  321. package/pages/c/_cluster/fleet/application/index.vue +5 -3
  322. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
  323. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
  324. package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
  325. package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
  326. package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
  327. package/pages/c/_cluster/fleet/index.vue +2 -2
  328. package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
  329. package/pages/c/_cluster/istio/index.vue +21 -6
  330. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -0
  331. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +815 -2
  332. package/pages/c/_cluster/uiplugins/index.vue +218 -197
  333. package/pages/diagnostic.vue +13 -17
  334. package/pages/fail-whale.vue +30 -7
  335. package/pages/home.vue +93 -306
  336. package/pages/readme.vue +88 -0
  337. package/plugins/clean-html.d.ts +9 -0
  338. package/plugins/dashboard-store/__tests__/resource-class.test.ts +181 -0
  339. package/plugins/dashboard-store/actions.js +40 -18
  340. package/plugins/dashboard-store/resource-class.js +67 -9
  341. package/plugins/steve/__tests__/actions.test.ts +212 -0
  342. package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
  343. package/plugins/steve/actions.js +96 -0
  344. package/plugins/steve/steve-pagination-utils.ts +12 -4
  345. package/plugins/steve/subscribe.js +35 -5
  346. package/rancher-components/Accordion/Accordion.vue +53 -9
  347. package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
  348. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +10 -4
  349. package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -52
  350. package/rancher-components/Form/Radio/RadioButton.vue +17 -1
  351. package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
  352. package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
  353. package/rancher-components/RcButton/RcButton.test.ts +140 -1
  354. package/rancher-components/RcButton/RcButton.vue +126 -17
  355. package/rancher-components/RcButton/types.ts +3 -0
  356. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
  357. package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
  358. package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
  359. package/rancher-components/RcSection/RcSection.vue +28 -3
  360. package/scripts/extension/helm/package/Dockerfile +1 -1
  361. package/scripts/test-plugins-build.sh +2 -1
  362. package/store/__tests__/catalog.test.ts +115 -1
  363. package/store/__tests__/notifications.test.ts +434 -0
  364. package/store/__tests__/type-map.test.ts +556 -1
  365. package/store/action-menu.js +8 -3
  366. package/store/auth.js +1 -1
  367. package/store/aws.js +27 -16
  368. package/store/catalog.js +84 -3
  369. package/store/digitalocean.js +20 -38
  370. package/store/index.js +2 -0
  371. package/store/linode.js +25 -40
  372. package/store/plugins.js +7 -4
  373. package/store/pnap.js +1 -0
  374. package/store/type-map.js +111 -29
  375. package/tsconfig.paths.json +8 -8
  376. package/types/components/buttonGroup.ts +5 -0
  377. package/types/kube/kube-api.ts +14 -1
  378. package/types/rancher/steve.api.ts +12 -12
  379. package/types/resources/settings.d.ts +2 -1
  380. package/types/shell/index.d.ts +206 -72
  381. package/types/store/dashboard-store.types.ts +108 -11
  382. package/types/store/pagination.types.ts +6 -3
  383. package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
  384. package/utils/__tests__/async.test.ts +87 -0
  385. package/utils/__tests__/auth.test.ts +273 -0
  386. package/utils/__tests__/aws.test.ts +140 -0
  387. package/utils/__tests__/banners.test.ts +176 -0
  388. package/utils/__tests__/chart.test.ts +64 -1
  389. package/utils/__tests__/color.test.ts +226 -0
  390. package/utils/__tests__/computed.test.ts +193 -0
  391. package/utils/__tests__/cspAdaptor.test.ts +163 -0
  392. package/utils/__tests__/dom.test.ts +81 -0
  393. package/utils/__tests__/duration.test.ts +176 -0
  394. package/utils/__tests__/dynamic-importer.test.ts +102 -0
  395. package/utils/__tests__/fleet-appco.test.ts +312 -0
  396. package/utils/__tests__/fleet.test.ts +340 -0
  397. package/utils/__tests__/ingress.test.ts +553 -0
  398. package/utils/__tests__/kube.test.ts +68 -0
  399. package/utils/__tests__/monitoring.test.ts +130 -0
  400. package/utils/__tests__/namespace-filter.test.ts +109 -0
  401. package/utils/__tests__/object.test.ts +22 -0
  402. package/utils/__tests__/pagination-utils.test.ts +361 -0
  403. package/utils/__tests__/parse-externalid.test.ts +137 -0
  404. package/utils/__tests__/perf-setting.utils.test.ts +98 -0
  405. package/utils/__tests__/platform.test.ts +91 -0
  406. package/utils/__tests__/poller-sequential.test.ts +177 -0
  407. package/utils/__tests__/poller.test.ts +170 -0
  408. package/utils/__tests__/position.test.ts +237 -0
  409. package/utils/__tests__/promise.test.ts +346 -0
  410. package/utils/__tests__/provider.test.ts +51 -1
  411. package/utils/__tests__/queue.test.ts +232 -0
  412. package/utils/__tests__/release-notes.test.ts +221 -0
  413. package/utils/__tests__/router.test.js +254 -1
  414. package/utils/__tests__/select.test.ts +208 -0
  415. package/utils/__tests__/settings.test.ts +140 -0
  416. package/utils/__tests__/sort-utils.test.ts +301 -0
  417. package/utils/__tests__/string-utils.test.ts +798 -0
  418. package/utils/__tests__/string.test.ts +23 -1
  419. package/utils/__tests__/style.test.ts +154 -0
  420. package/utils/__tests__/svg-filter.test.ts +184 -0
  421. package/utils/__tests__/time.test.ts +265 -1
  422. package/utils/__tests__/title.test.ts +47 -0
  423. package/utils/__tests__/units.test.ts +417 -0
  424. package/utils/__tests__/versions.test.ts +128 -0
  425. package/utils/__tests__/width.test.ts +53 -0
  426. package/utils/__tests__/window.test.ts +158 -0
  427. package/utils/__tests__/xccdf.test.ts +511 -0
  428. package/utils/chart.js +36 -0
  429. package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
  430. package/utils/crypto/__tests__/index.test.ts +144 -0
  431. package/utils/duration.ts +104 -0
  432. package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
  433. package/utils/dynamic-content/info.ts +2 -1
  434. package/utils/error.js +13 -0
  435. package/utils/fleet-appco.ts +323 -0
  436. package/utils/fleet.ts +13 -3
  437. package/utils/gatekeeper/__tests__/util.test.ts +174 -0
  438. package/utils/gc/__tests__/gc-interval.test.ts +119 -0
  439. package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
  440. package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
  441. package/utils/gc/__tests__/gc.test.ts +487 -0
  442. package/utils/ingress.ts +9 -1
  443. package/utils/object.js +22 -2
  444. package/utils/pagination-utils.ts +2 -1
  445. package/utils/provider.ts +12 -0
  446. package/utils/string.js +25 -2
  447. package/utils/uiplugins.ts +5 -5
  448. package/utils/validators/__tests__/cluster-name.test.ts +110 -0
  449. package/utils/validators/__tests__/container-images.test.ts +104 -0
  450. package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
  451. package/utils/validators/__tests__/flow-output.test.ts +91 -0
  452. package/utils/validators/__tests__/index.test.ts +481 -0
  453. package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
  454. package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
  455. package/utils/validators/__tests__/misc-validators.test.ts +246 -0
  456. package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
  457. package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
  458. package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
  459. package/utils/validators/__tests__/role-template.test.ts +149 -0
  460. package/utils/validators/__tests__/service.test.ts +283 -0
  461. package/utils/validators/__tests__/setting.test.js +32 -0
  462. package/utils/validators/formRules/__tests__/index.test.ts +50 -0
  463. package/utils/validators/formRules/index.ts +5 -5
  464. package/utils/validators/machine-pool.ts +1 -1
  465. package/utils/validators/setting.js +18 -3
  466. package/utils/xccdf.ts +415 -0
  467. package/vue.config.js +1 -1
  468. package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
  469. package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
  470. package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
  471. package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
  472. package/pages/support/index.vue +0 -264
  473. package/utils/duration.js +0 -43
@@ -0,0 +1,487 @@
1
+ import type defaultGc from '@shell/utils/gc/gc';
2
+ import { MANAGEMENT } from '@shell/config/types';
3
+
4
+ type GcInstance = typeof defaultGc;
5
+
6
+ const DEFAULT_PREFS = {
7
+ enabled: true,
8
+ enabledInterval: true,
9
+ interval: 300,
10
+ enabledOnNavigate: true,
11
+ ageThreshold: 120, // seconds → maxAge = 120_000 ms
12
+ countThreshold: 500,
13
+ };
14
+
15
+ let stampCounter = 1000;
16
+
17
+ function makeRootState(prefs = DEFAULT_PREFS, clusterReady = true): any {
18
+ stampCounter++;
19
+
20
+ return {
21
+ clusterReady,
22
+ management: {
23
+ types: {
24
+ [MANAGEMENT.SETTING]: {
25
+ list: [
26
+ {
27
+ id: 'ui-performance',
28
+ value: JSON.stringify({ garbageCollection: prefs }),
29
+ metadata: { generation: stampCounter, resourceVersion: '1' },
30
+ },
31
+ ],
32
+ },
33
+ },
34
+ },
35
+ };
36
+ }
37
+
38
+ function makeEmptyRootState(): any {
39
+ return {
40
+ clusterReady: true,
41
+ management: { types: { [MANAGEMENT.SETTING]: { list: [] } } },
42
+ };
43
+ }
44
+
45
+ function makeCtx(options: {
46
+ namespace?: string;
47
+ supportsGc?: boolean;
48
+ gcIgnoreTypes?: Record<string, boolean>;
49
+ prefs?: Partial<typeof DEFAULT_PREFS>;
50
+ dispatch?: jest.Mock;
51
+ countsByType?: Record<string, number>;
52
+ clusterReady?: boolean;
53
+ } = {}): any {
54
+ const {
55
+ namespace = 'teststore',
56
+ supportsGc = true,
57
+ gcIgnoreTypes = {},
58
+ prefs,
59
+ dispatch = jest.fn(),
60
+ countsByType = {},
61
+ clusterReady = true,
62
+ } = options;
63
+
64
+ const rootState = makeRootState(
65
+ prefs ? { ...DEFAULT_PREFS, ...prefs } : DEFAULT_PREFS,
66
+ clusterReady
67
+ );
68
+
69
+ return {
70
+ state: { config: { supportsGc, namespace } },
71
+ rootState,
72
+ getters: {
73
+ gcIgnoreTypes,
74
+ all: () => [{
75
+ counts: Object.fromEntries(
76
+ Object.entries(countsByType).map(([t, c]) => [t, { summary: { count: c } }])
77
+ ),
78
+ }],
79
+ },
80
+ dispatch,
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Each test in the outer describe gets a fresh gc instance (gcLastRun = 0,
86
+ * empty caches) so tests do not interfere with each other via shared singleton state.
87
+ */
88
+ describe('gc', () => {
89
+ let gc: GcInstance;
90
+
91
+ beforeEach(() => {
92
+ jest.resetModules();
93
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
94
+ gc = require('@shell/utils/gc/gc').default as GcInstance;
95
+ });
96
+
97
+ afterEach(() => {
98
+ jest.useRealTimers();
99
+ });
100
+
101
+ // ─── gcEnabledForStore ─────────────────────────────────────────────────────
102
+
103
+ describe('gcEnabledForStore', () => {
104
+ it.each([
105
+ {
106
+ desc: 'true when supportsGc is true', state: { config: { supportsGc: true } }, expected: true
107
+ },
108
+ {
109
+ desc: 'false when supportsGc is false', state: { config: { supportsGc: false } }, expected: false
110
+ },
111
+ {
112
+ desc: 'undefined when state is undefined', state: undefined, expected: undefined
113
+ },
114
+ ])('returns $desc', ({ state, expected }) => {
115
+ expect(gc.gcEnabledForStore(state)).toBe(expected);
116
+ });
117
+ });
118
+
119
+ // ─── gcEnabledForType ──────────────────────────────────────────────────────
120
+
121
+ describe('gcEnabledForType', () => {
122
+ it.each([
123
+ {
124
+ desc: 'false when type is empty string', gcIgnoreTypes: {}, type: '', expected: false
125
+ },
126
+ {
127
+ desc: 'false when type is in gcIgnoreTypes', gcIgnoreTypes: { pods: true }, type: 'pods', expected: false
128
+ },
129
+ {
130
+ desc: 'true when type is non-empty and not ignored', gcIgnoreTypes: {}, type: 'deployments', expected: true
131
+ },
132
+ ])('returns $desc', ({ gcIgnoreTypes, type, expected }) => {
133
+ expect(gc.gcEnabledForType({ getters: { gcIgnoreTypes } }, type)).toBe(expected);
134
+ });
135
+ });
136
+
137
+ // ─── gcEnabledSetting ──────────────────────────────────────────────────────
138
+
139
+ describe('gcEnabledSetting', () => {
140
+ it('returns true when GC is enabled in ui-performance setting', () => {
141
+ const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, enabled: true }) };
142
+
143
+ expect(gc.gcEnabledSetting(ctx)).toBe(true);
144
+ });
145
+
146
+ it('returns false when GC is disabled in ui-performance setting', () => {
147
+ const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, enabled: false }) };
148
+
149
+ expect(gc.gcEnabledSetting(ctx)).toBe(false);
150
+ });
151
+
152
+ it('returns undefined when ui-performance setting is absent', () => {
153
+ const ctx = { rootState: makeEmptyRootState() };
154
+
155
+ expect(gc.gcEnabledSetting(ctx)).toBeUndefined();
156
+ });
157
+ });
158
+
159
+ // ─── gcEnabledAll ──────────────────────────────────────────────────────────
160
+
161
+ describe('gcEnabledAll', () => {
162
+ it.each([
163
+ {
164
+ desc: 'true when all checks pass', options: {}, type: 'deployments', expected: true
165
+ },
166
+ {
167
+ desc: 'false when store does not support GC', options: { supportsGc: false }, type: 'deployments', expected: false
168
+ },
169
+ {
170
+ desc: 'false when GC is disabled in settings', options: { prefs: { enabled: false } }, type: 'deployments', expected: false
171
+ },
172
+ {
173
+ desc: 'false when type is in gcIgnoreTypes', options: { gcIgnoreTypes: { schema: true } }, type: 'schema', expected: false
174
+ },
175
+ ])('returns $desc', ({ options, type, expected }) => {
176
+ expect(gc.gcEnabledAll(makeCtx(options), type)).toBe(expected);
177
+ });
178
+ });
179
+
180
+ // ─── gcEnabledInterval ─────────────────────────────────────────────────────
181
+
182
+ describe('gcEnabledInterval', () => {
183
+ it('returns enabledInterval and interval from settings', () => {
184
+ const ctx = {
185
+ rootState: makeRootState({
186
+ ...DEFAULT_PREFS, enabledInterval: true, interval: 600
187
+ })
188
+ };
189
+
190
+ expect(gc.gcEnabledInterval(ctx)).toStrictEqual({ enabled: true, interval: 600 });
191
+ });
192
+
193
+ it('returns enabled: undefined and interval: 0 when setting is absent', () => {
194
+ const ctx = { rootState: makeEmptyRootState() };
195
+
196
+ expect(gc.gcEnabledInterval(ctx)).toStrictEqual({ enabled: undefined, interval: 0 });
197
+ });
198
+
199
+ it('returns interval: 0 when the interval value is falsy', () => {
200
+ const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, interval: 0 }) };
201
+
202
+ expect(gc.gcEnabledInterval(ctx)).toStrictEqual({ enabled: true, interval: 0 });
203
+ });
204
+ });
205
+
206
+ // ─── gcEnabledRoute ────────────────────────────────────────────────────────
207
+
208
+ describe('gcEnabledRoute', () => {
209
+ it('returns enabledOnNavigate from settings', () => {
210
+ const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, enabledOnNavigate: false }) };
211
+
212
+ expect(gc.gcEnabledRoute(ctx)).toBe(false);
213
+ });
214
+
215
+ it('returns undefined when setting is absent', () => {
216
+ const ctx = { rootState: makeEmptyRootState() };
217
+
218
+ expect(gc.gcEnabledRoute(ctx)).toBeUndefined();
219
+ });
220
+ });
221
+
222
+ // ─── gcUpdateRouteChanged ──────────────────────────────────────────────────
223
+
224
+ describe('gcUpdateRouteChanged', () => {
225
+ /**
226
+ * Condition in garbageCollect:
227
+ * if (lastRouteChange < lastAccessed) → skip (resource is in current route)
228
+ *
229
+ * So: route changed at T1, resource accessed at T2 > T1
230
+ * → lastRouteChange (T1) < lastAccessed (T2) → GC skips this type.
231
+ */
232
+ it('prevents a resource from being GC\'d when route changed before last access', () => {
233
+ const dispatch = jest.fn();
234
+ const type = 'pods';
235
+ const namespace = 'routetest';
236
+
237
+ jest.useFakeTimers();
238
+
239
+ // Route change at t=200_000 ms
240
+ jest.setSystemTime(200_000);
241
+ gc.gcUpdateRouteChanged();
242
+
243
+ // Resource accessed at t=300_000 ms (AFTER route change → in current route)
244
+ jest.setSystemTime(300_000);
245
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
246
+
247
+ // GC runs at t=600_000 ms
248
+ // now - lastAccessed = 300_000 > maxAge(120_000) ✓ age check passes
249
+ // lastRouteChange(200_000) < lastAccessed(300_000) → skip (in current route)
250
+ jest.setSystemTime(600_000);
251
+ gc.garbageCollect(makeCtx({
252
+ namespace,
253
+ countsByType: { [type]: 1000 },
254
+ dispatch,
255
+ }));
256
+
257
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
258
+ });
259
+ });
260
+
261
+ // ─── garbageCollect ────────────────────────────────────────────────────────
262
+
263
+ describe('garbageCollect', () => {
264
+ it('skips when recently run (within GC_RE_RUN_GAP of 5 s)', () => {
265
+ const dispatch = jest.fn();
266
+
267
+ jest.useFakeTimers();
268
+ jest.setSystemTime(10_000);
269
+
270
+ // First call: cluster not ready → gcLastRun = 10_000
271
+ gc.garbageCollect(makeCtx({ clusterReady: false, dispatch }));
272
+ // Second call at same time: 10_000 - 10_000 = 0 < 5000 → skips
273
+ gc.garbageCollect(makeCtx({ dispatch }));
274
+
275
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', expect.any(String));
276
+ });
277
+
278
+ it('skips when cluster is not ready', () => {
279
+ const dispatch = jest.fn();
280
+
281
+ jest.useFakeTimers();
282
+ jest.setSystemTime(10_000);
283
+
284
+ gc.garbageCollect(makeCtx({ clusterReady: false, dispatch }));
285
+
286
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', expect.any(String));
287
+ });
288
+
289
+ it('skips when ui-performance setting is absent', () => {
290
+ const dispatch = jest.fn();
291
+
292
+ jest.useFakeTimers();
293
+ jest.setSystemTime(10_000);
294
+
295
+ const ctx = {
296
+ state: { config: { supportsGc: true, namespace: 'teststore' } },
297
+ rootState: makeEmptyRootState(),
298
+ getters: { gcIgnoreTypes: {} },
299
+ dispatch,
300
+ };
301
+
302
+ gc.garbageCollect(ctx);
303
+
304
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', expect.any(String));
305
+ });
306
+
307
+ it('skips a type listed in the explicit ignoreTypes parameter', () => {
308
+ const dispatch = jest.fn();
309
+ const type = 'configmaps';
310
+ const namespace = 'ignoretypetest';
311
+
312
+ jest.useFakeTimers();
313
+
314
+ jest.setSystemTime(200_000);
315
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
316
+
317
+ jest.setSystemTime(300_000);
318
+ gc.gcUpdateRouteChanged();
319
+
320
+ jest.setSystemTime(400_000);
321
+ gc.garbageCollect(
322
+ makeCtx({
323
+ namespace, countsByType: { [type]: 1000 }, dispatch
324
+ }),
325
+ { [type]: true }
326
+ );
327
+
328
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
329
+ });
330
+
331
+ it('skips a type that was accessed within the ageThreshold', () => {
332
+ const dispatch = jest.fn();
333
+ const type = 'secrets';
334
+ const namespace = 'recenttest';
335
+
336
+ jest.useFakeTimers();
337
+
338
+ // Access 30 s ago (less than 120 s ageThreshold)
339
+ jest.setSystemTime(10_000);
340
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
341
+
342
+ jest.setSystemTime(40_000); // 30 s later
343
+ gc.garbageCollect(makeCtx({
344
+ namespace, countsByType: { [type]: 1000 }, dispatch
345
+ }));
346
+
347
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
348
+ });
349
+
350
+ it('skips a type whose count is below countThreshold', () => {
351
+ const dispatch = jest.fn();
352
+ const type = 'namespaces';
353
+ const namespace = 'lowcounttest';
354
+
355
+ jest.useFakeTimers();
356
+
357
+ jest.setSystemTime(200_000);
358
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
359
+
360
+ jest.setSystemTime(300_000);
361
+ gc.gcUpdateRouteChanged();
362
+
363
+ jest.setSystemTime(400_000);
364
+ // count(100) < countThreshold(500) → skip
365
+ gc.garbageCollect(makeCtx({
366
+ namespace, countsByType: { [type]: 100 }, dispatch
367
+ }));
368
+
369
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
370
+ });
371
+
372
+ it('dispatches forgetType for a resource that meets all GC criteria', () => {
373
+ const dispatch = jest.fn();
374
+ const type = 'events';
375
+ const namespace = 'gcqualifytest';
376
+
377
+ jest.useFakeTimers();
378
+
379
+ // Resource accessed at t=200_000
380
+ jest.setSystemTime(200_000);
381
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
382
+
383
+ // Route changed at t=300_000 (AFTER access → lastRouteChange > lastAccessed → no skip)
384
+ jest.setSystemTime(300_000);
385
+ gc.gcUpdateRouteChanged();
386
+
387
+ // GC at t=400_000: now - lastAccessed = 200_000 > maxAge(120_000) ✓
388
+ jest.setSystemTime(400_000);
389
+ gc.garbageCollect(makeCtx({
390
+ namespace, countsByType: { [type]: 1000 }, dispatch
391
+ }));
392
+
393
+ expect(dispatch).toHaveBeenCalledWith('forgetType', type);
394
+ });
395
+ });
396
+
397
+ // ─── gcResetStore ──────────────────────────────────────────────────────────
398
+
399
+ describe('gcResetStore', () => {
400
+ it('removes all cached entries for the store, preventing forgetType dispatch', () => {
401
+ const dispatch = jest.fn();
402
+ const type = 'ingresses';
403
+ const namespace = 'resetstoretest';
404
+
405
+ jest.useFakeTimers();
406
+
407
+ jest.setSystemTime(200_000);
408
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
409
+
410
+ jest.setSystemTime(300_000);
411
+ gc.gcUpdateRouteChanged();
412
+
413
+ gc.gcResetStore({ config: { namespace } });
414
+
415
+ jest.setSystemTime(400_000);
416
+ gc.garbageCollect(makeCtx({
417
+ namespace, countsByType: { [type]: 1000 }, dispatch
418
+ }));
419
+
420
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
421
+ });
422
+ });
423
+
424
+ // ─── gcResetType ───────────────────────────────────────────────────────────
425
+
426
+ describe('gcResetType', () => {
427
+ it('removes a specific type so it is not GC\'d while leaving other types intact', () => {
428
+ const dispatch = jest.fn();
429
+ const typeA = 'storageclasses';
430
+ const typeB = 'persistentvolumes';
431
+ const namespace = 'resettypetest';
432
+
433
+ jest.useFakeTimers();
434
+
435
+ jest.setSystemTime(200_000);
436
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), typeA);
437
+ gc.gcUpdateLastAccessed(makeCtx({ namespace }), typeB);
438
+
439
+ jest.setSystemTime(300_000);
440
+ gc.gcUpdateRouteChanged();
441
+
442
+ gc.gcResetType({ config: { namespace } }, typeA);
443
+
444
+ jest.setSystemTime(400_000);
445
+ gc.garbageCollect(makeCtx({
446
+ namespace,
447
+ countsByType: { [typeA]: 1000, [typeB]: 1000 },
448
+ dispatch,
449
+ }));
450
+
451
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', typeA);
452
+ expect(dispatch).toHaveBeenCalledWith('forgetType', typeB);
453
+ });
454
+
455
+ it('is a no-op when the store has no cached entries', () => {
456
+ expect(() => {
457
+ gc.gcResetType({ config: { namespace: 'nonexistent-store' } }, 'pods');
458
+ }).not.toThrow();
459
+ });
460
+ });
461
+
462
+ // ─── gcUpdateLastAccessed ──────────────────────────────────────────────────
463
+
464
+ describe('gcUpdateLastAccessed', () => {
465
+ it('does not populate cache when GC is disabled for the store', () => {
466
+ const dispatch = jest.fn();
467
+ const type = 'replicasets';
468
+ const namespace = 'disabledgctest';
469
+
470
+ jest.useFakeTimers();
471
+
472
+ // supportsGc: false → gcEnabledAll = false → cache not updated
473
+ jest.setSystemTime(200_000);
474
+ gc.gcUpdateLastAccessed(makeCtx({ namespace, supportsGc: false }), type);
475
+
476
+ jest.setSystemTime(300_000);
477
+ gc.gcUpdateRouteChanged();
478
+
479
+ jest.setSystemTime(400_000);
480
+ gc.garbageCollect(makeCtx({
481
+ namespace, countsByType: { [type]: 1000 }, dispatch
482
+ }));
483
+
484
+ expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
485
+ });
486
+ });
487
+ });
package/utils/ingress.ts CHANGED
@@ -56,7 +56,15 @@ class IngressDetailEditHelper {
56
56
  return services.map((service) => ({
57
57
  label: service.metadata.name,
58
58
  value: service.metadata.name,
59
- ports: service.spec.ports?.map((p: any) => p.port)
59
+ ports: service.spec.ports?.flatMap((p: any) => {
60
+ const options = [p.port];
61
+
62
+ if (p.name) {
63
+ options.push(p.name);
64
+ }
65
+
66
+ return options;
67
+ })
60
68
  }));
61
69
  }
62
70
  }
package/utils/object.js CHANGED
@@ -163,6 +163,9 @@ returns an object with no key/value pairs (including nested) where the value is:
163
163
  undefined
164
164
  */
165
165
  export function cleanUp(obj) {
166
+ if ( !obj || typeof obj !== 'object') {
167
+ return obj;
168
+ }
166
169
  Object.keys(obj).map((key) => {
167
170
  const val = obj[key];
168
171
 
@@ -267,7 +270,7 @@ export function diff(from, to, preventNull = false) {
267
270
  }
268
271
 
269
272
  if (preventNull) {
270
- // keys that come from "definedKeys" method are strings with "" chars inside... We need to clean them up
273
+ // keys that come from "definedKeys" method are strings with "" chars inside... We need to clean them up
271
274
  // so that we can access the value of the obj property
272
275
  let key = k;
273
276
 
@@ -282,7 +285,24 @@ export function diff(from, to, preventNull = false) {
282
285
  set(out, key, null);
283
286
  }
284
287
  } else {
285
- set(out, k, null);
288
+ const parts = splitObjectPath(k);
289
+
290
+ // Skip any missing nested key whose parent path in out is already a
291
+ // non-object. We don't want to attempt to null out the key that appeared
292
+ // in the diff when a pre-defined key
293
+ // (githubConfigSecret.github_token: '') gets updated to
294
+ // (githubConfigSecret: 'preexisting-secret')
295
+ const skip = parts.some((part) => {
296
+ const existingVal = out?.[part];
297
+
298
+ if (existingVal !== undefined && !isObject(existingVal)) {
299
+ return true;
300
+ }
301
+ });
302
+
303
+ if (!skip) {
304
+ set(out, k, null);
305
+ }
286
306
  }
287
307
  }
288
308
 
@@ -24,9 +24,10 @@ import { EXT_IDS } from '@shell/core/plugin';
24
24
  import { ExtensionManager } from '@shell/types/extension-manager';
25
25
  import { DEFAULT_PERF_SETTING } from '@shell/config/settings';
26
26
 
27
+ // This feature will be removed soon - https://github.com/rancher/dashboard/issues/17323
27
28
  const homePageClusterFeature: PaginationFeature<PaginationFeatureHomePageClusterConfig> = {
28
29
  version: 1,
29
- enabled: true,
30
+ enabled: false,
30
31
  configuration: {
31
32
  threshold: 500, results: 250, pagesPerRow: 25
32
33
  }
package/utils/provider.ts CHANGED
@@ -4,6 +4,10 @@ export function getHostedProviders(context: ClusterProvisionerContext) {
4
4
  return context?.$extension?.getProviders(context)?.filter((p: IClusterProvisioner) => p.group === 'hosted') || [];
5
5
  }
6
6
 
7
+ export function getCAPIProviders(context: ClusterProvisionerContext) {
8
+ return context?.$extension?.getProviders(context)?.filter((p: IClusterProvisioner) => p.group === 'capi') || [];
9
+ }
10
+
7
11
  export function isHostedProvider(context: ClusterProvisionerContext, provisioner: string) {
8
12
  if (!provisioner) {
9
13
  return false;
@@ -12,3 +16,11 @@ export function isHostedProvider(context: ClusterProvisionerContext, provisioner
12
16
 
13
17
  return provisioners.has(provisioner.toLowerCase());
14
18
  }
19
+ export function isCAPIProvider(context: ClusterProvisionerContext, provisioner: string) {
20
+ if (!provisioner) {
21
+ return false;
22
+ }
23
+ const provisioners = new Set(getCAPIProviders(context).map((p: IClusterProvisioner) => p.id.toLowerCase()));
24
+
25
+ return provisioners.has(provisioner.toLowerCase());
26
+ }
package/utils/string.js CHANGED
@@ -349,10 +349,33 @@ export function xOfy(x, y) {
349
349
  return `${ typeof x === 'number' ? x : '?' }/${ typeof y === 'number' ? y : '?' }`;
350
350
  }
351
351
 
352
+ const BASE64_REGEX = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
353
+
352
354
  export function isBase64(value) {
353
- const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
355
+ return BASE64_REGEX.test(value);
356
+ }
357
+
358
+ /**
359
+ * Checks if a value is a valid base64-encoded CA bundle.
360
+ * Unlike isBase64, this handles multiline base64 (e.g. openssl wraps at 76 chars)
361
+ * and rejects short strings that could be false positives.
362
+ * @param {string} value
363
+ * @returns {boolean}
364
+ */
365
+ export function isBase64EncodedCert(value) {
366
+ if (!value || typeof value !== 'string') {
367
+ return false;
368
+ }
369
+
370
+ // Strip whitespace to handle line-wrapped base64 output
371
+ const stripped = value.replace(/\s/g, '');
372
+
373
+ // CA certs are long enough that legitimate base64 will always exceed this
374
+ if (stripped.length < 16) {
375
+ return false;
376
+ }
354
377
 
355
- return base64regex.test(value);
378
+ return BASE64_REGEX.test(stripped);
356
379
  }
357
380
 
358
381
  export function generateRandomAlphaString(length) {
@@ -180,18 +180,19 @@ export async function getHelmRepositoryExact(store: any, url: string): Promise<H
180
180
  /**
181
181
  *
182
182
  * @param store Vue store
183
- * @param urlRegexes Regex to match a community repository
183
+ * @param urlRegexes Regex to match against the repository's urls
184
184
  * @param catalogImages Catalog images to match against the repository's labels
185
185
  * @returns HelmRepository
186
186
  */
187
187
  export async function getHelmRepositoryMatch(store: any, urlRegexes: string[], catalogImages: string[]): Promise<HelmRepository> {
188
188
  return await getHelmRepository(store, (repository: any) => {
189
- // if installed from rancher/ui-plugin-catalog or rancher/ui-extension-harvester-ui-extension
190
189
  const catalog = repository?.metadata?.labels?.[UI_PLUGIN_LABELS.CATALOG_IMAGE] || '';
191
190
 
192
- if (catalogImages.includes(catalog)) {
191
+ // if installed from rancher/ui-plugin-catalog or rancher/ui-extension-harvester-ui-extension
192
+ if (catalog && catalogImages.includes(catalog)) {
193
193
  return true;
194
194
  }
195
+
195
196
  const target = repository.spec?.gitBranch ? repository.spec?.gitRepo : repository.spec?.url;
196
197
 
197
198
  return matchesSomeRegex(target, urlRegexes);
@@ -272,8 +273,7 @@ export async function createHelmRepository(store: any, name: string, url: string
272
273
  });
273
274
 
274
275
  tries++;
275
-
276
- const downloaded = repo.status.conditions.find((s: any) => s.type === 'Downloaded');
276
+ const downloaded = repo.status?.conditions.find((s: any) => s.type === 'Downloaded');
277
277
 
278
278
  console.log(`Waiting for helm repository to be downloaded... try ${ tries } time(s).`); // eslint-disable-line no-console
279
279