@rancher/shell 2.0.1 → 2.0.2-rc.1

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 (89) hide show
  1. package/assets/translations/en-us.yaml +51 -26
  2. package/assets/translations/zh-hans.yaml +1 -0
  3. package/components/AssignTo.vue +2 -0
  4. package/components/Questions/index.vue +2 -2
  5. package/components/auth/RoleDetailEdit.vue +5 -4
  6. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  7. package/components/form/ProjectMemberEditor.vue +1 -1
  8. package/components/form/ResourceLabeledSelect.vue +11 -3
  9. package/components/form/labeled-select-utils/labeled-select.utils.ts +1 -1
  10. package/config/pagination-table-headers.js +5 -4
  11. package/config/roles.ts +34 -19
  12. package/config/router/navigation-guards/attempt-first-login.js +1 -1
  13. package/config/router/navigation-guards/authentication.js +1 -1
  14. package/config/router/navigation-guards/i18n.js +1 -1
  15. package/config/router/navigation-guards/index.js +2 -1
  16. package/config/router/navigation-guards/load-initial-settings.js +1 -1
  17. package/config/router/navigation-guards/runtime-extension-route.js +31 -0
  18. package/config/router/routes.js +10 -1
  19. package/config/uiplugins.js +130 -61
  20. package/core/plugin.ts +5 -0
  21. package/core/plugins.js +7 -1
  22. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +86 -13
  23. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +3 -134
  24. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +209 -0
  25. package/edit/provisioning.cattle.io.cluster/index.vue +8 -4
  26. package/edit/provisioning.cattle.io.cluster/rke2.vue +115 -17
  27. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +50 -0
  28. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +29 -64
  29. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +42 -3
  30. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +22 -86
  31. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +8 -2
  32. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +61 -0
  33. package/initialize/entry-helpers.js +4 -21
  34. package/mixins/__tests__/chart.test.ts +4 -1
  35. package/mixins/chart.js +30 -14
  36. package/models/__tests__/apps.deployment.test.ts +93 -0
  37. package/models/apps.deployment.js +18 -4
  38. package/models/management.cattle.io.cluster.js +2 -2
  39. package/models/management.cattle.io.user.js +3 -3
  40. package/models/nodedriver.js +5 -0
  41. package/models/provisioning.cattle.io.cluster.js +4 -0
  42. package/package.json +1 -1
  43. package/pages/404.vue +15 -0
  44. package/pages/auth/login.vue +4 -1
  45. package/pages/auth/setup.vue +4 -1
  46. package/pages/c/_cluster/explorer/index.vue +5 -0
  47. package/pages/c/_cluster/manager/jwt.authentication/index.vue +10 -4
  48. package/pages/c/_cluster/settings/performance.vue +2 -2
  49. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +7 -10
  50. package/pages/c/_cluster/uiplugins/index.vue +24 -16
  51. package/pages/home.vue +1 -13
  52. package/plugins/dashboard-store/actions.js +1 -1
  53. package/plugins/dashboard-store/getters.js +1 -1
  54. package/plugins/steve/__tests__/getters.test.ts +5 -5
  55. package/plugins/steve/getters.js +6 -4
  56. package/plugins/steve/hybrid-class.js +1 -5
  57. package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +1 -1
  58. package/scripts/publish-shell.sh +53 -55
  59. package/scripts/test-plugins-build.sh +45 -39
  60. package/shell/types/shell/index.d.ts +2 -0
  61. package/store/type-map.js +4 -2
  62. package/types/store/pagination.types.ts +1 -1
  63. package/utils/cluster.js +9 -0
  64. package/utils/settings.ts +3 -1
  65. package/creators/app/app.package.json +0 -14
  66. package/creators/app/files/.eslintignore +0 -16
  67. package/creators/app/files/.eslintrc.js +0 -173
  68. package/creators/app/files/.gitignore +0 -70
  69. package/creators/app/files/.gitlab-ci.yml +0 -14
  70. package/creators/app/files/.vscode/settings.json +0 -21
  71. package/creators/app/files/babel.config.js +0 -1
  72. package/creators/app/files/tsconfig.json +0 -42
  73. package/creators/app/files/vue.config.js +0 -6
  74. package/creators/app/init +0 -120
  75. package/creators/app/package.json +0 -25
  76. package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +0 -24
  77. package/creators/pkg/files/.github/workflows/build-extension-charts.yml +0 -22
  78. package/creators/pkg/files/babel.config.js +0 -1
  79. package/creators/pkg/files/index.ts +0 -14
  80. package/creators/pkg/files/tsconfig.json +0 -53
  81. package/creators/pkg/files/vue.config.js +0 -1
  82. package/creators/pkg/init +0 -286
  83. package/creators/pkg/package.json +0 -19
  84. package/creators/pkg/pkg.package.json +0 -21
  85. package/creators/pkg/vue-shim.ts +0 -4
  86. package/creators/update/init +0 -56
  87. package/creators/update/package.json +0 -20
  88. package/creators/update/upgrade +0 -56
  89. package/types/shell/index.d.ts +0 -4585
