@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.5

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 (315) hide show
  1. package/assets/styles/global/_button.scss +1 -1
  2. package/assets/styles/global/_layout.scss +4 -0
  3. package/assets/translations/en-us.yaml +183 -51
  4. package/assets/translations/zh-hans.yaml +1 -7
  5. package/chart/monitoring/ClusterSelector.vue +0 -21
  6. package/chart/monitoring/prometheus/index.vue +6 -3
  7. package/components/ActionDropdownShell.vue +5 -3
  8. package/components/ButtonGroup.vue +26 -1
  9. package/components/CruResource.vue +212 -16
  10. package/components/ExplorerMembers.vue +8 -4
  11. package/components/ExplorerProjectsNamespaces.vue +10 -6
  12. package/components/GrowlManager.vue +4 -0
  13. package/components/MgmtNodeList.vue +184 -0
  14. package/components/PromptRestore.vue +93 -32
  15. package/components/Questions/index.vue +1 -0
  16. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
  17. package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
  18. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
  19. package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
  20. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
  21. package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
  22. package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
  23. package/components/ResourceDetail/index.vue +1 -1
  24. package/components/ResourceList/Masthead.vue +7 -1
  25. package/components/ResourceList/index.vue +82 -1
  26. package/components/ResourceTable.vue +1 -0
  27. package/components/RichTranslation.vue +5 -2
  28. package/components/Setting.vue +1 -0
  29. package/components/SortableTable/index.vue +4 -3
  30. package/components/SubtleLink.vue +31 -6
  31. package/components/Tabbed/Tab.vue +29 -3
  32. package/components/Tabbed/index.vue +25 -3
  33. package/components/TableOfContents/TableOfContents.vue +109 -0
  34. package/components/TableOfContents/composables.ts +258 -0
  35. package/components/Window/ContainerShell.vue +21 -11
  36. package/components/Window/__tests__/ContainerShell.test.ts +107 -37
  37. package/components/Wizard.vue +23 -5
  38. package/components/__tests__/ButtonGroup.test.ts +56 -0
  39. package/components/__tests__/PromptRestore.test.ts +169 -19
  40. package/components/fleet/AppCoChartGrid.vue +401 -0
  41. package/components/fleet/AppCoEmptyState.vue +127 -0
  42. package/components/fleet/AppCoPageHeader.vue +119 -0
  43. package/components/fleet/AppCoVersionSelect.vue +70 -0
  44. package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
  45. package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
  46. package/components/fleet/FleetClusterTargets/index.vue +189 -146
  47. package/components/fleet/FleetIntro.vue +7 -3
  48. package/components/fleet/FleetNoWorkspaces.vue +7 -3
  49. package/components/fleet/FleetSecretSelector.vue +5 -3
  50. package/components/fleet/FleetValuesFrom.vue +8 -2
  51. package/components/fleet/GitRepoAdvancedTab.vue +1 -0
  52. package/components/fleet/GitRepoMetadataTab.vue +5 -0
  53. package/components/fleet/GitRepoTargetTab.vue +0 -2
  54. package/components/fleet/HelmOpAdvancedTab.vue +19 -53
  55. package/components/fleet/HelmOpAppCoConfigTab.vue +597 -0
  56. package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
  57. package/components/fleet/HelmOpMetadataTab.vue +5 -0
  58. package/components/fleet/HelmOpResourcesSection.vue +82 -0
  59. package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
  60. package/components/fleet/HelmOpTargetTab.vue +64 -60
  61. package/components/fleet/HelmOpValuesTab.vue +129 -105
  62. package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
  63. package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
  64. package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
  65. package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
  66. package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
  67. package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
  68. package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
  69. package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
  70. package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
  71. package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
  72. package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
  73. package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
  74. package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
  75. package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
  76. package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
  77. package/components/fleet/dashboard/Empty.vue +8 -4
  78. package/components/fleet/dashboard/ResourceCard.vue +28 -0
  79. package/components/fleet/dashboard/ResourceDetails.vue +28 -0
  80. package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
  81. package/components/form/ArrayList.vue +61 -4
  82. package/components/form/FileSelector.vue +39 -1
  83. package/components/form/KeyValue.vue +23 -2
  84. package/components/form/LabeledSelect.vue +39 -1
  85. package/components/form/Labels.vue +22 -3
  86. package/components/form/NameNsDescription.vue +13 -5
  87. package/components/form/PrivateRegistry.constants.ts +7 -0
  88. package/components/form/PrivateRegistry.vue +253 -18
  89. package/components/form/ResourceTabs/index.vue +1 -0
  90. package/components/form/SelectOrCreateAuthSecret.vue +140 -17
  91. package/components/form/__tests__/FileSelector.test.ts +23 -0
  92. package/components/form/__tests__/NameNsDescription.test.ts +75 -0
  93. package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
  94. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
  95. package/components/formatter/EtcdSnapshotName.vue +73 -0
  96. package/components/formatter/InternalExternalIP.vue +10 -4
  97. package/components/formatter/ServiceTargets.vue +26 -7
  98. package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
  99. package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
  100. package/components/nav/Header.vue +12 -1
  101. package/components/nav/TopLevelMenu.vue +7 -2
  102. package/components/nav/__tests__/Header.test.ts +15 -0
  103. package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
  104. package/components/templates/default.vue +16 -4
  105. package/components/templates/home.vue +9 -4
  106. package/components/templates/plain.vue +9 -4
  107. package/composables/useHelmOpResources.test.ts +56 -0
  108. package/composables/useHelmOpResources.ts +32 -0
  109. package/composables/useStateColor.test.ts +325 -0
  110. package/composables/useStateColor.ts +128 -0
  111. package/config/features.js +1 -0
  112. package/config/home-links.js +1 -1
  113. package/config/labels-annotations.js +3 -0
  114. package/config/product/explorer.js +17 -4
  115. package/config/product/manager.js +8 -0
  116. package/config/router/index.js +16 -0
  117. package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
  118. package/config/router/navigation-guards/authentication.js +10 -4
  119. package/config/router/routes.js +20 -6
  120. package/config/secret.ts +10 -0
  121. package/config/settings.ts +6 -4
  122. package/config/table-headers.js +3 -4
  123. package/config/types.js +16 -0
  124. package/core/plugin-products-base.ts +3 -3
  125. package/core/plugin-types.ts +83 -30
  126. package/core/plugin.ts +3 -0
  127. package/core/types-provisioning.ts +34 -1
  128. package/core/types.ts +15 -2
  129. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
  130. package/detail/__tests__/workload.test.ts +3 -152
  131. package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
  132. package/detail/provisioning.cattle.io.cluster.vue +109 -7
  133. package/detail/workload/index.vue +12 -55
  134. package/dialog/RotateEncryptionKeyDialog.vue +33 -9
  135. package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
  136. package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
  137. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
  138. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +206 -0
  139. package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
  140. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  141. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
  142. package/edit/auth/__tests__/azuread.test.ts +34 -9
  143. package/edit/auth/__tests__/github.test.ts +234 -0
  144. package/edit/auth/__tests__/oidc.test.ts +26 -6
  145. package/edit/auth/__tests__/saml.test.ts +196 -0
  146. package/edit/auth/azuread.vue +128 -95
  147. package/edit/auth/github.vue +72 -13
  148. package/edit/auth/ldap/__tests__/index.test.ts +206 -0
  149. package/edit/auth/ldap/config.vue +8 -0
  150. package/edit/auth/ldap/index.vue +75 -1
  151. package/edit/auth/oidc.vue +119 -73
  152. package/edit/auth/saml.vue +76 -12
  153. package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
  154. package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
  155. package/edit/fleet.cattle.io.gitrepo.vue +70 -16
  156. package/edit/fleet.cattle.io.helmop.vue +542 -141
  157. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  158. package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
  159. package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
  160. package/edit/management.cattle.io.user.vue +5 -2
  161. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
  162. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
  163. package/edit/provisioning.cattle.io.cluster/rke2.vue +89 -11
  164. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
  165. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
  166. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
  167. package/list/group.principal.vue +5 -4
  168. package/list/harvesterhci.io.management.cluster.vue +8 -9
  169. package/list/management.cattle.io.user.vue +12 -9
  170. package/list/provisioning.cattle.io.cluster.vue +16 -10
  171. package/mixins/__tests__/auth-config.test.ts +90 -0
  172. package/mixins/__tests__/chart.test.ts +94 -0
  173. package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
  174. package/mixins/auth-config.js +7 -0
  175. package/mixins/chart.js +11 -2
  176. package/mixins/child-hook.js +12 -6
  177. package/mixins/create-edit-view/impl.js +5 -3
  178. package/mixins/resource-fetch-api-pagination.js +21 -1
  179. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
  180. package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
  181. package/models/__tests__/fleet-application.test.ts +175 -0
  182. package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
  183. package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
  184. package/models/__tests__/management.cattle.io.node.ts +22 -0
  185. package/models/__tests__/namespace.test.ts +36 -0
  186. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +205 -0
  187. package/models/__tests__/secret.test.ts +68 -1
  188. package/models/__tests__/workload.test.ts +401 -26
  189. package/models/catalog.cattle.io.clusterrepo.js +28 -4
  190. package/models/compliance.cattle.io.clusterscan.js +39 -4
  191. package/models/fleet-application.js +4 -0
  192. package/models/fleet.cattle.io.helmop.js +20 -1
  193. package/models/management.cattle.io.cluster.js +39 -5
  194. package/models/management.cattle.io.node.js +44 -3
  195. package/models/namespace.js +1 -1
  196. package/models/pod.js +46 -3
  197. package/models/provisioning.cattle.io.cluster.js +64 -14
  198. package/models/rke.cattle.io.etcdsnapshot.js +17 -9
  199. package/models/secret.js +19 -0
  200. package/models/workload.js +120 -20
  201. package/models/workload.service.js +5 -0
  202. package/package.json +14 -13
  203. package/pages/about.vue +5 -6
  204. package/pages/auth/login.vue +0 -35
  205. package/pages/auth/setup.vue +11 -0
  206. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
  207. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
  208. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
  209. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
  210. package/pages/c/_cluster/apps/charts/chart.vue +2 -1
  211. package/pages/c/_cluster/apps/charts/index.vue +48 -10
  212. package/pages/c/_cluster/apps/charts/install.vue +236 -144
  213. package/pages/c/_cluster/auth/roles/index.vue +5 -4
  214. package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
  215. package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
  216. package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
  217. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
  218. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
  219. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
  220. package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
  221. package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
  222. package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
  223. package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
  224. package/pages/c/_cluster/fleet/application/create.vue +187 -136
  225. package/pages/c/_cluster/fleet/application/index.vue +5 -3
  226. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
  227. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
  228. package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
  229. package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
  230. package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
  231. package/pages/c/_cluster/fleet/index.vue +2 -2
  232. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
  233. package/pages/c/_cluster/uiplugins/index.vue +15 -0
  234. package/pages/fail-whale.vue +16 -11
  235. package/pages/home.vue +16 -46
  236. package/pkg/require-asset.lib.js +25 -0
  237. package/pkg/vue.config.js +7 -0
  238. package/plugins/clean-html.d.ts +9 -0
  239. package/plugins/dashboard-store/__tests__/resource-class.test.ts +177 -0
  240. package/plugins/dashboard-store/getters.js +0 -1
  241. package/plugins/dashboard-store/resource-class.js +114 -19
  242. package/plugins/steve/__tests__/actions.test.ts +212 -0
  243. package/plugins/steve/actions.js +96 -0
  244. package/plugins/steve/steve-pagination-utils.ts +1 -1
  245. package/rancher-components/Accordion/Accordion.vue +53 -9
  246. package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
  247. package/rancher-components/Form/Radio/RadioButton.vue +17 -1
  248. package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
  249. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
  250. package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
  251. package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
  252. package/rancher-components/RcButton/RcButton.test.ts +103 -0
  253. package/rancher-components/RcButton/RcButton.vue +94 -15
  254. package/rancher-components/RcButton/index.ts +1 -1
  255. package/rancher-components/RcButton/types.ts +3 -0
  256. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
  257. package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
  258. package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
  259. package/rancher-components/RcSection/RcSection.vue +28 -3
  260. package/scripts/extension/helm/package/Dockerfile +1 -1
  261. package/scripts/test-plugins-build.sh +2 -1
  262. package/store/__tests__/features.test.ts +131 -0
  263. package/store/__tests__/growl.test.ts +374 -0
  264. package/store/__tests__/modal.test.ts +131 -0
  265. package/store/__tests__/notifications.test.ts +434 -0
  266. package/store/__tests__/slideInPanel.test.ts +88 -0
  267. package/store/__tests__/type-map.utils.test.ts +433 -0
  268. package/store/catalog.js +57 -0
  269. package/store/features.js +4 -0
  270. package/store/plugins.js +7 -4
  271. package/types/components/buttonGroup.ts +5 -0
  272. package/types/shell/index.d.ts +166 -70
  273. package/utils/__tests__/auth.test.ts +273 -0
  274. package/utils/__tests__/computed.test.ts +193 -0
  275. package/utils/__tests__/cspAdaptor.test.ts +163 -0
  276. package/utils/__tests__/dom.test.ts +81 -0
  277. package/utils/__tests__/duration.test.ts +37 -1
  278. package/utils/__tests__/dynamic-importer.test.ts +102 -0
  279. package/utils/__tests__/fleet-appco.test.ts +312 -0
  280. package/utils/__tests__/monitoring.test.ts +130 -0
  281. package/utils/__tests__/object.test.ts +22 -0
  282. package/utils/__tests__/operation-cr.test.ts +34 -0
  283. package/utils/__tests__/platform.test.ts +91 -0
  284. package/utils/__tests__/position.test.ts +237 -0
  285. package/utils/__tests__/provider.test.ts +51 -1
  286. package/utils/__tests__/queue.test.ts +232 -0
  287. package/utils/__tests__/release-notes.test.ts +221 -0
  288. package/utils/__tests__/router.test.js +254 -1
  289. package/utils/__tests__/select.test.ts +208 -0
  290. package/utils/__tests__/time.test.ts +265 -1
  291. package/utils/__tests__/title.test.ts +47 -0
  292. package/utils/__tests__/width.test.ts +53 -0
  293. package/utils/__tests__/window.test.ts +158 -0
  294. package/utils/__tests__/xccdf.test.ts +126 -6
  295. package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
  296. package/utils/crypto/__tests__/index.test.ts +144 -0
  297. package/utils/duration.ts +104 -0
  298. package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
  299. package/utils/dynamic-content/info.ts +2 -1
  300. package/utils/error.js +13 -0
  301. package/utils/fleet-appco.ts +323 -0
  302. package/utils/object.js +22 -2
  303. package/utils/operation-cr.js +19 -0
  304. package/utils/provider.ts +12 -0
  305. package/utils/require-asset.ts +7 -0
  306. package/utils/validators/__tests__/container-images.test.ts +104 -0
  307. package/utils/validators/__tests__/flow-output.test.ts +91 -0
  308. package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
  309. package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
  310. package/utils/validators/__tests__/private-registry.test.ts +27 -15
  311. package/utils/validators/private-registry.ts +15 -4
  312. package/utils/xccdf.ts +39 -42
  313. package/vue.config.js +1 -1
  314. package/pages/support/index.vue +0 -264
  315. package/utils/duration.js +0 -43
