@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
@@ -69,4 +69,94 @@ describe('mixin: authConfigMixin', () => {
69
69
  expect(instance.model.scope).toStrictEqual(scope);
70
70
  });
71
71
  });
72
+
73
+ describe('accessMode on enable', () => {
74
+ const FakeComponent = {
75
+ render() {},
76
+ mixins: [authConfigMixin, childHook],
77
+ methods: { applyHooks: jest.fn() },
78
+ };
79
+
80
+ const createMock = (model: any, overrides: Record<string, any> = {}) => ({
81
+ data: () => ({
82
+ value: { configType: 'oidc' },
83
+ model,
84
+ ...overrides,
85
+ }),
86
+ computed: { principal: () => ({ me: {} }) },
87
+ global: {
88
+ mocks: {
89
+ $store: { dispatch: () => model },
90
+ $route: {
91
+ params: { id: model.id || '123' },
92
+ query: { mode: 'edit' },
93
+ },
94
+ }
95
+ }
96
+ });
97
+
98
+ it.each([
99
+ 'github',
100
+ 'githubapp',
101
+ ])('should default accessMode to restricted for %s on enable', async(id) => {
102
+ const model = {
103
+ id,
104
+ enabled: false,
105
+ authConfigName: 'whatever',
106
+ doAction: jest.fn(),
107
+ save: jest.fn(),
108
+ };
109
+ const instance = mount(FakeComponent, createMock(model)).vm as any;
110
+
111
+ await instance.save(jest.fn());
112
+
113
+ expect(model.save).toHaveBeenCalled();
114
+ expect(instance.model.accessMode).toStrictEqual('required');
115
+ });
116
+
117
+ it('should default accessMode to unrestricted for non-github oauth on enable', async() => {
118
+ const model = {
119
+ id: 'googleoauth',
120
+ enabled: false,
121
+ authConfigName: 'whatever',
122
+ doAction: jest.fn(),
123
+ save: jest.fn(),
124
+ };
125
+ const instance = mount(FakeComponent, createMock(model)).vm as any;
126
+
127
+ await instance.save(jest.fn());
128
+
129
+ expect(instance.model.accessMode).toStrictEqual('required');
130
+ });
131
+
132
+ it('should set accessMode to required after enabling a provider', async() => {
133
+ const model = {
134
+ enabled: false,
135
+ accessMode: 'unrestricted',
136
+ authConfigName: 'whatever',
137
+ doAction: jest.fn(),
138
+ save: async() => {}
139
+ };
140
+ const instance = mount(FakeComponent, createMock(model)).vm as any;
141
+
142
+ await instance.save(jest.fn());
143
+
144
+ expect(instance.model.accessMode).toStrictEqual('required');
145
+ });
146
+
147
+ it('should not change accessMode when editing an already enabled provider', async() => {
148
+ const model = {
149
+ enabled: true,
150
+ accessMode: 'unrestricted',
151
+ authConfigName: 'whatever',
152
+ doAction: jest.fn(),
153
+ save: async() => {}
154
+ };
155
+ const instance = mount(FakeComponent, createMock(model, { editConfig: true })).vm as any;
156
+
157
+ await instance.save(jest.fn());
158
+
159
+ expect(instance.model.accessMode).toStrictEqual('unrestricted');
160
+ });
161
+ });
72
162
  });
@@ -214,6 +214,72 @@ describe('chartMixin', () => {
214
214
  id: 'custom-ns/custom-name'
215
215
  });
216
216
  });
