@rancher/shell 2.0.1 → 2.0.2
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/translations/en-us.yaml +73 -34
- package/assets/translations/zh-hans.yaml +1 -0
- package/components/AssignTo.vue +2 -0
- package/components/PromptRemove.vue +8 -3
- package/components/Questions/index.vue +2 -2
- package/components/ResourceDetail/Masthead.vue +1 -0
- package/components/auth/RoleDetailEdit.vue +5 -4
- package/components/fleet/FleetClusters.vue +0 -3
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/ProjectMemberEditor.vue +1 -1
- package/components/form/ResourceLabeledSelect.vue +11 -3
- package/components/form/labeled-select-utils/labeled-select.utils.ts +1 -1
- package/components/formatter/CloudCredExpired.vue +69 -0
- package/components/formatter/Date.vue +1 -1
- package/components/nav/Header.vue +9 -5
- package/components/nav/TopLevelMenu.vue +115 -51
- package/components/nav/__tests__/TopLevelMenu.test.ts +53 -27
- package/config/labels-annotations.js +2 -0
- package/config/pagination-table-headers.js +5 -4
- package/config/roles.ts +34 -19
- package/config/router/navigation-guards/attempt-first-login.js +1 -1
- package/config/router/navigation-guards/authentication.js +1 -1
- package/config/router/navigation-guards/i18n.js +1 -1
- package/config/router/navigation-guards/index.js +2 -1
- package/config/router/navigation-guards/load-initial-settings.js +1 -1
- package/config/router/navigation-guards/runtime-extension-route.js +31 -0
- package/config/router/routes.js +10 -1
- package/config/uiplugins.js +130 -61
- package/core/plugin.ts +5 -0
- package/core/plugins.js +7 -1
- package/detail/catalog.cattle.io.app.vue +17 -4
- package/detail/fleet.cattle.io.cluster.vue +11 -9
- package/detail/fleet.cattle.io.gitrepo.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +86 -13
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +3 -134
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +209 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/rke2.vue +128 -17
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +50 -0
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +29 -64
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +42 -3
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +22 -86
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +8 -2
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +61 -0
- package/initialize/entry-helpers.js +4 -21
- package/list/provisioning.cattle.io.cluster.vue +56 -5
- package/mixins/__tests__/chart.test.ts +4 -1
- package/mixins/chart.js +36 -16
- package/models/__tests__/apps.deployment.test.ts +93 -0
- package/models/apps.deployment.js +18 -4
- package/models/catalog.cattle.io.app.js +108 -21
- package/models/cloudcredential.js +159 -2
- package/models/fleet.cattle.io.gitrepo.js +4 -13
- package/models/management.cattle.io.cluster.js +15 -4
- package/models/management.cattle.io.user.js +3 -3
- package/models/nodedriver.js +5 -0
- package/models/provisioning.cattle.io.cluster.js +41 -3
- package/package.json +1 -1
- package/pages/404.vue +15 -0
- package/pages/auth/login.vue +4 -1
- package/pages/auth/setup.vue +4 -1
- package/pages/c/_cluster/apps/charts/install.vue +2 -1
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +6 -2
- package/pages/c/_cluster/fleet/index.vue +11 -5
- package/pages/c/_cluster/manager/cloudCredential/index.vue +68 -4
- package/pages/c/_cluster/manager/jwt.authentication/index.vue +10 -4
- package/pages/c/_cluster/settings/performance.vue +2 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +7 -10
- package/pages/c/_cluster/uiplugins/index.vue +28 -18
- package/pages/home.vue +2 -13
- package/plugins/dashboard-store/actions.js +1 -1
- package/plugins/dashboard-store/getters.js +1 -1
- package/plugins/steve/__tests__/getters.test.ts +5 -5
- package/plugins/steve/getters.js +6 -4
- package/plugins/steve/hybrid-class.js +1 -5
- package/scripts/extension/bundle +1 -1
- package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +1 -1
- package/scripts/publish-shell.sh +56 -59
- package/scripts/test-plugins-build.sh +45 -39
- package/scripts/typegen.sh +26 -23
- package/store/type-map.js +4 -2
- package/types/shell/index.d.ts +10 -0
- package/types/store/pagination.types.ts +1 -1
- package/utils/cluster.js +9 -0
- package/utils/settings.ts +3 -1
- package/utils/string.js +9 -0
- package/utils/v-sphere.ts +251 -0
- package/creators/app/app.package.json +0 -14
- package/creators/app/files/.eslintignore +0 -16
- package/creators/app/files/.eslintrc.js +0 -173
- package/creators/app/files/.gitignore +0 -70
- package/creators/app/files/.gitlab-ci.yml +0 -14
- package/creators/app/files/.vscode/settings.json +0 -21
- package/creators/app/files/babel.config.js +0 -1
- package/creators/app/files/tsconfig.json +0 -42
- package/creators/app/files/vue.config.js +0 -6
- package/creators/app/init +0 -120
- package/creators/app/package.json +0 -25
- package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +0 -24
- package/creators/pkg/files/.github/workflows/build-extension-charts.yml +0 -22
- package/creators/pkg/files/babel.config.js +0 -1
- package/creators/pkg/files/index.ts +0 -14
- package/creators/pkg/files/tsconfig.json +0 -53
- package/creators/pkg/files/vue.config.js +0 -1
- package/creators/pkg/init +0 -286
- package/creators/pkg/package.json +0 -19
- package/creators/pkg/pkg.package.json +0 -21
- package/creators/pkg/vue-shim.ts +0 -4
- package/creators/update/init +0 -56
- package/creators/update/package.json +0 -20
- package/creators/update/upgrade +0 -56
|
@@ -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`;
|
|
@@ -5,7 +5,7 @@ import { mount, Wrapper } from '@vue/test-utils';
|
|
|
5
5
|
// DISCLAIMER: This should not be added here, although we have several store requests which are irrelevant
|
|
6
6
|
const defaultStore = {
|
|
7
7
|
'management/byId': jest.fn(),
|
|
8
|
-
'management/schemaFor':
|
|
8
|
+
'management/schemaFor': () => ({}),
|
|
9
9
|
'i18n/t': jest.fn(),
|
|
10
10
|
'features/get': jest.fn(),
|
|
11
11
|
'prefs/theme': jest.fn(),
|
|
@@ -20,7 +20,11 @@ describe('topLevelMenu', () => {
|
|
|
20
20
|
mocks: {
|
|
21
21
|
$store: {
|
|
22
22
|
getters: {
|
|
23
|
-
'management/all': () => [{
|
|
23
|
+
'management/all': () => [{
|
|
24
|
+
name: 'whatever',
|
|
25
|
+
id: 'an-id1',
|
|
26
|
+
mgmt: { id: 'an-id1' },
|
|
27
|
+
}],
|
|
24
28
|
...defaultStore
|
|
25
29
|
},
|
|
26
30
|
},
|
|
@@ -48,21 +52,21 @@ describe('topLevelMenu', () => {
|
|
|
48
52
|
'management/all': () => [
|
|
49
53
|
{
|
|
50
54
|
name: 'x32-cwf5-name',
|
|
51
|
-
id: '
|
|
55
|
+
id: 'an-id1',
|
|
52
56
|
mgmt: { id: 'an-id1' },
|
|
53
57
|
nameDisplay: 'c-cluster',
|
|
54
58
|
isReady: true
|
|
55
59
|
},
|
|
56
60
|
{
|
|
57
61
|
name: 'x33-cwf5-name',
|
|
58
|
-
id: '
|
|
62
|
+
id: 'an-id2',
|
|
59
63
|
mgmt: { id: 'an-id2' },
|
|
60
64
|
nameDisplay: 'a-cluster',
|
|
61
65
|
isReady: true
|
|
62
66
|
},
|
|
63
67
|
{
|
|
64
68
|
name: 'x34-cwf5-name',
|
|
65
|
-
id: '
|
|
69
|
+
id: 'an-id3',
|
|
66
70
|
mgmt: { id: 'an-id3' },
|
|
67
71
|
nameDisplay: 'b-cluster',
|
|
68
72
|
isReady: true
|
|
@@ -70,7 +74,7 @@ describe('topLevelMenu', () => {
|
|
|
70
74
|
{
|
|
71
75
|
name: 'local-name',
|
|
72
76
|
id: 'local',
|
|
73
|
-
mgmt: { id: '
|
|
77
|
+
mgmt: { id: 'local' },
|
|
74
78
|
nameDisplay: 'local',
|
|
75
79
|
isReady: true
|
|
76
80
|
},
|
|
@@ -103,21 +107,21 @@ describe('topLevelMenu', () => {
|
|
|
103
107
|
'management/all': () => [
|
|
104
108
|
{
|
|
105
109
|
name: 'x32-cwf5-name',
|
|
106
|
-
id: '
|
|
110
|
+
id: 'an-id1',
|
|
107
111
|
mgmt: { id: 'an-id1' },
|
|
108
112
|
nameDisplay: 'c-cluster',
|
|
109
113
|
isReady: true
|
|
110
114
|
},
|
|
111
115
|
{
|
|
112
116
|
name: 'x33-cwf5-name',
|
|
113
|
-
id: '
|
|
117
|
+
id: 'an-id2',
|
|
114
118
|
mgmt: { id: 'an-id2' },
|
|
115
119
|
nameDisplay: 'a-cluster',
|
|
116
120
|
isReady: false
|
|
117
121
|
},
|
|
118
122
|
{
|
|
119
123
|
name: 'x34-cwf5-name',
|
|
120
|
-
id: '
|
|
124
|
+
id: 'an-id3',
|
|
121
125
|
mgmt: { id: 'an-id3' },
|
|
122
126
|
nameDisplay: 'b-cluster',
|
|
123
127
|
isReady: true
|
|
@@ -125,7 +129,7 @@ describe('topLevelMenu', () => {
|
|
|
125
129
|
{
|
|
126
130
|
name: 'local-name',
|
|
127
131
|
id: 'local',
|
|
128
|
-
mgmt: { id: '
|
|
132
|
+
mgmt: { id: 'local' },
|
|
129
133
|
nameDisplay: 'local',
|
|
130
134
|
isReady: true
|
|
131
135
|
},
|
|
@@ -158,7 +162,7 @@ describe('topLevelMenu', () => {
|
|
|
158
162
|
'management/all': () => [
|
|
159
163
|
{
|
|
160
164
|
name: 'x32-cwf5-name',
|
|
161
|
-
id: '
|
|
165
|
+
id: 'an-id1',
|
|
162
166
|
mgmt: { id: 'an-id1' },
|
|
163
167
|
nameDisplay: 'c-cluster',
|
|
164
168
|
isReady: true,
|
|
@@ -166,7 +170,7 @@ describe('topLevelMenu', () => {
|
|
|
166
170
|
},
|
|
167
171
|
{
|
|
168
172
|
name: 'x33-cwf5-name',
|
|
169
|
-
id: '
|
|
173
|
+
id: 'an-id2',
|
|
170
174
|
mgmt: { id: 'an-id2' },
|
|
171
175
|
nameDisplay: 'a-cluster',
|
|
172
176
|
isReady: true,
|
|
@@ -174,7 +178,7 @@ describe('topLevelMenu', () => {
|
|
|
174
178
|
},
|
|
175
179
|
{
|
|
176
180
|
name: 'x34-cwf5-name',
|
|
177
|
-
id: '
|
|
181
|
+
id: 'an-id3',
|
|
178
182
|
mgmt: { id: 'an-id3' },
|
|
179
183
|
nameDisplay: 'b-cluster',
|
|
180
184
|
isReady: true,
|
|
@@ -183,7 +187,7 @@ describe('topLevelMenu', () => {
|
|
|
183
187
|
{
|
|
184
188
|
name: 'local-name',
|
|
185
189
|
id: 'local',
|
|
186
|
-
mgmt: { id: '
|
|
190
|
+
mgmt: { id: 'local' },
|
|
187
191
|
nameDisplay: 'local',
|
|
188
192
|
isReady: true,
|
|
189
193
|
pinned: true
|
|
@@ -217,7 +221,7 @@ describe('topLevelMenu', () => {
|
|
|
217
221
|
'management/all': () => [
|
|
218
222
|
{
|
|
219
223
|
name: 'x32-cwf5-name',
|
|
220
|
-
id: '
|
|
224
|
+
id: 'an-id1',
|
|
221
225
|
mgmt: { id: 'an-id1' },
|
|
222
226
|
nameDisplay: 'c-cluster',
|
|
223
227
|
isReady: true,
|
|
@@ -225,7 +229,7 @@ describe('topLevelMenu', () => {
|
|
|
225
229
|
},
|
|
226
230
|
{
|
|
227
231
|
name: 'x33-cwf5-name',
|
|
228
|
-
id: '
|
|
232
|
+
id: 'an-id2',
|
|
229
233
|
mgmt: { id: 'an-id2' },
|
|
230
234
|
nameDisplay: 'a-cluster',
|
|
231
235
|
isReady: true,
|
|
@@ -233,7 +237,7 @@ describe('topLevelMenu', () => {
|
|
|
233
237
|
},
|
|
234
238
|
{
|
|
235
239
|
name: 'x34-cwf5-name',
|
|
236
|
-
id: '
|
|
240
|
+
id: 'an-id3',
|
|
237
241
|
mgmt: { id: 'an-id3' },
|
|
238
242
|
nameDisplay: 'b-cluster',
|
|
239
243
|
isReady: false,
|
|
@@ -242,7 +246,7 @@ describe('topLevelMenu', () => {
|
|
|
242
246
|
{
|
|
243
247
|
name: 'local-name',
|
|
244
248
|
id: 'local',
|
|
245
|
-
mgmt: { id: '
|
|
249
|
+
mgmt: { id: 'local' },
|
|
246
250
|
nameDisplay: 'local',
|
|
247
251
|
isReady: true,
|
|
248
252
|
pinned: true
|
|
@@ -333,7 +337,7 @@ describe('topLevelMenu', () => {
|
|
|
333
337
|
it('should show description if it is available on the mgmt cluster (relevant for RKE1/ember world)', async() => {
|
|
334
338
|
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
335
339
|
data: () => {
|
|
336
|
-
return { hasProvCluster:
|
|
340
|
+
return { hasProvCluster: true, showPinClusters: true };
|
|
337
341
|
},
|
|
338
342
|
mocks: {
|
|
339
343
|
$store: {
|
|
@@ -347,6 +351,7 @@ describe('topLevelMenu', () => {
|
|
|
347
351
|
{
|
|
348
352
|
name: 'whatever',
|
|
349
353
|
id: 'an-id1',
|
|
354
|
+
mgmt: { id: 'an-id1' },
|
|
350
355
|
description: 'some-description1',
|
|
351
356
|
nameDisplay: 'some-label',
|
|
352
357
|
isReady: true,
|
|
@@ -356,6 +361,7 @@ describe('topLevelMenu', () => {
|
|
|
356
361
|
{
|
|
357
362
|
name: 'whatever',
|
|
358
363
|
id: 'an-id2',
|
|
364
|
+
mgmt: { id: 'an-id2' },
|
|
359
365
|
description: 'some-description2',
|
|
360
366
|
nameDisplay: 'some-label',
|
|
361
367
|
pinned: true
|
|
@@ -364,6 +370,7 @@ describe('topLevelMenu', () => {
|
|
|
364
370
|
{
|
|
365
371
|
name: 'whatever',
|
|
366
372
|
id: 'an-id3',
|
|
373
|
+
mgmt: { id: 'an-id3' },
|
|
367
374
|
description: 'some-description3',
|
|
368
375
|
nameDisplay: 'some-label',
|
|
369
376
|
isReady: true
|
|
@@ -372,6 +379,7 @@ describe('topLevelMenu', () => {
|
|
|
372
379
|
{
|
|
373
380
|
name: 'whatever',
|
|
374
381
|
id: 'an-id4',
|
|
382
|
+
mgmt: { id: 'an-id4' },
|
|
375
383
|
description: 'some-description4',
|
|
376
384
|
nameDisplay: 'some-label'
|
|
377
385
|
},
|
|
@@ -430,11 +438,15 @@ describe('topLevelMenu', () => {
|
|
|
430
438
|
describe('should displays a no results message if have clusters but', () => {
|
|
431
439
|
it('given no matching clusters', () => {
|
|
432
440
|
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
433
|
-
data: () => ({ clusterFilter: 'whatever' }),
|
|
441
|
+
data: () => ({ hasProvCluster: true, clusterFilter: 'whatever' }),
|
|
434
442
|
mocks: {
|
|
435
443
|
$store: {
|
|
436
444
|
getters: {
|
|
437
|
-
'management/all': () => [{
|
|
445
|
+
'management/all': () => [{
|
|
446
|
+
id: 'an-id1',
|
|
447
|
+
mgmt: { id: 'an-id1' },
|
|
448
|
+
nameDisplay: 'something else'
|
|
449
|
+
}],
|
|
438
450
|
...defaultStore
|
|
439
451
|
},
|
|
440
452
|
},
|
|
@@ -449,11 +461,16 @@ describe('topLevelMenu', () => {
|
|
|
449
461
|
|
|
450
462
|
it('given no matched pinned clusters', () => {
|
|
451
463
|
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
452
|
-
data: () => ({ clusterFilter: 'whatever' }),
|
|
464
|
+
data: () => ({ hasProvCluster: true, clusterFilter: 'whatever' }),
|
|
453
465
|
mocks: {
|
|
454
466
|
$store: {
|
|
455
467
|
getters: {
|
|
456
|
-
'management/all': () => [{
|
|
468
|
+
'management/all': () => [{
|
|
469
|
+
id: 'an-id1',
|
|
470
|
+
mgmt: { id: 'an-id1' },
|
|
471
|
+
nameDisplay: 'something else',
|
|
472
|
+
pinned: true
|
|
473
|
+
}],
|
|
457
474
|
...defaultStore
|
|
458
475
|
},
|
|
459
476
|
},
|
|
@@ -471,11 +488,15 @@ describe('topLevelMenu', () => {
|
|
|
471
488
|
it('given matching clusters', () => {
|
|
472
489
|
const search = 'you found me';
|
|
473
490
|
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
474
|
-
data: () => ({ clusterFilter: search }),
|
|
491
|
+
data: () => ({ hasProvCluster: true, clusterFilter: search }),
|
|
475
492
|
mocks: {
|
|
476
493
|
$store: {
|
|
477
494
|
getters: {
|
|
478
|
-
'management/all': () => [{
|
|
495
|
+
'management/all': () => [{
|
|
496
|
+
id: 'an-id1',
|
|
497
|
+
mgmt: { id: 'an-id1' },
|
|
498
|
+
nameDisplay: search
|
|
499
|
+
}],
|
|
479
500
|
...defaultStore
|
|
480
501
|
},
|
|
481
502
|
},
|
|
@@ -492,11 +513,16 @@ describe('topLevelMenu', () => {
|
|
|
492
513
|
it('given clusters with status pinned', () => {
|
|
493
514
|
const search = 'you found me';
|
|
494
515
|
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
495
|
-
data: () => ({ clusterFilter: search }),
|
|
516
|
+
data: () => ({ hasProvCluster: true, clusterFilter: search }),
|
|
496
517
|
mocks: {
|
|
497
518
|
$store: {
|
|
498
519
|
getters: {
|
|
499
|
-
'management/all': () => [{
|
|
520
|
+
'management/all': () => [{
|
|
521
|
+
nameDisplay: search,
|
|
522
|
+
pinned: true,
|
|
523
|
+
id: 'an-id1',
|
|
524
|
+
mgmt: { id: 'an-id1' },
|
|
525
|
+
}],
|
|
500
526
|
...defaultStore
|
|
501
527
|
},
|
|
502
528
|
},
|
|
@@ -17,15 +17,16 @@ export const STEVE_ID_COL = {
|
|
|
17
17
|
name: 'steve-id',
|
|
18
18
|
labelKey: 'tableHeaders.id',
|
|
19
19
|
value: 'id',
|
|
20
|
-
sort: ['id'],
|
|
21
|
-
search: 'id',
|
|
20
|
+
sort: false, // sort: ['id'], // Pending API support
|
|
21
|
+
search: false, // search: 'id', // Pending API support
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
export const STEVE_STATE_COL = {
|
|
25
25
|
...STATE,
|
|
26
|
-
//
|
|
26
|
+
// Note, we're show the 'state' as per model, not the 'metadata.state.name' that's available in the model to remotely sort/filter
|
|
27
|
+
// Need to investigate whether we should 'dumb down' the state we show to the native one (tracked via https://github.com/rancher/dashboard/issues/8527)
|
|
27
28
|
// This means we'll show something different to what we sort and filter on.
|
|
28
|
-
sort:
|
|
29
|
+
sort: false, // ['metadata.state.name'], // Pending API support
|
|
29
30
|
search: false, // 'metadata.state.name', // Pending API support
|
|
30
31
|
};
|
|
31
32
|
|
package/config/roles.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
export const enum SCOPED_RESOURCE_GROUPS {
|
|
2
|
+
GLOBAL = 'globalScopedApiGroups', // eslint-disable-line no-unused-vars
|
|
3
|
+
CLUSTER = 'clusterScopedApiGroups', // eslint-disable-line no-unused-vars
|
|
4
|
+
PROJECT_NAMESPACE = 'projectScopedApiGroups', // eslint-disable-line no-unused-vars
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resources users can select when creating grants when managing global, cluster and project/namespace roles
|
|
9
|
+
*
|
|
10
|
+
* **************NOTE*****************
|
|
11
|
+
* Global roles will show ALL entries
|
|
12
|
+
* Cluster roles will show cluster AND project/namespace entries
|
|
13
|
+
* Project/Namespace roles will show ONLY project/namespace entries
|
|
14
|
+
*/
|
|
1
15
|
export const SCOPED_RESOURCES = {
|
|
2
16
|
// With this hardcoded list, it will be easier to curate a more useful
|
|
3
17
|
// and human-understandable list of resources to choose from
|
|
@@ -13,7 +27,7 @@ export const SCOPED_RESOURCES = {
|
|
|
13
27
|
// the global scoped list, and the project role creation form includes a
|
|
14
28
|
// subset of the cluster scoped list.
|
|
15
29
|
|
|
16
|
-
|
|
30
|
+
[SCOPED_RESOURCE_GROUPS.GLOBAL]: {
|
|
17
31
|
// Global scoped resources are resources for
|
|
18
32
|
// Rancher's global apps, mainly Cluster
|
|
19
33
|
// Management and Continuous Delivery.
|
|
@@ -130,9 +144,9 @@ export const SCOPED_RESOURCES = {
|
|
|
130
144
|
resources: [
|
|
131
145
|
'Clusters'
|
|
132
146
|
]
|
|
133
|
-
}
|
|
147
|
+
},
|
|
134
148
|
},
|
|
135
|
-
|
|
149
|
+
[SCOPED_RESOURCE_GROUPS.CLUSTER]: {
|
|
136
150
|
// Cluster scoped resources are for non-namespaced
|
|
137
151
|
// resources at the cluster level, for example,
|
|
138
152
|
// storage resources.
|
|
@@ -201,15 +215,16 @@ export const SCOPED_RESOURCES = {
|
|
|
201
215
|
},
|
|
202
216
|
neuvectorApi: {
|
|
203
217
|
resources: [
|
|
204
|
-
'
|
|
205
|
-
'
|
|
206
|
-
'
|
|
207
|
-
'
|
|
208
|
-
'
|
|
218
|
+
'AdmissionControl',
|
|
219
|
+
'Authentication',
|
|
220
|
+
'CIScan',
|
|
221
|
+
'Cluster',
|
|
222
|
+
'Federation',
|
|
223
|
+
'Vulnerability',
|
|
209
224
|
]
|
|
210
225
|
}
|
|
211
226
|
},
|
|
212
|
-
|
|
227
|
+
[SCOPED_RESOURCE_GROUPS.PROJECT_NAMESPACE]: {
|
|
213
228
|
// Project scoped resources include all other namespaced
|
|
214
229
|
// resources.
|
|
215
230
|
coreKubernetesApi: {
|
|
@@ -378,16 +393,16 @@ export const SCOPED_RESOURCES = {
|
|
|
378
393
|
},
|
|
379
394
|
neuvectorApi: {
|
|
380
395
|
resources: [
|
|
381
|
-
'
|
|
382
|
-
'
|
|
383
|
-
'
|
|
384
|
-
'
|
|
385
|
-
'
|
|
386
|
-
'
|
|
387
|
-
'
|
|
388
|
-
'
|
|
389
|
-
'
|
|
390
|
-
'
|
|
396
|
+
'AuditEvents',
|
|
397
|
+
'Authorization',
|
|
398
|
+
'Compliance',
|
|
399
|
+
'Events',
|
|
400
|
+
'Namespace',
|
|
401
|
+
'RegistryScan',
|
|
402
|
+
'RuntimePolicy',
|
|
403
|
+
'RuntimeScan',
|
|
404
|
+
'SecurityEvents',
|
|
405
|
+
'SystemConfig',
|
|
391
406
|
]
|
|
392
407
|
}
|
|
393
408
|
}
|
|
@@ -5,7 +5,7 @@ import { tryInitialSetup } from '@shell/utils/auth';
|
|
|
5
5
|
import { routeRequiresAuthentication } from '@shell/utils/router';
|
|
6
6
|
|
|
7
7
|
export function install(router, context) {
|
|
8
|
-
router.beforeEach((to, from, next) => attemptFirstLogin(to, from, next, context));
|
|
8
|
+
router.beforeEach(async(to, from, next) => await attemptFirstLogin(to, from, next, context));
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export async function attemptFirstLogin(to, from, next, { store }) {
|
|
@@ -2,7 +2,7 @@ import { routeRequiresAuthentication } from '@shell/utils/router';
|
|
|
2
2
|
import { isLoggedIn, notLoggedIn, noAuth, findMe } from '@shell/utils/auth';
|
|
3
3
|
|
|
4
4
|
export function install(router, context) {
|
|
5
|
-
router.beforeEach((to, from, next) => authenticate(to, from, next, context));
|
|
5
|
+
router.beforeEach(async(to, from, next) => await authenticate(to, from, next, context));
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export async function authenticate(to, from, next, { store }) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function install(router, context) {
|
|
2
|
-
router.beforeEach((to, from, next) => loadI18n(to, from, next, context));
|
|
2
|
+
router.beforeEach(async(to, from, next) => await loadI18n(to, from, next, context));
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export async function loadI18n(to, from, next, { store }) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { install as installLoadInitialSettings } from '@shell/config/router/navigation-guards/load-initial-settings';
|
|
2
2
|
import { install as installAttemptFirstLogin } from '@shell/config/router/navigation-guards/attempt-first-login';
|
|
3
3
|
import { install as installAuthentication } from '@shell/config/router/navigation-guards/authentication';
|
|
4
|
+
import { install as installRuntimeExtensionRoute } from '@shell/config/router/navigation-guards/runtime-extension-route';
|
|
4
5
|
import { install as installI18N } from '@shell/config/router/navigation-guards/i18n';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -10,7 +11,7 @@ export function installNavigationGuards(router, context) {
|
|
|
10
11
|
// NOTE: the order of the installation matters.
|
|
11
12
|
// Be intentional when adding, removing or modifying the guards that are installed.
|
|
12
13
|
|
|
13
|
-
const navigationGuardInstallers = [installLoadInitialSettings, installAttemptFirstLogin, installAuthentication, installI18N];
|
|
14
|
+
const navigationGuardInstallers = [installLoadInitialSettings, installAttemptFirstLogin, installAuthentication, installRuntimeExtensionRoute, installI18N];
|
|
14
15
|
|
|
15
16
|
navigationGuardInstallers.forEach((installer) => installer(router, context));
|
|
16
17
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fetchInitialSettings } from '@shell/utils/settings';
|
|
2
2
|
|
|
3
3
|
export function install(router, context) {
|
|
4
|
-
router.beforeEach((to, from, next) => loadInitialSettings(to, from, next, context));
|
|
4
|
+
router.beforeEach(async(to, from, next) => await loadInitialSettings(to, from, next, context));
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export async function loadInitialSettings(to, from, next, { store }) {
|