@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
@@ -174,7 +174,7 @@ export default {
174
174
  await wait(5000);
175
175
  }
176
176
 
177
- const user = this.value.save();
177
+ const user = await this.value.save();
178
178
 
179
179
  return user;
180
180
  },
@@ -214,8 +214,10 @@ export default {
214
214
  return;
215
215
  }
216
216
 
217
+ const userId = user?.id || this.value.id;
218
+
217
219
  try {
218
- await this.$refs.grb.save(user.id);
220
+ await this.$refs.grb.save(userId);
219
221
  } catch (err) {
220
222
  if (this.isCreate) {
221
223
  try {
@@ -245,6 +247,7 @@ export default {
245
247
  :can-yaml="false"
246
248
  class="create-edit"
247
249
  @finish="save"
250
+ @error="e=>errors = e"
248
251
  >
249
252
  <div class="credentials">
250
253
  <h2> {{ t("user.edit.credentials.label") }}</h2>
@@ -43,7 +43,9 @@ export default {
43
43
  const backend = get(this.value.spec, this.value.defaultBackendPath);
44
44
 
45
45
  this.serviceName = get(backend, this.value.serviceNamePath) || '';
46
- this.servicePort = get(backend, this.value.servicePortPath) || '';
46
+ this.servicePort = get(backend, this.value.servicePortPath) ||
47
+ get(backend, this.value.servicePortNamePath) ||
48
+ '';
47
49
  },
48
50
  computed: {
49
51
  isView() {
@@ -75,10 +77,14 @@ export default {
75
77
  },
76
78
  methods: {
77
79
  update() {
78
- const backend = get(this.value.spec, this.value.defaultBackendPath) || {};
80
+ // Fresh object so the old port path (name vs number) doesn't linger.
81
+ const backend = {};
82
+ const parsed = Number.parseInt(this.servicePort);
83
+ const servicePort = Number.isNaN(parsed) ? this.servicePort : parsed;
84
+ const portPath = typeof servicePort === 'number' ? this.value.servicePortPath : this.value.servicePortNamePath;
79
85
 
80
86
  set(backend, this.value.serviceNamePath, this.serviceName);
81
- set(backend, this.value.servicePortPath, this.servicePort);
87
+ set(backend, portPath, servicePort);
82
88
  set(this.value.spec, this.value.defaultBackendPath, backend);
83
89
 
84
90
  this.$emit('update:value', this.value);
@@ -119,10 +125,12 @@ export default {
119
125
  class="col span-3"
120
126
  :style="{'margin-right': '0px'}"
121
127
  >
128
+ <!-- :required drives the asterisk; portRequired doesn't have .name === 'required' -->
122
129
  <LabeledInput
123
130
  v-if="portOptions.length === 0 || isView"
124
- v-model:value.number="servicePort"
131
+ v-model:value="servicePort"
125
132
  :mode="mode"
133
+ :required="true"
126
134
  :label="t('ingress.defaultBackend.port.label')"
127
135
  :placeholder="t('ingress.defaultBackend.port.placeholder')"
128
136
  :rules="rules.port"
@@ -132,6 +140,7 @@ export default {
132
140
  v-else
133
141
  v-model:value="servicePort"
134
142
  :mode="mode"
143
+ :required="true"
135
144
  :options="portOptions"
136
145
  :label="t('ingress.defaultBackend.port.label')"
137
146
  :placeholder="t('ingress.defaultBackend.port.placeholder')"
@@ -79,20 +79,24 @@ export default {
79
79
  set(this.value, 'path', this.value.path || '');
80
80
  set(this.value, 'pathType', this.value.pathType || this.pathTypes[0]);
81
81
  set(this.value.backend, this.ingress.serviceNamePath, get(this.value.backend, this.ingress.serviceNamePath) || '');
82
- set(this.value.backend, this.ingress.servicePortPath, get(this.value.backend, this.ingress.servicePortPath) || '');
83
82
 
84
83
  this.serviceName = get(this.value.backend, this.ingress.serviceNamePath);
85
- this.servicePort = get(this.value.backend, this.ingress.servicePortPath);
84
+ this.servicePort = get(this.value.backend, this.ingress.servicePortPath) ||
85
+ get(this.value.backend, this.ingress.servicePortNamePath) ||
86
+ '';
86
87
  },
87
88
  methods: {
88
89
  update() {
89
- const servicePort = Number.parseInt(this.servicePort) || this.servicePort;
90
+ const parsed = Number.parseInt(this.servicePort);
91
+ const servicePort = Number.isNaN(parsed) ? this.servicePort : parsed;
90
92
  const serviceName = this.serviceName.label || this.serviceName;
91
93
  const out = {
92
94
  id: this.value.id, backend: {}, path: this.path, pathType: this.pathType
93
95
  };
94
96
 
95
- set(out.backend, this.ingress.servicePortPath, servicePort);
97
+ const portPath = typeof servicePort === 'number' ? this.ingress.servicePortPath : this.ingress.servicePortNamePath;
98
+
99
+ set(out.backend, portPath, servicePort);
96
100
  set(out.backend, this.ingress.serviceNamePath, serviceName);
97
101
 
98
102
  this.$emit('update:value', out);
@@ -87,21 +87,21 @@ export default {
87
87
  path: 'spec.rules.http.paths.path', rules: ['absolutePath'], translationKey: 'ingress.rules.path.label'
88
88
  },
89
89
  {
90
- path: 'spec.rules.http.paths.backend.service.port.number', rules: ['required'], translationKey: 'ingress.rules.port.label'
90
+ path: 'spec.rules.http.paths.backend.service.port', rules: ['portRequired', 'portRange'], translationKey: 'ingress.rules.port.label'
91
91
  },
92
92
  {
93
93
  path: 'spec.rules.http.paths.backend.service.name', rules: ['required'], translationKey: 'ingress.rules.target.label'
94
94
  },
95
95
  { path: 'spec', rules: ['backEndOrRules'] },
96
96
  {
97
- path: 'spec.defaultBackend.service.name', rules: ['required'], translationKey: 'ingress.defaultBackend.targetService.label'
97
+ path: 'spec.defaultBackend.service.name', rules: ['defaultBackendNameRequired'], translationKey: 'ingress.defaultBackend.targetService.label'
98
98
  },
99
99
  {
100
- path: 'spec.defaultBackend.service.port.number', rules: ['required', 'requiredInt', 'portNumber'], translationKey: 'ingress.defaultBackend.port.label'
100
+ path: 'spec.defaultBackend.service.port', rules: ['defaultBackendPortRequired', 'portRange'], translationKey: 'ingress.defaultBackend.port.label'
101
101
  },
102
102
  { path: 'spec.tls.hosts', rules: ['required', 'wildcardHostname'] }
103
103
  ],
104
- fvReportedValidationPaths: ['spec.rules.http.paths.backend.service.port.number', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.name']
104
+ fvReportedValidationPaths: ['spec.rules.http.paths.backend.service.port', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.name']
105
105
  };
106
106
  },
107
107
 
@@ -125,35 +125,89 @@ export default {
125
125
  }
126
126
  };
127
127
 
128
- return { backEndOrRules };
128
+ const portLabel = this.t('ingress.rules.port.label');
129
+
130
+ // Built-in `required` won't work: it passes for empty objects like {} or { name: '' }.
131
+ const portRequired = (port) => {
132
+ if (typeof port === 'string' || typeof port === 'number') {
133
+ if (!port) {
134
+ return this.t('validation.required', { key: portLabel });
135
+ }
136
+ } else if (!port || (!port.number && !port.name)) {
137
+ return this.t('validation.required', { key: portLabel });
138
+ }
139
+ };
140
+
141
+ const portRange = (port) => {
142
+ let num;
143
+
144
+ if (typeof port === 'number') {
145
+ num = port;
146
+ } else if (typeof port === 'string') {
147
+ num = Number.parseInt(port);
148
+ } else if (port?.number) {
149
+ num = port.number;
150
+ }
151
+
152
+ if (num !== undefined && !Number.isNaN(num) && (num < 1 || num > 65535)) {
153
+ return this.t('validation.number.between', {
154
+ key: portLabel, min: '1', max: '65535'
155
+ });
156
+ }
157
+ };
158
+
159
+ const hasDefaultBackendService = () => {
160
+ const backend = get(this.value?.spec, this.value.defaultBackendPath);
161
+
162
+ return !!get(backend, this.value.serviceNamePath);
163
+ };
164
+
165
+ const nameLabel = this.t('ingress.defaultBackend.targetService.label');
166
+
167
+ // Only enforce required on the default backend when a service is selected.
168
+ // Selecting "None" means the user wants to remove the backend; willSave() handles cleanup.
169
+ const defaultBackendNameRequired = (name) => {
170
+ if (hasDefaultBackendService() && !name) {
171
+ return this.t('validation.required', { key: nameLabel });
172
+ }
173
+ };
174
+
175
+ const defaultBackendPortRequired = (port) => {
176
+ if (!hasDefaultBackendService()) {
177
+ return;
178
+ }
179
+
180
+ return portRequired(port);
181
+ };
182
+
183
+ return {
184
+ backEndOrRules,
185
+ portRequired,
186
+ portRange,
187
+ defaultBackendNameRequired,
188
+ defaultBackendPortRequired,
189
+ };
129
190
  },
130
191
  tabErrors() {
131
192
  return {
132
- rules: this.fvGetPathErrors(['spec.rules.host', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.port.number', 'spec.rules.http.paths.backend.service.name'])?.length > 0,
133
- defaultBackend: this.fvGetPathErrors(['spec.defaultBackend.service.name', 'spec.defaultBackend.service.port.number'])?.length > 0
193
+ rules: this.fvGetPathErrors(['spec.rules.host', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.port', 'spec.rules.http.paths.backend.service.name'])?.length > 0,
194
+ defaultBackend: this.fvGetPathErrors(['spec.defaultBackend.service.name', 'spec.defaultBackend.service.port'])?.length > 0
134
195
  };
135
196
  },
136
197
  rulesPathRules() {
137
198
  return {
138
199
  requestHost: this.fvGetAndReportPathRules('spec.rules.host'),
139
200
  path: this.fvGetAndReportPathRules('spec.rules.http.paths.path'),
140
- port: this.fvGetAndReportPathRules('spec.rules.http.paths.backend.service.port.number'),
201
+ port: this.fvGetAndReportPathRules('spec.rules.http.paths.backend.service.port'),
141
202
  target: this.fvGetAndReportPathRules('spec.rules.http.paths.backend.service.name'),
142
203
 
143
204
  };
144
205
  },
145
206
  defaultBackendPathRules() {
146
- const rulesExist = (this.value?.spec?.rules || []).length > 0;
147
- const defaultBackendExist = !!this.value?.spec?.defaultBackend?.service;
148
-
149
- if (!rulesExist || defaultBackendExist) {
150
- return {
151
- name: this.fvGetAndReportPathRules('spec.defaultBackend.service.name'),
152
- port: this.fvGetAndReportPathRules('spec.defaultBackend.service.port.number'),
153
- };
154
- }
155
-
156
- return { name: [], port: [] };
207
+ return {
208
+ name: this.fvGetAndReportPathRules('spec.defaultBackend.service.name'),
209
+ port: this.fvGetAndReportPathRules('spec.defaultBackend.service.port'),
210
+ };
157
211
  },
158
212
  serviceTargets() {
159
213
  return this.ingressHelper.findAndMapServiceTargets(this.services);
@@ -188,7 +242,8 @@ export default {
188
242
  willSave() {
189
243
  const backend = get(this.value.spec, this.value.defaultBackendPath);
190
244
  const serviceName = get(backend, this.value.serviceNamePath);
191
- const servicePort = get(backend, this.value.servicePortPath);
245
+ const servicePort = get(backend, this.value.servicePortPath) ||
246
+ get(backend, this.value.servicePortNamePath);
192
247
 
193
248
  if (backend && (!serviceName || !servicePort)) {
194
249
  const path = this.value.defaultBackendPath;
@@ -0,0 +1,104 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import MachinePool from '@shell/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue';
3
+
4
+ const TRANSLATION_KEY = '%cluster.machinePool.name.unique%';
5
+
6
+ function createPool(name: string, { remove = false } = {}) {
7
+ return {
8
+ id: `pool-${ name }`,
9
+ remove,
10
+ create: false,
11
+ update: true,
12
+ pool: {
13
+ name,
14
+ etcdRole: false,
15
+ controlPlaneRole: false,
16
+ workerRole: true,
17
+ quantity: 1,
18
+ },
19
+ config: null,
20
+ };
21
+ }
22
+
23
+ function mountMachinePool(currentPool: ReturnType<typeof createPool>, allPools: ReturnType<typeof createPool>[]) {
24
+ return shallowMount(MachinePool, {
25
+ props: {
26
+ value: currentPool,
27
+ mode: 'create',
28
+ provider: 'custom',
29
+ idx: 0,
30
+ machinePools: allPools,
31
+ poolId: currentPool.id,
32
+ poolCreateMode: true,
33
+ },
34
+ global: {
35
+ mocks: {
36
+ $store: {
37
+ getters: {
38
+ 'i18n/t': (key: string) => key,
39
+ 'i18n/exists': () => false,
40
+ 'type-map/hasCustomMachineConfigComponent': () => false,
41
+ 'type-map/importMachineConfig': () => null,
42
+ 'features/get': () => false,
43
+ },
44
+ dispatch: jest.fn(),
45
+ },
46
+ },
47
+ stubs: {
48
+ LabeledInput: true,
49
+ Checkbox: true,
50
+ Taints: true,
51
+ KeyValue: true,
52
+ AdvancedSection: true,
53
+ Banner: true,
54
+ UnitInput: true,
55
+ },
56
+ },
57
+ });
58
+ }
59
+
60
+ describe('component: MachinePool', () => {
61
+ describe('uniquePoolName validation', () => {
62
+ it('should return undefined when the name is empty', () => {
63
+ const pool = createPool('');
64
+ const wrapper = mountMachinePool(pool, [pool]);
65
+
66
+ expect(wrapper.vm.fvExtraRules.uniquePoolName('')).toBeUndefined();
67
+ });
68
+
69
+ it('should return undefined when the pool name is unique', () => {
70
+ const pool1 = createPool('pool1');
71
+ const pool2 = createPool('pool2');
72
+ const wrapper = mountMachinePool(pool1, [pool1, pool2]);
73
+
74
+ expect(wrapper.vm.fvExtraRules.uniquePoolName('pool1')).toBeUndefined();
75
+ });
76
+
77
+ it('should return an error message when the pool name is duplicated', () => {
78
+ const pool1 = createPool('same-name');
79
+ const pool2 = createPool('same-name');
80
+ const wrapper = mountMachinePool(pool1, [pool1, pool2]);
81
+
82
+ expect(wrapper.vm.fvExtraRules.uniquePoolName('same-name')).toStrictEqual(TRANSLATION_KEY);
83
+ });
84
+
85
+ it('should ignore pools marked for removal', () => {
86
+ const pool1 = createPool('same-name');
87
+ const pool2 = createPool('same-name', { remove: true });
88
+ const wrapper = mountMachinePool(pool1, [pool1, pool2]);
89
+
90
+ expect(wrapper.vm.fvExtraRules.uniquePoolName('same-name')).toBeUndefined();
91
+ });
92
+
93
+ it.each([
94
+ ['Pool1', 'pool1'],
95
+ ['POOL', 'pool'],
96
+ ])('should flag names that differ only by case as duplicates (%s vs %s)', (nameA, nameB) => {
97
+ const pool1 = createPool(nameA);
98
+ const pool2 = createPool(nameB);
99
+ const wrapper = mountMachinePool(pool1, [pool1, pool2]);
100
+
101
+ expect(wrapper.vm.fvExtraRules.uniquePoolName(nameA)).toStrictEqual(TRANSLATION_KEY);
102
+ });
103
+ });
104
+ });
@@ -5,7 +5,7 @@ import { Banner } from '@components/Banner';
5
5
  import CruResource from '@shell/components/CruResource';
6
6
  import SelectIconGrid from '@shell/components/SelectIconGrid';
7
7
  import {
8
- CHART, FROM_CLUSTER, SUB_TYPE, RKE_TYPE, _EDIT, _IMPORT, _CONFIG, _VIEW
8
+ CHART, FROM_CLUSTER, SUB_TYPE, RKE_TYPE, _EDIT, _IMPORT, _CONFIG, _VIEW, _CREATE
9
9
  } from '@shell/config/query-params';
10
10
  import { mapGetters } from 'vuex';
11
11
  import { sortBy } from '@shell/utils/sort';
@@ -80,16 +80,20 @@ export default {
80
80
  },
81
81
 
82
82
  async fetch() {
83
- const hash = {
84
- // These aren't explicitly used, but need to be listening for change events
85
- mgmtClusters: this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }),
86
- provClusters: this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }),
87
- };
83
+ const hash = {};
84
+
85
+ if (this.mode === _CREATE) {
86
+ // After we create we wait for these to exist, so start watching
87
+ await this.$store.dispatch('management/watch', { type: MANAGEMENT.CLUSTER, registerType: true });
88
+ await this.$store.dispatch('management/watch', { type: CAPI.RANCHER_CLUSTER, registerType: true });
89
+ } else {
90
+ hash.mgmtClusters = this.value.waitForMgmt();
91
+ }
88
92
 
89
93
  // No need to fetch charts when editing an RKE1 cluster
90
94
  // The computed property `isRke1` in this file is based on the RKE1/RKE2 toggle, which is not applicable in this case
91
95
  // Instead, we should rely on the value from the model: `this.value.isRke1`
92
- if (!this.value.isRke1 || (this.value.isRke1 && this.mode !== 'edit')) {
96
+ if (!this.value.isRke1 || (this.value.isRke1 && this.mode !== _EDIT)) {
93
97
  hash['catalog'] = this.$store.dispatch('catalog/load');
94
98
  }
95
99
 
@@ -94,8 +94,8 @@ const NODE_TOTAL = {
94
94
  };
95
95
  const CLUSTER_AGENT_CUSTOMIZATION = 'clusterAgentDeploymentCustomization';
96
96
  const FLEET_AGENT_CUSTOMIZATION = 'fleetAgentDeploymentCustomization';
97
-
98
97
  const REGISTRIES_TAB_NAME = 'registry';
98
+ const INIT_HOOKS = '_initHooks';
99
99
 
100
100
  const isAzureK8sUnsupported = (version) => semver.gte(version, '1.30.0');
101
101
 
@@ -174,7 +174,7 @@ export default {
174
174
  Object.entries(this.chartValues).forEach(([name, value]) => {
175
175
  const key = this.chartVersionKey(name);
176
176
 
177
- this.set(this.userChartValues, key, value);
177
+ this.userChartValues[key] = value;
178
178
  });
179
179
  this.setAgentConfiguration();
180
180
  },
@@ -274,6 +274,7 @@ export default {
274
274
  truncateLimit: this.value.defaultHostnameLengthLimit || 0,
275
275
  busy: false,
276
276
  machinePoolValidation: {}, // map of validation states for each machine pool
277
+ infrastructureClusterValid: true,
277
278
  machinePoolErrors: {},
278
279
  addonConfigValidation: {}, // validation state of each addon config (boolean of whether codemirror's yaml lint passed)
279
280
  stackPreferenceError: false, // spec.networking.stackPreference is validated in conjunction with hasOnlyIpv6Pools
@@ -298,7 +299,9 @@ export default {
298
299
  isEmpty,
299
300
  AGENT_CONFIGURATION_TYPES,
300
301
  basicsValid: true,
302
+ registryConfigValid: true,
301
303
  originalIngressController: this.value.spec.rkeConfig.machineGlobalConfig?.[INGRESS_CONTROLLER] || INGRESS_NONE,
304
+ infrastructureCluster: null,
302
305
  };
303
306
  },
304
307
 
@@ -328,6 +331,14 @@ export default {
328
331
  return this.provider === ELEMENTAL_CLUSTER_PROVIDER || this.value?.machineProvider?.toLowerCase() === KIND.MACHINE_INV_SELECTOR_TEMPLATES.toLowerCase();
329
332
  },
330
333
 
334
+ isUpstreamCAPIProvider() {
335
+ if (this.extensionProvider?.isUpstreamCAPIProvider !== undefined) {
336
+ return !!this.extensionProvider.isUpstreamCAPIProvider;
337
+ }
338
+
339
+ return false;
340
+ },
341
+
331
342
  chartValues() {
332
343
  return this.value.spec.rkeConfig.chartValues;
333
344
  },
@@ -547,7 +558,7 @@ export default {
547
558
  getters: this.$store.getters,
548
559
  axios: this.$store.$axios,
549
560
  $extension: this.$store.app.$extension,
550
- $t: this.t,
561
+ t: (...args) => this.t.apply(this, args),
551
562
  isCreate: this.isCreate
552
563
  });
553
564
  }
@@ -825,6 +836,10 @@ export default {
825
836
  return null;
826
837
  },
827
838
 
839
+ extensionInfrastructureSection() {
840
+ return this.extensionProvider?.extensionInfrastructureSection || null;
841
+ },
842
+
828
843
  showForm() {
829
844
  return !!this.credentialId || !this.needCredential;
830
845
  },
@@ -878,7 +893,9 @@ export default {
878
893
 
879
894
  const hasAddonConfigErrors = Object.values(this.addonConfigValidation).filter((v) => v === false).length > 0;
880
895
 
881
- return validRequiredPools && base && !hasAddonConfigErrors && !this.stackPreferenceError;
896
+ const hasInfrastructureClusterError = this.isUpstreamCAPIProvider ? !this.infrastructureClusterValid : false;
897
+
898
+ return validRequiredPools && base && !hasAddonConfigErrors && !hasInfrastructureClusterError && !this.stackPreferenceError;
882
899
  },
883
900
 
884
901
  currentCluster() {
@@ -906,7 +923,8 @@ export default {
906
923
  return this.validationPassed &&
907
924
  this.fvFormIsValid &&
908
925
  this.etcdConfigValid &&
909
- this.basicsValid;
926
+ this.basicsValid &&
927
+ this.registryConfigValid;
910
928
  },
911
929
  nginxSupported() {
912
930
  if (this.serverArgs?.disable?.options.includes(RKE2_INGRESS_NGINX)) {
@@ -1013,6 +1031,11 @@ export default {
1013
1031
  },
1014
1032
 
1015
1033
  created() {
1034
+ // Hooks to be run when cluster is getting initialized
1035
+ if (this.extensionProvider?.registerInitHooks) {
1036
+ this.extensionProvider.registerInitHooks(this.registerHook.bind(this, INIT_HOOKS), this.value);
1037
+ }
1038
+ // Other hooks to be run before/after saving the cluster
1016
1039
  this.registerBeforeHook(this.showIpv6Warning, 'show-ipv6-warning', 1);
1017
1040
  this.registerBeforeHook(this.saveMachinePools, 'save-machine-pools', 2);
1018
1041
  this.registerBeforeHook(this.setRegistryConfig, 'set-registry-config');
@@ -1031,6 +1054,21 @@ export default {
1031
1054
  methods: {
1032
1055
  set,
1033
1056
 
1057
+ updateExtensionInfrastructureSection(neu) {
1058
+ if (!neu || typeof neu !== 'object') {
1059
+ return;
1060
+ }
1061
+
1062
+ if (!this.infrastructureCluster || typeof this.infrastructureCluster !== 'object') {
1063
+ this.infrastructureCluster = neu;
1064
+
1065
+ return;
1066
+ }
1067
+
1068
+ // Preserve the original resource model instance while applying extension updates.
1069
+ mergeWithReplace(this.infrastructureCluster, neu, { mutateOriginal: true });
1070
+ },
1071
+
1034
1072
  async handleVsphereCpiSecret() {
1035
1073
  return VsphereUtils.handleVsphereCpiSecret(this);
1036
1074
  },
@@ -1054,8 +1092,8 @@ export default {
1054
1092
  if (!this.value.spec.machineSelectorConfig.find((x) => !x.machineLabelSelector)) {
1055
1093
  this.value.spec.machineSelectorConfig.unshift({ config: {} });
1056
1094
  }
1057
-
1058
- if (this.value.spec.cloudCredentialSecretName) {
1095
+ // TODO handle upstream capi once credentials part is clear
1096
+ if (this.value.spec.cloudCredentialSecretName ) {
1059
1097
  await this.$store.dispatch('rancher/findAll', { type: NORMAN.CLOUD_CREDENTIAL });
1060
1098
  this.credentialId = `${ this.value.spec.cloudCredentialSecretName }`;
1061
1099
  }
@@ -1104,6 +1142,9 @@ export default {
1104
1142
  if ( isEmpty(this.value?.spec?.localClusterAuthEndpoint) ) {
1105
1143
  set(this.value, 'spec.localClusterAuthEndpoint', { enabled: false });
1106
1144
  }
1145
+
1146
+ await this.applyHooks(INIT_HOOKS, this.value);
1147
+ this.localValue = this.value;
1107
1148
  },
1108
1149
 
1109
1150
  /**
@@ -1279,6 +1320,10 @@ export default {
1279
1320
 
1280
1321
  if (this.isElementalCluster) {
1281
1322
  type = ELEMENTAL_SCHEMA_IDS.MACHINE_INV_SELECTOR_TEMPLATES;
1323
+ } else if (this.isUpstreamCAPIProvider && pool.machineConfigRef?.apiVersion) {
1324
+ const [group] = (pool.machineConfigRef.apiVersion || '').split('/');
1325
+
1326
+ type = `${ group }.${ pool.machineConfigRef.kind.toLowerCase() }`;
1282
1327
  } else {
1283
1328
  type = `${ CAPI.MACHINE_CONFIG_GROUP }.${ pool.machineConfigRef.kind.toLowerCase() }`;
1284
1329
  }
@@ -1384,10 +1429,20 @@ export default {
1384
1429
  pool.pool.machineOS = 'linux';
1385
1430
  }
1386
1431
 
1387
- if (this.isElementalCluster) {
1432
+ if (this.isElementalCluster && this.machineConfigSchema?.attributes) {
1388
1433
  pool.pool.machineConfigRef.apiVersion = `${ this.machineConfigSchema.attributes.group }/${ this.machineConfigSchema.attributes.version }`;
1389
1434
  }
1390
1435
 
1436
+ // Upstream CAPI MachineTemplate resources are referenced by full apiVersion so that
1437
+ // initMachinePools can resolve the correct management store type on subsequent loads.
1438
+ if (this.isUpstreamCAPIProvider && this.machineConfigSchema?.attributes) {
1439
+ const { group, version } = this.machineConfigSchema.attributes;
1440
+
1441
+ if (group && version) {
1442
+ pool.pool.machineConfigRef.apiVersion = `${ group }/${ version }`;
1443
+ }
1444
+ }
1445
+
1391
1446
  this.machinePools.push(pool);
1392
1447
 
1393
1448
  this.$nextTick(() => {
@@ -1536,6 +1591,10 @@ export default {
1536
1591
  },
1537
1592
 
1538
1593
  async cleanupMachinePools() {
1594
+ // Allow the extension provider to handle its own resource cleanup
1595
+ if (this.extensionProvider?.cleanupMachinePools) {
1596
+ return await this.extensionProvider.cleanupMachinePools(this.machinePools);
1597
+ }
1539
1598
  for (const entry of this.machinePools) {
1540
1599
  if (entry.remove && entry.config) {
1541
1600
  try {
@@ -2347,7 +2406,8 @@ export default {
2347
2406
  if (this.errors) {
2348
2407
  clear(this.errors);
2349
2408
  }
2350
- if (this.value.cloudProvider === 'aws') {
2409
+
2410
+ if ( this.value.cloudProvider === 'aws') {
2351
2411
  const missingProfileName = this.machinePools.some((mp) => !mp.config.iamInstanceProfile);
2352
2412
 
2353
2413
  if (missingProfileName) {
@@ -2356,7 +2416,7 @@ export default {
2356
2416
  }
2357
2417
 
2358
2418
  for (const [index] of this.machinePools.entries()) { // validator machine config
2359
- if (typeof this.$refs.pool[index]?.test === 'function') {
2419
+ if (typeof this.$refs.pool?.[index]?.test === 'function') {
2360
2420
  try {
2361
2421
  const res = await this.$refs.pool[index].test();
2362
2422
 
@@ -2473,7 +2533,22 @@ export default {
2473
2533
  >
2474
2534
  {{ appsOSWarning }}
2475
2535
  </Banner>
2476
-
2536
+ <div class="span-12">
2537
+ <component
2538
+ :is="extensionInfrastructureSection"
2539
+ v-if="extensionInfrastructureSection"
2540
+ :value="infrastructureCluster"
2541
+ :mode="mode"
2542
+ :provider="provider"
2543
+ :credential-id="credentialId"
2544
+ :provisioning-cluster="value"
2545
+ data-testid="extension-top-section"
2546
+ class="span-12"
2547
+ @update:value="updateExtensionInfrastructureSection"
2548
+ @error="e => errors.push(e)"
2549
+ @validationChanged="(val) => infrastructureClusterValid = val"
2550
+ />
2551
+ </div>
2477
2552
  <!-- Pools Extras -->
2478
2553
  <template v-if="hasMachinePools">
2479
2554
  <div class="clearfix">
@@ -2507,7 +2582,6 @@ export default {
2507
2582
  />
2508
2583
  </div>
2509
2584
  </div>
2510
-
2511
2585
  <!-- Extra Tabs for Machine Pool -->
2512
2586
  <Tabbed
2513
2587
  ref="pools"
@@ -2518,14 +2592,14 @@ export default {
2518
2592
  >
2519
2593
  <template
2520
2594
  v-for="(obj, idx) in machinePools"
2521
- :key="idx"
2595
+ :key="obj.id"
2522
2596
  >
2523
2597
  <Tab
2524
2598
  v-if="!obj.remove"
2525
2599
  :key="obj.id"
2526
2600
  :weight="-1 * idx"
2527
2601
  :name="obj.id"
2528
- :label="obj.pool.name || '(Not Named)'"
2602
+ :label="obj.pool.name || t('cluster.machinePool.name.notNamed')"
2529
2603
  :show-header="false"
2530
2604
  :error="!machinePoolValidation[obj.id]"
2531
2605
  >
@@ -2542,6 +2616,8 @@ export default {
2542
2616
  :busy="busy"
2543
2617
  :pool-id="obj.id"
2544
2618
  :pool-create-mode="obj.create"
2619
+ :infrastructure-cluster="infrastructureCluster"
2620
+ :hide-advanced="isUpstreamCAPIProvider"
2545
2621
  @error="handleMachinePoolError"
2546
2622
  @validationChanged="v => machinePoolValidationChanged(obj.id, v)"
2547
2623
  />
@@ -2688,6 +2764,7 @@ export default {
2688
2764
  <Tab
2689
2765
  :name="REGISTRIES_TAB_NAME"
2690
2766
  label-key="cluster.tabs.registry"
2767
+ :error="!registryConfigValid"
2691
2768
  >
2692
2769
  <Registries
2693
2770
  v-if="isActiveTabRegistries"
@@ -2703,6 +2780,7 @@ export default {
2703
2780
  @custom-registry-changed="toggleCustomRegistry"
2704
2781
  @registry-host-changed="handleRegistryHostChanged"
2705
2782
  @registry-secret-changed="handleRegistrySecretChanged"
2783
+ @registry-validation-changed="(val) => registryConfigValid = val"
2706
2784
  />
2707
2785
  </Tab>
2708
2786