217
+
218
+ it('should fall back to matchingInstalledApps when version namespace lookup fails', async() => {
219
+ const installedApp = {
220
+ id: 'other-ns/custom-name',
221
+ spec: { chart: { metadata: { version: '0.9.0' } } }
222
+ };
223
+
224
+ const mockStore = {
225
+ dispatch: jest.fn((action, payload) => {
226
+ if (action === 'cluster/find') {
227
+ return Promise.reject(new Error('not found'));
228
+ }
229
+
230
+ return Promise.resolve();
231
+ }),
232
+ getters: {
233
+ currentCluster: () => {},
234
+ isRancher: () => true,
235
+ 'catalog/repo': () => {
236
+ return () => 'repo';
237
+ },
238
+ 'catalog/chart': () => {
239
+ return {
240
+ id: 'chart-id',
241
+ versions: [{ version: '1.0.0' }],
242
+ matchingInstalledApps: [installedApp]
243
+ };
244
+ },
245
+ 'catalog/version': () => ({
246
+ version: '1.0.0',
247
+ annotations: {
248
+ [CATALOG_ANNOTATIONS.NAMESPACE]: 'custom-ns',
249
+ [CATALOG_ANNOTATIONS.RELEASE_NAME]: 'custom-name',
250
+ }
251
+ }),
252
+ 'prefs/get': () => {},
253
+ 'i18n/t': () => jest.fn()
254
+ }
255
+ };
256
+
257
+ const DummyComponent = {
258
+ mixins: [ChartMixin],
259
+ template: '<div></div>',
260
+ };
261
+
262
+ const wrapper = mount(
263
+ DummyComponent,
264
+ {
265
+ global: {
266
+ mocks: {
267
+ $store: mockStore,
268
+ $route: {
269
+ query: {
270
+ chart: 'chart_name',
271
+ versionName: '1.0.0'
272
+ }
273
+ }
274
+ }
275
+ }
276
+ });
277
+
278
+ await wrapper.vm.fetchChart();
279
+
280
+ expect(wrapper.vm.existing).toStrictEqual(installedApp);
281
+ expect(wrapper.vm.mode).toStrictEqual('edit');
282
+ });
217
283
  });
218
284
 
219
285
  describe('action', () => {
@@ -366,6 +432,52 @@ describe('chartMixin', () => {
366
432
  });
367
433
  });
368
434
 
