@rancher/shell 3.0.1-rc.3 → 3.0.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.
- package/assets/data/aws-regions.json +1 -0
- package/assets/styles/base/_basic.scss +5 -0
- package/assets/styles/base/_mixins.scss +8 -0
- package/assets/styles/global/_button.scss +5 -0
- package/assets/styles/themes/_dark.scss +2 -0
- package/assets/styles/themes/_light.scss +2 -0
- package/assets/translations/en-us.yaml +40 -22
- package/assets/translations/zh-hans.yaml +1 -7
- package/chart/monitoring/StorageClassSelector.vue +1 -1
- package/components/AssignTo.vue +1 -0
- package/components/AsyncButton.vue +1 -0
- package/components/BackLink.vue +8 -2
- package/components/PaginatedResourceTable.vue +135 -0
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceDetail/index.vue +66 -11
- package/components/ResourceList/index.vue +0 -1
- package/components/ResourceTable.vue +6 -1
- package/components/ResourceYaml.vue +0 -53
- package/components/SortableTable/index.vue +8 -6
- package/components/Tabbed/index.vue +35 -2
- package/components/form/ResourceLabeledSelect.vue +2 -2
- package/components/form/ResourceTabs/index.vue +0 -23
- package/components/form/Taints.vue +1 -1
- package/components/form/UnitInput.vue +1 -1
- package/components/form/__tests__/UnitInput.test.ts +1 -1
- package/components/nav/TopLevelMenu.helper.ts +546 -0
- package/components/nav/TopLevelMenu.vue +125 -160
- package/components/nav/WindowManager/ContainerShell.vue +13 -4
- package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +20 -18
- package/components/nav/__tests__/TopLevelMenu.test.ts +338 -326
- package/composables/useLabeledFormElement.ts +6 -2
- package/config/pagination-table-headers.js +4 -4
- package/config/product/explorer.js +2 -0
- package/config/router/navigation-guards/index.js +1 -2
- package/config/router/routes.js +1 -1
- package/config/settings.ts +15 -8
- package/core/plugin.ts +8 -1
- package/core/types-provisioning.ts +5 -0
- package/core/types.ts +26 -1
- package/dialog/DrainNode.vue +6 -6
- package/edit/catalog.cattle.io.clusterrepo.vue +95 -52
- package/edit/provisioning.cattle.io.cluster/index.vue +8 -3
- package/edit/workload/index.vue +1 -1
- package/edit/workload/storage/csi/index.vue +29 -1
- package/edit/workload/storage/index.vue +1 -0
- package/initialize/App.vue +3 -10
- package/initialize/install-plugins.js +1 -2
- package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +6 -2
- package/list/node.vue +8 -5
- package/mixins/resource-fetch-api-pagination.js +40 -5
- package/mixins/resource-fetch.js +48 -5
- package/models/management.cattle.io.nodepool.js +5 -4
- package/models/nodedriver.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +3 -11
- package/package.json +7 -8
- package/pages/about.vue +22 -0
- package/pages/auth/setup.vue +7 -28
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +36 -24
- package/pages/c/_cluster/explorer/index.vue +100 -59
- package/pages/home.vue +308 -123
- package/plugins/dashboard-store/__tests__/mutations.test.ts +2 -0
- package/plugins/dashboard-store/actions.js +29 -19
- package/plugins/dashboard-store/getters.js +5 -2
- package/plugins/dashboard-store/mutations.js +4 -2
- package/plugins/steve/__tests__/mutations.test.ts +2 -1
- package/plugins/steve/steve-pagination-utils.ts +25 -2
- package/plugins/steve/subscribe.js +22 -8
- package/rancher-components/Banner/Banner.vue +1 -0
- package/rancher-components/Form/Checkbox/Checkbox.vue +2 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +2 -0
- package/rancher-components/Form/Radio/RadioButton.vue +2 -0
- package/rancher-components/Form/Radio/RadioGroup.vue +2 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +2 -0
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +3 -0
- package/rancher-components/StringList/StringList.test.ts +15 -15
- package/rancher-components/StringList/StringList.vue +3 -0
- package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +0 -2
- package/scripts/extension/parse-tag-name +2 -0
- package/scripts/test-plugins-build.sh +4 -2
- package/store/index.js +31 -9
- package/tsconfig.json +7 -1
- package/types/resources/settings.d.ts +1 -1
- package/types/shell/index.d.ts +1107 -1276
- package/types/store/dashboard-store.types.ts +4 -0
- package/types/store/pagination.types.ts +13 -0
- package/types/store/vuex.d.ts +8 -0
- package/types/vue-shim.d.ts +6 -31
- package/utils/cluster.js +92 -1
- package/utils/pagination-utils.ts +17 -8
- package/utils/pagination-wrapper.ts +70 -0
- package/utils/uiplugins.ts +307 -0
- package/components/templates/error.vue +0 -131
- package/config/router/navigation-guards/history.js +0 -13
- package/plugins/back-button.js +0 -3
|
@@ -19,13 +19,17 @@ export default {
|
|
|
19
19
|
required: true,
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
|
+
emits: ['error'],
|
|
22
23
|
|
|
23
24
|
async fetch() {
|
|
24
25
|
const inStore = this.$store.getters['currentStore']();
|
|
25
26
|
|
|
27
|
+
try {
|
|
26
28
|
// Fetch storage classes so we can determine if a PVC can be expanded
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
await this.$store.dispatch(`${ inStore }/findAll`, { type: STORAGE_CLASS });
|
|
30
|
+
} catch (e) {
|
|
31
|
+
this.$emit('error', e?.data || e);
|
|
32
|
+
}
|
|
29
33
|
await this.$fetchType(this.resource);
|
|
30
34
|
}
|
|
31
35
|
};
|
package/list/node.vue
CHANGED
|
@@ -21,6 +21,7 @@ import { COLUMN_BREAKPOINTS } from '@shell/types/store/type-map';
|
|
|
21
21
|
|
|
22
22
|
import ResourceFetch from '@shell/mixins/resource-fetch';
|
|
23
23
|
import { mapGetters } from 'vuex';
|
|
24
|
+
import { FetchPageSecondaryResourcesOpts } from 'components/PaginatedResourceTable.vue';
|
|
24
25
|
|
|
25
26
|
export default defineComponent({
|
|
26
27
|
name: 'ListNode',
|
|
@@ -36,10 +37,12 @@ export default defineComponent({
|
|
|
36
37
|
type: String,
|
|
37
38
|
required: true,
|
|
38
39
|
},
|
|
40
|
+
|
|
39
41
|
schema: {
|
|
40
42
|
type: Object,
|
|
41
43
|
required: true,
|
|
42
44
|
},
|
|
45
|
+
|
|
43
46
|
useQueryParamsForSimpleFiltering: {
|
|
44
47
|
type: Boolean,
|
|
45
48
|
default: false
|
|
@@ -209,8 +212,8 @@ export default defineComponent({
|
|
|
209
212
|
*
|
|
210
213
|
* So when we have a page.... use those entries as filters when fetching the other resources
|
|
211
214
|
*/
|
|
212
|
-
async fetchPageSecondaryResources(force
|
|
213
|
-
if (!
|
|
215
|
+
async fetchPageSecondaryResources({ canPaginate, force, page }: FetchPageSecondaryResourcesOpts) {
|
|
216
|
+
if (!page?.length) {
|
|
214
217
|
return;
|
|
215
218
|
}
|
|
216
219
|
|
|
@@ -220,7 +223,7 @@ export default defineComponent({
|
|
|
220
223
|
const opt: ActionFindPageArgs = {
|
|
221
224
|
force,
|
|
222
225
|
pagination: new FilterArgs({
|
|
223
|
-
filters: PaginationParamFilter.createMultipleFields(
|
|
226
|
+
filters: PaginationParamFilter.createMultipleFields(page.map((r: any) => new PaginationFilterField({
|
|
224
227
|
field: 'status.nodeName',
|
|
225
228
|
value: r.id
|
|
226
229
|
}))),
|
|
@@ -242,7 +245,7 @@ export default defineComponent({
|
|
|
242
245
|
namespaced: namespace,
|
|
243
246
|
pagination: new FilterArgs({
|
|
244
247
|
filters: PaginationParamFilter.createMultipleFields(
|
|
245
|
-
|
|
248
|
+
page.reduce((res: PaginationFilterField[], r: any ) => {
|
|
246
249
|
const name = r.metadata?.annotations?.[CAPI_ANNOTATIONS.MACHINE_NAME];
|
|
247
250
|
|
|
248
251
|
if (name) {
|
|
@@ -268,7 +271,7 @@ export default defineComponent({
|
|
|
268
271
|
force,
|
|
269
272
|
pagination: new FilterArgs({
|
|
270
273
|
filters: PaginationParamFilter.createMultipleFields(
|
|
271
|
-
|
|
274
|
+
page.map((r: any) => new PaginationFilterField({
|
|
272
275
|
field: 'spec.nodeName',
|
|
273
276
|
value: r.id,
|
|
274
277
|
}))
|
|
@@ -13,6 +13,21 @@ import stevePaginationUtils from '@shell/plugins/steve/steve-pagination-utils';
|
|
|
13
13
|
*/
|
|
14
14
|
export default {
|
|
15
15
|
|
|
16
|
+
props: {
|
|
17
|
+
namespaced: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: null, // Automatic from schema
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Where in the ui this mixin is used. For instance the home page cluster list would be `home`
|
|
24
|
+
*/
|
|
25
|
+
context: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: null,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
|
|
16
31
|
data() {
|
|
17
32
|
return {
|
|
18
33
|
forceUpdateLiveAndDelayed: 0,
|
|
@@ -68,7 +83,7 @@ export default {
|
|
|
68
83
|
},
|
|
69
84
|
|
|
70
85
|
namespaceFilterChanged(neu) {
|
|
71
|
-
if (!this.canPaginate || !this.
|
|
86
|
+
if (!this.canPaginate || !this.isNamespaced) {
|
|
72
87
|
return;
|
|
73
88
|
}
|
|
74
89
|
|
|
@@ -166,7 +181,16 @@ export default {
|
|
|
166
181
|
return;
|
|
167
182
|
}
|
|
168
183
|
|
|
169
|
-
|
|
184
|
+
if (!this.resource) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const args = {
|
|
189
|
+
id: this.resource.id || this.resource,
|
|
190
|
+
context: this.context,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return this.resource && this.$store.getters[`${ this.inStore }/paginationEnabled`]?.(args);
|
|
170
194
|
},
|
|
171
195
|
|
|
172
196
|
paginationResult() {
|
|
@@ -182,7 +206,7 @@ export default {
|
|
|
182
206
|
return;
|
|
183
207
|
}
|
|
184
208
|
|
|
185
|
-
return this.$store.getters[`${ this.
|
|
209
|
+
return this.$store.getters[`${ this.inStore }/havePage`](this.resource);
|
|
186
210
|
},
|
|
187
211
|
|
|
188
212
|
/**
|
|
@@ -197,6 +221,15 @@ export default {
|
|
|
197
221
|
*/
|
|
198
222
|
showDynamicRancherNamespaces() {
|
|
199
223
|
return this.$store.getters['prefs/get'](ALL_NAMESPACES);
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
isNamespaced() {
|
|
227
|
+
if (this.namespaced !== null) { // null is the default value
|
|
228
|
+
// This is an override, but only if it's set
|
|
229
|
+
return !!this.namespaced;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return this.schema?.attributes?.namespaced;
|
|
200
233
|
}
|
|
201
234
|
},
|
|
202
235
|
|
|
@@ -221,7 +254,7 @@ export default {
|
|
|
221
254
|
namespaceFilters: {
|
|
222
255
|
immediate: true,
|
|
223
256
|
async handler(neu, old) {
|
|
224
|
-
if (!this.canPaginate || !this.
|
|
257
|
+
if (!this.canPaginate || !this.isNamespaced) {
|
|
225
258
|
return;
|
|
226
259
|
}
|
|
227
260
|
|
|
@@ -298,7 +331,9 @@ export default {
|
|
|
298
331
|
return;
|
|
299
332
|
}
|
|
300
333
|
|
|
301
|
-
await this.fetchPageSecondaryResources(
|
|
334
|
+
await this.fetchPageSecondaryResources({
|
|
335
|
+
canPaginate: this.canPaginate, force: false, page: this.rows, pagResult: this.paginationResult
|
|
336
|
+
});
|
|
302
337
|
}
|
|
303
338
|
},
|
|
304
339
|
};
|
package/mixins/resource-fetch.js
CHANGED
|
@@ -31,11 +31,18 @@ export default {
|
|
|
31
31
|
perfConfig = DEFAULT_PERF_SETTING;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Normally owner components supply `resource` and `inStore` as part of their data, however these are needed here before parent data runs
|
|
35
|
+
// So set up both here
|
|
36
|
+
const params = { ...this.$route.params };
|
|
37
|
+
const resource = params.resource || this.schema?.id; // Resource can either be on a page showing single list, or a page of a resource showing a list of another resource
|
|
38
|
+
const inStore = this.$store.getters['currentStore'](resource);
|
|
39
|
+
|
|
34
40
|
return {
|
|
41
|
+
inStore,
|
|
35
42
|
perfConfig,
|
|
36
43
|
init: false,
|
|
37
44
|
multipleResources: [],
|
|
38
|
-
loadResources: [
|
|
45
|
+
loadResources: [resource],
|
|
39
46
|
// manual refresh vars
|
|
40
47
|
hasManualRefresh: false,
|
|
41
48
|
watch: true,
|
|
@@ -60,17 +67,47 @@ export default {
|
|
|
60
67
|
}
|
|
61
68
|
},
|
|
62
69
|
|
|
70
|
+
props: {
|
|
71
|
+
/**
|
|
72
|
+
* Add additional filtering to the rows
|
|
73
|
+
*
|
|
74
|
+
* Should only be used when we have all results, otherwise we're filtering a page which already has been filtered...
|
|
75
|
+
*/
|
|
76
|
+
localFilter: {
|
|
77
|
+
type: Function,
|
|
78
|
+
default: null,
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Add additional filtering to the pagination api request
|
|
83
|
+
*/
|
|
84
|
+
apiFilter: {
|
|
85
|
+
type: Function,
|
|
86
|
+
default: null,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
|
|
63
90
|
computed: {
|
|
64
91
|
...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }),
|
|
92
|
+
|
|
65
93
|
rows() {
|
|
66
94
|
const currResource = this.fetchedResourceType.find((item) => item.type === this.resource);
|
|
67
95
|
|
|
68
96
|
if (currResource) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
const rows = this.$store.getters[`${ currResource.currStore }/all`](this.resource);
|
|
98
|
+
|
|
99
|
+
if (this.canPaginate) {
|
|
100
|
+
if (this.havePaginated) {
|
|
101
|
+
return rows;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
return this.localFilter ? this.localFilter(rows) : rows;
|
|
105
|
+
}
|
|
72
106
|
}
|
|
107
|
+
|
|
108
|
+
return [];
|
|
73
109
|
},
|
|
110
|
+
|
|
74
111
|
loading() {
|
|
75
112
|
if (this.canPaginate) {
|
|
76
113
|
return this.paginating;
|
|
@@ -86,7 +123,9 @@ export default {
|
|
|
86
123
|
if (this.init && neu) {
|
|
87
124
|
await this.$fetch();
|
|
88
125
|
if (this.canPaginate && this.fetchPageSecondaryResources) {
|
|
89
|
-
this.fetchPageSecondaryResources(
|
|
126
|
+
this.fetchPageSecondaryResources({
|
|
127
|
+
canPaginate: this.canPaginate, force: true, page: this.rows, pagResult: this.paginationResult
|
|
128
|
+
});
|
|
90
129
|
}
|
|
91
130
|
}
|
|
92
131
|
}
|
|
@@ -140,6 +179,10 @@ export default {
|
|
|
140
179
|
force: this.paginating !== null // Fix for manual refresh (before ripped out).
|
|
141
180
|
};
|
|
142
181
|
|
|
182
|
+
if (this.apiFilter) {
|
|
183
|
+
opt.paginating = this.apiFilter(opt.pagination);
|
|
184
|
+
}
|
|
185
|
+
|
|
143
186
|
this['paginating'] = true;
|
|
144
187
|
|
|
145
188
|
const that = this;
|
|
@@ -4,11 +4,12 @@ import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
|
4
4
|
import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
|
|
5
5
|
|
|
6
6
|
export default class MgmtNodePool extends HybridModel {
|
|
7
|
-
get
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
get nodeTemplateId() {
|
|
8
|
+
return (this.spec?.nodeTemplateName || '').replace(/:/, '/');
|
|
9
|
+
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
get nodeTemplate() {
|
|
12
|
+
return this.$getters['byId'](MANAGEMENT.NODE_TEMPLATE, this.nodeTemplateId);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
get provider() {
|
package/models/nodedriver.js
CHANGED
|
@@ -18,7 +18,7 @@ export default class NodeDriver extends Driver {
|
|
|
18
18
|
icon: 'icon icon-play',
|
|
19
19
|
bulkable: true,
|
|
20
20
|
bulkAction: 'activateBulk',
|
|
21
|
-
enabled: !!this.actions
|
|
21
|
+
enabled: !!this.actions?.activate && this.state === 'inactive',
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
action: 'deactivate',
|
|
@@ -26,7 +26,7 @@ export default class NodeDriver extends Driver {
|
|
|
26
26
|
icon: 'icon icon-pause',
|
|
27
27
|
bulkable: true,
|
|
28
28
|
bulkAction: 'deactivateBulk',
|
|
29
|
-
enabled: !!this.actions
|
|
29
|
+
enabled: !!this.actions?.deactivate && this.state === 'active',
|
|
30
30
|
weight: -1,
|
|
31
31
|
},
|
|
32
32
|
{ divider: true },
|
|
@@ -245,7 +245,7 @@ export default class ProvCluster extends SteveModel {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
get canDelete() {
|
|
248
|
-
return super.canDelete && this.stateObj
|
|
248
|
+
return super.canDelete && this.stateObj?.name !== 'removing';
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
get canEditYaml() {
|
|
@@ -349,19 +349,11 @@ export default class ProvCluster extends SteveModel {
|
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
get mgmtClusterId() {
|
|
352
|
-
return this.
|
|
352
|
+
return this.status?.clusterName;
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
get mgmt() {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
if ( !name ) {
|
|
359
|
-
return null;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const out = this.$rootGetters['management/byId'](MANAGEMENT.CLUSTER, name);
|
|
363
|
-
|
|
364
|
-
return out;
|
|
356
|
+
return this.$rootGetters['management/byId'](MANAGEMENT.CLUSTER, this.mgmtClusterId);
|
|
365
357
|
}
|
|
366
358
|
|
|
367
359
|
get isReady() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.1
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancherlabs/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@popperjs/core": "2.4.4",
|
|
40
40
|
"@rancher/icons": "2.0.29",
|
|
41
41
|
"@types/is-url": "1.2.30",
|
|
42
|
-
"@types/node": "
|
|
42
|
+
"@types/node": "20.10.8",
|
|
43
43
|
"@types/semver": "^7.5.8",
|
|
44
44
|
"@typescript-eslint/eslint-plugin": "~5.4.0",
|
|
45
45
|
"@typescript-eslint/parser": "~5.4.0",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"color": "4.2.3",
|
|
61
61
|
"codemirror": ">=5.64.0 <6",
|
|
62
62
|
"codemirror-editor-vue3": "2.7.1",
|
|
63
|
-
"cookie": "0.
|
|
63
|
+
"cookie": "0.7.0",
|
|
64
64
|
"cookie-universal": "2.2.2",
|
|
65
65
|
"core-js": "3.25.3",
|
|
66
66
|
"cron-validator": "1.3.1",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"js-yaml": "4.1.0",
|
|
105
105
|
"js-yaml-loader": "1.2.2",
|
|
106
106
|
"jsdiff": "1.1.1",
|
|
107
|
-
"jsonpath-plus": "10.0.
|
|
107
|
+
"jsonpath-plus": "10.0.7",
|
|
108
108
|
"jsrsasign": "10.5.25",
|
|
109
109
|
"jszip": "3.8.0",
|
|
110
110
|
"lodash": "4.17.21",
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"start-server-and-test": "1.13.1",
|
|
124
124
|
"style-loader": "1.2.1",
|
|
125
125
|
"ts-node": "8.10.2",
|
|
126
|
-
"typescript": "
|
|
126
|
+
"typescript": "5.6.3",
|
|
127
127
|
"ufo": "0.7.11",
|
|
128
128
|
"unfetch": "4.2.0",
|
|
129
129
|
"url-parse": "1.5.10",
|
|
@@ -131,7 +131,6 @@
|
|
|
131
131
|
"vue-router": "4.4.3",
|
|
132
132
|
"vue-select": "4.0.0-beta.6",
|
|
133
133
|
"vue-server-renderer": "2.7.16",
|
|
134
|
-
"vue-template-compiler": "2.7.16",
|
|
135
134
|
"vue3-resize": "0.2.0",
|
|
136
135
|
"vue3-virtual-scroll-list": "0.2.1",
|
|
137
136
|
"vuedraggable": "4.1.0",
|
|
@@ -161,7 +160,7 @@
|
|
|
161
160
|
"roarr": "7.0.4",
|
|
162
161
|
"semver": "7.5.4",
|
|
163
162
|
"@types/lodash": "4.17.5",
|
|
164
|
-
"@types/node": "
|
|
163
|
+
"@types/node": "20.10.8",
|
|
165
164
|
"@vue/cli-service/html-webpack-plugin": "^5.0.0"
|
|
166
165
|
},
|
|
167
166
|
"nyc": {
|
|
@@ -170,4 +169,4 @@
|
|
|
170
169
|
".vue"
|
|
171
170
|
]
|
|
172
171
|
}
|
|
173
|
-
}
|
|
172
|
+
}
|
package/pages/about.vue
CHANGED
|
@@ -108,6 +108,9 @@ export default {
|
|
|
108
108
|
:to="{ name: 'diagnostic' }"
|
|
109
109
|
class="btn role-primary"
|
|
110
110
|
data-testid="about__diagnostics_button"
|
|
111
|
+
role="button"
|
|
112
|
+
:aria-label="t('about.diagnostic.title')"
|
|
113
|
+
@keyup.space="$router.push({ name: 'diagnostic' })"
|
|
111
114
|
>
|
|
112
115
|
{{ t('about.diagnostic.title') }}
|
|
113
116
|
</router-link>
|
|
@@ -126,6 +129,8 @@ export default {
|
|
|
126
129
|
href="https://github.com/rancher/rancher"
|
|
127
130
|
target="_blank"
|
|
128
131
|
rel="nofollow noopener noreferrer"
|
|
132
|
+
role="link"
|
|
133
|
+
:aria-label="t('about.versions.githubRepo', {name: t(`about.versions.rancher`) })"
|
|
129
134
|
>
|
|
130
135
|
{{ t("about.versions.rancher") }}
|
|
131
136
|
</a>
|
|
@@ -137,6 +142,8 @@ export default {
|
|
|
137
142
|
href="https://github.com/rancher/dashboard"
|
|
138
143
|
target="_blank"
|
|
139
144
|
rel="nofollow noopener noreferrer"
|
|
145
|
+
role="link"
|
|
146
|
+
:aria-label="t('about.versions.githubRepo', {name: t(`generic.dashboard`)})"
|
|
140
147
|
>
|
|
141
148
|
{{ t("generic.dashboard") }}
|
|
142
149
|
</a>
|
|
@@ -148,6 +155,8 @@ export default {
|
|
|
148
155
|
href="https://github.com/rancher/cli"
|
|
149
156
|
target="_blank"
|
|
150
157
|
rel="nofollow noopener noreferrer"
|
|
158
|
+
role="link"
|
|
159
|
+
:aria-label="t('about.versions.githubRepo', {name: t(`about.versions.cli`) })"
|
|
151
160
|
>
|
|
152
161
|
{{ appName }} {{ t("about.versions.cli") }}
|
|
153
162
|
</a>
|
|
@@ -159,6 +168,8 @@ export default {
|
|
|
159
168
|
href="https://github.com/rancher/helm"
|
|
160
169
|
target="_blank"
|
|
161
170
|
rel="nofollow noopener noreferrer"
|
|
171
|
+
role="link"
|
|
172
|
+
:aria-label="t('about.versions.githubRepo', {name: t(`about.versions.helm`) })"
|
|
162
173
|
>
|
|
163
174
|
{{ t("about.versions.helm") }}
|
|
164
175
|
</a>
|
|
@@ -170,6 +181,8 @@ export default {
|
|
|
170
181
|
href="https://github.com/rancher/machine"
|
|
171
182
|
target="_blank"
|
|
172
183
|
rel="nofollow noopener noreferrer"
|
|
184
|
+
role="link"
|
|
185
|
+
:aria-label="t('about.versions.githubRepo', {name: t(`about.versions.machine`) })"
|
|
173
186
|
>
|
|
174
187
|
{{ t("about.versions.machine") }}
|
|
175
188
|
</a>
|
|
@@ -178,9 +191,12 @@ export default {
|
|
|
178
191
|
</table>
|
|
179
192
|
<p class="pt-20">
|
|
180
193
|
<a
|
|
194
|
+
class="release-notes-link"
|
|
181
195
|
:href="releaseNotesUrl"
|
|
182
196
|
target="_blank"
|
|
183
197
|
rel="nofollow noopener noreferrer"
|
|
198
|
+
role="link"
|
|
199
|
+
:aria-label="t('about.versions.releaseNotes')"
|
|
184
200
|
>
|
|
185
201
|
{{ t('about.versions.releaseNotes') }}
|
|
186
202
|
</a>
|
|
@@ -202,8 +218,12 @@ export default {
|
|
|
202
218
|
<td>
|
|
203
219
|
<a
|
|
204
220
|
v-if="d.imageList"
|
|
221
|
+
tabindex="0"
|
|
205
222
|
:data-testid="`image_list_download_link__${d.label}`"
|
|
223
|
+
role="link"
|
|
224
|
+
:aria-label="t('about.versions.downloadImages', { listName: t(d.label) })"
|
|
206
225
|
@click="d.imageList"
|
|
226
|
+
@keyup.enter="d.imageList"
|
|
207
227
|
>
|
|
208
228
|
{{ t('asyncButton.download.action') }}
|
|
209
229
|
</a>
|
|
@@ -230,6 +250,8 @@ export default {
|
|
|
230
250
|
<a
|
|
231
251
|
v-if="d.cliLink"
|
|
232
252
|
:href="d.cliLink"
|
|
253
|
+
role="link"
|
|
254
|
+
:aria-label="t('about.versions.downloadCli', { os: t(d.label) })"
|
|
233
255
|
>{{ d.cliFile }}</a>
|
|
234
256
|
</td>
|
|
235
257
|
</tr>
|
package/pages/auth/setup.vue
CHANGED
|
@@ -11,7 +11,6 @@ import { getVendor, getProduct, setVendor } from '@shell/config/private-label';
|
|
|
11
11
|
import { RadioGroup } from '@components/Form/Radio';
|
|
12
12
|
import { setSetting } from '@shell/utils/settings';
|
|
13
13
|
import { SETTING } from '@shell/config/settings';
|
|
14
|
-
import { isDevBuild } from '@shell/utils/version';
|
|
15
14
|
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
16
15
|
import Password from '@shell/components/form/Password';
|
|
17
16
|
import { applyProducts } from '@shell/store/type-map';
|
|
@@ -66,7 +65,6 @@ export default {
|
|
|
66
65
|
v3User: null,
|
|
67
66
|
serverUrl: null,
|
|
68
67
|
mcmEnabled: null,
|
|
69
|
-
telemetry: null,
|
|
70
68
|
eula: false,
|
|
71
69
|
principals: null,
|
|
72
70
|
errors: []
|
|
@@ -101,16 +99,7 @@ export default {
|
|
|
101
99
|
},
|
|
102
100
|
|
|
103
101
|
async fetch() {
|
|
104
|
-
const telemetrySetting = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.TELEMETRY);
|
|
105
102
|
const serverUrlSetting = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.SERVER_URL);
|
|
106
|
-
const rancherVersionSetting = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.VERSION_RANCHER);
|
|
107
|
-
let telemetry = true;
|
|
108
|
-
|
|
109
|
-
if (telemetrySetting?.value && telemetrySetting.value !== 'prompt') {
|
|
110
|
-
telemetry = telemetrySetting.value !== 'out';
|
|
111
|
-
} else if (!rancherVersionSetting?.value || isDevBuild(rancherVersionSetting?.value)) {
|
|
112
|
-
telemetry = false;
|
|
113
|
-
}
|
|
114
103
|
|
|
115
104
|
let plSetting;
|
|
116
105
|
|
|
@@ -163,7 +152,6 @@ export default {
|
|
|
163
152
|
this['v3User'] = v3User;
|
|
164
153
|
this['serverUrl'] = serverUrl;
|
|
165
154
|
this['mcmEnabled'] = mcmEnabled;
|
|
166
|
-
this['telemetry'] = telemetry;
|
|
167
155
|
this['principals'] = principals;
|
|
168
156
|
},
|
|
169
157
|
|
|
@@ -244,7 +232,6 @@ export default {
|
|
|
244
232
|
|
|
245
233
|
if (this.isFirstLogin) {
|
|
246
234
|
promises.push( setSetting(this.$store, SETTING.EULA_AGREED, (new Date()).toISOString()) );
|
|
247
|
-
promises.push( setSetting(this.$store, SETTING.TELEMETRY, this.telemetry ? 'in' : 'out') );
|
|
248
235
|
|
|
249
236
|
if ( this.mcmEnabled && this.serverUrl ) {
|
|
250
237
|
promises.push( setSetting(this.$store, SETTING.SERVER_URL, this.serverUrl) );
|
|
@@ -406,20 +393,6 @@ export default {
|
|
|
406
393
|
</div>
|
|
407
394
|
</template>
|
|
408
395
|
|
|
409
|
-
<div class="checkbox mt-40">
|
|
410
|
-
<Checkbox
|
|
411
|
-
id="checkbox-telemetry"
|
|
412
|
-
v-model:value="telemetry"
|
|
413
|
-
>
|
|
414
|
-
<template #label>
|
|
415
|
-
<t
|
|
416
|
-
k="setup.telemetry"
|
|
417
|
-
:raw="true"
|
|
418
|
-
:name="productName"
|
|
419
|
-
/>
|
|
420
|
-
</template>
|
|
421
|
-
</Checkbox>
|
|
422
|
-
</div>
|
|
423
396
|
<div class="checkbox pt-10 eula">
|
|
424
397
|
<Checkbox
|
|
425
398
|
id="checkbox-eula"
|
|
@@ -461,6 +434,9 @@ export default {
|
|
|
461
434
|
</h4>
|
|
462
435
|
</div>
|
|
463
436
|
</div>
|
|
437
|
+
<div>
|
|
438
|
+
|
|
439
|
+
</div>
|
|
464
440
|
</div>
|
|
465
441
|
<BrandImage
|
|
466
442
|
class="col span-6 landscape"
|
|
@@ -517,11 +493,14 @@ export default {
|
|
|
517
493
|
width: 51%;
|
|
518
494
|
|
|
519
495
|
& > div:first-of-type {
|
|
520
|
-
flex:3;
|
|
496
|
+
flex: 3;
|
|
521
497
|
}
|
|
522
498
|
& > div:nth-of-type(2) {
|
|
523
499
|
flex: 9;
|
|
524
500
|
}
|
|
501
|
+
& > div:nth-of-type(3) {
|
|
502
|
+
flex: 2;
|
|
503
|
+
}
|
|
525
504
|
}
|
|
526
505
|
|
|
527
506
|
.setup-title {
|
|
@@ -99,7 +99,7 @@ describe('page: cluster dashboard', () => {
|
|
|
99
99
|
[STATES_ENUM.HEALTHY, 'icon-checkmark', true, false, false, [{ status: 'True' }], 1, 0],
|
|
100
100
|
]]
|
|
101
101
|
])('%p cluster - %p agent health box :', (_, agentId, isLocal, agentResources, statuses) => {
|
|
102
|
-
it.each(statuses)('should
|
|
102
|
+
it.each(statuses)('should NOT show %p status due to missing canList permissions', (status, iconClass, isLoaded, disconnected, error, conditions, readyReplicas, unavailableReplicas) => {
|
|
103
103
|
const options = clone(mountOptions);
|
|
104
104
|
|
|
105
105
|
options.global.mocks.$store.getters.currentCluster.isLocal = isLocal;
|
|
@@ -138,41 +138,48 @@ describe('page: cluster dashboard', () => {
|
|
|
138
138
|
|
|
139
139
|
describe.each([
|
|
140
140
|
['local', 'fleet', true, ['fleetDeployment', 'fleetStatefulSet'], [
|
|
141
|
-
[STATES_ENUM.IN_PROGRESS, 'icon-spinner', false, false, false, '', 0, 0],
|
|
142
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, false, false, [{ status: 'False' }], 0, 0],
|
|
143
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, false, true, [{ status: 'True' }], 0, 0],
|
|
144
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, [{ status: 'True' }], 0, 0],
|
|
145
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, false, false, [{ status: 'True' }], 0, 0],
|
|
146
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, false, false, [{ status: 'True' }], 0, 1],
|
|
147
|
-
[STATES_ENUM.HEALTHY, 'icon-checkmark', true, false, false, [{ status: 'True' }], 1, 0],
|
|
141
|
+
[STATES_ENUM.IN_PROGRESS, 'icon-spinner', false, false, false, false, '', 0, 0],
|
|
142
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, false, [{ status: 'False' }], 0, 0],
|
|
143
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, true, [{ status: 'True' }], 0, 0],
|
|
144
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, true, false, [{ status: 'True' }], 0, 0],
|
|
145
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, false, [{ status: 'True' }], 0, 0],
|
|
146
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, false, [{ status: 'True' }], 0, 1],
|
|
147
|
+
[STATES_ENUM.HEALTHY, 'icon-checkmark', false, true, false, false, [{ status: 'True' }], 1, 0],
|
|
148
148
|
]],
|
|
149
149
|
['downstream RKE2', 'fleet', false, ['fleetStatefulSet'], [
|
|
150
|
-
[STATES_ENUM.IN_PROGRESS, 'icon-spinner', false, false, false, '', 0, 0],
|
|
151
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, false, false, [{ status: 'False' }], 0, 0],
|
|
152
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, false, true, [{ status: 'True' }], 0, 0],
|
|
153
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, [{ status: 'True' }], 0, 0],
|
|
154
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, false, false, [{ status: 'True' }], 0, 0],
|
|
155
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, false, false, [{ status: 'True' }], 0, 1],
|
|
156
|
-
[STATES_ENUM.HEALTHY, 'icon-checkmark', true, false, false, [{ status: 'True' }], 1, 0],
|
|
150
|
+
[STATES_ENUM.IN_PROGRESS, 'icon-spinner', false, false, false, false, '', 0, 0],
|
|
151
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, false, [{ status: 'False' }], 0, 0],
|
|
152
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, true, [{ status: 'True' }], 0, 0],
|
|
153
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, true, false, [{ status: 'True' }], 0, 0],
|
|
154
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, false, [{ status: 'True' }], 0, 0],
|
|
155
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, false, [{ status: 'True' }], 0, 1],
|
|
156
|
+
[STATES_ENUM.HEALTHY, 'icon-checkmark', false, true, false, false, [{ status: 'True' }], 1, 0],
|
|
157
157
|
]],
|
|
158
158
|
['downstream RKE2', 'cattle', false, ['cattleDeployment'], [
|
|
159
|
-
[STATES_ENUM.IN_PROGRESS, 'icon-spinner', false, false, false, '', 0, 0],
|
|
160
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, false, false, [{ status: 'False' }], 0, 0],
|
|
161
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, [{ status: 'True' }], 0, 0],
|
|
162
|
-
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, false, true, [{ status: 'True' }], 0, 0],
|
|
163
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, false, false, [{ status: 'True' }], 0, 0],
|
|
164
|
-
[STATES_ENUM.WARNING, 'icon-warning', true, false, false, [{ status: 'True' }], 0, 1],
|
|
165
|
-
[STATES_ENUM.HEALTHY, 'icon-checkmark', true, false, false, [{ status: 'True' }], 1, 0],
|
|
159
|
+
[STATES_ENUM.IN_PROGRESS, 'icon-spinner', false, false, false, false, '', 0, 0],
|
|
160
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, false, [{ status: 'False' }], 0, 0],
|
|
161
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, true, false, [{ status: 'True' }], 0, 0],
|
|
162
|
+
[STATES_ENUM.UNHEALTHY, 'icon-warning', true, true, false, true, [{ status: 'True' }], 0, 0],
|
|
163
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, false, [{ status: 'True' }], 0, 0],
|
|
164
|
+
[STATES_ENUM.WARNING, 'icon-warning', true, true, false, false, [{ status: 'True' }], 0, 1],
|
|
165
|
+
[STATES_ENUM.HEALTHY, 'icon-checkmark', false, true, false, false, [{ status: 'True' }], 1, 0],
|
|
166
166
|
]]
|
|
167
167
|
])('%p cluster - %p agent health box ::', (_, agentId, isLocal, agentResources, statuses) => {
|
|
168
|
-
it.each(statuses)('should show %p status', (status, iconClass, isLoaded, disconnected, error, conditions, readyReplicas, unavailableReplicas) => {
|
|
168
|
+
it.each(statuses)('should show %p status', async(status, iconClass, clickable, isLoaded, disconnected, error, conditions, readyReplicas, unavailableReplicas) => {
|
|
169
|
+
let agentRoute = null;
|
|
170
|
+
|
|
169
171
|
const options = clone(mountOptions);
|
|
170
172
|
|
|
171
173
|
options.global.mocks.$store.getters.currentCluster.isLocal = isLocal;
|
|
172
174
|
|
|
173
|
-
// let's pass the canList now
|
|
174
175
|
options.global.mocks.$store.getters['cluster/canList'] = (type: string) => !!(type === WORKLOAD_TYPES.DEPLOYMENT) || !!(type === WORKLOAD_TYPES.STATEFUL_SET);
|
|
175
176
|
|
|
177
|
+
options.global.mocks.$router = {
|
|
178
|
+
push: (route: any) => {
|
|
179
|
+
agentRoute = route;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
176
183
|
const resources = agentResources.reduce((acc, r) => {
|
|
177
184
|
const agent = {
|
|
178
185
|
metadata: { state: { error } },
|
|
@@ -204,7 +211,12 @@ describe('page: cluster dashboard', () => {
|
|
|
204
211
|
|
|
205
212
|
expect(box.element).toBeDefined();
|
|
206
213
|
expect(box.element.classList).toContain(status);
|
|
214
|
+
expect(!!(box.element as any).$_popper).toBe(clickable);
|
|
207
215
|
expect(icon.element.classList).toContain(iconClass);
|
|
216
|
+
|
|
217
|
+
await box.trigger('click');
|
|
218
|
+
|
|
219
|
+
expect(!!agentRoute).toBe(clickable);
|
|
208
220
|
});
|
|
209
221
|
});
|
|
210
222
|
|