@@ -150,6 +150,7 @@ export default {
150
150
  tabbed="multiple"
151
151
  :target-namespace="value.metadata.namespace"
152
152
  :source="selectedNamespaceQuestions"
153
+ :mode="mode"
153
154
  />
154
155
  </Tabbed>
155
156
  </div>
@@ -32,13 +32,14 @@ export default {
32
32
  const t = this.$store.getters['i18n/t'];
33
33
 
34
34
  return {
35
- setting: ALLOWED_SETTINGS[this.value.id],
36
- description: t(`advancedSettings.descriptions.${ this.value.id }`),
37
- editHelp: t(`advancedSettings.editHelp.${ this.value.id }`),
38
- enumOptions: [],
39
- canReset: false,
40
- errors: [],
41
- fvFormRuleSets: [],
35
+ setting: ALLOWED_SETTINGS[this.value.id],
36
+ description: t(`advancedSettings.descriptions.${ this.value.id }`),
37
+ editHelp: t(`advancedSettings.editHelp.${ this.value.id }`),
38
+ enumOptions: [],
39
+ canReset: false,
40
+ errors: [],
41
+ fvFormRuleSets: [],
42
+ customEditComponent: null
42
43
  };
43
44
  },
44
45
 
@@ -60,6 +61,14 @@ export default {
60
61
  if (isServerUrl(this.value.id) && !this.value.default) {
61
62
  this.canReset = false;
62
63
  }
64
+
65
+ let component;
66
+
67
+ try {
68
+ component = require(`@shell/edit/management.cattle.io.setting/${ this.value.id }.vue`).default;
69
+ } catch {}
70
+
71
+ this.customEditComponent = component;
63
72
  },
64
73
 
65
74
  computed: {
@@ -195,8 +204,22 @@ export default {
195
204
  :label="err"
196
205
  data-testid="setting-error-banner"
197
206
  />
198
-
199
- <div class="mt-20">
207
+ <div
208
+ v-if="customEditComponent"
209
+ class="mt-20"
210
+ >
211
+ <component
212
+ :is="customEditComponent"
213
+ :setting-value="value.value"
214
+ :default-value="value.default"
215
+ :rules="fvGetAndReportPathRules('value')"
216
+ @update:setting-value="value.value=$event"
217
+ />
218
+ </div>
219
+ <div
220
+ v-else
221
+ class="mt-20"
222
+ >
200
223
  <div v-if="setting.kind === 'enum'">
201
224
  <LabeledSelect
202
225
  v-model:value="value.value"
@@ -0,0 +1,81 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed, onMounted, toRef } from 'vue';
3
+ import { useStore } from 'vuex';
4
+ import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
5
+ import { SECRET } from '@shell/config/types';
6
+ import { SECRET_TYPES } from '@shell/config/secret';
7
+
8
+ const AUTH_TYPES = [
9
+ SECRET_TYPES.DOCKER_JSON,
10
+ SECRET_TYPES.BASIC,
11
+ SECRET_TYPES.SSH,
12
+ SECRET_TYPES.RKE_AUTH_CONFIG
13
+ ];
14
+
15
+ const props = defineProps<{
16
+ settingValue: Record<string, any>;
17
+ defaultValue?: Record<string, any>;
18
+ rules?: Array<(value: any) => string | undefined>;
19
+ }>();
20
+
21
+ const emit = defineEmits(['update:settingValue']);
22
+
23
+ const store = useStore();
24
+ const settingValue = toRef(props, 'settingValue');
25
+ const defaultValue = toRef(props, 'defaultValue');
26
+ const secrets = ref<any[]>([]);
27
+
28
+ const secretOptions = computed(() => secrets.value
29
+ .filter((s) => AUTH_TYPES.includes(s._type))
30
+ .map((s) => {
31
+ const { dataPreview, subTypeDisplay, metadata } = s;
32
+
33
+ const label = subTypeDisplay && dataPreview ? `${ metadata.name } (${ subTypeDisplay }: ${ dataPreview })` : `${ metadata.name } (${ subTypeDisplay })`;
34
+
35
+ return {
36
+ label,
37
+ value: s.metadata?.name
38
+ };
39
+ })
40
+ );
41
+
42
+ const selectedSecrets = computed({
43
+ get: () => {
44
+ const sValue = settingValue.value || defaultValue.value || '';
45
+
46
+ return sValue.split(',').reduce((all: string[], secret: string) => {
47
+ if (!!secret.trim()) {
48
+ all.push(secret.trim());
49
+ }
50
+
51
+ return all;
52
+ }, []);
53
+ },
54
+ set: (neu: string[]) => {
55
+ const newSettingValue = neu?.length ? neu.join(',') : null;
56
+
57
+ emit('update:settingValue', newSettingValue);
58
+ },
59
+ });
60
+
61
+ onMounted(async() => {
62
+ const res = await store.dispatch('management/findAll', {
63
+ type: SECRET,
64
+ opt: { namespaced: 'cattle-system' },
65
+ });
66
+
67
+ secrets.value = Array.isArray(res) ? res : [];
68
+ });
69
+
70
+ </script>
71
+
72
+ <template>
73
+ <LabeledSelect
74
+ id="pull-secrets"
75
+ v-model:value="selectedSecrets"
76
+ label="Image Pull Secrets"
77
+ :options="secretOptions"
78
+ :rules="rules"
79
+ :multiple="true"
80
+ />
81
+ </template>
@@ -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>
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import Loading from '@shell/components/Loading';
3
3
  import LabeledSelect from '@shell/components/form/LabeledSelect';
4
- import { NORMAN, DEFAULT_WORKSPACE } from '@shell/config/types';
4
+ import { NORMAN } from '@shell/config/types';
5
5
  import CreateEditView from '@shell/mixins/create-edit-view';
6
6
  import CruResource from '@shell/components/CruResource';
7
7
  import NameNsDescription from '@shell/components/form/NameNsDescription';
@@ -50,11 +50,8 @@ export default {
50
50
  const field = this.$store.getters['plugins/credentialFieldForDriver'](this.driverName);
51
51
 
52
52
  this.newCredential = await this.$store.dispatch('rancher/create', {
53
- type: NORMAN.CLOUD_CREDENTIAL,
54
- metadata: {
55
- namespace: DEFAULT_WORKSPACE,
56
- annotations: { [CAPI.CREDENTIAL_DRIVER]: this.driverName }
57
- },
53
+ type: NORMAN.CLOUD_CREDENTIAL,
54
+ annotations: { [CAPI.CREDENTIAL_DRIVER]: this.driverName },
58
55
  [`${ field }credentialConfig`]: {}
59
56
  });
60
57
 
@@ -216,12 +213,6 @@ export default {
216
213
  }
217
214
  }
218
215
 
219
- if ( this.newCredential.metadata.name ) {
220
- delete this.newCredential.metadata.generateName;
221
- } else {
222
- this.newCredential.metadata.generateName = 'cloud-credential-';
223
- }
224
-
225
216
  try {
226
217
  const res = await this.newCredential.save();
227
218
 
@@ -806,4 +806,22 @@ describe('component: rke2', () => {
806
806
  expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(INGRESS_NGINX);
807
807
  });
808
808
  });
809
+
810
+ describe('computed: canEditAsYaml', () => {
811
+ it('should return false when isUpstreamCAPIProvider is true', () => {
812
+ const vm = { isUpstreamCAPIProvider: true } as any;
813
+
814
+ const canEditAsYaml = rke2.computed!.canEditAsYaml.call(vm);
815
+
816
+ expect(canEditAsYaml).toBe(false);
817
+ });
818
+
819
+ it('should return true when isUpstreamCAPIProvider is false', () => {
820
+ const vm = { isUpstreamCAPIProvider: false } as any;
821
+
822
+ const canEditAsYaml = rke2.computed!.canEditAsYaml.call(vm);
823
+
824
+ expect(canEditAsYaml).toBe(true);
825
+ });
826
+ });
809
827
  });