435
+ describe('isChartTargeted', () => {
436
+ const DummyComponent = {
437
+ mixins: [ChartMixin],
438
+ template: '<div></div>',
439
+ };
440
+
441
+ const mockStore = {
442
+ dispatch: jest.fn(() => Promise.resolve()),
443
+ getters: { 'i18n/t': (key: string) => key }
444
+ };
445
+
446
+ it('should return truthy when version annotations have both namespace and release-name', () => {
447
+ const wrapper = mount(DummyComponent, {
448
+ data: () => ({
449
+ version: {
450
+ annotations: {
451
+ [CATALOG_ANNOTATIONS.NAMESPACE]: 'custom-ns',
452
+ [CATALOG_ANNOTATIONS.RELEASE_NAME]: 'custom-name',
453
+ }
454
+ }
455
+ }),
456
+ global: { mocks: { $store: mockStore } }
457
+ });
458
+
459
+ expect(wrapper.vm.isChartTargeted).toBeTruthy();
460
+ });
461
+
462
+ it('should return falsy when version annotations are missing', () => {
463
+ const wrapper = mount(DummyComponent, {
464
+ data: () => ({ version: { annotations: {} } }),
465
+ global: { mocks: { $store: mockStore } }
466
+ });
467
+
468
+ expect(wrapper.vm.isChartTargeted).toBeFalsy();
469
+ });
470
+
471
+ it('should return falsy when version is null', () => {
472
+ const wrapper = mount(DummyComponent, {
473
+ data: () => ({ version: null }),
474
+ global: { mocks: { $store: mockStore } }
475
+ });
476
+
477
+ expect(wrapper.vm.isChartTargeted).toBeFalsy();
478
+ });
479
+ });
480
+
369
481
  describe('mappedVersions', () => {
370
482
  it('should return versions sorted by semver (descending)', () => {
371
483
  const versions = [
@@ -469,5 +581,99 @@ describe('chartMixin', () => {
469
581
  '0.0.1'
470
582
  ]);
471
583
  });
584
+
585
+ it('should correctly format current version when it is Linux-only', () => {
586
+ const versions = [
587
+ {
588
+ version: '1.0.0',
589
+ created: '2026-01-01',
590
+ annotations: { 'catalog.cattle.io/permits-os': 'linux' }
591
+ }
592
+ ];
593
+
594
+ const mockStore = {
595
+ dispatch: jest.fn(() => Promise.resolve()),
596
+ getters: {
597
+ currentCluster: () => ({ workerOSs: ['linux'] }),
598
+ isRancher: () => true,
599
+ 'catalog/repo': () => () => 'repo',
600
+ 'catalog/chart': () => ({ versions }),
601
+ 'prefs/get': () => () => true,
602
+ 'i18n/t': () => jest.fn()
603
+ }
604
+ };
605
+
606
+ const DummyComponent = {
607
+ mixins: [ChartMixin],
608
+ template: '<div></div>',
609
+ };
610
+
611
+ const wrapper = mount(
612
+ DummyComponent,
613
+ {
614
+ data: () => ({
615
+ chart: { versions },
616
+ existing: { spec: { chart: { metadata: { version: '1.0.0' } } } }
617
+ }),
618
+ global: {
619
+ mocks: {
620
+ $store: mockStore,
621
+ $route: { query: { version: '1.0.0' } },
622
+ t: (key: string, args: any) => `${ args?.ver } (Current, Linux-only)`
623
+ }
624
+ }
625
+ });
626
+
627
+ const result = (wrapper.vm as any).mappedVersions;
628
+
629
+ expect(result[0].label).toBe('1.0.0 (Current, Linux-only)');
630
+ });
631
+
632
+ it('should correctly format current version when it is not OS-restricted', () => {
633
+ const versions = [
634
+ {
635
+ version: '1.0.0',
636
+ created: '2026-01-01',
637
+ annotations: {}
638
+ }
639
+ ];
640
+
641
+ const mockStore = {
642
+ dispatch: jest.fn(() => Promise.resolve()),
643
+ getters: {
644
+ currentCluster: () => ({ workerOSs: ['linux'] }),
645
+ isRancher: () => true,
646
+ 'catalog/repo': () => () => 'repo',
647
+ 'catalog/chart': () => ({ versions }),
648
+ 'prefs/get': () => () => true,
649
+ 'i18n/t': () => jest.fn()
650
+ }
651
+ };
652
+
653
+ const DummyComponent = {
654
+ mixins: [ChartMixin],
655
+ template: '<div></div>',
656
+ };
657
+
658
+ const wrapper = mount(
659
+ DummyComponent,
660
+ {
661
+ data: () => ({
662
+ chart: { versions },
663
+ existing: { spec: { chart: { metadata: { version: '1.0.0' } } } }
664
+ }),
665
+ global: {
666
+ mocks: {
667
+ $store: mockStore,
668
+ $route: { query: { version: '1.0.0' } },
669
+ t: (key: string, args: any) => `${ args?.ver } (Current)`
670
+ }
671
+ }
672
+ });
673
+
674
+ const result = (wrapper.vm as any).mappedVersions;
675
+
676
+ expect(result[0].label).toBe('1.0.0 (Current)');
677
+ });
472
678
  });
473
679
  });
