@rancher/shell 0.3.24 → 0.3.26

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 (115) hide show
  1. package/assets/styles/themes/_light.scss +1 -1
  2. package/assets/translations/en-us.yaml +36 -7
  3. package/assets/translations/zh-hans.yaml +1 -1
  4. package/components/ClusterIconMenu.vue +143 -0
  5. package/components/CruResource.vue +10 -1
  6. package/components/ExplorerProjectsNamespaces.vue +11 -1
  7. package/components/FixedBanner.vue +17 -1
  8. package/components/Markdown.vue +1 -1
  9. package/components/Questions/__tests__/Yaml.test.ts +3 -2
  10. package/components/SortableTable/index.vue +3 -2
  11. package/components/__tests__/ProjectRow.test.ts +63 -0
  12. package/components/auth/RoleDetailEdit.vue +19 -2
  13. package/components/auth/__tests__/RoleDetailEdit.test.ts +41 -0
  14. package/components/auth/login/saml.vue +12 -1
  15. package/components/form/LabeledSelect.vue +12 -5
  16. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  17. package/components/form/Members/MembershipEditor.vue +6 -1
  18. package/components/form/ResourceQuota/ProjectRow.vue +6 -2
  19. package/components/form/__tests__/KeyValue.test.ts +6 -3
  20. package/components/form/__tests__/LabeledSelect.test.ts +18 -0
  21. package/components/formatter/PodsUsage.vue +11 -36
  22. package/components/formatter/PrincipalGroupBindings.vue +8 -5
  23. package/components/formatter/__tests__/PodsUsage.test.ts +36 -19
  24. package/components/nav/Group.vue +25 -27
  25. package/components/nav/Header.vue +12 -5
  26. package/components/nav/Pinned.vue +47 -0
  27. package/components/nav/TopLevelMenu.vue +233 -60
  28. package/components/nav/Type.vue +57 -3
  29. package/config/home-links.js +1 -1
  30. package/config/product/istio.js +15 -5
  31. package/config/router.js +3 -9
  32. package/config/table-headers.js +5 -6
  33. package/config/uiplugins.js +1 -0
  34. package/core/plugin-helpers.js +3 -0
  35. package/core/types.ts +6 -1
  36. package/creators/app/files/.vscode/settings.json +0 -1
  37. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +118 -0
  38. package/detail/autoscaling.horizontalpodautoscaler/index.vue +4 -4
  39. package/detail/provisioning.cattle.io.cluster.vue +7 -5
  40. package/edit/__tests__/management.cattle.io.clusterroletemplatebinding.test.ts +58 -0
  41. package/edit/__tests__/namespace.test.ts +5 -3
  42. package/edit/management.cattle.io.clusterroletemplatebinding.vue +3 -11
  43. package/edit/namespace.vue +8 -4
  44. package/edit/provisioning.cattle.io.cluster/Basics.vue +662 -0
  45. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +6 -0
  46. package/edit/provisioning.cattle.io.cluster/DrainOptions.vue +13 -8
  47. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -2
  48. package/edit/provisioning.cattle.io.cluster/MemberRoles.vue +40 -0
  49. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +237 -0
  50. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.tests.ts +71 -23
  51. package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +52 -0
  52. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -142
  53. package/edit/provisioning.cattle.io.cluster/rke2.vue +211 -599
  54. package/edit/workload/storage/__tests__/Storage.test.ts +2 -2
  55. package/edit/workload/storage/persistentVolumeClaim/__tests__/persistentvolumeclaim.test.ts +36 -0
  56. package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +15 -7
  57. package/initialize/index.js +5 -5
  58. package/layouts/default.vue +6 -6
  59. package/layouts/home.vue +6 -2
  60. package/layouts/plain.vue +9 -2
  61. package/list/fleet.cattle.io.cluster.vue +2 -2
  62. package/list/management.cattle.io.feature.vue +1 -1
  63. package/machine-config/vmwarevsphere.vue +48 -7
  64. package/mixins/brand.js +0 -8
  65. package/mixins/child-hook.js +2 -2
  66. package/mixins/create-edit-view/impl.js +3 -3
  67. package/models/__tests__/management.cattle.io.node.ts +96 -0
  68. package/models/__tests__/node.ts +74 -0
  69. package/models/cluster/node.js +6 -5
  70. package/models/cluster.x-k8s.io.machinedeployment.js +2 -2
  71. package/models/management.cattle.io.cluster.js +22 -1
  72. package/models/management.cattle.io.clusterroletemplatebinding.js +3 -3
  73. package/models/management.cattle.io.globalrole.js +17 -2
  74. package/models/management.cattle.io.node.js +6 -4
  75. package/models/management.cattle.io.projectroletemplatebinding.js +3 -3
  76. package/models/management.cattle.io.roletemplate.js +17 -2
  77. package/package.json +2 -6
  78. package/pages/about.vue +2 -0
  79. package/pages/auth/setup.vue +5 -4
  80. package/pages/c/_cluster/monitoring/index.vue +8 -3
  81. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +9 -66
  82. package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +182 -0
  83. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +15 -32
  84. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +8 -46
  85. package/pages/c/_cluster/uiplugins/index.vue +64 -64
  86. package/pages/diagnostic.vue +0 -39
  87. package/pages/home.vue +1 -1
  88. package/plugins/dashboard-store/normalize.js +4 -4
  89. package/plugins/int-number.js +5 -2
  90. package/plugins/positive-int-number.js +19 -0
  91. package/plugins/steve/__tests__/getters.spec.ts +15 -0
  92. package/plugins/steve/getters.js +22 -10
  93. package/rancher-components/Form/LabeledInput/LabeledInput.vue +0 -8
  94. package/rancher-components/Form/Radio/RadioButton.test.ts +3 -7
  95. package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +2 -2
  96. package/store/index.js +4 -0
  97. package/store/prefs.js +1 -0
  98. package/types/shell/index.d.ts +13 -4
  99. package/utils/__tests__/cluster.test.ts +55 -0
  100. package/utils/__tests__/object.test.ts +21 -2
  101. package/utils/cluster.js +47 -1
  102. package/utils/object.js +12 -5
  103. package/utils/validators/formRules/__tests__/index.test.ts +13 -1
  104. package/utils/validators/formRules/index.ts +4 -0
  105. package/utils/validators/role-template.js +9 -1
  106. package/utils/version.js +1 -1
  107. package/yarn-error.log +16 -16
  108. package/components/ClusterProviderIconMenu.vue +0 -161
  109. package/content/docs/en-us/getting-started.md +0 -224
  110. package/content/docs/en-us/whats-new.md +0 -29
  111. package/content/docs/zh-hans/getting-started.md +0 -224
  112. package/content/docs/zh-hans/whats-new.md +0 -28
  113. package/pages/docs/_doc.vue +0 -345
  114. package/pages/docs/toc.js +0 -27
  115. package/plugins/console.js +0 -34
