@rancher/shell 2.0.2-rc.1 → 2.0.3

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 (59) hide show
  1. package/assets/translations/en-us.yaml +53 -31
  2. package/components/PromptRemove.vue +8 -3
  3. package/components/ResourceDetail/Masthead.vue +1 -0
  4. package/components/ResourceDetail/index.vue +2 -1
  5. package/components/SideNav.vue +1 -1
  6. package/components/TableDataUserIcon.vue +1 -1
  7. package/components/fleet/FleetClusters.vue +0 -3
  8. package/components/fleet/FleetRepos.vue +0 -7
  9. package/components/formatter/CloudCredExpired.vue +69 -0
  10. package/components/formatter/ClusterProvider.vue +3 -3
  11. package/components/formatter/Date.vue +1 -1
  12. package/components/nav/Header.vue +9 -5
  13. package/components/nav/TopLevelMenu.vue +127 -63
  14. package/components/nav/__tests__/TopLevelMenu.test.ts +53 -27
  15. package/config/labels-annotations.js +3 -0
  16. package/core/types-provisioning.ts +5 -0
  17. package/core/types.ts +26 -1
  18. package/detail/catalog.cattle.io.app.vue +17 -4
  19. package/detail/fleet.cattle.io.bundle.vue +5 -68
  20. package/detail/fleet.cattle.io.cluster.vue +11 -9
  21. package/detail/fleet.cattle.io.gitrepo.vue +3 -2
  22. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +109 -24
  23. package/edit/provisioning.cattle.io.cluster/index.vue +10 -4
  24. package/edit/provisioning.cattle.io.cluster/rke2.vue +13 -2
  25. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +1 -0
  26. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +177 -26
  27. package/list/provisioning.cattle.io.cluster.vue +56 -5
  28. package/mixins/chart.js +6 -2
  29. package/models/__tests__/management.cattle.io.cluster.test.ts +3 -3
  30. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +0 -86
  31. package/models/catalog.cattle.io.app.js +108 -21
  32. package/models/cloudcredential.js +159 -2
  33. package/models/fleet.cattle.io.bundle.js +3 -1
  34. package/models/fleet.cattle.io.gitrepo.js +50 -61
  35. package/models/management.cattle.io.cluster.js +15 -7
  36. package/models/provisioning.cattle.io.cluster.js +62 -15
  37. package/package.json +1 -1
  38. package/pages/c/_cluster/apps/charts/install.vue +2 -1
  39. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  40. package/pages/c/_cluster/explorer/index.vue +1 -2
  41. package/pages/c/_cluster/fleet/index.vue +12 -5
  42. package/pages/c/_cluster/manager/cloudCredential/index.vue +68 -4
  43. package/pages/c/_cluster/uiplugins/index.vue +4 -2
  44. package/pages/home.vue +1 -0
  45. package/scripts/extension/bundle +1 -1
  46. package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +0 -2
  47. package/scripts/extension/parse-tag-name +21 -12
  48. package/scripts/publish-shell.sh +10 -4
  49. package/scripts/typegen.sh +27 -22
  50. package/store/features.js +1 -0
  51. package/types/resources/fleet.d.ts +40 -0
  52. package/types/shell/index.d.ts +4692 -0
  53. package/utils/auth.js +1 -1
  54. package/utils/cluster.js +1 -1
  55. package/utils/fleet.ts +159 -0
  56. package/utils/string.js +9 -0
  57. package/utils/v-sphere.ts +282 -0
  58. package/vue.config.js +3 -3
  59. package/shell/types/shell/index.d.ts +0 -2
@@ -9,7 +9,8 @@ import RelatedResources from '@shell/components/RelatedResources';
9
9
  import jsyaml from 'js-yaml';
10
10
  import merge from 'lodash/merge';
11
11
  import { CATALOG } from '@shell/config/types';
12
- import { sortBy } from '~shell/utils/sort';
12
+ import { sortBy } from '@shell/utils/sort';
13
+ import { allHash } from '@shell/utils/promise';
13
14
 