@@ -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
 
@@ -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
@@ -300,6 +301,7 @@ export default {
300
301
  basicsValid: true,
301
302
  registryConfigValid: true,
302
303
  originalIngressController: this.value.spec.rkeConfig.machineGlobalConfig?.[INGRESS_CONTROLLER] || INGRESS_NONE,
304
+ infrastructureCluster: null,
303
305
  };
304
306
  },
305
307
 
@@ -329,6 +331,14 @@ export default {
329
331
  return this.provider === ELEMENTAL_CLUSTER_PROVIDER || this.value?.machineProvider?.toLowerCase() === KIND.MACHINE_INV_SELECTOR_TEMPLATES.toLowerCase();
330
332
  },
331
333
 
334
+ isUpstreamCAPIProvider() {
335
+ if (this.extensionProvider?.isUpstreamCAPIProvider !== undefined) {
336
+ return !!this.extensionProvider.isUpstreamCAPIProvider;
337
+ }
338
+
339
+ return false;
340
+ },
341
+
332
342
  chartValues() {
333
343
  return this.value.spec.rkeConfig.chartValues;
334
344
  },
@@ -548,7 +558,7 @@ export default {
548
558
  getters: this.$store.getters,
549
559
  axios: this.$store.$axios,
550
560
  $extension: this.$store.app.$extension,
551
- $t: this.t,
561
+ t: (...args) => this.t.apply(this, args),
552
562
  isCreate: this.isCreate
553
563
  });