@@ -68,6 +68,36 @@ export const UI_PLUGIN_METADATA = {
68
68
  DISPLAY_NAME: 'displayName',
69
69
  };
70
70
 
71
+ export const EXTENSIONS_INCOMPATIBILITY_TYPES = {
72
+ UI: 'uiVersion',
73
+ EXTENSIONS_API: 'extensionsApiVersion',
74
+ KUBE: 'kubeVersion',
75
+ HOST: 'host'
76
+ };
77
+
78
+ export const EXTENSIONS_INCOMPATIBILITY_DATA = {
79
+ UI: {
80
+ type: EXTENSIONS_INCOMPATIBILITY_TYPES.UI,
81
+ cardMessageKey: 'plugins.incompatibleRancherVersion',
82
+ tooltipKey: 'plugins.info.requiresRancherVersion',
83
+ },
84
+ EXTENSIONS_API: {
85
+ type: EXTENSIONS_INCOMPATIBILITY_TYPES.EXTENSIONS_API,
86
+ cardMessageKey: 'plugins.incompatibleUiExtensionsApiVersion',
87
+ tooltipKey: 'plugins.info.requiresExtensionApiVersion',
88
+ },
89
+ KUBE: {
90
+ type: EXTENSIONS_INCOMPATIBILITY_TYPES.KUBE,
91
+ cardMessageKey: 'plugins.incompatibleKubeVersion',
92
+ tooltipKey: 'plugins.info.requiresKubeVersion',
93
+ },
94
+ HOST: {
95
+ type: EXTENSIONS_INCOMPATIBILITY_TYPES.HOST,
96
+ cardMessageKey: 'plugins.incompatibleHost',
97
+ tooltipKey: 'plugins.info.requiresHost',
98
+ }
99
+ };
100
+
71
101
  export function isUIPlugin(chart) {
72
102
  return !!chart?.versions.find((v) => {
73
103
  return v.annotations && v.annotations[UI_PLUGIN_ANNOTATION_NAME] === UI_PLUGIN_ANNOTATION_VALUE;
@@ -91,130 +121,169 @@ export function uiPluginAnnotation(chart, name) {
91
121
  return undefined;
92
122
  }
93
123
 
124
+ /**
125
+ * Parse the rancher version string
126
+ */
127
+ function parseRancherVersion(v) {
128
+ let parsedRancherVersion = semver.coerce(v)?.version;
129
+ const splitArr = parsedRancherVersion.split('.');
130
+
131
+ // this is a scenario where we are on a "head" version of some sort... we can't infer the patch version from it
132
+ // so we apply a big patch version number to make sure we follow through with the minor
133
+ if (v.includes('-') && splitArr?.length === 3) {
134
+ parsedRancherVersion = `${ splitArr[0] }.${ splitArr[1] }.999`;
135
+ }
136
+
137
+ return parsedRancherVersion;
138
+ }
139
+
94
140
  // i18n-uses plugins.error.generic, plugins.error.api, plugins.error.host
95
141
 
96
- // Should we load a plugin, based on the metadata returned by the backend?
97
- // Returns error key string or false
98
- export function shouldNotLoadPlugin(plugin, rancherVersion, loadedPlugins) {
99
- if (!plugin.name || !plugin.version || !plugin.endpoint) {
142
+ /**
143
+ * Whether an extension should be loaded based on the metadata returned by the backend in the UIPlugins resource instance
144
+ * @returns String || Boolean
145
+ */
146
+ export function shouldNotLoadPlugin(UIPluginResource, rancherVersion, loadedPlugins) {
147
+ if (!UIPluginResource.name || !UIPluginResource.version || !UIPluginResource.endpoint) {
100
148
  return 'plugins.error.generic';
101
149
  }
102
150
 
103
- // Plugin specified a required extension API version
151
+ // Extension chart specified a required extension API version
104
152
  // we are propagating the annotations in pkg/package.json for any extension
105
153
  // inside the "spec.plugin.metadata" property of UIPlugin resource
106
- const requiredAPI = plugin.spec?.plugin?.metadata?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
154
+ const requiredUiExtensionsVersion = UIPluginResource.spec?.plugin?.metadata?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
155
+ // semver.coerce will get rid of any suffix on the version numbering (-rc, -head, etc)
156
+ const parsedUiExtensionsApiVersion = semver.coerce(UI_EXTENSIONS_API_VERSION)?.version || UI_EXTENSIONS_API_VERSION;
157
+ const parsedRancherVersion = rancherVersion ? parseRancherVersion(rancherVersion) : '';
107
158
 
108
- if (requiredAPI && !semver.satisfies(UI_EXTENSIONS_API_VERSION, requiredAPI)) {
159
+ if (requiredUiExtensionsVersion && !semver.satisfies(parsedUiExtensionsApiVersion, requiredUiExtensionsVersion)) {
109
160
  return 'plugins.error.api';
110
161
  }
111
162
 
112
163
  // Host application
113
- const requiredHost = plugin.metadata?.[UI_PLUGIN_METADATA.EXTENSIONS_HOST];
164
+ const requiredHost = UIPluginResource.metadata?.[UI_PLUGIN_METADATA.EXTENSIONS_HOST];
114
165
 
115
166
  if (requiredHost && requiredHost !== UI_PLUGIN_HOST_APP) {
116
167
  return 'plugins.error.host';
117
168
  }
118
169
 
119
170
  // Rancher version
120
- if (rancherVersion) {
121
- const requiredRancherVersion = plugin.metadata?.[UI_PLUGIN_METADATA.RANCHER_VERSION];
171
+ if (parsedRancherVersion) {
172
+ const requiredRancherVersion = UIPluginResource.metadata?.[UI_PLUGIN_METADATA.RANCHER_VERSION];
122
173
 
123
- if (requiredRancherVersion && !semver.satisfies(rancherVersion, requiredRancherVersion)) {
174
+ if (requiredRancherVersion && !semver.satisfies(parsedRancherVersion, requiredRancherVersion)) {
124
175
  return 'plugins.error.version';
125
176
  }
126
177
  }
127
178
 
128
179
  // check if a builtin extension has been loaded before - improve developer experience
129
- const checkLoaded = loadedPlugins.find((p) => p?.name === plugin?.name);
180
+ const checkLoaded = loadedPlugins.find((p) => p?.name === UIPluginResource?.name);
130
181
 
131
182
  if (checkLoaded && checkLoaded.builtin) {
132
183
  return 'plugins.error.developerPkg';
133
184
  }
134
185
 
135
- if (plugin.metadata?.[UI_PLUGIN_LABELS.CATALOG]) {
186
+ if (UIPluginResource.metadata?.[UI_PLUGIN_LABELS.CATALOG]) {
136
187
  return true;
137
188
  }
138
189
 
139
190
  return false;
140
191
  }
141
192
 
142
- // Can a chart version be used for this Rancher (based on the annotations on the chart)?
143
- export function isSupportedChartVersion(versionsData) {
144
- const { version, rancherVersion, kubeVersion } = versionsData;
193
+ /**
194
+ * Wether an extension version is available to be installed, based on the annotations present in the Helm chart version
195
+ * backend may not automatically "limit" a particular version but dashboard will disable that version for install with this check
196
+ * @returns Boolean || Object
197
+ */
198
+ export function isSupportedChartVersion(versionData, returnObj = false) {
199
+ const { version, rancherVersion, kubeVersion } = versionData;
145
200
 
146
- // Plugin specified a required extension API version
147
- const requiredAPI = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
201
+ // semver.coerce will get rid of any suffix on the version numbering (-rc, -head, etc)
202
+ const parsedRancherVersion = rancherVersion ? parseRancherVersion(rancherVersion) : '';
203
+ const requiredUiVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.UI_VERSION];
204
+ const requiredKubeVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
205
+ const versionObj = { ...version };
148
206
 
149
- if (requiredAPI && !semver.satisfies(UI_EXTENSIONS_API_VERSION, requiredAPI)) {
150
- return false;
151
- }
207
+ // reset compatibility property
208
+ versionObj.isVersionCompatible = true;
209
+ versionObj.versionIncompatibilityData = {};
152
210
 
153
- // Host application
154
- const requiredHost = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST];
211
+ // check "catalog.cattle.io/kube-version" annotation
212
+ // we keep it as first check since there is a card notification to be displayed
213
+ // in case an extension version installed has an incompatibility with the kube version and is not loaded
214
+ if (kubeVersion && requiredKubeVersion && !semver.satisfies(kubeVersion, requiredKubeVersion)) {
215
+ if (!returnObj) {
216
+ return false;
217
+ }
155
218
 
156
- if (requiredHost && requiredHost !== UI_PLUGIN_HOST_APP) {
157
- return false;
219
+ versionObj.isVersionCompatible = false;
220
+ versionObj.versionIncompatibilityData = Object.assign({}, EXTENSIONS_INCOMPATIBILITY_DATA.KUBE);
221
+ versionObj.versionIncompatibilityData.required = requiredKubeVersion;
222
+
223
+ return versionObj;
158
224
  }
159
225
 
160
- // Rancher version
161
- if (rancherVersion) {
226
+ // we aren't on a "published" version of Rancher and therefore in a "-head" or similar
227
+ // Backend will NOT block an extension version from being available IF we are on HEAD versions!!
228
+ // we need to enforce that check if we are on a HEAD world
229
+ if (rancherVersion && rancherVersion.includes('-')) {
162
230
  const requiredRancherVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.RANCHER_VERSION];
163
231
 
164
- if (requiredRancherVersion && !semver.satisfies(rancherVersion, requiredRancherVersion)) {
165
- return false;
232
+ if (parsedRancherVersion && !semver.satisfies(parsedRancherVersion, requiredRancherVersion)) {
233
+ if (!returnObj) {
234
+ return false;
235
+ }
236
+
237
+ versionObj.isVersionCompatible = false;
238
+ versionObj.versionIncompatibilityData = Object.assign({}, EXTENSIONS_INCOMPATIBILITY_DATA.UI);
239
+ versionObj.versionIncompatibilityData.required = requiredRancherVersion;
240
+
241
+ return versionObj;
166
242
  }
167
243
  }
168
244
 
169
- // Kube version
170
- if (kubeVersion) {
171
- const requiredKubeVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
245
+ // check host application
246
+ const requiredHost = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_HOST];
172
247
 
173
- if (requiredKubeVersion && !semver.satisfies(kubeVersion, requiredKubeVersion)) {
248
+ if (requiredHost && requiredHost !== UI_PLUGIN_HOST_APP) {
249
+ if (!returnObj) {
174
250
  return false;
175
251
  }
176
- }
177
252
 
178
- return true;
179
- }
180
-
181
- export function isChartVersionAvailableForInstall(versionsData, returnObj = false) {
182
- const { version, rancherVersion, kubeVersion } = versionsData;
253
+ versionObj.isVersionCompatible = false;
254
+ versionObj.versionIncompatibilityData = Object.assign({}, EXTENSIONS_INCOMPATIBILITY_DATA.HOST);
255
+ versionObj.versionIncompatibilityData.required = requiredHost;
183
256
 
184
- const parsedRancherVersion = rancherVersion.split('-')?.[0];
185
- const regexHashString = new RegExp('^[A-Za-z0-9]{9}$');
186
- const isRancherVersionHashString = regexHashString.test(rancherVersion);
187
- const requiredUiVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.UI_VERSION];
188
- const requiredKubeVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
189
- const versionObj = { ...version };
257
+ return versionObj;
258
+ }
190
259
 
191
- versionObj.isCompatibleWithUi = true;
192
- versionObj.isCompatibleWithKubeVersion = true;
260
+ // check "catalog.cattle.io/ui-extensions-version" annotation
261
+ const requiredUiExtensionsApiVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.EXTENSIONS_VERSION];
262
+ const parsedUiExtensionsApiVersion = semver.coerce(UI_EXTENSIONS_API_VERSION)?.version || UI_EXTENSIONS_API_VERSION;
193
263
 
194
- // if it's a head version of Rancher, then we skip the validation and enable them all
195
- if (!isRancherVersionHashString && requiredUiVersion && !semver.satisfies(parsedRancherVersion, requiredUiVersion)) {
264
+ if (requiredUiExtensionsApiVersion && parsedUiExtensionsApiVersion && !semver.satisfies(parsedUiExtensionsApiVersion, requiredUiExtensionsApiVersion)) {
196
265
  if (!returnObj) {
197
266
  return false;
198
267
  }
199
- versionObj.isCompatibleWithUi = false;
200
- versionObj.requiredUiVersion = requiredUiVersion;
201
268
 
202
- if (returnObj) {
203
- return versionObj;
204
- }
269
+ versionObj.isVersionCompatible = false;
270
+ versionObj.versionIncompatibilityData = Object.assign({}, EXTENSIONS_INCOMPATIBILITY_DATA.EXTENSIONS_API);
271
+ versionObj.versionIncompatibilityData.required = requiredUiExtensionsApiVersion;
272
+
273
+ return versionObj;
205
274
  }
206
275
 
207
- // check kube version
208
- if (kubeVersion && requiredKubeVersion && !semver.satisfies(kubeVersion, requiredKubeVersion)) {
276
+ // check "catalog.cattle.io/ui-version" annotation
277
+ if (requiredUiVersion && parsedRancherVersion && !semver.satisfies(parsedRancherVersion, requiredUiVersion)) {
209
278
  if (!returnObj) {
210
279
  return false;
211
280
  }
212
- versionObj.isCompatibleWithKubeVersion = false;
213
- versionObj.requiredKubeVersion = requiredKubeVersion;
214
281
 
215
- if (returnObj) {
216
- return versionObj;
217
- }
282
+ versionObj.isVersionCompatible = false;
283
+ versionObj.versionIncompatibilityData = Object.assign({}, EXTENSIONS_INCOMPATIBILITY_DATA.UI);
284
+ versionObj.versionIncompatibilityData.required = requiredUiVersion;
285
+
286
+ return versionObj;
218
287
  }
219
288
 
220
289
  if (returnObj) {
package/core/plugin.ts CHANGED
@@ -132,6 +132,11 @@ export class Plugin implements IPlugin {
132
132
  console.warn(`Layouts have been deprecated. We still have parent routes which use the same name and styling as the previous layouts. You should specify a parent, we're currently setting the parent to 'default'`); // eslint-disable-line no-console
133
133
  parentOverride = 'default';
134
134
  }
135
+
136
+ // Fix for Home page components with wrong layout - need to ensure the parentOverride is set
137
+ if (typelessRoute.component && typelessRoute.name === 'home' && typelessRoute.path === '/home') {
138
+ parentOverride = 'home_layout';
139
+ }
135
140
  }
136
141
 
137
142
  route.meta = {
package/core/plugins.js CHANGED
@@ -90,6 +90,10 @@ export default function(context, inject, vueApp) {
90
90
  delete window[oldPlugin.id];
91
91
 
92
92
  delete plugins[oldPlugin.id];
93
+
94
+ const oldElement = document.getElementById(oldPlugin.id);
95
+
96
+ oldElement.parentElement.removeChild(oldElement);
93
97
  });
94
98
  }
95
99
 
@@ -124,7 +128,9 @@ export default function(context, inject, vueApp) {
124
128
  };
125
129
 
126
130
  element.onerror = (e) => {
127
- // Massage the error into something useful
131
+ element.parentElement.removeChild(element);
132
+
133
+ // Massage the error into something useful
128
134
  const errorMessage = `Failed to load script from '${ e.target.src }'`;
129
135
 
130
136
  console.error(errorMessage, e); // eslint-disable-line no-console
@@ -27,19 +27,36 @@ const defaultComputed = {
27
27
  const mockAgentArgs = { 'cloud-provider-name': { options: [], profile: { options: [{ anything: 'yes' }] } } };
28
28
  const mockServerArgs = { disable: {}, cni: { options: [] } };
29
29
 
30
- const rke2Versions =
31
- [
32
- {
33
- id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
34
- },
35
- {
36
- id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
37
- },
38
- {
39
- id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
40
- }
41
- ];
30
+ const rke2Versions = [
31
+ {
32
+ id: 'v1.31.0+rke2r1', value: 'v1.31.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
33
+ },
34
+ {
35
+ id: 'v1.30.0+rke2r1', value: 'v1.30.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
36
+ },
37
+ {
38
+ id: 'v1.29.1+rke2r1', value: 'v1.29.1+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
39
+ },
40
+ {
41
+ id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
42
+ },
43
+ {
44
+ id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
45
+ },
46
+ {
47
+ id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
48
+ }
49
+ ];
42
50
  const k3sVersions = [
51
+ {
52
+ id: 'v1.31.0+k3s1', value: 'v1.31.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
53
+ },
54
+ {
55
+ id: 'v1.30.0+k3s1', value: 'v1.30.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
56
+ },
57
+ {
58
+ id: 'v1.29.1+k3s1', value: 'v1.29.1+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
59
+ },
43
60
  {
44
61
  id: 'v1.25.0+k3s1', value: 'v1.25.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
45
62
  },
@@ -88,7 +105,7 @@ const newOffValue = { ipv6: { enabled: false } };
88
105
  const bmOnValue = { bandwidthManager: { enabled: true } };
89
106
  const bmOffValue = { bandwidthManager: { enabled: false } };
90
107
 
91
- function createBasicsTab(version : string, userChartValues: any) {
108
+ function createBasicsTab(version : string, userChartValues: any, options = {}) {
92
109
  const k8s = mockVersionOptions.find((v) => v.id === version) || mockVersionOptions[0];
93
110
  const label = 'whatever';
94
111
  const wrapper = mount(Basics, {
@@ -122,6 +139,7 @@ function createBasicsTab(version : string, userChartValues: any) {
122
139
  showCloudProvider: false,
123
140
  unsupportedCloudProvider: false,
124
141
  cloudProviderOptions: [{ label: 'Default - RKE2 Embedded', value: '' }],
142
+ ...options
125
143
  },
126
144
  computed: defaultComputed,
127
145
  mocks: {
@@ -470,4 +488,59 @@ describe('component: Basics', () => {
470
488
 
471
489
  expect(JSON.stringify(latest)).toStrictEqual(expected);
472
490
  });
491
+
492
+ it.each([
493
+ ['create', true, true, '%cluster.banner.cloudProviderUnsupportedAzure%'],
494
+ ['create', false, true, undefined],
495
+ ['create', true, false, undefined],
496
+ ['edit', true, true, undefined],
497
+ ['view', true, true, undefined],
498
+ ])('should display Unsupported Azure provider warning message', (mode, showCloudProvider, isAzureProviderUnsupported, warningMessage) => {
499
+ const wrapper = createBasicsTab('v1.31.0+rke2r1', {}, {
500
+ mode,
501
+ showCloudProvider,
502
+ isAzureProviderUnsupported,
503
+ canAzureMigrateOnEdit: true
504
+ });
505
+
506
+ const cloudProviderUnsupportedAzureWarningMessage = wrapper.find('[data-testid="clusterBasics__showCloudProviderUnsupportedAzureWarning"]')?.element?.textContent;
507
+
508
+ expect(cloudProviderUnsupportedAzureWarningMessage).toBe(warningMessage);
509
+ });
510
+
511
+ it.each([
512
+ ['edit', true, true, '%cluster.banner.cloudProviderMigrateAzure%'],
513
+ ['edit', false, true, undefined],
514
+ ['edit', true, false, undefined],
515
+ ['create', true, true, undefined],
516
+ ['view', true, true, undefined],
517
+ ])('should display Azure Migration warning message', (mode, showCloudProvider, canAzureMigrateOnEdit, warningMessage) => {
518
+ const wrapper = createBasicsTab('v1.31.0+rke2r1', {}, {
519
+ mode,
520
+ showCloudProvider,
521
+ canAzureMigrateOnEdit,
522
+ isAzureProviderUnsupported: true,
523
+ });
524
+
525
+ const cloudProviderMigrateAzureWarningMessage = wrapper.find('[data-testid="clusterBasics__showCloudProviderMigrateAzureWarning"]')?.element?.textContent;
526
+
527
+ expect(cloudProviderMigrateAzureWarningMessage).toBe(warningMessage);
528
+ });
529
+
530
+ it.each([
531
+ ['create', true, false],
532
+ ['edit', false, true],
533
+ ['edit', true, false],
534
+ ['view', true, false],
535
+ ])('should disable Cloud Provider', (mode, canAzureMigrateOnEdit, disabled) => {
536
+ const wrapper = createBasicsTab('v1.31.0+rke2r1', {}, {
537
+ mode,
538
+ showCloudProvider: true,
539
+ canAzureMigrateOnEdit,
540
+ });
541
+
542
+ const cloudProvider = wrapper.find('[data-testid="clusterBasics__cloudProvider"]');
543
+
544
+ expect(cloudProvider.props().disabled).toBe(disabled);
545
+ });
473
546
  });
@@ -33,39 +33,15 @@ describe('component: DirectoryConfig', () => {
33
33
  );
34
34
 
35
35
  const title = wrapper.find('h3');
36
- const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
37
- const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
38
36
  const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
39
37
  const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
40
38
  const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
41
39
 
42
40
  expect(title.exists()).toBe(true);
43
- expect(checkbox.exists()).toBe(true);
44
- // for the default config, checkbox should be checked
45
- expect(wrapper.vm.isSettingCommonConfig).toBe(true);
46
- expect(commonInput.exists()).toBe(true);
47
-
48
- // since we have all of the vars empty, then the individual inputs should not be there
49
- expect(systemAgentInput.exists()).toBe(false);
50
- expect(provisioningInput.exists()).toBe(false);
51
- expect(k8sDistroInput.exists()).toBe(false);
52
- });
53
-
54
- it('updating common config path should set the correct values on each data dir variable', async() => {
55
- wrapper = mount(
56
- DirectoryConfig,
57
- mountOptions
58
- );
59
41
 
60
- const inputPath = 'some-data-dir';
61
- const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
62
-
63
- commonInput.setValue(inputPath);
64
- await wrapper.vm.$nextTick();
65
-
66
- expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath);
67
- expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath);
68
- expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath);
42
+ expect(systemAgentInput.exists()).toBe(true);
43
+ expect(provisioningInput.exists()).toBe(true);
44
+ expect(k8sDistroInput.exists()).toBe(true);
69
45
  });
70
46
 
71
47
  it('updating each individual data dir should set the correct values on each data dir variable', async() => {
@@ -75,13 +51,6 @@ describe('component: DirectoryConfig', () => {
75
51
  );
76
52
 
77
53
  const inputPath = 'some-data-dir';
78
- const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
79
-
80
- await checkbox.find('label').trigger('click');
81
- await checkbox.vm.$nextTick();
82
- await wrapper.vm.$nextTick();
83
-
84
- expect(wrapper.vm.isSettingCommonConfig).toBe(false);
85
54
 
86
55
  const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
87
56
  const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
@@ -97,101 +66,6 @@ describe('component: DirectoryConfig', () => {
97
66
  expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath);
98
67
  });
99
68
 
100
- it('checkbox should be checked if all data dir values are the same (with all data dir values filled)', () => {
101
- const newMountOptions = clone(mountOptions);
102
- const inputPath = 'some-data-dir';
103
-
104
- newMountOptions.propsData.value.systemAgent = inputPath;
105
- newMountOptions.propsData.value.provisioning = inputPath;
106
- newMountOptions.propsData.value.k8sDistro = inputPath;
107
-
108
- wrapper = mount(
109
- DirectoryConfig,
110
- newMountOptions
111
- );
112
-
113
- const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
114
-
115
- expect(checkbox.exists()).toBe(true);
116
- expect(wrapper.vm.isSettingCommonConfig).toBe(true);
117
-
118
- const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
119
- const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
120
- const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
121
- const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
122
-
123
- expect(commonInput.exists()).toBe(true);
124
- expect(systemAgentInput.exists()).toBe(false);
125
- expect(provisioningInput.exists()).toBe(false);
126
- expect(k8sDistroInput.exists()).toBe(false);
127
-
128
- expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath);
129
- expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath);
130
- expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath);
131
- });
132
-
133
- it('checkbox should NOT be checked if some data dir values are the different (with all data dir values filled)', () => {
134
- const newMountOptions = clone(mountOptions);
135
- const inputPath1 = 'some-data-dir1';
136
- const inputPath2 = 'some-data-dir2';
137
- const inputPath3 = 'some-data-dir3';
138
-
139
- newMountOptions.propsData.value.systemAgent = inputPath1;
140
- newMountOptions.propsData.value.provisioning = inputPath2;
141
- newMountOptions.propsData.value.k8sDistro = inputPath3;
142
-
143
- wrapper = mount(
144
- DirectoryConfig,
145
- newMountOptions
146
- );
147
-
148
- expect(wrapper.vm.isSettingCommonConfig).toBe(false);
149
-
150
- const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
151
- const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
152
- const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
153
- const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
154
-
155
- expect(commonInput.exists()).toBe(false);
156
- expect(systemAgentInput.exists()).toBe(true);
157
- expect(provisioningInput.exists()).toBe(true);
158
- expect(k8sDistroInput.exists()).toBe(true);
159
-
160
- expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath1);
161
- expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath2);
162
- expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath3);
163
- });
164
-
165
- it('on a mode different than _CREATE all visible inputs should be disabled (with common config)', () => {
166
- const newMountOptions = clone(mountOptions);
167
- const inputPath = 'some-data-dir';
168
-
169
- newMountOptions.propsData.value.systemAgent = inputPath;
170
- newMountOptions.propsData.value.provisioning = inputPath;
171
- newMountOptions.propsData.value.k8sDistro = inputPath;
172
- newMountOptions.propsData.mode = _EDIT;
173
-
174
- wrapper = mount(
175
- DirectoryConfig,
176
- newMountOptions
177
- );
178
-
179
- const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
180
- const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
181
- const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
182
- const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
183
- const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
184
-
185
- expect(checkbox.exists()).toBe(true);
186
- expect(commonInput.exists()).toBe(true);
187
- expect(systemAgentInput.exists()).toBe(false);
188
- expect(provisioningInput.exists()).toBe(false);
189
- expect(k8sDistroInput.exists()).toBe(false);
190
-
191
- expect(checkbox.find('label').classes('disabled')).toBe(true);
192
- expect(commonInput.attributes('disabled')).toBe('disabled');
193
- });
194
-
195
69
  it('on a mode different than _CREATE all visible inputs should be disabled (with different values)', () => {
196
70
  const newMountOptions = clone(mountOptions);
197
71
  const inputPath1 = 'some-data-dir1';
@@ -208,19 +82,14 @@ describe('component: DirectoryConfig', () => {
208
82
  newMountOptions
209
83
  );
210
84
 
211
- const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
212
- const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
213
85
  const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
214
86
  const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
215
87
  const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
216
88
 
217
- expect(checkbox.exists()).toBe(true);
218
- expect(commonInput.exists()).toBe(false);
219
89
  expect(systemAgentInput.exists()).toBe(true);
220
90
  expect(provisioningInput.exists()).toBe(true);
221
91
  expect(k8sDistroInput.exists()).toBe(true);
222
92
 
223
- expect(checkbox.find('label').classes('disabled')).toBe(true);
224
93
  expect(systemAgentInput.attributes('disabled')).toBe('disabled');
225
94
  expect(provisioningInput.attributes('disabled')).toBe('disabled');
226
95
  expect(k8sDistroInput.attributes('disabled')).toBe('disabled');