14
15
  export default {
15
16
  name: 'DetailRelease',
@@ -30,9 +31,15 @@ export default {
30
31
  },
31
32
 
32
33
  async fetch() {
33
- await this.$store.dispatch('catalog/load');
34
+ const promises = {
35
+ catalog: this.$store.dispatch('catalog/load'),
36
+ allOperations: this.$store.dispatch('cluster/findAll', { type: CATALOG.OPERATION }),
37
+ secrets: this.value.fetchValues(true),
38
+ };
34
39
 
35
- this.allOperations = await this.$store.dispatch('cluster/findAll', { type: CATALOG.OPERATION });
40
+ const res = await allHash(promises);
41
+
42
+ this.allOperations = res.allOperations;
36
43
  },
37
44
 
38
45
  computed: {
@@ -45,7 +52,7 @@ export default {
45
52
  },
46
53
 
47
54
  valuesYaml() {
48
- const combined = merge(merge({}, this.value?.spec?.chart?.values || {}), this.value?.spec?.values || {});
55
+ const combined = merge(merge({}, this.value?.chartValues || {}), this.value?.values || {});
49
56
 
50
57
  return jsyaml.dump(combined);
51
58
  },
@@ -95,6 +102,12 @@ export default {
95
102
  }
96
103
  },
97
104
  },
105
+
106
+ watch: {
107
+ 'value.secretId'(neu, old) {
108
+ this.value.fetchValues(true);
109
+ }
110
+ },
98
111
  };
99
112
  </script>
100
113
 
@@ -1,77 +1,25 @@
1
1
  <script>
2
- import { FLEET } from '@shell/config/types';
3
2
  import FleetBundleResources from '@shell/components/fleet/FleetBundleResources.vue';
4
- import SortableTable from '@shell/components/SortableTable';
3
+ import FleetUtils from '@shell/utils/fleet';
5
4
 
6
5
  export default {
7
6
  name: 'FleetBundleDetail',
8
7
 
9
- components: {
10
- FleetBundleResources,
11
- SortableTable,
12
- },
13
- props: {
8
+ components: { FleetBundleResources },
9
+ props: {
14
10
  value: {
15
11
  type: Object,
16
12
  required: true,
17
13
  }
18
14
  },
19
15
 
20
- data() {
21
- return { repo: null };
22
- },
23
-
24
- async fetch() {
25
- const { namespace, labels } = this.value.metadata;
26
- const repoName = `${ namespace }/${ labels['fleet.cattle.io/repo-name'] }`;
27
-
28
- if (this.hasRepoLabel) {
29
- this.repo = await this.$store.dispatch('management/find', { type: FLEET.GIT_REPO, id: repoName });
30
- }
31
- },
32
-
33
16
  computed: {
34
- hasRepoLabel() {
35
- return !!(this.value?.metadata?.labels && this.value?.metadata?.labels['fleet.cattle.io/repo-name']);
36
- },
37
17
  bundleResources() {
38
- if (this.hasRepoLabel) {
39
- const bundleResourceIds = this.bundleResourceIds;
40
-
41
- return this.repo?.status?.resources?.filter((resource) => {
42
- return bundleResourceIds.includes(resource.name);
43
- });
44
- } else if (this.value?.spec?.resources?.length) {
45
- return this.value?.spec?.resources.map((item) => {
46
- return {
47
- content: item.content,
48
- name: item.name.includes('.') ? item.name.split('.')[0] : item.name
49
- };
50
- });
51
- }
52
-
53
- return [];
54
- },
55
- resourceHeaders() {
56
- return [
57
- {
58
- name: 'name',
59
- value: 'name',
60
- sort: ['name'],
61
- labelKey: 'tableHeaders.name',
62
- },
63
- ];
18
+ return FleetUtils.resourcesFromBundleStatus(this.value?.status);
64
19
  },
65
20
  resourceCount() {
66
- return (this.bundleResources && this.bundleResources.length) || this.value?.spec?.resources?.length;
21
+ return this.bundleResources.length;
67
22
  },
68
- bundleResourceIds() {
69
- if (this.value.status?.resourceKey) {
70
- return this.value?.status?.resourceKey.map((item) => item.name);
71
- }
72
-
73
- return [];
74
- }
75
23
  }
76
24
  };
77
25
 
@@ -84,19 +32,8 @@ export default {
84
32
  <span>{{ resourceCount }}</span>
85
33
  </div>
86
34
  <FleetBundleResources
87
- v-if="hasRepoLabel"
88
35
  :value="bundleResources"
89
36
  />
90
- <SortableTable
91
- v-else
92
- :rows="bundleResources"
93
- :headers="resourceHeaders"
94
- :table-actions="false"
95
- :row-actions="false"
96
- key-field="tableKey"
97
- default-sort-by="state"
98
- :paged="true"
99
- />
100
37
  </div>
101
38
  </template>
102
39
 
@@ -6,6 +6,7 @@ import ResourceTabs from '@shell/components/form/ResourceTabs';
6
6
  import Tab from '@shell/components/Tabbed/Tab';
7
7
  import { MANAGEMENT, FLEET } from '@shell/config/types';
8
8
  import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
9
+ import { allHash } from 'utils/promise';
9
10
 
10
11
  export default {
11
12
  name: 'FleetDetailCluster',
@@ -27,17 +28,18 @@ export default {
27
28
 
28
29
  async fetch() {
29
30
  const clusterId = this.value?.metadata?.labels[FLEET_LABELS.CLUSTER_NAME];
30
-
31
- this.rancherCluster = await this.$store.dispatch('management/find', {
32
- type: MANAGEMENT.CLUSTER,
33
- id: clusterId
31
+ const hash = await allHash({
32
+ rancherCluster: this.$store.dispatch('management/find', {
33
+ type: MANAGEMENT.CLUSTER,
34
+ id: clusterId
35
+ }),
36
+ repos: this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO }),
37
+ workspaces: this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE }),
38
+ bundleDeployments: this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT })
34
39
  });
35
40
 
36
- this.allRepos = await this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO });
37
-
38
- await this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE });
39
-
40
- await this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT });
41
+ this.rancherCluster = hash.rancherCluster;
42
+ this.allRepos = hash.repos;
41
43
  },
