@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
@@ -6,7 +6,9 @@ import SortableTable from '@shell/components/SortableTable';
6
6
  import CopyCode from '@shell/components/CopyCode';
7
7
  import Tab from '@shell/components/Tabbed/Tab';
8
8
  import { allHash } from '@shell/utils/promise';
9
- import { CAPI, MANAGEMENT, NORMAN, SNAPSHOT } from '@shell/config/types';
9
+ import {
10
+ CAPI, MANAGEMENT, NORMAN, SNAPSHOT, OPERATION
11
+ } from '@shell/config/types';
10
12
  import {
11
13
  STATE, NAME as NAME_COL, AGE, INTERNAL_EXTERNAL_IP, STATE_NORMAN, ROLES, MACHINE_NODE_OS, MANAGEMENT_NODE_OS, NAME,
12
14
  } from '@shell/config/table-headers';
@@ -96,7 +98,18 @@ export default {
96
98
  await this.value.waitForProvisioner();
97
99
 
98
100
  // Support for the 'provisioner' extension
99
- const extClass = this.$extension.getDynamic('provisioner', this.value.machineProvider);
101
+ let extClass = this.$extension.getDynamic('provisioner', this.value.machineProvider);
102
+ let provider = this.value.machineProvider;
103
+
104
+ if (!extClass) {
105
+ extClass = this.$extension.getDynamic('provisioner', this.value.provisioner.toLowerCase());
106
+ provider = this.value.provisioner.toLowerCase();
107
+ }
108
+
109
+ if (!extClass && this.value.isImported) {
110
+ extClass = this.$extension.getDynamic('provisioner', 'imported');
111
+ provider = 'imported';
112
+ }
100
113
 
101
114
  if (extClass) {
102
115
  this.extProvider = new extClass({
@@ -111,7 +124,7 @@ export default {
111
124
  ...this.extDetailTabs,
112
125
  ...this.extProvider.detailTabs
113
126
  };
114
- this.extCustomParams = { provider: this.value.machineProvider };
127
+ this.extCustomParams = { provider };
115
128
  }
116
129
 
117
130
  // Support for a model extension
@@ -120,7 +133,7 @@ export default {
120
133
  ...this.extDetailTabs,
121
134
  ...this.value.customProvisionerHelper.detailTabs
122
135
  };
123
- this.extCustomParams = { provider: this.value.machineProvider };
136
+ this.extCustomParams = { provider };
124
137
  }
125
138
 
126
139
  const schema = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
@@ -138,6 +151,21 @@ export default {
138
151
  fetchOne.snapshots = this.$store.dispatch('management/findAll', { type: SNAPSHOT });
139
152
  }
140
153
 
154
+ // Fetch operation CRDs for clusters with day 2 ops enabled
155
+ if ( this.value.isImportedWithDayTwoOps ) {
156
+ const operationTypes = [
157
+ OPERATION.ETCD_SNAPSHOT,
158
+ OPERATION.ETCD_SNAPSHOT_RESTORE,
159
+ OPERATION.ENCRYPTION_KEY_ROTATE,
160
+ ];
161
+
162
+ for (const opType of operationTypes) {
163
+ if (this.$store.getters['management/canList'](opType)) {
164
+ fetchOne[`operations_${ opType }`] = this.$store.dispatch('management/findAll', { type: opType });
165
+ }
166
+ }
167
+ }
168
+
141
169
  if ( this.value.isImported || this.value.isCustom || this.value.isHostedKubernetesProvider ) {
142
170
  fetchOne.clusterToken = this.value.getOrCreateToken();
143
171
  }
@@ -281,6 +309,7 @@ export default {
281
309
  registration: true, // in this component
282
310
  snapshots: true, // in this component
283
311
  autoscaler: true, // in this component
312
+ operations: true, // in this component
284
313
  related: true, // in ResourceTabs
285
314
  events: true, // in ResourceTabs
286
315
  conditions: true, // in ResourceTabs
@@ -402,8 +431,23 @@ export default {
402
431
 
403
432
  const templateNamePrefix = `${ pool.metadata.name }-`;
404
433
 
434
+ // The MachineDeployment still exists for empty pools. The
435
+ // infrastructureRef points to the template that matches the current
436
+ // config. Fallback to the prefix-match to return an arbitrary template
437
+ // when multiple exist
438
+ const machineDeployment = this.allMachineDeployments.find(
439
+ (d) => d.metadata.name === pool.metadata.name && d.metadata.namespace === pool.metadata.namespace
440
+ );
441
+ const activeTemplateName = machineDeployment?.spec?.template?.spec?.infrastructureRef?.name;
442
+
405
443
  // All of these properties are needed to ensure the pool displays correctly and that we can scale up and down
406
- pool._template = this.machineTemplates.find((t) => t.metadata.name.startsWith(templateNamePrefix));
444
+ pool._template = this.machineTemplates.find((t) => {
445
+ if (activeTemplateName) {
446
+ return t.metadata.name === activeTemplateName;
447
+ }
448
+
449
+ return t.metadata.name.startsWith(templateNamePrefix);
450
+ });
407
451
  pool._cluster = this.value;
408
452
  pool._clusterSpec = mp;
409
453
 
@@ -451,13 +495,54 @@ export default {
451
495
  showSnapshots() {
452
496
  if (this.value.isRke1) {
453
497
  return false;
454
- } else if (this.value.isRke2) {
498
+ } else if (this.value.isRke2 || (this.value.isImported && this.value.isDayTwoOpsEnabled)) {
455
499
  return this.$store.getters['management/canList'](SNAPSHOT) && this.extDetailTabs.snapshots;
456
500
  }
457
501
 
458
502
  return false;
459
503
  },
460
504
 
505
+ showOperations() {
506
+ return this.value.isImportedWithDayTwoOps && this.extDetailTabs.operations;
507
+ },
508
+
509
+ clusterOperations() {
510
+ if (!this.value.isImportedWithDayTwoOps) {
511
+ return [];
512
+ }
513
+
514
+ const mgmtId = this.value.mgmt?.id;
515
+ const operationTypes = [
516
+ OPERATION.ETCD_SNAPSHOT,
517
+ OPERATION.ETCD_SNAPSHOT_RESTORE,
518
+ OPERATION.ENCRYPTION_KEY_ROTATE,
519
+ ];
520
+
521
+ const allOps = [];
522
+
523
+ for (const opType of operationTypes) {
524
+ const resources = this.$store.getters['management/all'](opType) || [];
525
+
526
+ allOps.push(...resources.filter((op) => op.spec?.clusterRef?.name === mgmtId));
527
+ }
528
+
529
+ return allOps;
530
+ },
531
+
532
+ operationHeaders() {
533
+ return [
534
+ STATE,
535
+ NAME,
536
+ {
537
+ name: 'type',
538
+ labelKey: 'tableHeaders.type',
539
+ value: 'type',
540
+ sort: 'type',
541
+ },
542
+ AGE,
543
+ ];
544
+ },
545
+
461
546
  isRke1() {
462
547
  return this.value.isRke1;
463
548
  },
@@ -540,7 +625,10 @@ export default {
540
625
  {
541
626
  ...STATE_NORMAN, value: 'snapshotFile.status', formatterOpts: { arbitrary: true }
542
627
  },
543
- NAME,
628
+ {
629
+ ...NAME,
630
+ formatter: 'EtcdSnapshotName',
631
+ },
544
632
  {
545
633
  name: 'size',
546
634
  labelKey: 'tableHeaders.size',
@@ -1124,6 +1212,20 @@ export default {
1124
1212
  </template>
1125
1213
  </SortableTable>
1126
1214
  </Tab>
1215
+ <Tab
1216
+ v-if="showOperations"
1217
+ name="operations"
1218
+ :label="t('cluster.tabs.operations')"
1219
+ :weight="0"
1220
+ >
1221
+ <SortableTable
1222
+ :headers="operationHeaders"
1223
+ default-sort-by="age"
1224
+ :table-actions="false"
1225
+ :rows="clusterOperations"
1226
+ :search="false"
1227
+ />
1228
+ </Tab>
1127
1229
  <AutoscalerTab
1128
1230
  v-if="showAutoScalerTab"
1129
1231
  :value="value"
@@ -36,7 +36,8 @@ export default {
36
36
  nodes: fetchNodesForServiceTargets({
37
37
  $store: this.$store,
38
38
  inStore: this.$store.getters['currentStore']()
39
- })
39
+ }),
40
+ summaries: this.value.fetchSummaries()
40
41
  };
41
42
 
42
43
  if (this.podSchema) {
@@ -71,7 +72,6 @@ export default {
71
72
  this.showProjectMetrics = await allDashboardsExist(this.$store, this.currentCluster.id, [this.WORKLOAD_PROJECT_METRICS_DETAIL_URL, this.WORKLOAD_PROJECT_METRICS_SUMMARY_URL], 'cluster', projectId);
72
73
  }
73
74
  }
74
- this.findMatchingIngresses();
75
75
  },
76
76
 
77
77
  async unmounted() {
@@ -82,8 +82,6 @@ export default {
82
82
 
83
83
  data() {
84
84
  return {
85
- allIngresses: [],
86
- matchingIngresses: [],
87
85
  WORKLOAD_METRICS_DETAIL_URL,
88
86
  WORKLOAD_METRICS_SUMMARY_URL,
89
87
  POD_PROJECT_METRICS_DETAIL_URL: '',
@@ -124,6 +122,10 @@ export default {
124
122
  return this.$store.getters['cluster/schemaFor'](SERVICE);
125
123
  },
126
124
 
125
+ relatedServices() {
126
+ return this.value.relatedServices;
127
+ },
128
+
127
129
  podTemplateSpec() {
128
130
  if ( this.value.type === WORKLOAD_TYPES.CRON_JOB ) {
129
131
  return this.value.spec.jobTemplate.spec.template.spec;
@@ -208,51 +210,6 @@ export default {
208
210
  }
209
211
  },
210
212
 
211
- methods: {
212
- findMatchingIngresses() {
213
- if (!this.ingressSchema) {
214
- return [];
215
- }
216
-
217
- // Find Ingresses that forward traffic to Services
218
- // that select this workload.
219
- const matchingIngresses = this.allIngresses.filter((ingress) => {
220
- try {
221
- const rules = ingress.spec.rules;
222
-
223
- if (!rules || !Array.isArray(rules)) return false;
224
-
225
- for (let i = 0; i < rules.length; i++) {
226
- const paths = rules[i]?.http?.paths;
227
-
228
- if (!paths || !Array.isArray(paths)) continue;
229
- // For each Ingress, check if any Services that match
230
- // this workload are also target backends for the Ingress.
231
- for (let j = 0; j < paths.length; j++) {
232
- const pathData = paths[j];
233
- const targetServiceName = pathData?.backend?.service?.name;
234
-
235
- if (!targetServiceName) continue;
236
-
237
- for (let k = 0; k < this.value.relatedServices.length; k++) {
238
- const service = this.value.relatedServices[k];
239
- const matchingServiceName = service?.metadata?.name;
240
-
241
- if (ingress.metadata?.namespace === this.value.metadata?.namespace && matchingServiceName === targetServiceName) {
242
- return true;
243
- }
244
- }
245
- }
246
- }
247
- } catch (err) {
248
- return false;
249
- }
250
- });
251
-
252
- this.matchingIngresses = matchingIngresses;
253
- }
254
- },
255
-
256
213
  watch: {
257
214
  async 'value.jobRelationships.length'(neu, old) {
258
215
  // If there are MORE jobs ensure we go out and fetch them (changes and removals are tracked by watches)
@@ -348,7 +305,7 @@ export default {
348
305
  {{ t('workload.detail.cannotViewServices') }}
349
306
  </p>
350
307
  <p
351
- v-else-if="value.relatedServices.length === 0"
308
+ v-else-if="relatedServices.length === 0"
352
309
  class="caption"
353
310
  >
354
311
  {{ t('workload.detail.cannotFindServices') }}
@@ -360,8 +317,8 @@ export default {
360
317
  {{ t('workload.detail.serviceListCaption') }}
361
318
  </p>
362
319
  <ResourceTable
363
- v-if="serviceSchema && value.relatedServices.length > 0"
364
- :rows="value.relatedServices"
320
+ v-if="serviceSchema && relatedServices.length > 0"
321
+ :rows="relatedServices"
365
322
  :headers="serviceHeaders"
366
323
  key-field="id"
367
324
  :schema="serviceSchema"
@@ -390,7 +347,7 @@ export default {
390
347
  {{ t('workload.detail.cannotViewIngresses') }}
391
348
  </p>
392
349
  <p
393
- v-else-if="matchingIngresses.length === 0"
350
+ v-else-if="value.matchingIngresses.length === 0"
394
351
  class="caption"
395
352
  >
396
353
  {{ t('workload.detail.cannotFindIngresses') }}
@@ -402,8 +359,8 @@ export default {
402
359
  {{ t('workload.detail.ingressListCaption') }}
403
360
  </p>
404
361
  <ResourceTable
405
- v-if="ingressSchema && matchingIngresses.length > 0"
406
- :rows="matchingIngresses"
362
+ v-if="ingressSchema && value.matchingIngresses.length > 0"
363
+ :rows="value.matchingIngresses"
407
364
  :headers="ingressHeaders"
408
365
  key-field="id"
409
366
  :schema="ingressSchema"
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { SNAPSHOT } from '@shell/config/types';
2
+ import { SNAPSHOT, OPERATION } from '@shell/config/types';
3
3
  import AsyncButton from '@shell/components/AsyncButton';
4
4
  import { Card } from '@components/Card';
5
5
  import { Banner } from '@components/Banner';
@@ -10,7 +10,7 @@ import day from 'dayjs';
10
10
  import { escapeHtml } from '@shell/utils/string';
11
11
  import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
12
12
  import { set } from '@shell/utils/object';
13
-
13
+ import { createOperationCR } from '@shell/utils/operation-cr';
14
14
  export default {
15
15
  emits: ['close'],
16
16
 
@@ -66,6 +66,10 @@ export default {
66
66
  async getEtcdBackups() {
67
67
  let etcdBackups = await this.$store.dispatch('management/findAll', { type: SNAPSHOT });
68
68
 
69
+ if (this.cluster.isImportedWithDayTwoOps) {
70
+ return etcdBackups
71
+ .filter((backup) => backup.metadata.namespace === this.cluster.mgmt?.id && backup.spec?.clusterName === this.cluster.mgmt?.metadata?.name );
72
+ }
69
73
  etcdBackups = etcdBackups.filter((backup) => backup.clusterId === this.cluster.id);
70
74
 
71
75
  return etcdBackups;
@@ -82,12 +86,32 @@ export default {
82
86
 
83
87
  async apply(buttonDone) {
84
88
  try {
85
- const currentGeneration = this.cluster.spec?.rkeConfig?.rotateEncryptionKeys?.generation || 0;
86
-
87
- // To rotate the encryption keys, increment
88
- // rkeConfig.rotateEncyrptionKeys.generation in the YAML.
89
- set(this.cluster, 'spec.rkeConfig.rotateEncryptionKeys.generation', currentGeneration + 1);
90
- await this.cluster.save();
89
+ const isImportedWithDayTwoOps = this.cluster?.isImportedWithDayTwoOps || this.cluster?.mgmt?.isDayTwoOpsEnabled;
90
+
91
+ if (isImportedWithDayTwoOps) {
92
+ if (!isImportedWithDayTwoOps) {
93
+ throw new Error(this.t('promptRotateEncryptionKey.error.unableToResolveTargetCluster'));
94
+ }
95
+ // For imported clusters with day 2 ops, create an encryption key rotation operation CR
96
+ const namespace = this.cluster.mgmt?.id;
97
+ const safePrefix = this.cluster.mgmt?.id;
98
+ const spec = {
99
+ clusterRef: {
100
+ apiVersion: 'management.cattle.io/v3',
101
+ kind: 'Cluster',
102
+ name: this.cluster.mgmt?.id,
103
+ }
104
+ };
105
+
106
+ createOperationCR(this.$store.dispatch, OPERATION.ENCRYPTION_KEY_ROTATE, spec, namespace, safePrefix);
107
+ } else {
108
+ const currentGeneration = this.cluster.spec?.rkeConfig?.rotateEncryptionKeys?.generation || 0;
109
+
110
+ // To rotate the encryption keys, increment
111
+ // rkeConfig.rotateEncyrptionKeys.generation in the YAML.
112
+ set(this.cluster, 'spec.rkeConfig.rotateEncryptionKeys.generation', currentGeneration + 1);
113
+ await this.cluster.save();
114
+ }
91
115
 
92
116
  this.close(buttonDone);
93
117
  } catch (err) {
@@ -128,7 +152,7 @@ export default {
128
152
  <Banner
129
153
  v-else
130
154
  color="error"
131
- label-key="promptRotateEncryptionKey.error"
155
+ label-key="promptRotateEncryptionKey.error.noBackup"
132
156
  />
133
157
  </div>
134
158
  </div>
@@ -0,0 +1,78 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import RotateEncryptionKeyDialog from '@shell/dialog/RotateEncryptionKeyDialog.vue';
3
+ import { OPERATION } from '@shell/config/types';
4
+ import { createOperationCR } from '@shell/utils/operation-cr';
5
+
6
+ jest.mock('@shell/utils/operation-cr', () => ({ createOperationCR: jest.fn() }));
7
+
8
+ describe('component: RotateEncryptionKeyDialog', () => {
9
+ const t = (key: string) => key;
10
+
11
+ const createWrapper = (cluster: any, dispatch = jest.fn()) => {
12
+ return shallowMount(RotateEncryptionKeyDialog, {
13
+ propsData: { cluster },
14
+ global: {
15
+ mocks: {
16
+ t,
17
+ $store: {
18
+ dispatch,
19
+ getters: {
20
+ isRancher: true,
21
+ 'prefs/get': jest.fn((key: string) => (key.includes('date') ? 'YYYY-MM-DD' : 'HH:mm:ss')),
22
+ }
23
+ },
24
+ },
25
+ directives: { 'clean-html': true }
26
+ }
27
+ });
28
+ };
29
+
30
+ beforeEach(() => {
31
+ jest.clearAllMocks();
32
+ });
33
+
34
+ it('should create operation CR for imported day 2 ops clusters', async() => {
35
+ (createOperationCR as jest.Mock).mockResolvedValue(undefined);
36
+
37
+ const cluster = {
38
+ isImportedWithDayTwoOps: true,
39
+ mgmt: { id: 'c-m-1' },
40
+ save: jest.fn(),
41
+ spec: { rkeConfig: {} }
42
+ };
43
+ const dispatch = jest.fn();
44
+ const buttonDone = jest.fn();
45
+ const wrapper = createWrapper(cluster, dispatch);
46
+
47
+ await wrapper.vm.apply(buttonDone);
48
+
49
+ expect(createOperationCR).toHaveBeenCalledWith(dispatch, OPERATION.ENCRYPTION_KEY_ROTATE, {
50
+ clusterRef: {
51
+ apiVersion: 'management.cattle.io/v3',
52
+ kind: 'Cluster',
53
+ name: 'c-m-1',
54
+ }
55
+ }, 'c-m-1', 'c-m-1');
56
+ expect(cluster.save).not.toHaveBeenCalled();
57
+ expect(buttonDone).toHaveBeenCalledWith(true);
58
+ });
59
+
60
+ it('should update generation and save for non-day-2 clusters', async() => {
61
+ const save = jest.fn().mockResolvedValue(undefined);
62
+ const cluster = {
63
+ isImportedWithDayTwoOps: false,
64
+ mgmt: { id: 'c-m-1' },
65
+ save,
66
+ spec: { rkeConfig: { rotateEncryptionKeys: { generation: 4 } } }
67
+ };
68
+ const buttonDone = jest.fn();
69
+ const wrapper = createWrapper(cluster);
70
+
71
+ await wrapper.vm.apply(buttonDone);
72
+
73
+ expect(createOperationCR).not.toHaveBeenCalled();
74
+ expect(cluster.spec.rkeConfig.rotateEncryptionKeys.generation).toBe(5);
75
+ expect(save).toHaveBeenCalledWith();
76
+ expect(buttonDone).toHaveBeenCalledWith(true);
77
+ });
78
+ });