@rancher/shell 3.0.0-rc.7 → 3.0.0-rc.8
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/styles/global/_tooltip.scss +1 -12
- package/assets/translations/en-us.yaml +13 -1
- package/components/CodeMirror.vue +18 -15
- package/components/PromptRemove.vue +2 -2
- package/components/Questions/index.vue +2 -2
- package/components/ResourceDetail/Masthead.vue +1 -0
- package/components/ResourceDetail/index.vue +6 -7
- package/components/auth/RoleDetailEdit.vue +1 -6
- package/components/auth/__tests__/RoleDetailEdit.test.ts +53 -16
- package/components/form/ArrayList.vue +7 -3
- package/components/formatter/CloudCredExpired.vue +69 -0
- package/components/formatter/Date.vue +1 -1
- package/components/nav/TopLevelMenu.vue +115 -51
- package/components/nav/__tests__/TopLevelMenu.test.ts +49 -23
- package/config/labels-annotations.js +9 -5
- package/core/types.ts +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +0 -4
- package/edit/management.cattle.io.project.vue +4 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +7 -2
- package/edit/provisioning.cattle.io.cluster/rke2.vue +28 -5
- package/list/provisioning.cattle.io.cluster.vue +57 -10
- package/machine-config/vmwarevsphere.vue +133 -95
- package/mixins/vue-select-overrides.js +0 -1
- package/models/catalog.cattle.io.app.js +4 -3
- package/models/cloudcredential.js +158 -2
- package/models/management.cattle.io.globalrole.js +6 -0
- package/models/management.cattle.io.roletemplate.js +6 -0
- package/models/nodedriver.js +5 -0
- package/models/provisioning.cattle.io.cluster.js +35 -1
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/index.vue +0 -6
- package/pages/c/_cluster/manager/cloudCredential/index.vue +68 -4
- package/pages/home.vue +1 -0
- package/plugins/dashboard-store/mutations.js +24 -3
- package/plugins/dashboard-store/resource-class.js +6 -0
- package/store/type-map.js +4 -2
- package/types/shell/index.d.ts +12 -1
|
@@ -15,10 +15,7 @@
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.v-popper__arrow-container {
|
|
18
|
-
width: 0;
|
|
19
|
-
height: 0;
|
|
20
18
|
border: 0 solid transparent;
|
|
21
|
-
position: absolute;
|
|
22
19
|
z-index: 1;
|
|
23
20
|
|
|
24
21
|
.v-popper__arrow-inner {
|
|
@@ -30,9 +27,7 @@
|
|
|
30
27
|
.v-popper__arrow-container {
|
|
31
28
|
|
|
32
29
|
.v-popper__arrow-outer {
|
|
33
|
-
border-bottom-width: 0;
|
|
34
30
|
border-top-color: var(--tooltip-bg);
|
|
35
|
-
left: -$triangle-inner-size;
|
|
36
31
|
}
|
|
37
32
|
}
|
|
38
33
|
}
|
|
@@ -42,9 +37,7 @@
|
|
|
42
37
|
.v-popper__arrow-container {
|
|
43
38
|
|
|
44
39
|
.v-popper__arrow-outer {
|
|
45
|
-
border-top-width: 0;
|
|
46
40
|
border-bottom-color: var(--tooltip-bg);
|
|
47
|
-
left: -$triangle-inner-size;
|
|
48
41
|
background: transparent;
|
|
49
42
|
}
|
|
50
43
|
}
|
|
@@ -55,8 +48,6 @@
|
|
|
55
48
|
|
|
56
49
|
.v-popper__arrow-outer {
|
|
57
50
|
border-right-color: var(--tooltip-bg);
|
|
58
|
-
top: -$triangle-inner-size;
|
|
59
|
-
border-left-width: 0;
|
|
60
51
|
}
|
|
61
52
|
}
|
|
62
53
|
}
|
|
@@ -65,9 +56,7 @@
|
|
|
65
56
|
.v-popper__arrow-container {
|
|
66
57
|
|
|
67
58
|
.v-popper__arrow-outer {
|
|
68
|
-
border-right-width: 0;
|
|
69
59
|
border-left-color: var(--tooltip-bg);
|
|
70
|
-
top: -$triangle-inner-size;
|
|
71
60
|
}
|
|
72
61
|
}
|
|
73
62
|
}
|
|
@@ -173,4 +162,4 @@
|
|
|
173
162
|
//icon tooltip
|
|
174
163
|
.icon-info.v-popper--has-tooltip {
|
|
175
164
|
font-size: 14px;
|
|
176
|
-
}
|
|
165
|
+
}
|
|
@@ -1822,6 +1822,13 @@ cluster:
|
|
|
1822
1822
|
other { {pool_name}: The provided values for {fields} were not found in the list of expected values. This can happen with clusters provisioned outside of Rancher or when options for the provider have changed. }
|
|
1823
1823
|
}
|
|
1824
1824
|
rkeTemplateUpgrade: Template revision {name} available for upgrade
|
|
1825
|
+
cloudCredentials:
|
|
1826
|
+
renew: Renew Cloud Credentials
|
|
1827
|
+
expired: Cloud Credential expired, please Renew Cloud Credentials
|
|
1828
|
+
expiring: Cloud Credential will expire on { expires }, please Renew Cloud Credentials
|
|
1829
|
+
banners:
|
|
1830
|
+
expiring: "{count} {count, plural, =1 { Cluster has a Cloud Credential that expires soon} other { Clusters have Cloud Credentials that expire soon}}, please Renew Cloud {count, plural, =1 { Credential} other { Credentials}}"
|
|
1831
|
+
expired: "{count} {count, plural, =1 { Cluster has a Cloud Credential that has expired} other { Clusters have Cloud Credentials that have expired}}, please Renew Cloud {count, plural, =1 { Credential} other { Credentials}}"
|
|
1825
1832
|
|
|
1826
1833
|
architecture:
|
|
1827
1834
|
label:
|
|
@@ -5655,7 +5662,6 @@ tableHeaders:
|
|
|
5655
5662
|
createdAt: Created At
|
|
5656
5663
|
customVerbs: Custom Verbs
|
|
5657
5664
|
description: Description
|
|
5658
|
-
expires: Expires
|
|
5659
5665
|
cpu: CPU
|
|
5660
5666
|
currentReplicas: Current Replicas
|
|
5661
5667
|
date: Date
|
|
@@ -5672,6 +5678,7 @@ tableHeaders:
|
|
|
5672
5678
|
distinguisherMethod: Distinguisher Method
|
|
5673
5679
|
effect: Effect
|
|
5674
5680
|
endpoints: Endpoints
|
|
5681
|
+
expires: Expires
|
|
5675
5682
|
firstSeen: First Seen
|
|
5676
5683
|
fleetBundleType: Type
|
|
5677
5684
|
flow: Flow
|
|
@@ -7751,6 +7758,11 @@ volumeClaimTemplate:
|
|
|
7751
7758
|
manager:
|
|
7752
7759
|
cloudCredentials:
|
|
7753
7760
|
label: Cloud Credentials
|
|
7761
|
+
renew: Renew
|
|
7762
|
+
expired: Expired
|
|
7763
|
+
banners:
|
|
7764
|
+
expiring: "{count} Cloud {count, plural, =1 { Credential expires soon} other { Credentials expire soon}}, please Renew"
|
|
7765
|
+
expired: "{count} Cloud {count, plural, =1 { Credential has expired} other { Credentials have expired}}, please Renew"
|
|
7754
7766
|
drivers:
|
|
7755
7767
|
label: Drivers
|
|
7756
7768
|
rkeTemplates:
|
|
@@ -292,11 +292,24 @@ export default {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
.code-mirror
|
|
296
|
-
|
|
297
|
-
|
|
295
|
+
.code-mirror {
|
|
296
|
+
position: relative;
|
|
297
|
+
|
|
298
|
+
.codemirror-container {
|
|
299
|
+
z-index: 0;
|
|
300
|
+
font-size: inherit !important;
|
|
301
|
+
|
|
302
|
+
//rm no longer extant selector
|
|
303
|
+
.CodeMirror {
|
|
304
|
+
height: initial;
|
|
305
|
+
background: none
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.CodeMirror-gutters {
|
|
309
|
+
background: inherit;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
298
312
|
|
|
299
|
-
// Keyboard mapping overlap
|
|
300
313
|
.keymap.overlay {
|
|
301
314
|
position: absolute;
|
|
302
315
|
display: flex;
|
|
@@ -352,16 +365,6 @@ export default {
|
|
|
352
365
|
}
|
|
353
366
|
}
|
|
354
367
|
}
|
|
355
|
-
|
|
356
|
-
//rm no longer extant selector
|
|
357
|
-
.CodeMirror {
|
|
358
|
-
height: initial;
|
|
359
|
-
background: none
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
.CodeMirror-gutters {
|
|
363
|
-
background: inherit;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
368
|
}
|
|
369
|
+
|
|
367
370
|
</style>
|
|
@@ -105,8 +105,8 @@ export default {
|
|
|
105
105
|
return null;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
if (this.toRemove[0].
|
|
109
|
-
return this.toRemove[0].
|
|
108
|
+
if (this.toRemove[0].doneOverride) {
|
|
109
|
+
return this.toRemove[0].doneOverride;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
const currentRoute = this.toRemove[0].currentRoute();
|
|
@@ -45,9 +45,9 @@ export function componentForQuestion(q) {
|
|
|
45
45
|
|
|
46
46
|
if ( knownTypes[type] ) {
|
|
47
47
|
return type;
|
|
48
|
-
} else if ( type.startsWith('array
|
|
48
|
+
} else if ( type.startsWith('array') ) { // This only really works for array[string|multiline], but close enough for now.
|
|
49
49
|
return ArrayType;
|
|
50
|
-
} else if ( type.startsWith('map
|
|
50
|
+
} else if ( type.startsWith('map') ) { // Same, only works with map[string|multiline]
|
|
51
51
|
return MapType;
|
|
52
52
|
} else if ( type.startsWith('reference[') ) { // Same, only works with map[string|multiline]
|
|
53
53
|
return ReferenceType;
|
|
@@ -318,9 +318,12 @@ export default {
|
|
|
318
318
|
},
|
|
319
319
|
|
|
320
320
|
watch: {
|
|
321
|
-
'$route
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
'$route'(current, prev) {
|
|
322
|
+
if (current.name !== prev.name) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const neu = clone(current.query);
|
|
326
|
+
const old = clone(prev.query);
|
|
324
327
|
|
|
325
328
|
delete neu[PREVIEW];
|
|
326
329
|
delete old[PREVIEW];
|
|
@@ -332,10 +335,6 @@ export default {
|
|
|
332
335
|
|
|
333
336
|
const queryDiff = Object.keys(diff(neu, old));
|
|
334
337
|
|
|
335
|
-
if (Object.keys(neu).length <= 0) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
338
|
if (queryDiff.includes(MODE) || queryDiff.includes(AS)) {
|
|
340
339
|
this.$fetch();
|
|
341
340
|
}
|
|
@@ -127,12 +127,6 @@ export default {
|
|
|
127
127
|
|
|
128
128
|
created() {
|
|
129
129
|
this.value['rules'] = this.value.rules || [];
|
|
130
|
-
this.value.rules.forEach((rule) => {
|
|
131
|
-
if (rule.verbs[0] === '*') {
|
|
132
|
-
rule['verbs'] = [...VERBS];
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
|
|
136
130
|
const query = { ...this.$route.query };
|
|
137
131
|
const { roleContext } = query;
|
|
138
132
|
|
|
@@ -701,6 +695,7 @@ export default {
|
|
|
701
695
|
<template #columns="props">
|
|
702
696
|
<div class="columns row mr-20">
|
|
703
697
|
<div :class="ruleClass">
|
|
698
|
+
<!-- Select verbs -->
|
|
704
699
|
<Select
|
|
705
700
|
:value="props.row.value.verbs"
|
|
706
701
|
class="lg"
|
|
@@ -2,22 +2,20 @@ import { mount } from '@vue/test-utils';
|
|
|
2
2
|
import RoleDetailEdit from '@shell/components/auth/RoleDetailEdit.vue';
|
|
3
3
|
import { SUBTYPE_MAPPING } from '@shell/models/management.cattle.io.roletemplate';
|
|
4
4
|
|
|
5
|
-
const role = {
|
|
6
|
-
apiVersion: 'management.cattle.io/v3',
|
|
7
|
-
kind: 'GlobalRole',
|
|
8
|
-
metadata: { name: 'global-role-with-inherited' },
|
|
9
|
-
inheritedClusterRoles: ['cluster-admin'],
|
|
10
|
-
rules:
|
|
11
|
-
[{
|
|
12
|
-
verbs: ['get', 'list'],
|
|
13
|
-
resources: ['pods'],
|
|
14
|
-
apiGroups: ['']
|
|
15
|
-
}],
|
|
16
|
-
subtype: SUBTYPE_MAPPING.GLOBAL.id
|
|
17
|
-
};
|
|
18
|
-
|
|
19
5
|
describe('component: RoleDetailEdit', () => {
|
|
20
6
|
it('does not have validation errors when the role has no displayName', () => {
|
|
7
|
+
const role = {
|
|
8
|
+
apiVersion: 'management.cattle.io/v3',
|
|
9
|
+
kind: 'GlobalRole',
|
|
10
|
+
metadata: { name: 'global-role-with-inherited' },
|
|
11
|
+
inheritedClusterRoles: ['cluster-admin'],
|
|
12
|
+
rules: [{
|
|
13
|
+
verbs: ['get', 'list'],
|
|
14
|
+
resources: ['pods'],
|
|
15
|
+
apiGroups: ['']
|
|
16
|
+
}],
|
|
17
|
+
subtype: SUBTYPE_MAPPING.GLOBAL.id
|
|
18
|
+
};
|
|
21
19
|
const wrapper = mount(RoleDetailEdit, {
|
|
22
20
|
props: { value: role },
|
|
23
21
|
|
|
@@ -28,14 +26,16 @@ describe('component: RoleDetailEdit', () => {
|
|
|
28
26
|
$store: {
|
|
29
27
|
dispatch: jest.fn(),
|
|
30
28
|
getters: {
|
|
31
|
-
currentStore:
|
|
29
|
+
currentStore: () => 'store',
|
|
30
|
+
'i18n/t': jest.fn(),
|
|
31
|
+
'store/schemaFor': jest.fn(),
|
|
32
|
+
'store/customisation/': jest.fn()
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
},
|
|
35
36
|
|
|
36
37
|
stubs: {
|
|
37
38
|
CruResource: { template: '<div><slot></slot></div>' },
|
|
38
|
-
// NameNsDescription: true,
|
|
39
39
|
Tab: { template: '<div><slot></slot></div>' },
|
|
40
40
|
},
|
|
41
41
|
},
|
|
@@ -43,4 +43,41 @@ describe('component: RoleDetailEdit', () => {
|
|
|
43
43
|
|
|
44
44
|
expect((wrapper.vm as any).fvFormIsValid).toBe(true);
|
|
45
45
|
});
|
|
46
|
+
|
|
47
|
+
it.each([
|
|
48
|
+
[['*']],
|
|
49
|
+
[['create', 'delete', 'get', 'list', 'patch', 'update', 'watch']],
|
|
50
|
+
])('should display the verbs %p', (verbs: string[]) => {
|
|
51
|
+
const wrapper = mount(RoleDetailEdit, {
|
|
52
|
+
props: {
|
|
53
|
+
value: {
|
|
54
|
+
rules: [{ verbs }],
|
|
55
|
+
subtype: 'GLOBAL'
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
global: {
|
|
60
|
+
mocks: {
|
|
61
|
+
$fetchState: { pending: false },
|
|
62
|
+
$route: { name: 'anything' },
|
|
63
|
+
$store: {
|
|
64
|
+
dispatch: jest.fn(),
|
|
65
|
+
getters: {
|
|
66
|
+
currentStore: () => 'store',
|
|
67
|
+
'i18n/t': jest.fn(),
|
|
68
|
+
'store/schemaFor': jest.fn(),
|
|
69
|
+
'store/customisation/': jest.fn()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
stubs: {
|
|
75
|
+
CruResource: { template: '<div><slot></slot></div>' },
|
|
76
|
+
Tab: { template: '<div><slot></slot></div>' },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(wrapper.vm.value.rules[0].verbs).toStrictEqual(verbs);
|
|
82
|
+
});
|
|
46
83
|
});
|
|
@@ -138,10 +138,14 @@ export default {
|
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
140
|
watch: {
|
|
141
|
-
value
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
value: {
|
|
142
|
+
deep: true,
|
|
143
|
+
handler() {
|
|
144
|
+
this.lastUpdateWasFromValue = true;
|
|
145
|
+
this.rows = (this.value || []).map((v) => ({ value: v }));
|
|
146
|
+
}
|
|
144
147
|
},
|
|
148
|
+
|
|
145
149
|
rows: {
|
|
146
150
|
deep: true,
|
|
147
151
|
handler(newValue, oldValue) {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
props: {
|
|
5
|
+
value: {
|
|
6
|
+
type: [Number, String],
|
|
7
|
+
required: true
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
row: {
|
|
11
|
+
type: Object,
|
|
12
|
+
default: () => {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
verbose: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: false,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
computed: {
|
|
25
|
+
outputString() {
|
|
26
|
+
return this.verbose ? this.verboseOutputString : this.row.expiresString;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
verboseOutputString() {
|
|
30
|
+
const expireData = this.row?.expireData;
|
|
31
|
+
|
|
32
|
+
if (expireData?.expired) {
|
|
33
|
+
return this.t('cluster.cloudCredentials.expired');
|
|
34
|
+
} else if (expireData?.expiring) {
|
|
35
|
+
return this.t('cluster.cloudCredentials.expiring', { expires: this.row.expiresString });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<div
|
|
46
|
+
v-if="outputString"
|
|
47
|
+
class="cloud-cred-expired"
|
|
48
|
+
:class="{ 'text-error': row.expireData.expired, 'text-warning': row.expireData.expiring}"
|
|
49
|
+
>
|
|
50
|
+
<div class="token-icon mr-5">
|
|
51
|
+
<i
|
|
52
|
+
class="icon"
|
|
53
|
+
:class="{'icon-error': row.expireData.expired, 'icon-warning': row.expireData.expiring}"
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
{{ outputString }}
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<style lang="scss" scoped>
|
|
61
|
+
.cloud-cred-expired {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
.token-icon {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
@@ -76,58 +76,102 @@ export default {
|
|
|
76
76
|
return this.clusters.length > this.maxClustersToShow;
|
|
77
77
|
},
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Filter mgmt clusters by
|
|
81
|
+
* 1. Harvester type 1 (filterOnlyKubernetesClusters)
|
|
82
|
+
* 2. Harvester type 2 (filterHiddenLocalCluster)
|
|
83
|
+
* 3. There's a matching prov cluster
|
|
84
|
+
*
|
|
85
|
+
* Convert remaining clusters to special format
|
|
86
|
+
*/
|
|
79
87
|
clusters() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
if (!this.hasProvCluster) {
|
|
89
|
+
// We're filtering out mgmt clusters without prov clusters, so if the user can't see any prov clusters at all
|
|
90
|
+
// exit early
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
const all = this.$store.getters['management/all'](MANAGEMENT.CLUSTER);
|
|
95
|
+
const mgmtClusters = filterHiddenLocalCluster(filterOnlyKubernetesClusters(all, this.$store), this.$store);
|
|
96
|
+
const provClusters = this.$store.getters['management/all'](CAPI.RANCHER_CLUSTER);
|
|
97
|
+
const provClustersByMgmtId = provClusters.reduce((res, provCluster) => {
|
|
98
|
+
if (provCluster.mgmt?.id) {
|
|
99
|
+
res[provCluster.mgmt.id] = provCluster;
|
|
100
|
+
}
|
|
88
101
|
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
return res;
|
|
103
|
+
}, {});
|
|
91
104
|
|
|
105
|
+
return (mgmtClusters || []).reduce((res, mgmtCluster) => {
|
|
92
106
|
// Filter to only show mgmt clusters that exist for the available provisioning clusters
|
|
93
107
|
// Addresses issue where a mgmt cluster can take some time to get cleaned up after the corresponding
|
|
94
108
|
// provisioning cluster has been deleted
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
if (!provClustersByMgmtId[mgmtCluster.id]) {
|
|
110
|
+
return res;
|
|
111
|
+
}
|
|
97
112
|
|
|
98
|
-
|
|
99
|
-
|
|
113
|
+
const pCluster = provClustersByMgmtId[mgmtCluster.id];
|
|
114
|
+
|
|
115
|
+
res.push({
|
|
116
|
+
id: mgmtCluster.id,
|
|
117
|
+
label: mgmtCluster.nameDisplay,
|
|
118
|
+
ready: mgmtCluster.isReady && !pCluster?.hasError,
|
|
119
|
+
osLogo: mgmtCluster.providerOsLogo,
|
|
120
|
+
providerNavLogo: mgmtCluster.providerMenuLogo,
|
|
121
|
+
badge: mgmtCluster.badge,
|
|
122
|
+
isLocal: mgmtCluster.isLocal,
|
|
123
|
+
isHarvester: mgmtCluster.isHarvester,
|
|
124
|
+
pinned: mgmtCluster.pinned,
|
|
125
|
+
description: pCluster?.description || mgmtCluster.description,
|
|
126
|
+
pin: () => mgmtCluster.pin(),
|
|
127
|
+
unpin: () => mgmtCluster.unpin(),
|
|
128
|
+
clusterRoute: { name: 'c-cluster-explorer', params: { cluster: mgmtCluster.id } }
|
|
129
|
+
});
|
|
100
130
|
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
label: x.nameDisplay,
|
|
104
|
-
ready: x.isReady && !pCluster?.hasError,
|
|
105
|
-
osLogo: x.providerOsLogo,
|
|
106
|
-
providerNavLogo: x.providerMenuLogo,
|
|
107
|
-
badge: x.badge,
|
|
108
|
-
isLocal: x.isLocal,
|
|
109
|
-
isHarvester: x.isHarvester,
|
|
110
|
-
pinned: x.pinned,
|
|
111
|
-
description: pCluster?.description || x.description,
|
|
112
|
-
pin: () => x.pin(),
|
|
113
|
-
unpin: () => x.unpin(),
|
|
114
|
-
clusterRoute: { name: 'c-cluster-explorer', params: { cluster: x.id } }
|
|
115
|
-
};
|
|
116
|
-
}) || [];
|
|
131
|
+
return res;
|
|
132
|
+
}, []);
|
|
117
133
|
},
|
|
118
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Filter clusters by
|
|
137
|
+
* 1. Not pinned
|
|
138
|
+
* 2. Includes search term
|
|
139
|
+
*
|
|
140
|
+
* Sort remaining clusters
|
|
141
|
+
*
|
|
142
|
+
* Reduce number of clusters if too many too show
|
|
143
|
+
*
|
|
144
|
+
* Important! This is used to show unpinned clusters OR results of search
|
|
145
|
+
*/
|
|
119
146
|
clustersFiltered() {
|
|
120
147
|
const search = (this.clusterFilter || '').toLowerCase();
|
|
121
|
-
|
|
122
|
-
const sorted = sortBy(out, ['ready:desc', 'label']);
|
|
148
|
+
let localCluster = null;
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
150
|
+
const filtered = this.clusters.filter((c) => {
|
|
151
|
+
// If we're searching we don't care if pinned or not
|
|
152
|
+
if (search) {
|
|
153
|
+
if (!c.label?.toLowerCase().includes(search)) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
} else if (c.pinned) {
|
|
157
|
+
// Not searching, not pinned, don't care
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!localCluster && c.id === 'local') {
|
|
162
|
+
// Local cluster is a special case, we're inserting it at top so don't include in the middle
|
|
163
|
+
localCluster = c;
|
|
164
|
+
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
129
167
|
|
|
130
|
-
|
|
168
|
+
return true;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const sorted = sortBy(filtered, ['ready:desc', 'label']);
|
|
172
|
+
|
|
173
|
+
// put local cluster on top of list always - https://github.com/rancher/dashboard/issues/10975
|
|
174
|
+
if (localCluster) {
|
|
131
175
|
sorted.unshift(localCluster);
|
|
132
176
|
}
|
|
133
177
|
|
|
@@ -141,25 +185,45 @@ export default {
|
|
|
141
185
|
this.searchActive = false;
|
|
142
186
|
|
|
143
187
|
if (sorted.length >= this.maxClustersToShow) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return sortedPinOut;
|
|
147
|
-
} else {
|
|
148
|
-
return sorted.filter((item) => !item.pinned);
|
|
188
|
+
return sorted.slice(0, this.maxClustersToShow);
|
|
149
189
|
}
|
|
190
|
+
|
|
191
|
+
return sorted;
|
|
150
192
|
},
|
|
151
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Filter clusters by
|
|
196
|
+
* 1. Not pinned
|
|
197
|
+
* 2. Includes search term
|
|
198
|
+
*
|
|
199
|
+
* Sort remaining clusters
|
|
200
|
+
*
|
|
201
|
+
* Reduce number of clusters if too many too show
|
|
202
|
+
*
|
|
203
|
+
* Important! This is hidden if there's a filter (user searching)
|
|
204
|
+
*/
|
|
152
205
|
pinFiltered() {
|
|
153
|
-
|
|
154
|
-
const
|
|
206
|
+
let localCluster = null;
|
|
207
|
+
const filtered = this.clusters.filter((c) => {
|
|
208
|
+
if (!c.pinned) {
|
|
209
|
+
// We only care about pinned clusters
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (c.id === 'local') {
|
|
214
|
+
// Special case, we're going to add this at the start so filter out
|
|
215
|
+
localCluster = c;
|
|
216
|
+
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return true;
|
|
221
|
+
});
|
|
155
222
|
|
|
156
|
-
|
|
157
|
-
// https://github.com/rancher/dashboard/issues/10975
|
|
158
|
-
if (sorted.findIndex((c) => c.id === 'local') > 0) {
|
|
159
|
-
const localCluster = sorted.find((c) => c.id === 'local');
|
|
160
|
-
const localIndex = sorted.findIndex((c) => c.id === 'local');
|
|
223
|
+
const sorted = sortBy(filtered, ['ready:desc', 'label']);
|
|
161
224
|
|
|
162
|
-
|
|
225
|
+
// put local cluster on top of list always - https://github.com/rancher/dashboard/issues/10975
|
|
226
|
+
if (localCluster) {
|
|
163
227
|
sorted.unshift(localCluster);
|
|
164
228
|
}
|
|
165
229
|
|
|
@@ -167,7 +231,7 @@ export default {
|
|
|
167
231
|
},
|
|
168
232
|
|
|
169
233
|
pinnedClustersHeight() {
|
|
170
|
-
const pinCount = this.
|
|
234
|
+
const pinCount = this.pinFiltered.length;
|
|
171
235
|
const height = pinCount > 2 ? (pinCount * 43) : 90;
|
|
172
236
|
|
|
173
237
|
return `min-height: ${ height }px`;
|