42
44
 
43
45
  data() {
@@ -40,7 +40,7 @@ export default {
40
40
  },
41
41
  computed: {
42
42
  gitRepoHasClusters() {
43
- return this.value?.clusterResourceStatus?.length;
43
+ return this.value.status.desiredReadyClusters;
44
44
  },
45
45
  clusterSchema() {
46
46
  return this.$store.getters['management/schemaFor'](FLEET.CLUSTER);
@@ -80,7 +80,8 @@ export default {
80
80
  const allDispatches = await checkSchemasForFindAllHash({
81
81
  allBundles: {
82
82
  inStoreType: 'management',
83
- type: FLEET.BUNDLE
83
+ type: FLEET.BUNDLE,
84
+ opt: { excludeFields: ['metadata.managedFields', 'spec.resources'] },
84
85
  },
85
86
 
86
87
  allBundleDeployments: {
@@ -1,6 +1,7 @@
1
+ import { nextTick } from 'vue';
1
2
  /* eslint-disable jest/no-hooks */
2
3
  import { mount, Wrapper } from '@vue/test-utils';
3
- import DirectoryConfig from '@shell/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue';
4
+ import DirectoryConfig, { DATA_DIR_RADIO_OPTIONS, DEFAULT_SUBDIRS } from '@shell/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue';
4
5
  import { _EDIT, _CREATE } from '@shell/config/query-params';
5
6
  import { clone } from '@shell/utils/object';
6
7
 
@@ -14,7 +15,8 @@ describe('component: DirectoryConfig', () => {
14
15
  provisioning: '',
15
16
  k8sDistro: '',
16
17
  },
17
- mode: _CREATE,
18
+ k8sVersion: 'k3s',
19
+ mode: _CREATE,
18
20
  },
19
21
  mocks: {
20
22
  $store: {
@@ -33,48 +35,88 @@ describe('component: DirectoryConfig', () => {
33
35
  );
34
36
 
35
37
  const title = wrapper.find('h3');
38
+ const radioInput = wrapper.find('[data-testid="rke2-directory-config-radio-input"]');
39
+ const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
36
40
  const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
37
41
  const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
38
42
  const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
39
43
 
40
44
  expect(title.exists()).toBe(true);
45
+ expect(radioInput.exists()).toBe(true);
41
46
 
42
- expect(systemAgentInput.exists()).toBe(true);
43
- expect(provisioningInput.exists()).toBe(true);
44
- expect(k8sDistroInput.exists()).toBe(true);
47
+ // for the default config, the default radio input should be "default"
48
+ expect(wrapper.vm.dataConfigRadioValue).toBe(DATA_DIR_RADIO_OPTIONS.DEFAULT);
49
+
50
+ // since we have all of the vars empty, then the inputs should not be there
51
+ expect(commonInput.exists()).toBe(false);
52
+ expect(systemAgentInput.exists()).toBe(false);
53
+ expect(provisioningInput.exists()).toBe(false);
54
+ expect(k8sDistroInput.exists()).toBe(false);
45
55
  });
46
56
 
47
- it('updating each individual data dir should set the correct values on each data dir variable', async() => {
57
+ it('updating common base directory should set the correct values on each data dir variable', async() => {
58
+ const newMountOptions = clone(mountOptions);
59
+
48
60
  wrapper = mount(
49
61
  DirectoryConfig,
50
- mountOptions
62
+ {
63
+ ...newMountOptions,
64
+ // couldn't use setData, so this is the next best solution
65
+ data() {
66
+ return { dataConfigRadioValue: DATA_DIR_RADIO_OPTIONS.COMMON };
67
+ }
68
+ }
51
69
  );
52
70
 
53
71
  const inputPath = 'some-data-dir';
72
+ const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
73
+
74
+ // update base dir value
75
+ expect(commonInput.exists()).toBe(true);
76
+ commonInput.setValue(inputPath);
77
+ await nextTick();
78
+
79
+ expect(wrapper.vm.value.systemAgent).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`);
80
+ expect(wrapper.vm.value.provisioning).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`);
81
+ expect(wrapper.vm.value.k8sDistro).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_K3S }`);
82
+ });
83
+
84
+ it('updating each individual data dir should set the correct values on each data dir variable', async() => {
85
+ const newMountOptions = clone(mountOptions);
86
+
87
+ wrapper = mount(
88
+ DirectoryConfig,
89
+ {
90
+ ...newMountOptions,
91
+ // couldn't use setData, so this is the next best solution
92
+ data() {
93
+ return { dataConfigRadioValue: DATA_DIR_RADIO_OPTIONS.CUSTOM };
94
+ }
95
+ }
96
+ );
97
+ const inputPath = 'some-data-dir';
98
+ const agentValue = `${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`;
99
+ const provisioningValue = `${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`;
100
+ const k8sDistroValue = `${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_RKE2 }`;
54
101
 
55
102
  const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
56
103
  const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
57
104
  const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
58
105
 
59
- systemAgentInput.setValue(inputPath);
60
- provisioningInput.setValue(inputPath);
61
- k8sDistroInput.setValue(inputPath);
62
- await wrapper.vm.$nextTick();
106
+ systemAgentInput.setValue(agentValue);
107
+ provisioningInput.setValue(provisioningValue);
108
+ k8sDistroInput.setValue(k8sDistroValue);
109
+ await nextTick();
63
110
 
64
- expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath);
65
- expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath);
66
- expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath);
111
+ expect(wrapper.vm.value.systemAgent).toStrictEqual(agentValue);
112
+ expect(wrapper.vm.value.provisioning).toStrictEqual(provisioningValue);
113
+ expect(wrapper.vm.value.k8sDistro).toStrictEqual(k8sDistroValue);
67
114
  });
68
115
 
69
- it('on a mode different than _CREATE all visible inputs should be disabled (with different values)', () => {
116
+ it('should render the component with configuration being an empty object, without errors and radio be of value DATA_DIR_RADIO_OPTIONS.CUSTOM (edit scenario)', () => {
70
117
  const newMountOptions = clone(mountOptions);
71
- const inputPath1 = 'some-data-dir1';
72
- const inputPath2 = 'some-data-dir2';
73
- const inputPath3 = 'some-data-dir3';
74
118
 
75
- newMountOptions.propsData.value.systemAgent = inputPath1;
76
- newMountOptions.propsData.value.provisioning = inputPath2;
77
- newMountOptions.propsData.value.k8sDistro = inputPath3;
119
+ newMountOptions.propsData.value = {};
78
120
  newMountOptions.propsData.mode = _EDIT;
79
121
 
80
122
  wrapper = mount(
@@ -82,16 +124,59 @@ describe('component: DirectoryConfig', () => {
82
124
  newMountOptions
83
125
  );
84
126
 
127
+ const title = wrapper.find('h3');
128
+ const radioInput = wrapper.find('[data-testid="rke2-directory-config-radio-input"]');
85
129
  const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
86
130
  const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
87
131
  const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
88
132
 
133
+ expect(title.exists()).toBe(true);
134
+ expect(radioInput.isVisible()).toBe(false);
135
+
136
+ expect(wrapper.vm.dataConfigRadioValue).toBe(DATA_DIR_RADIO_OPTIONS.CUSTOM);
137
+
138
+ // since we have all of the vars empty, then the inputs should not be there
89
139
  expect(systemAgentInput.exists()).toBe(true);
90
140
  expect(provisioningInput.exists()).toBe(true);
91
141
  expect(k8sDistroInput.exists()).toBe(true);
92
142
 
93
- expect(systemAgentInput.attributes('disabled')).toBe('disabled');
94
- expect(provisioningInput.attributes('disabled')).toBe('disabled');
95
- expect(k8sDistroInput.attributes('disabled')).toBe('disabled');
143
+ expect(systemAgentInput.attributes().disabled).toBeDefined();
144
+ expect(provisioningInput.attributes().disabled).toBeDefined();
145
+ expect(k8sDistroInput.attributes().disabled).toBeDefined();
146
+ });
147
+
148
+ it('radio input should be set to DATA_DIR_RADIO_OPTIONS.CUSTOM with all data dir values existing and different (edit scenario)', () => {
149
+ const newMountOptions = clone(mountOptions);
150
+ const inputPath = 'some-data-dir';
151
+
152
+ newMountOptions.propsData.value.systemAgent = `${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`;
153
+ newMountOptions.propsData.value.provisioning = `${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`;
154
+ newMountOptions.propsData.value.k8sDistro = `${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_K3S }`;
155
+ newMountOptions.propsData.mode = _EDIT;
156
+
157
+ wrapper = mount(
158
+ DirectoryConfig,
159
+ newMountOptions
160
+ );
161
+
162
+ expect(wrapper.vm.dataConfigRadioValue).toBe(DATA_DIR_RADIO_OPTIONS.CUSTOM);
163
+
164
+ const radioInput = wrapper.find('[data-testid="rke2-directory-config-radio-input"]');
165
+ const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
166
+ const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
167
+ const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
168
+
169
+ expect(radioInput.isVisible()).toBe(false);
170
+ expect(systemAgentInput.isVisible()).toBe(true);
171
+ expect(provisioningInput.isVisible()).toBe(true);
172
+ expect(k8sDistroInput.isVisible()).toBe(true);
173
+
174
+ expect(systemAgentInput.attributes().disabled).toBeDefined();
175
+ expect(provisioningInput.attributes().disabled).toBeDefined();
176
+ expect(k8sDistroInput.attributes().disabled).toBeDefined();
177
+
178
+ expect(wrapper.vm.value.systemAgent).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`);
179
+ expect(wrapper.vm.value.provisioning).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`);
180
+ expect(wrapper.vm.value.k8sDistro).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_K3S }`);
96
181
  });
97
182
  });
@@ -203,8 +203,9 @@ export default {
203
203
 
204
204
  emberLink() {
205
205
  if (this.value) {
206
+ // set subtype if editing EKS/GKE/AKS cluster -- this ensures that the component provided by extension is loaded instead of iframing old ember ui
206
207
  if (this.value.provisioner) {
207
- const matchingSubtype = this.subTypes.find((st) => st.id.toLowerCase() === this.value.provisioner.toLowerCase() || DRIVER_TO_IMPORT[st.id.toLowerCase()] === this.value.provisioner.toLowerCase());
208
+ const matchingSubtype = this.subTypes.find((st) => DRIVER_TO_IMPORT[st.id.toLowerCase()] === this.value.provisioner.toLowerCase());
208
209
 
209
210
  if (matchingSubtype) {
210
211
  this.selectType(matchingSubtype.id, false);
@@ -395,7 +396,8 @@ export default {
395
396
  disabled: ext.disabled || false,
396
397
  link: ext.link,
397
398
  tag: ext.tag,
398
- component: ext.component
399
+ component: ext.component,
400
+ hidden: ext.hidden,
399
401
  };
400
402
 
401
403
  out.push(subtype);
@@ -440,10 +442,14 @@ export default {
440
442
  }
441
443
  },
442
444
 
445
+ filteredSubTypes() {
446
+ return this.subTypes.filter((subtype) => !subtype.hidden);
447
+ },
448
+
443
449
  groupedSubTypes() {
444
450
  const out = {};
445
451
 
446
- for ( const row of this.subTypes ) {
452
+ for ( const row of this.filteredSubTypes ) {
447
453
  const name = row.group;
448
454
  let entry = out[name];
449
455
 
@@ -605,7 +611,7 @@ export default {
605
611
  <div
606
612
  v-for="(obj, i) in groupedSubTypes"
607
613
  :key="obj.id"
608
- class="mb-20"
614
+ :class="{'mt-5': i === 0, 'mt-20': i !== 0 }"
609
615
  style="width: 100%;"
610
616
  >
611
617
  <h4>
@@ -64,13 +64,12 @@ import AddOnConfig from '@shell/edit/provisioning.cattle.io.cluster/tabs/AddOnCo
64
64
  import Advanced from '@shell/edit/provisioning.cattle.io.cluster/tabs/Advanced';
65
65
  import ClusterAppearance from '@shell/components/form/ClusterAppearance';
66
66
  import AddOnAdditionalManifest from '@shell/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest';
67
+ import VsphereUtils, { VMWARE_VSPHERE } from '@shell/utils/v-sphere';
67
68
 
68
69
  const HARVESTER = 'harvester';
69
70
  const HARVESTER_CLOUD_PROVIDER = 'harvester-cloud-provider';
70
71
  const NETBIOS_TRUNCATION_LENGTH = 15;
71
72
 
72
- const VMWARE_VSPHERE = 'vmwarevsphere';
73
-
74
73
  /**
75
74
  * Classes to be adopted by the node badges in Machine pools
76
75
  */
@@ -892,6 +891,8 @@ export default {
892
891
  created() {
893
892
  this.registerBeforeHook(this.saveMachinePools, 'save-machine-pools', 1);
894
893
  this.registerBeforeHook(this.setRegistryConfig, 'set-registry-config');
894
+ this.registerBeforeHook(this.handleVsphereCpiSecret, 'sync-vsphere-cpi');
895
+ this.registerBeforeHook(this.handleVsphereCsiSecret, 'sync-vsphere-csi');
895
896
  this.registerAfterHook(this.cleanupMachinePools, 'cleanup-machine-pools');
896
897
  this.registerAfterHook(this.saveRoleBindings, 'save-role-bindings');
897
898
 
@@ -904,6 +905,14 @@ export default {
904
905
  methods: {
905
906
  set,
906
907
 
908
+ async handleVsphereCpiSecret() {
909
+ return VsphereUtils.handleVsphereCpiSecret(this);
910
+ },
911
+
912
+ async handleVsphereCsiSecret() {
913
+ return VsphereUtils.handleVsphereCsiSecret(this);
914
+ },
915
+
907
916
  /**
908
917
  * Initialize all the cluster specs
909
918
  */
@@ -2420,8 +2429,10 @@ export default {
2420
2429
  name="additionalmanifest"
2421
2430
  label-key="cluster.tabs.addOnAdditionalManifest"
2422
2431
  :showHeader="false"
2432
+ @active="refreshComponentWithYamls('additionalmanifest')"
2423
2433
  >
2424
2434
  <AddOnAdditionalManifest
2435
+ ref="additionalmanifest"
2425
2436
  :value="value"
2426
2437
  :mode="mode"
2427
2438
  @additional-manifest-changed="updateAdditionalManifest"
@@ -101,6 +101,7 @@ export default {
101
101
  <template v-if="haveArgInfo">
102
102
  <DirectoryConfig
103
103
  v-model="value.spec.rkeConfig.dataDirectories"
104
+ :k8s-version="value.spec.kubernetesVersion"
104
105
  :mode="mode"
105
106
  />
106
107
  <h3>{{ t('cluster.advanced.argInfo.title') }}</h3>