@@ -0,0 +1,48 @@
1
+ import { parseStateFilter } from '@shell/mixins/resource-fetch-api-pagination';
2
+ import { PaginationFilterEquality } from '@shell/types/store/pagination.types';
3
+
4
+ describe('parseStateFilter', () => {
5
+ it('should return null for null input', () => {
6
+ expect(parseStateFilter(null)).toBeNull();
7
+ });
8
+
9
+ it('should return null for undefined input', () => {
10
+ expect(parseStateFilter(undefined)).toBeNull();
11
+ });
12
+
13
+ it('should return null for empty string', () => {
14
+ expect(parseStateFilter('')).toBeNull();
15
+ });
16
+
17
+ it('should parse a single state', () => {
18
+ const result = parseStateFilter('running');
19
+
20
+ expect(result).toHaveLength(1);
21
+ expect(result?.[0].field).toStrictEqual('metadata.state.name');
22
+ expect(result?.[0].value).toStrictEqual('running');
23
+ expect(result?.[0].equality).toStrictEqual(PaginationFilterEquality.IN);
24
+ });
25
+
26
+ it('should parse multiple comma-separated states', () => {
27
+ const result = parseStateFilter('running,active');
28
+
29
+ expect(result).toHaveLength(1);
30
+ expect(result?.[0].field).toStrictEqual('metadata.state.name');
31
+ expect(result?.[0].value).toStrictEqual('running,active');
32
+ expect(result?.[0].equality).toStrictEqual(PaginationFilterEquality.IN);
33
+ });
34
+
35
+ it('should parse three comma-separated states', () => {
36
+ const result = parseStateFilter('running,active,waiting');
37
+
38
+ expect(result).toHaveLength(1);
39
+ expect(result?.[0].value).toStrictEqual('running,active,waiting');
40
+ });
41
+
42
+ it('should ignore empty segments from trailing commas', () => {
43
+ const result = parseStateFilter('running,,active,');
44
+
45
+ expect(result).toHaveLength(1);
46
+ expect(result?.[0].value).toStrictEqual('running,active');
47
+ });
48
+ });
@@ -201,6 +201,9 @@ export default {
201
201
  if (!this.model.accessMode) {
202
202
  this.model.accessMode = 'unrestricted';
203
203
  }
204
+ if (this.model.id === 'github' || this.model.id === 'githubapp') {
205
+ this.model.accessMode = 'restricted';
206
+ }
204
207
  await this.model.doAction('testAndApply', obj, { redirectUnauthorized: false });
205
208
  }
206
209
 
@@ -241,6 +244,10 @@ export default {
241
244
  } else {
242
245
  console.warn(`Unable to find principal marked as 'me'`); // eslint-disable-line no-console
243
246
  }
247
+
248
+ if (!wasEnabled) {
249
+ this.model.accessMode = 'required';
250
+ }
244
251
  }