@@ -2,6 +2,7 @@
2
2
  import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
3
3
  import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
4
4
  import UnitInput from '@shell/components/form/UnitInput.vue';
5
+ import { mapGetters } from 'vuex';
5
6
 
6
7
  const DEFAULTS = {
7
8
  deleteEmptyDirData: true, // Show; Kill pods using emptyDir volumes and lose the data
@@ -51,6 +52,8 @@ export default {
51
52
  this.update();
52
53
  },
53
54
 
55
+ computed: { ...mapGetters({ t: 'i18n/t' }) },
56
+
54
57
  methods: {
55
58
  update() {
56
59
  const out = {};
@@ -90,8 +93,8 @@ export default {
90
93
  <div class="mt-20">
91
94
  <Checkbox
92
95
  v-model="deleteEmptyDirData"
93
- label="Delete pods using emptyDir volumes"
94
- tooltip="emptyDir volumes are often used for ephemeral data, but the data will be permanently deleted. Draining will fail if this is not set and there are pods using emptyDir."
96
+ label-key="cluster.rke2.drain.deleteEmptyDir.label"
97
+ tooltip-key="cluster.rke2.drain.deleteEmptyDir.tooltip"
95
98
  @input="update"
96
99
  />
97
100
  </div>
@@ -99,21 +102,23 @@ export default {
99
102
  <Checkbox
100
103
  v-model="force"
101
104
  label="Delete standalone pods"
105
+ label-key="cluster.rke2.drain.force.label"
102
106
  tooltip="Delete standalone pods which are not managed by a Workload controller (Deployment, Job, etc). Draining will fail if this is not set and there are standalone pods."
107
+ tooltop-key="cluster.rke2.drain.force.tooltip"
103
108
  @input="update"
104
109
  />
105
110
  </div>
106
111
  <div>
107
112
  <Checkbox
108
113
  v-model="customGracePeriod"
109
- label="Override pod termination grace periods"
114
+ label-key="cluster.rke2.drain.gracePeriod.checkboxLabel"
110
115
  @input="update"
111
116
  />
112
117
  <UnitInput
113
118
  v-if="customGracePeriod"
114
119
  v-model="gracePeriod"
115
- label="Grace Period"
116
- suffix="Seconds"
120
+ label-key="cluster.rke2.drain.gracePeriod.inputLabel"
121
+ :suffix="t('suffix.seconds', {count: timeout})"
117
122
  class="mb-10"
118
123
  @input="update"
119
124
  />
@@ -121,14 +126,14 @@ export default {
121
126
  <div>
122
127
  <Checkbox
123
128
  v-model="customTimeout"
124
- label="Timeout after"
129
+ label-key="cluster.rke2.drain.timeout.checkboxLabel"
125
130
  @input="update"
126
131
  />
127
132
  <UnitInput
128
133
  v-if="customTimeout"
129
134
  v-model="timeout"
130
- label="Drain Timeout"
131
- suffix="Seconds"
135
+ label-key="cluster.rke2.drain.timeout.inputLabel"
136
+ :suffix="t('suffix.seconds', {count: timeout})"
132
137
  class="drain-timeout"
133
138
  @input="update"
134
139
  />
@@ -64,6 +64,11 @@ export default {
64
64
  busy: {
65
65
  type: Boolean,
66
66
  default: false,
67
+ },
68
+
69
+ poolId: {
70
+ type: String,
71
+ required: true,
67
72
  }
68
73
  },
69
74
 
@@ -108,7 +113,7 @@ export default {
108
113
  return {
109
114
  uuid: randomStr(),
110
115
 
111
- unhealthyNodeTimeoutInteger: this.value.pool.unhealthyNodeTimeout ? parseDuration(this.value.pool.unhealthyNodeTimeout) : 0
116
+ unhealthyNodeTimeoutInteger: this.value.pool.unhealthyNodeTimeout ? parseDuration(this.value.pool.unhealthyNodeTimeout) : 0,
112
117
  };
113
118
  },
114
119
 
@@ -151,6 +156,9 @@ export default {
151
156
  },
152
157
 
153
158
  methods: {
159
+ emitError(e) {
160
+ this.$emit('error', e);
161
+ },
154
162
  async test() {
155
163
  if ( typeof this.$refs.configComponent?.test === 'function' ) {
156
164
  let errors = [];
@@ -260,9 +268,10 @@ export default {
260
268
  :provider="provider"
261
269
  :credential-id="credentialId"
262
270
  :pool-index="idx"
271
+ :pool-id="poolId"
263
272
  :machine-pools="machinePools"
264
273
  :busy="busy"
265
- @error="e=>errors = e"
274
+ @error="emitError"
266
275
  @updateMachineCount="updateMachineCount"
267
276
  @expandAdvanced="expandAdvanced"
268
277
  @validationChanged="validationChanged"
@@ -0,0 +1,40 @@
1
+ <script>
2
+
3
+ import ClusterMembershipEditor from '@shell/components/form/Members/ClusterMembershipEditor';
4
+ import CreateEditView from '@shell/mixins/create-edit-view';
5
+ import { Banner } from '@components/Banner';
6
+ export default {
7
+ components: { ClusterMembershipEditor, Banner },
8
+ mixins: [CreateEditView],
9
+ props: {
10
+ mode: {
11
+ type: String,
12
+ required: true,
13
+ },
14
+
15
+ value: {
16
+ type: Object,
17
+ required: true,
18
+ },
19
+ onMembershipUpdate: {
20
+ type: Function,
21
+ required: true
22
+ }
23
+ }
24
+ };
25
+ </script>
26
+ <template>
27
+ <div>
28
+ <Banner
29
+ v-if="isEdit"
30
+ color="info"
31
+ >
32
+ {{ t('cluster.memberRoles.removeMessage') }}
33
+ </Banner>
34
+ <ClusterMembershipEditor
35
+ :mode="mode"
36
+ :parent-id="value.mgmt ? value.mgmt.id : null"
37
+ @membership-update="onMembershipUpdate"
38
+ />
39
+ </div>
40
+ </template>
@@ -0,0 +1,237 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import Basics from '@shell/edit/provisioning.cattle.io.cluster/Basics';
3
+
4
+ const defaultStubs = {
5
+ Banner: true,
6
+ LabeledSelect: true,
7
+ YamlEditor: true,
8
+ Checkbox: true
9
+ };
10
+
11
+ const defaultComputed = {
12
+ showk8s21LegacyWarning() {
13
+ return false;
14
+ },
15
+ profileOptions() {
16
+ return [{ label: 'anything', value: 'anything' }];
17
+ }
18
+ };
19
+
20
+ const mockAgentArgs = { 'cloud-provider-name': { options: [], profile: { options: [{ anything: 'yes' }] } } };
21
+ const mockServerArgs = { disable: {}, cni: { options: [] } };
22
+
23
+ const rke2Versions =
24
+ [
25
+ {
26
+ id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
27
+ },
28
+ {
29
+ id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
30
+ },
31
+ {
32
+ id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
33
+ }
34
+ ];
35
+ const k3sVersions = [
36
+ {
37
+ id: 'v1.25.0+k3s1', value: 'v1.25.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
38
+ },
39
+ {
40
+ id: 'v1.24.0+k3s1', value: 'v1.24.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
41
+ },
42
+ {
43
+ id: 'v1.23.0+k3s1', value: 'v1.23.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
44
+ }
45
+ ];
46
+ const mockVersionOptions = [...rke2Versions, ...k3sVersions];
47
+
48
+ const defaultGetters = {
49
+ currentStore: () => 'current_store',
50
+ 'management/schemaFor': jest.fn(),
51
+ 'current_store/all': jest.fn(),
52
+ 'i18n/t': jest.fn(),
53
+ 'i18n/withFallback': jest.fn(),
54
+ 'plugins/cloudProviderForDriver': jest.fn()
55
+ };
56
+
57
+ const defaultMocks = {
58
+ $route: {
59
+ name: 'anything',
60
+ query: { AS: 'yaml' },
61
+ },
62
+ };
63
+
64
+ const defaultSpec = {
65
+ rkeConfig: { etcd: { disableSnapshots: false }, machineGlobalConfig: { cni: 'calico' } },
66
+ chartValues: {},
67
+ };
68
+
69
+ describe('component: Basics', () => {
70
+ /**
71
+ * DISCLAIMER ***************************************************************************************
72
+ * Logs are prevented to avoid polluting the test output.
73
+ ****************************************************************************************************
74
+ */
75
+ // eslint-disable-next-line jest/no-hooks
76
+ beforeEach(() => {
77
+ jest.spyOn(console, 'log').mockImplementation(() => { });
78
+ });
79
+
80
+ it.each(mockVersionOptions)('should display PSA option', (k8s) => {
81
+ const label = 'whatever';
82
+ const wrapper = mount(Basics, {
83
+ propsData: {
84
+ mode: 'create',
85
+ value: {
86
+ spec: {
87
+ ...defaultSpec,
88
+ defaultPodSecurityAdmissionConfigurationTemplateName: label,
89
+ kubernetesVersion: k8s.value
90
+ },
91
+ agentConfig: { 'cloud-provider-name': '' },
92
+ },
93
+ provider: 'whatever',
94
+ userChartValues: {},
95
+ cisOverride: false,
96
+ cisPsaChangeBanner: true,
97
+ allPsas: [],
98
+ needsPsp: false,
99
+ selectedVersion: k8s,
100
+ versionOptions: mockVersionOptions,
101
+ isHarvesterDriver: false,
102
+ isHarvesterIncompatible: false,
103
+ showDeprecatedPatchVersions: false,
104
+ clusterIsAlreadyCreated: false,
105
+ isElementalCluster: false,
106
+ hasPsaTemplates: false,
107
+ isK3s: true,
108
+ haveArgInfo: false,
109
+ showCni: true,
110
+ showCloudProvider: true,
111
+ unsupportedCloudProvider: false,
112
+ cloudProviderOptions: [{ label: 'Default - RKE2 Embedded', value: '' }],
113
+ },
114
+ computed: defaultComputed,
115
+ mocks: {
116
+ ...defaultMocks,
117
+ $store: { getters: defaultGetters },
118
+ },
119
+ stubs: defaultStubs
120
+ });
121
+
122
+ const select = wrapper.find('[data-testid="rke2-custom-edit-psa"]');
123
+
124
+ expect((select.vm as unknown as any).options[0].label).toBe(`${ label } (Current)`);
125
+ });
126
+
127
+ it.each([
128
+ ['v1.25.0+rke2r1', 'none'],
129
+ ['v1.24.0+rke2r1', 'default'],
130
+ ['v1.23.0+rke2r1', 'default'],
131
+ ['v1.25.0+k3s1', 'none'],
132
+ ['v1.24.0+k3s1', 'default'],
133
+ ['v1.23.0+k3s1', 'default'],
134
+ ])('should display for version %p PSA option label %p', (k8s, partialLabel) => {
135
+ const label = `cluster.rke2.defaultPodSecurityAdmissionConfigurationTemplateName.option.${ partialLabel }`;
136
+ const wrapper = mount(Basics, {
137
+ propsData: {
138
+ mode: 'create',
139
+ value: {
140
+ spec: {
141
+ ...defaultSpec,
142
+ defaultPodSecurityAdmissionConfigurationTemplateName: label,
143
+ kubernetesVersion: k8s
144
+ },
145
+ agentConfig: { 'cloud-provider-name': '' },
146
+ },
147
+ provider: 'whatever',
148
+ userChartValues: {},
149
+ cisOverride: false,
150
+ cisPsaChangeBanner: true,
151
+ allPsas: [],
152
+ needsPsp: false,
153
+ selectedVersion: mockVersionOptions[0],
154
+ versionOptions: mockVersionOptions,
155
+ isHarvesterDriver: false,
156
+ isHarvesterIncompatible: false,
157
+ showDeprecatedPatchVersions: false,
158
+ clusterIsAlreadyCreated: false,
159
+ isElementalCluster: false,
160
+ hasPsaTemplates: false,
161
+ isK3s: true,
162
+ haveArgInfo: false,
163
+ showCni: true,
164
+ showCloudProvider: true,
165
+ unsupportedCloudProvider: false,
166
+ cloudProviderOptions: [{ label: 'Default - RKE2 Embedded', value: '' }],
167
+ },
168
+ computed: defaultComputed,
169
+ mocks: {
170
+ ...defaultMocks,
171
+ $store: { getters: defaultGetters },
172
+ },
173
+ stubs: defaultStubs
174
+ });
175
+
176
+ const select = wrapper.find('[data-testid="rke2-custom-edit-psa"]');
177
+
178
+ expect((select.vm as unknown as any).options[0].label).toStrictEqual(`${ label } (Current)`);
179
+ });
180
+
181
+ it.each([
182
+ ['anything', false, true],
183
+ ['', false, false],
184
+ ['', true, false],
185
+ ])('given CIS value as %p and its override as %p, it should set PSA dropdown as disabled %p', (cis, override, disabled) => {
186
+ const label = 'whatever';
187
+ const k8s = 'v1.25.0+rke2r1';
188
+ const wrapper = mount(Basics, {
189
+ propsData: {
190
+ mode: 'create',
191
+ value: {
192
+ agentConfig: { profile: cis, 'cloud-provider-name': '' },
193
+ spec: {
194
+ ...defaultSpec,
195
+ defaultPodSecurityAdmissionConfigurationTemplateName: label,
196
+ kubernetesVersion: k8s
197
+ }
198
+ },
199
+ provider: 'custom',
200
+ userChartValues: {},
201
+ cisPsaChangeBanner: true,
202
+ allPsas: [],
203
+ needsPsp: false,
204
+ cisOverride: override,
205
+ selectedVersion: mockVersionOptions[0],
206
+ versionOptions: [{
207
+ value: k8s,
208
+ agentArgs: { profile: { options: [cis] } },
209
+ charts: {},
210
+ profile: { options: [cis] }
211
+ }],
212
+ isHarvesterDriver: false,
213
+ isHarvesterIncompatible: false,
214
+ showDeprecatedPatchVersions: false,
215
+ clusterIsAlreadyCreated: false,
216
+ isElementalCluster: false,
217
+ hasPsaTemplates: true,
218
+ isK3s: true,
219
+ haveArgInfo: false,
220
+ showCni: true,
221
+ showCloudProvider: true,
222
+ unsupportedCloudProvider: false,
223
+ cloudProviderOptions: [{ label: 'Default - RKE2 Embedded', value: '' }],
224
+ },
225
+ computed: { ...defaultComputed },
226
+ mocks: {
227
+ ...defaultMocks,
228
+ $store: { getters: defaultGetters },
229
+ },
230
+ stubs: defaultStubs
231
+ });
232
+
233
+ const select = wrapper.find('[data-testid="rke2-custom-edit-psa"]');
234
+
235
+ expect((select.vm as unknown as any).disabled).toBe(disabled);
236
+ });
237
+ });
@@ -2,35 +2,83 @@ import { mount } from '@vue/test-utils';
2
2
  import CustomCommand from '@shell/edit/provisioning.cattle.io.cluster/CustomCommand.vue';
3
3
 
4
4
  describe('component: CustomCommand', () => {
5
- it('should return linux commands with the right flags based on cluster information', () => {
6
- const token = 'MY_TOKEN';
7
- const ip = 'MY_IP';
8
- const checkSum = 'MY_CHECKSUM';
9
- const wrapper = mount(CustomCommand, {
10
- propsData: {
11
- cluster: {},
12
- clusterToken: {
13
- insecureNodeCommand: ` curl --insecure -fL ${ ip }/system-agent-install.sh | sudo sh -s - --server ${ ip } --label 'cattle.io/os=linux' --token ${ token } --ca-checksum ${ checkSum }`,
14
- nodeCommand: ` curl -fL ${ ip }/system-agent-install.sh | sudo sh -s - --server ${ ip } --label 'cattle.io/os=linux' --token ${ token } --ca-checksum ${ checkSum }`
5
+ const token = 'MY_TOKEN';
6
+ const ip = 'MY_IP';
7
+ const checkSum = 'MY_CHECKSUM';
8
+ const wrapper = mount(CustomCommand, {
9
+ mocks: {
10
+ $store: {
11
+ getters: {
12
+ currentStore: () => 'current_store',
13
+ 'management/schemaFor': jest.fn(),
14
+ 'current_store/all': jest.fn(),
15
+ 'i18n/t': jest.fn(),
16
+ 'i18n/withFallback': jest.fn(),
15
17
  }
16
18
  },
17
- // stubs: { CopyCode: { template: '<div></div> ' } },
18
- data: () => ({
19
- address: '',
20
- controlPlane: true,
21
- etcd: true,
22
- insecure: false,
23
- internalAddress: '',
24
- labels: {},
25
- nodeName: '',
26
- taints: [],
27
- worker: true,
28
- }),
29
- });
19
+ },
20
+ propsData: {
21
+ cluster: {},
22
+ clusterToken: {
23
+ insecureNodeCommand: ` curl --insecure -fL ${ ip }/system-agent-install.sh | sudo sh -s - --server ${ ip } --label 'cattle.io/os=linux' --token ${ token } --ca-checksum ${ checkSum }`,
24
+ nodeCommand: ` curl -fL ${ ip }/system-agent-install.sh | sudo sh -s - --server ${ ip } --label 'cattle.io/os=linux' --token ${ token } --ca-checksum ${ checkSum }`
25
+ }
26
+ },
27
+ data: () => ({
28
+ address: '',
29
+ controlPlane: true,
30
+ etcd: true,
31
+ insecure: false,
32
+ internalAddress: '',
33
+ labels: {},
34
+ nodeName: '',
35
+ taints: [],
36
+ worker: true,
37
+ }),
38
+ });
30
39
 
40
+ it('should return linux commands with the right flags based on cluster information', () => {
31
41
  const value = `curl -fL ${ ip }/system-agent-install.sh | sudo sh -s - --server ${ ip } --label 'cattle.io/os=linux' --token ${ token } --ca-checksum ${ checkSum } --etcd --controlplane --worker`;
32
42
  const element = wrapper.find('#copiedLinux').element;
33
43
 
34
44
  expect(element.textContent).toContain(value);
35
45
  });
46
+
47
+ it('should not display warning message if all node roles are selected', async() => {
48
+ await wrapper.setData({
49
+ controlPlane: true,
50
+ etcd: true,
51
+ worker: true,
52
+ });
53
+
54
+ const element = wrapper.find('[data-testid="node-role-warning"]').element;
55
+
56
+ expect(element).toBeUndefined();
57
+ });
58
+
59
+ describe('should display warning message if at least one of the node roles is unselected', () => {
60
+ it.each([
61
+ [true, true, false],
62
+ [true, false, true],
63
+ [true, false, false],
64
+ [false, true, true],
65
+ [false, true, false],
66
+ [false, false, true],
67
+ [false, false, false],
68
+ ])('controlPlane: %p, etcd: %p, worker: %p', async(
69
+ controlPlane,
70
+ etcd,
71
+ worker
72
+ ) => {
73
+ await wrapper.setData({
74
+ controlPlane,
75
+ etcd,
76
+ worker
77
+ });
78
+
79
+ const element = wrapper.find('[data-testid="node-role-warning"]').element;
80
+
81
+ expect(element).toBeDefined();
82
+ });
83
+ });
36
84
  });
@@ -0,0 +1,52 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import DrainOptions from '@shell/edit/provisioning.cattle.io.cluster/DrainOptions.vue';
3
+ import { DefaultProps } from 'vue/types/options';
4
+ import { ExtendedVue, Vue } from 'vue/types/vue';
5
+
6
+ describe('drain options', () => {
7
+ it('should update an empty value with default drain options', () => {
8
+ const wrapper = mount(DrainOptions as unknown as ExtendedVue<Vue, {}, {}, {}, DefaultProps>, {
9
+ propsData: { value: { }, mode: 'create' },
10
+ mocks: { $store: { getters: { 'i18n/t': jest.fn() } } },
11
+
12
+ });
13
+
14
+ expect(wrapper.emitted('input')?.[0]?.[0]).toStrictEqual({
15
+ deleteEmptyDirData: true,
16
+ disableEviction: false,
17
+ enabled: false,
18
+ force: false,
19
+ gracePeriod: -1,
20
+ ignoreDaemonSets: true,
21
+ skipWaitForDeleteTimeoutSeconds: 0,
22
+ timeout: 120,
23
+ });
24
+ });
25
+
26
+ it('should not overwrite existing drain option values', () => {
27
+ const upgradeStrategy = {
28
+ deleteEmptyDirData: false,
29
+ disableEviction: false,
30
+ enabled: false,
31
+ force: true,
32
+ ignoreDaemonSets: false,
33
+ timeout: 90,
34
+ };
35
+ const wrapper = mount(DrainOptions as unknown as ExtendedVue<Vue, {}, {}, {}, DefaultProps>, {
36
+ propsData: { value: upgradeStrategy, mode: 'create' },
37
+ mocks: { $store: { getters: { 'i18n/t': jest.fn() } } },
38
+
39
+ });
40
+
41
+ expect(wrapper.emitted('input')?.[0]?.[0]).toStrictEqual({
42
+ deleteEmptyDirData: false,
43
+ disableEviction: false,
44
+ enabled: false,
45
+ force: true,
46
+ gracePeriod: -1,
47
+ ignoreDaemonSets: false,
48
+ skipWaitForDeleteTimeoutSeconds: 0,
49
+ timeout: 90,
50
+ });
51
+ });
52
+ });