554
564
  }
@@ -826,6 +836,10 @@ export default {
826
836
  return null;
827
837
  },
828
838
 
839
+ extensionInfrastructureSection() {
840
+ return this.extensionProvider?.extensionInfrastructureSection || null;
841
+ },
842
+
829
843
  showForm() {
830
844
  return !!this.credentialId || !this.needCredential;
831
845
  },
@@ -879,7 +893,9 @@ export default {
879
893
 
880
894
  const hasAddonConfigErrors = Object.values(this.addonConfigValidation).filter((v) => v === false).length > 0;
881
895
 
882
- return validRequiredPools && base && !hasAddonConfigErrors && !this.stackPreferenceError;
896
+ const hasInfrastructureClusterError = this.isUpstreamCAPIProvider ? !this.infrastructureClusterValid : false;
897
+
898
+ return validRequiredPools && base && !hasAddonConfigErrors && !hasInfrastructureClusterError && !this.stackPreferenceError;
883
899
  },
884
900
 
885
901
  currentCluster() {
@@ -903,6 +919,10 @@ export default {
903
919
  return this.needCredential && !this.credentialId;
904
920
  },
905
921
 
922
+ canEditAsYaml() {
923
+ return !(this.isUpstreamCAPIProvider);
924
+ },
925
+
906
926
  overallFormValidationPassed() {
907
927
  return this.validationPassed &&
908
928
  this.fvFormIsValid &&
@@ -1015,6 +1035,11 @@ export default {
1015
1035
  },
1016
1036
 
1017
1037
  created() {
1038
+ // Hooks to be run when cluster is getting initialized
1039
+ if (this.extensionProvider?.registerInitHooks) {
1040
+ this.extensionProvider.registerInitHooks(this.registerHook.bind(this, INIT_HOOKS), this.value);
1041
+ }
1042
+ // Other hooks to be run before/after saving the cluster
1018
1043
  this.registerBeforeHook(this.showIpv6Warning, 'show-ipv6-warning', 1);
1019
1044
  this.registerBeforeHook(this.saveMachinePools, 'save-machine-pools', 2);
1020
1045
  this.registerBeforeHook(this.setRegistryConfig, 'set-registry-config');
@@ -1033,6 +1058,21 @@ export default {
1033
1058
  methods: {
1034
1059
  set,
1035
1060
 
1061
+ updateExtensionInfrastructureSection(neu) {
1062
+ if (!neu || typeof neu !== 'object') {
1063
+ return;
1064
+ }
1065
+
1066
+ if (!this.infrastructureCluster || typeof this.infrastructureCluster !== 'object') {
1067
+ this.infrastructureCluster = neu;
1068
+
1069
+ return;
1070
+ }
1071
+
1072
+ // Preserve the original resource model instance while applying extension updates.
1073
+ mergeWithReplace(this.infrastructureCluster, neu, { mutateOriginal: true });
1074
+ },
1075
+
1036
1076
  async handleVsphereCpiSecret() {
1037
1077
  return VsphereUtils.handleVsphereCpiSecret(this);
1038
1078
  },
@@ -1056,8 +1096,8 @@ export default {
1056
1096
  if (!this.value.spec.machineSelectorConfig.find((x) => !x.machineLabelSelector)) {
1057
1097
  this.value.spec.machineSelectorConfig.unshift({ config: {} });
1058
1098
  }
1059
-
1060
- if (this.value.spec.cloudCredentialSecretName) {
1099
+ // TODO handle upstream capi once credentials part is clear
1100
+ if (this.value.spec.cloudCredentialSecretName ) {
1061
1101
  await this.$store.dispatch('rancher/findAll', { type: NORMAN.CLOUD_CREDENTIAL });
1062
1102
  this.credentialId = `${ this.value.spec.cloudCredentialSecretName }`;
1063
1103
  }
@@ -1082,7 +1122,6 @@ export default {
1082
1122
 
1083
1123
  this.rkeConfig.etcd.disableSnapshots = disableSnapshots;
1084
1124
  }
1085
-
1086
1125
  // Namespaces if required - this is mainly for custom provisioners via extensions that want
1087
1126
  // to allow creating their resources in a different namespace
1088
1127
  if (this.needsNamespace) {
@@ -1106,6 +1145,9 @@ export default {
1106
1145
  if ( isEmpty(this.value?.spec?.localClusterAuthEndpoint) ) {
1107
1146
  set(this.value, 'spec.localClusterAuthEndpoint', { enabled: false });
1108
1147
  }
1148
+
1149
+ await this.applyHooks(INIT_HOOKS, this.value);
1150
+ this.localValue = this.value;
1109
1151
  },
1110
1152
 
1111
1153
  /**
@@ -1281,6 +1323,10 @@ export default {
1281
1323
 
1282
1324
  if (this.isElementalCluster) {
1283
1325
  type = ELEMENTAL_SCHEMA_IDS.MACHINE_INV_SELECTOR_TEMPLATES;
1326
+ } else if (this.isUpstreamCAPIProvider && pool.machineConfigRef?.apiVersion) {
1327
+ const [group] = (pool.machineConfigRef.apiVersion || '').split('/');
1328
+
1329
+ type = `${ group }.${ pool.machineConfigRef.kind.toLowerCase() }`;
1284
1330
  } else {
1285
1331
  type = `${ CAPI.MACHINE_CONFIG_GROUP }.${ pool.machineConfigRef.kind.toLowerCase() }`;
1286
1332
  }
@@ -1386,10 +1432,20 @@ export default {
1386
1432
  pool.pool.machineOS = 'linux';
1387
1433
  }
1388
1434
 
1389
- if (this.isElementalCluster) {
1435
+ if (this.isElementalCluster && this.machineConfigSchema?.attributes) {
1390
1436
  pool.pool.machineConfigRef.apiVersion = `${ this.machineConfigSchema.attributes.group }/${ this.machineConfigSchema.attributes.version }`;
1391
1437
  }
1392
1438
 
1439
+ // Upstream CAPI MachineTemplate resources are referenced by full apiVersion so that
1440
+ // initMachinePools can resolve the correct management store type on subsequent loads.
1441
+ if (this.isUpstreamCAPIProvider && this.machineConfigSchema?.attributes) {
1442
+ const { group, version } = this.machineConfigSchema.attributes;
1443
+
1444
+ if (group && version) {
1445
+ pool.pool.machineConfigRef.apiVersion = `${ group }/${ version }`;
1446
+ }
1447
+ }
1448
+
1393
1449
  this.machinePools.push(pool);
1394
1450
 
1395
1451
  this.$nextTick(() => {
@@ -1538,6 +1594,10 @@ export default {
1538
1594
  },
1539
1595
 
1540
1596
  async cleanupMachinePools() {
1597
+ // Allow the extension provider to handle its own resource cleanup
1598
+ if (this.extensionProvider?.cleanupMachinePools) {
1599
+ return await this.extensionProvider.cleanupMachinePools(this.machinePools);
1600
+ }
1541
1601
  for (const entry of this.machinePools) {
1542
1602
  if (entry.remove && entry.config) {
1543
1603
  try {
@@ -2349,7 +2409,8 @@ export default {
2349
2409
  if (this.errors) {
2350
2410
  clear(this.errors);
2351
2411
  }
2352
- if (this.value.cloudProvider === 'aws') {
2412
+
2413
+ if ( this.value.cloudProvider === 'aws') {
2353
2414
  const missingProfileName = this.machinePools.some((mp) => !mp.config.iamInstanceProfile);
2354
2415
 
2355
2416
  if (missingProfileName) {
@@ -2358,7 +2419,7 @@ export default {
2358
2419
  }
2359
2420
 
2360
2421
  for (const [index] of this.machinePools.entries()) { // validator machine config
2361
- if (typeof this.$refs.pool[index]?.test === 'function') {
2422
+ if (typeof this.$refs.pool?.[index]?.test === 'function') {
2362
2423
  try {
2363
2424
  const res = await this.$refs.pool[index].test();
2364
2425
 
@@ -2401,6 +2462,7 @@ export default {
2401
2462
  :done-route="doneRoute"
2402
2463
  :apply-hooks="applyHooks"
2403
2464
  :generate-yaml="generateYaml"
2465
+ :can-yaml="canEditAsYaml"
2404
2466
  class="rke2"
2405
2467
  component-testid="rke2-custom-create"
2406
2468
  @done="done"
@@ -2475,7 +2537,22 @@ export default {
2475
2537
  >
2476
2538
  {{ appsOSWarning }}
2477
2539
  </Banner>
2478
-
2540
+ <div class="span-12">
2541
+ <component
2542
+ :is="extensionInfrastructureSection"
2543
+ v-if="extensionInfrastructureSection"
2544
+ :value="infrastructureCluster"
2545
+ :mode="mode"
2546
+ :provider="provider"
2547
+ :credential-id="credentialId"
2548
+ :provisioning-cluster="value"
2549
+ data-testid="extension-top-section"
2550
+ class="span-12"
2551
+ @update:value="updateExtensionInfrastructureSection"
2552
+ @error="e => errors.push(e)"
2553
+ @validationChanged="(val) => infrastructureClusterValid = val"
2554
+ />
2555
+ </div>
2479
2556
  <!-- Pools Extras -->
2480
2557
  <template v-if="hasMachinePools">
2481
2558
  <div class="clearfix">
@@ -2509,7 +2586,6 @@ export default {
2509
2586
  />
2510
2587
  </div>
2511
2588
  </div>
2512
-
2513
2589
  <!-- Extra Tabs for Machine Pool -->
2514
2590
  <Tabbed
2515
2591
  ref="pools"
@@ -2544,6 +2620,8 @@ export default {
2544
2620
  :busy="busy"
2545
2621
  :pool-id="obj.id"
2546
2622
  :pool-create-mode="obj.create"
2623
+ :infrastructure-cluster="infrastructureCluster"
2624
+ :hide-advanced="isUpstreamCAPIProvider"
2547
2625
  @error="handleMachinePoolError"
2548
2626
  @validationChanged="v => machinePoolValidationChanged(obj.id, v)"
2549
2627
  />
@@ -41,6 +41,11 @@ export default {
41
41
  default: () => ({})
42
42
  },
43
43
 
44
+ infrastructureCluster: {
45
+ type: Object,
46
+ default: () => ({})
47
+ },
48
+
44
49
  // no credentials are required for elemental machine pools
45
50
  credentialId: {
46
51
  type: String,
@@ -86,6 +91,10 @@ export default {
86
91
  poolCreateMode: {
87
92
  type: Boolean,
88
93
  required: true,
94
+ },
95
+ hideAdvanced: {
96
+ type: Boolean,
97
+ default: false
89
98
  }
90
99
  },
91
100
 
@@ -368,6 +377,7 @@ export default {
368
377
  v-model:is-ipv6="value.isIpv6"
369
378
  v-model:is-dualStack="value.isDualStack"
370
379
  :cluster="cluster"
380
+ :infrastructure-cluster="infrastructureCluster"
371
381
  :uuid="uuid"
372
382
  :mode="mode"
373
383
  :value="value.config"
@@ -396,6 +406,7 @@ export default {
396
406
  />
397
407
 
398
408
  <AdvancedSection
409
+ v-if="!hideAdvanced"
399
410
  ref="advanced"
400
411
  :mode="mode"
401
412
  class="advanced"
@@ -40,7 +40,6 @@ export default {
40
40
  type: Function,
41
41
  required: true,
42
42
  },
43
-
44
43
  },
45
44
 
46
45
  computed: {
@@ -1,8 +1,6 @@
1
1
  <script>
2
- import { LabeledInput } from '@components/Form/LabeledInput';
3
2
  import { Banner } from '@components/Banner';
4
- import { Checkbox } from '@components/Form/Checkbox';
5
- import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthSecret';
3
+ import PrivateRegistry from '@shell/components/form/PrivateRegistry.vue';
6
4
  import AdvancedSection from '@shell/components/AdvancedSection.vue';
7
5
  import RegistryConfigs from '@shell/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs';
8
6
  import RegistryMirrors from '@shell/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryMirrors';
@@ -10,10 +8,8 @@ import RegistryMirrors from '@shell/edit/provisioning.cattle.io.cluster/tabs/reg
10
8
  export default {
11
9
  emits: ['custom-registry-changed', 'registry-host-changed', 'registry-secret-changed', 'input', 'update-configs-changed', 'registry-validation-changed'],
12
10
  components: {
13
- LabeledInput,
14
11
  Banner,
15
- Checkbox,
16
- SelectOrCreateAuthSecret,
12
+ PrivateRegistry,
17
13
  AdvancedSection,
18
14
  RegistryConfigs,
19
15
  RegistryMirrors
@@ -65,55 +61,18 @@ export default {
65
61
  <div class="row">
66
62
  <h3>{{ t('cluster.privateRegistry.label') }}</h3>
67
63
  </div>
68
- <div class="row">
69
- <div class="col span-12">
70
- <Banner
71
- :closable="false"
72
- class="cluster-tools-tip"
73
- color="info"
74
- label-key="cluster.privateRegistry.description"
75
- />
76
- </div>
77
- </div>
78
- <div class="row">
79
- <Checkbox
80
- :value="showCustomRegistryInput"
81
- :mode="mode"
82
- :label="t('cluster.privateRegistry.label')"
83
- data-testid="registries-enable-checkbox"
84
- @update:value="$emit('custom-registry-changed', $event)"
85
- />
86
- </div>
87
- <div
88
- v-if="showCustomRegistryInput"
89
- class="row mt-20"
90
- >
91
- <div class="col span-6">
92
- <LabeledInput
93
- :value="registryHost"
94
- :mode="mode"
95
- label-key="catalog.chart.registry.custom.inputLabel"
96
- placeholder-key="catalog.chart.registry.custom.placeholder"
97
- :min-height="30"
98
- data-testid="registry-host-input"
99
- @update:value="$emit('registry-host-changed', $event)"
100
- />
101
- <SelectOrCreateAuthSecret
102
- :value="registrySecret"
103
- :register-before-hook="registerBeforeHook"
104
- :hook-priority="1"
105
- :mode="mode"
106
- in-store="management"
107
- :allow-ssh="false"
108
- :allow-rke="true"
109
- :vertical="true"
110
- :namespace="value.metadata.namespace"
111
- generate-name="registryconfig-auth-"
112
- :cache-secrets="true"
113
- @update:value="$emit('registry-secret-changed', $event)"
114
- />
115
- </div>
116
- </div>
64
+ <PrivateRegistry
65
+ :value="registryHost"
66
+ :enabled="showCustomRegistryInput"
67
+ :mode="mode"
68
+ :pull-secret="registrySecret"
69
+ :register-before-hook="registerBeforeHook"
70
+ checkbox-test-id="registries-enable-checkbox"
71
+ input-test-id="registry-host-input"
72
+ @update:value="$emit('registry-host-changed', $event)"
73
+ @update:enabled="$emit('custom-registry-changed', $event)"
74
+ @update:pull-secret="$emit('registry-secret-changed', $event)"
75
+ />
117
76
  <div
118
77
  class="row"
119
78
  >
@@ -9,10 +9,11 @@ import { NAME } from '@shell/config/product/auth';
9
9
  import { MODE, _EDIT } from '@shell/config/query-params';
10
10
  import { mapState } from 'vuex';
11
11
  import { BLANK_CLUSTER } from '@shell/store/store-types.js';
12
+ import { RcButton } from '@components/RcButton';
12
13
 
13
14
  export default {
14
15
  components: {
15
- AsyncButton, ResourceTable, Masthead, Loading
16
+ AsyncButton, ResourceTable, Masthead, Loading, RcButton
16
17
  },
17
18
  props: {
18
19
  resource: {
@@ -130,13 +131,13 @@ export default {
130
131
  :class="{'mr-5': canCreateGlobalRoleBinding}"
131
132
  @click="refreshGroupMemberships"
132
133
  />
133
- <router-link
134
+ <rc-button
134
135
  v-if="canCreateGlobalRoleBinding"
136
+ size="large"
135
137
  :to="assignLocation"
136
- class="btn role-primary"
137
138
  >
138
139
  {{ t("authGroups.actions.assignRoles") }}
139
- </router-link>
140
+ </rc-button>
140
141
  </template>
141
142
  </Masthead>
142
143