245
252
  if (wasEnabled && configType === 'oauth') {
246
253
  await this.model.save({ ignoreFields: ['oauthCredential', 'serviceAccountCredential'] } );
package/mixins/brand.js CHANGED
@@ -183,7 +183,8 @@ export default {
183
183
  },
184
184
  setBodyClass() {
185
185
  const body = document.getElementsByTagName('body')[0];
186
- const cssClass = `overflow-hidden dashboard-body`;
186
+ const isStandalone = this.$route?.meta?.standalone;
187
+ const cssClass = isStandalone ? 'dashboard-body' : 'overflow-hidden dashboard-body';
187
188
  let bodyClass = `theme-${ this.theme } ${ cssClass }`;
188
189
 
189
190
  if ( this.brand ) {
package/mixins/chart.js CHANGED
@@ -13,7 +13,7 @@ import { CAPI, CATALOG } from '@shell/config/types';
13
13
  import { isPrerelease } from '@shell/utils/version';
14
14
  import { compareChartVersions } from '@shell/utils/chart';
15
15
  import difference from 'lodash/difference';
16
- import { LINUX, APP_UPGRADE_STATUS } from '@shell/store/catalog';
16
+ import { APP_UPGRADE_STATUS, isRancherRepo, getPermittedOSs } from '@shell/store/catalog';
17
17
  import { clone } from '@shell/utils/object';
18
18
  import { merge } from 'lodash';
19
19
 
@@ -71,6 +71,8 @@ export default {
71
71
 
72
72
  const selectedVersion = this.targetVersion;
73
73
  const OSs = this.currentCluster?.workerOSs;
74
+ const isRancher = isRancherRepo(this.repo, this.chart);
75
+ const permittedSystemsByVersion = new Map();
74
76
  const out = [];
75
77
 
76
78
  versions.forEach((version) => {
@@ -84,7 +86,9 @@ export default {
84
86
  keywords: version.keywords
85
87
  };
86
88
 
87
- const permittedSystems = (version?.annotations?.[CATALOG_ANNOTATIONS.PERMITTED_OS] || LINUX).split(',');
89
+ const permittedSystems = getPermittedOSs(version?.annotations, isRancher);
90
+
91
+ permittedSystemsByVersion.set(version.version, permittedSystems);
88
92
 
89
93
  if (permittedSystems.length > 0 && difference(OSs, permittedSystems).length > 0) {
90
94
  nue.disabled = true;
@@ -117,7 +121,13 @@ export default {
117
121
  const currentVersion = out.find((v) => v.originalVersion === this.currentVersion);
118
122
 
119
123
  if (currentVersion) {
120
- currentVersion.label = this.t('catalog.install.versions.current', { ver: this.currentVersion });
124
+ const permittedSystems = permittedSystemsByVersion.get(currentVersion.originalVersion) || [];
125
+
126
+ if (permittedSystems.length === 1) {
127
+ currentVersion.label = this.t(`catalog.install.versions.current_${ permittedSystems[0] }`, { ver: this.currentVersion });
128
+ } else {
129
+ currentVersion.label = this.t('catalog.install.versions.current', { ver: this.currentVersion });
130
+ }
121
131
  }
122
132
 
123
133
  return out;
@@ -271,7 +281,7 @@ export default {
271
281
  },
272
282
 
273
283
  isChartTargeted() {
274
- return this.chart?.targetNamespace && this.chart?.targetName;
284
+ return this.version?.annotations?.[CATALOG_ANNOTATIONS.NAMESPACE] && this.version?.annotations?.[CATALOG_ANNOTATIONS.RELEASE_NAME];
275
285
  },
276
286
 
277
287
  hasQuestions() {
@@ -386,8 +396,8 @@ export default {
386
396
  // Use those values to check for a catalog app resource.
387
397
  // If found, set the form to edit mode. If not, set the
388
398
  // form to create mode.
389
- // This is a hard blocker - installing a new instance is NOT allowed.
390
399
 
400
+ // This is a hard blocker - installing a new instance is NOT allowed.
391
401
  this.canInstallNew = false;
392
402
 
393
403
  try {
@@ -410,11 +420,10 @@ export default {
410
420
  if ( targetNamespace && targetName ) {
411
421
  // If the app name and namespace values are not provided in the
412
422
  // query, fall back on target values defined in the Helm chart itself.
413
-
414
423
  // Ask to install a special chart with fixed namespace/name
415
424
  // or edit it if there's an existing install.
416
- // This is a hard blocker - installing a new instance is NOT allowed.
417
425
 
426
+ // This is a hard blocker - installing a new instance is NOT allowed.
418
427
  this.canInstallNew = false;
419
428
 
420
429
  try {
@@ -424,8 +433,12 @@ export default {
424
433
  });
425
434
  this.mode = _EDIT;
426
435
  } catch (e) {
427
- this.mode = _CREATE;
428
- this.existing = null;
436
+ // Version targets a different namespace than where the app is installed.
437
+ // Fall back to matching installed apps (e.g. chart detail page).
438
+ const matching = this.chart?.matchingInstalledApps || [];
439
+
440
+ this.existing = matching[0] || null;
441
+ this.mode = this.existing ? _EDIT : _CREATE;
429
442
  }
430
443
  } else {
431
444
  // Regular chart (not targeted) - check if there are installed instances.
@@ -8,20 +8,26 @@ export const AFTER_SAVE_HOOKS = '_afterSaveHooks';
8
8
 
9
9
  export default {
10
10
  methods: {
11
+ registerHook(key, boundFn, name, priority = 99, boundFnContext) {
12
+ this._registerHook(key, boundFn, name, priority, boundFnContext);
13
+ },
14
+
11
15
  registerBeforeHook(boundFn, name, priority = 99, boundFnContext) {
12
- this._registerHook(BEFORE_SAVE_HOOKS, boundFn, name, priority, boundFnContext);
16
+ this.registerHook(BEFORE_SAVE_HOOKS, boundFn, name, priority, boundFnContext);
13
17
  },
14
18
 
15
- unregisterBeforeSaveHook(name) {
16
- this[BEFORE_SAVE_HOOKS] = this[BEFORE_SAVE_HOOKS].filter((hook) => {
17
- // BEFORE_SAVE_HOOKS is an array of objects with keys
18
- // fn, name and priority.
19
+ unregisterHook(key, name) {
20
+ this[key] = (this[key] || []).filter((hook) => {
19
21
  return hook.name !== name;
20
22
  });
21
23
  },
22
24
 
25
+ unregisterBeforeSaveHook(name) {
26
+ this.unregisterHook(BEFORE_SAVE_HOOKS, name);
27
+ },
28
+
23
29
  registerAfterHook(boundFn, name, priority = 99, boundFnContext) {
24
- this._registerHook(AFTER_SAVE_HOOKS, boundFn, name, priority, boundFnContext);
30
+ this.registerHook(AFTER_SAVE_HOOKS, boundFn, name, priority, boundFnContext);
25
31
  },
26
32
 
27
33
  async applyHooks(key, ...args) {
@@ -1,6 +1,6 @@
1
1
  import { _CREATE, _EDIT, _VIEW } from '@shell/config/query-params';
2
2
  import { LAST_NAMESPACE } from '@shell/store/prefs';
3
- import { exceptionToErrorsArray } from '@shell/utils/error';
3
+ import { exceptionToErrorsArray, isDoNotLogError } from '@shell/utils/error';
4
4
  import ChildHook, { BEFORE_SAVE_HOOKS, AFTER_SAVE_HOOKS } from '@shell/mixins/child-hook';
5
5
  import { clear } from '@shell/utils/array';
6
6
  import { DEFAULT_WORKSPACE } from '@shell/config/types';
@@ -184,8 +184,10 @@ export default {
184
184
  } else {
185
185
  this.errors = exceptionToErrorsArray(err);
186
186
  }
187
- // Provide a stack trace for easier debugging of save errors
188
- console.error('CreateEditView mixin failed to save: ', err); // eslint-disable-line no-console
187
+ if (!isDoNotLogError(err)) {
188
+ // Provide a stack trace for easier debugging of save errors
189
+ console.error('CreateEditView mixin failed to save: ', err); // eslint-disable-line no-console
190
+ }
189
191
  buttonDone && buttonDone(false);
190
192
  }
191
193
  },
@@ -1,14 +1,32 @@
1
1
  import { NAMESPACE_FILTER_NAMESPACED_YES, NAMESPACE_FILTER_NAMESPACED_NO, NAMESPACE_FILTER_ALL } from '@shell/utils/namespace-filter';
2
- import { NAMESPACE } from '@shell/config/types';
2
+ import { MANAGEMENT, NAMESPACE } from '@shell/config/types';
3
3
  import { ALL_NAMESPACES } from '@shell/store/prefs';
4
4
  import { mapGetters } from 'vuex';
5
5
  import { ResourceListComponentName } from '../components/ResourceList/resource-list.config';
6
6
  import paginationUtils from '@shell/utils/pagination-utils';
7
7
  import debounce from 'lodash/debounce';
8
- import { PaginationParamFilter, PaginationFilterField, PaginationArgs } from '@shell/types/store/pagination.types';
8
+ import { PaginationParamFilter, PaginationFilterField, PaginationFilterEquality, PaginationArgs } from '@shell/types/store/pagination.types';
9
9
  import stevePaginationUtils from '@shell/plugins/steve/steve-pagination-utils';
10
10
  import { STEVE_WATCH_MODE } from '@shell/types/store/subscribe.types';
11
11
 
12
+ export function parseStateFilter(stateFilter) {
13
+ if (!stateFilter) {
14
+ return null;
15
+ }
16
+
17
+ const states = stateFilter.split(',').filter(Boolean);
18
+
19
+ if (!states.length) {
20
+ return null;
21
+ }
22
+
23
+ return [new PaginationFilterField({
24
+ field: 'metadata.state.name',
25
+ value: states.join(','),
26
+ equality: PaginationFilterEquality.IN,
27
+ })];
28
+ }
29
+
12
30
  /**
13
31
  * Companion mixin used with `resource-fetch` for `ResourceList` to determine if the user needs to filter the list by a single namespace
14
32
  */
@@ -75,6 +93,7 @@ export default {
75
93
  const {
76
94
  page, perPage, filter, sort, descending
77
95
  } = event;
96
+ const stateFilters = parseStateFilter(this.$route?.query?.stateFilter) || [];
78
97
  const searchFilters = filter.searchQuery ? filter.searchFields.map((field) => new PaginationFilterField({
79
98
  field,
80
99
  value: filter.searchQuery,
@@ -91,6 +110,7 @@ export default {
91
110
  projectsOrNamespaces: this.requestFilters.projectsOrNamespaces,
92
111
  filters: [
93
112
  new PaginationParamFilter({ fields: searchFilters }),
113
+ new PaginationParamFilter({ fields: stateFilters }),
94
114
  ...this.requestFilters.filters, // Apply the additional filters. these aren't from the user but from ns filtering
95
115
  ]
96
116
  });
@@ -248,7 +268,7 @@ export default {
248
268
  namespaceFilters: {
249
269
  immediate: true,
250
270
  async handler(neu, old) {
251
- if (!this.canPaginate || !this.isNamespaced) {
271
+ if (!this.canPaginate || !this.isNamespaced || !this.currentProduct?.showNamespaceFilter) {
252
272
  return;
253
273
  }
254
274
 
@@ -283,7 +303,7 @@ export default {
283
303
  allNamespaces: this.$store.getters[`${ this.currentProduct?.inStore }/all`](NAMESPACE),
284
304
  selection: neu,
285
305
  isAllNamespaces: this.isAllNamespaces,
286
- isLocalCluster: this.$store.getters['currentCluster'].isLocal,
306
+ isLocalCluster: this.$store.getters['currentCluster']?.isLocal,
287
307
  showReservedRancherNamespaces: this.showDynamicRancherNamespaces,
288
308
  productHidesSystemNamespaces: this.productHidesSystemNamespaces,
289
309
  });
@@ -354,15 +374,51 @@ export default {
354
374
 
355
375
  async beforeUnmount() {
356
376
  if (this.havePaginated) {
377
+ const store = this.overrideInStore || this.inStore;
357
378
  // of type @STEVE_WATCH_PARAMS
358
379
  const watchArgs = {
359
380
  type: this.resource,
360
381
  mode: STEVE_WATCH_MODE.RESOURCE_CHANGES,
361
382
  };
362
383
 
363
- await this.$store.dispatch(`${ this.overrideInStore || this.inStore }/forgetType`, this.resource, (watchParams) => {
364
- return watchParams.type === watchArgs.type && watchParams.mode === watchArgs.type.mode;
384
+ // Ensure that a resource remains in the store... and it's the same reference as before
385
+ // We'll do this for the mgmt cluster if there's a currentCluster set, otherwise we become unstuck
386
+ // (on nav we ensure currentCluster exists, but beforeUnmount fires afterwards, removing the cluster from pages that are using it)
387
+ const retainResource = this.resource === MANAGEMENT.CLUSTER && this.currentCluster ? this.currentCluster : null;
388
+
389
+ // Forget (unwatch, clear from store) the list's resource
390
+ await this.$store.dispatch(`${ store }/forgetType`, {
391
+ type: this.resource,
392
+ compareWatches: (watchParams) => {
393
+ return watchParams.type === watchArgs.type && watchParams.mode === watchArgs.mode;
394
+ },
395
+ unwatch: true,
396
+ forget: !retainResource
365
397
  });
398
+
399
+ if (!!retainResource) {
400
+ // The end state should be just like we've dispatched `${store}/find`
401
+
402
+ try {
403
+ // Clone to ensure we can load each property of A into B without worrying about them being the same reference
404
+ const clone = await this.$store.dispatch(`${ store }/clone`, { resource: retainResource });
405
+
406
+ // Load the resource. It's already in the store but this makes sure any legacy state (like havePage) is reset
407
+ await this.$store.dispatch(`${ store }/load`, {
408
+ data: clone,
409
+ existing: retainResource,
410
+ invalidatePageCache: true,
411
+ });
412
+
413
+ // Watch the resource.
414
+ await this.$store.dispatch(`${ store }/watch`, {
415
+ type: this.resource,
416
+ id: retainResource.id,
417
+ });
418
+ } catch (error) {
419
+ console.error('Error occurred whilst trying to retain the management cluster in cache and correctly watched', error); // eslint-disable-line no-console
420
+ }
421
+ }
366
422
  }
367
423
  }
368
424
  };