@rancher/shell 3.0.9-rc.4 → 3.0.9-rc.5
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/brand/suse/metadata.json +2 -1
- package/assets/translations/en-us.yaml +91 -3
- package/components/ActionMenuShell.vue +1 -1
- package/components/Inactivity.vue +2 -2
- package/components/Resource/Detail/Card/ExtrasCard.vue +49 -15
- package/components/Resource/Detail/Card/__tests__/ExtrasCard.test.ts +111 -0
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +0 -17
- package/components/Resource/Detail/Masthead/index.vue +11 -4
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +3 -1
- package/components/Resource/Detail/Metadata/index.vue +1 -1
- package/components/Resource/Detail/ResourceRow.vue +1 -1
- package/components/ResourceDetail/Masthead/latest.vue +12 -2
- package/components/ResourceList/index.vue +9 -0
- package/components/ResourceTable.vue +38 -4
- package/components/Tabbed/Tab.vue +4 -0
- package/components/Tabbed/index.vue +4 -1
- package/components/__tests__/ProjectRow.test.ts +60 -0
- package/components/form/ChangePassword.vue +41 -35
- package/components/form/ResourceQuota/Project.vue +42 -1
- package/components/form/ResourceQuota/ProjectRow.vue +71 -4
- package/components/form/ResourceQuota/__tests__/Project.test.ts +63 -0
- package/components/form/SelectOrCreateAuthSecret.vue +6 -1
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +35 -0
- package/components/formatter/MachineSummaryGraph.vue +10 -2
- package/components/nav/TopLevelMenu.helper.ts +50 -2
- package/components/nav/TopLevelMenu.vue +14 -0
- package/components/nav/Type.vue +5 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +3 -3
- package/components/nav/__tests__/Type.test.ts +6 -4
- package/config/product/explorer.js +4 -3
- package/config/product/manager.js +18 -1
- package/config/router/navigation-guards/authentication.js +8 -9
- package/config/types.js +10 -2
- package/detail/auditlog.cattle.io.auditpolicy.vue +19 -0
- package/detail/management.cattle.io.user.vue +1 -2
- package/detail/node.vue +0 -1
- package/detail/provisioning.cattle.io.cluster.vue +2 -1
- package/dialog/ChangePasswordDialog.vue +8 -0
- package/dialog/GenericPrompt.vue +20 -3
- package/dialog/ScaleMachineDownDialog.vue +65 -15
- package/dialog/SearchDialog.vue +10 -2
- package/dialog/__tests__/ScaleMachineDownDialog.test.ts +184 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +89 -0
- package/edit/__tests__/management.cattle.io.project.test.js +56 -1
- package/edit/auditlog.cattle.io.auditpolicy/AdditionalRedactions.vue +114 -0
- package/edit/auditlog.cattle.io.auditpolicy/Filters.vue +119 -0
- package/edit/auditlog.cattle.io.auditpolicy/General.vue +180 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/AdditionalRedactions.test.ts +327 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/Filters.test.ts +449 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/General.test.ts +472 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/AdditionalRedactions.test.ts.snap +27 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/Filters.test.ts.snap +39 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +174 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +29 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/index.test.ts +215 -0
- package/edit/auditlog.cattle.io.auditpolicy/index.vue +104 -0
- package/edit/auditlog.cattle.io.auditpolicy/types.ts +28 -0
- package/edit/fleet.cattle.io.gitrepo.vue +16 -1
- package/edit/management.cattle.io.project.vue +8 -2
- package/edit/management.cattle.io.user.vue +29 -34
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +178 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +21 -2
- package/edit/provisioning.cattle.io.cluster/shared.ts +4 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -1
- package/list/auditlog.cattle.io.auditpolicy.vue +63 -0
- package/list/group.principal.vue +11 -15
- package/list/management.cattle.io.user.vue +11 -21
- package/machine-config/azure.vue +14 -0
- package/mixins/browser-tab-visibility.js +5 -4
- package/mixins/fetch.client.js +6 -0
- package/models/__tests__/auditlog.cattle.io.auditpolicy.test.ts +117 -0
- package/models/__tests__/workload.test.ts +49 -6
- package/models/auditlog.cattle.io.auditpolicy.js +46 -0
- package/models/cluster.x-k8s.io.machine.js +1 -1
- package/models/cluster.x-k8s.io.machinedeployment.js +5 -5
- package/models/event.js +5 -0
- package/models/ext.cattle.io.groupmembershiprefreshrequest.js +15 -0
- package/models/ext.cattle.io.passwordchangerequest.js +15 -0
- package/models/ext.cattle.io.selfuser.js +15 -0
- package/models/fleet-application.js +17 -7
- package/models/management.cattle.io.user.js +28 -31
- package/models/schema.js +18 -0
- package/models/secret.js +27 -24
- package/models/steve-schema.ts +39 -2
- package/models/workload.js +3 -2
- package/package.json +1 -1
- package/pages/account/index.vue +23 -16
- package/pages/auth/login.vue +15 -8
- package/pages/auth/setup.vue +52 -15
- package/pages/home.vue +9 -3
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -3
- package/plugins/dashboard-store/actions.js +7 -0
- package/plugins/dashboard-store/getters.js +23 -1
- package/plugins/dashboard-store/index.js +3 -2
- package/plugins/dashboard-store/mutations.js +4 -0
- package/plugins/dashboard-store/resource-class.js +12 -5
- package/plugins/steve/__tests__/steve-class.test.ts +167 -0
- package/plugins/steve/schema.d.ts +5 -0
- package/plugins/steve/steve-class.js +19 -0
- package/plugins/steve/steve-pagination-utils.ts +2 -1
- package/store/auth.js +57 -19
- package/store/notifications.ts +1 -1
- package/store/type-map.js +12 -1
- package/types/shell/index.d.ts +10 -14
- package/types/store/dashboard-store.types.ts +7 -0
- package/utils/pagination-wrapper.ts +11 -3
- package/vue.config.js +26 -13
- package/edit/provisioning.cattle.io.cluster/defaults.ts +0 -1
|
@@ -595,7 +595,7 @@ describe('topLevelMenu', () => {
|
|
|
595
595
|
jest.spyOn(sideNavService, 'init').mockImplementation(() => {});
|
|
596
596
|
const updateSpy = jest.fn();
|
|
597
597
|
const mockHelper = {
|
|
598
|
-
update: updateSpy, clustersPinned: [], clustersOthers: []
|
|
598
|
+
update: updateSpy, clustersPinned: [], clustersOthers: [], updateCount: () => {}
|
|
599
599
|
};
|
|
600
600
|
|
|
601
601
|
jest.spyOn(sideNavService, 'helper', 'get').mockReturnValue(mockHelper as any);
|
|
@@ -624,7 +624,7 @@ describe('topLevelMenu', () => {
|
|
|
624
624
|
jest.spyOn(sideNavService, 'init').mockImplementation(() => {});
|
|
625
625
|
const updateSpy = jest.fn();
|
|
626
626
|
const mockHelper = {
|
|
627
|
-
update: updateSpy, clustersPinned: [], clustersOthers: []
|
|
627
|
+
update: updateSpy, clustersPinned: [], clustersOthers: [], updateCount: () => {}
|
|
628
628
|
};
|
|
629
629
|
|
|
630
630
|
jest.spyOn(sideNavService, 'helper', 'get').mockReturnValue(mockHelper as any);
|
|
@@ -653,7 +653,7 @@ describe('topLevelMenu', () => {
|
|
|
653
653
|
jest.spyOn(sideNavService, 'init').mockImplementation(() => {});
|
|
654
654
|
const updateSpy = jest.fn();
|
|
655
655
|
const mockHelper = {
|
|
656
|
-
update: updateSpy, clustersPinned: [], clustersOthers: []
|
|
656
|
+
update: updateSpy, clustersPinned: [], clustersOthers: [], updateCount: () => {}
|
|
657
657
|
};
|
|
658
658
|
|
|
659
659
|
jest.spyOn(sideNavService, 'helper', 'get').mockReturnValue(mockHelper as any);
|
|
@@ -21,8 +21,9 @@ describe('component: Type', () => {
|
|
|
21
21
|
const defaultCount = 1;
|
|
22
22
|
const storeMock = {
|
|
23
23
|
getters: {
|
|
24
|
-
currentStore:
|
|
25
|
-
'cluster/count':
|
|
24
|
+
currentStore: () => 'cluster',
|
|
25
|
+
'cluster/count': () => defaultCount,
|
|
26
|
+
'type-map/optionsFor': () => {},
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
29
|
const routerMock = {
|
|
@@ -449,8 +450,9 @@ describe('component: Type', () => {
|
|
|
449
450
|
|
|
450
451
|
$store: {
|
|
451
452
|
getters: {
|
|
452
|
-
currentStore:
|
|
453
|
-
'cluster/count':
|
|
453
|
+
currentStore: () => 'cluster',
|
|
454
|
+
'cluster/count': () => null,
|
|
455
|
+
'type-map/optionsFor': () => {},
|
|
454
456
|
}
|
|
455
457
|
},
|
|
456
458
|
$router: routerMock,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
CONFIG_MAP,
|
|
4
4
|
EVENT,
|
|
5
5
|
NODE, SECRET, INGRESS,
|
|
6
|
-
WORKLOAD, WORKLOAD_TYPES, SERVICE, HPA, NETWORK_POLICY, PV, PVC, STORAGE_CLASS, POD, POD_DISRUPTION_BUDGET, LIMIT_RANGE, RESOURCE_QUOTA,
|
|
6
|
+
WORKLOAD, WORKLOAD_TYPES, SERVICE, HPA, NETWORK_POLICY, PV, PVC, STORAGE_CLASS, POD, POD_DISRUPTION_BUDGET, LIMIT_RANGE, RESOURCE_QUOTA, AUDIT_POLICY,
|
|
7
7
|
MANAGEMENT,
|
|
8
8
|
NAMESPACE,
|
|
9
9
|
NORMAN,
|
|
@@ -83,6 +83,7 @@ export function init(store) {
|
|
|
83
83
|
NETWORK_POLICY,
|
|
84
84
|
POD_DISRUPTION_BUDGET,
|
|
85
85
|
RESOURCE_QUOTA,
|
|
86
|
+
AUDIT_POLICY,
|
|
86
87
|
], 'policy');
|
|
87
88
|
|
|
88
89
|
basicType([
|
|
@@ -118,6 +119,7 @@ export function init(store) {
|
|
|
118
119
|
weightGroup('storage', 95, true);
|
|
119
120
|
weightGroup('policy', 94, true);
|
|
120
121
|
weightType(POD, -1, true);
|
|
122
|
+
weightType(AUDIT_POLICY, -1, true);
|
|
121
123
|
|
|
122
124
|
// here is where we define the usage of the WORKLOAD custom list view for
|
|
123
125
|
// all the workload types (ex: deployments, cron jobs, daemonsets, etc)
|
|
@@ -152,6 +154,7 @@ export function init(store) {
|
|
|
152
154
|
mapGroup('autoscaling', 'Autoscaling');
|
|
153
155
|
mapGroup('policy', 'Policy');
|
|
154
156
|
mapGroup('networking.k8s.io', 'Networking');
|
|
157
|
+
mapGroup('auditlog.cattle.io', 'Policy');
|
|
155
158
|
mapGroup(/^(.+\.)?api(server)?.*\.k8s\.io$/, 'API');
|
|
156
159
|
mapGroup('rbac.authorization.k8s.io', 'RBAC');
|
|
157
160
|
mapGroup('admissionregistration.k8s.io', 'admission');
|
|
@@ -181,7 +184,6 @@ export function init(store) {
|
|
|
181
184
|
|
|
182
185
|
const dePaginateBindings = configureConditionalDepaginate({ maxResourceCount: 5000 });
|
|
183
186
|
const dePaginateNormanBindings = configureConditionalDepaginate({ maxResourceCount: 5000, isNorman: true });
|
|
184
|
-
const dePaginateNormanUsers = configureConditionalDepaginate({ maxResourceCount: 5000, isNorman: true });
|
|
185
187
|
|
|
186
188
|
configureType(NODE, { isCreatable: false, isEditable: true });
|
|
187
189
|
configureType(WORKLOAD_TYPES.JOB, { isEditable: false, match: WORKLOAD_TYPES.JOB });
|
|
@@ -190,7 +192,6 @@ export function init(store) {
|
|
|
190
192
|
configureType(MANAGEMENT.PROJECT, { displayName: store.getters['i18n/t']('namespace.project.label') });
|
|
191
193
|
configureType(NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings });
|
|
192
194
|
configureType(NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings });
|
|
193
|
-
configureType(NORMAN.USER, { depaginate: dePaginateNormanUsers });
|
|
194
195
|
configureType(SNAPSHOT, { depaginate: true });
|
|
195
196
|
|
|
196
197
|
configureType(SECRET, { showListMasthead: false });
|
|
@@ -3,16 +3,20 @@ import {
|
|
|
3
3
|
CAPI,
|
|
4
4
|
CATALOG,
|
|
5
5
|
EXT,
|
|
6
|
+
COUNT,
|
|
6
7
|
NORMAN,
|
|
7
8
|
HCI,
|
|
8
9
|
MANAGEMENT,
|
|
9
10
|
SNAPSHOT,
|
|
10
11
|
VIRTUAL_TYPES,
|
|
11
|
-
HOSTED_PROVIDER
|
|
12
|
+
HOSTED_PROVIDER,
|
|
13
|
+
SAVED_COUNTS
|
|
12
14
|
} from '@shell/config/types';
|
|
13
15
|
import { MULTI_CLUSTER } from '@shell/store/features';
|
|
14
16
|
import { DSL } from '@shell/store/type-map';
|
|
15
17
|
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
18
|
+
import { markRaw } from 'vue';
|
|
19
|
+
|
|
16
20
|
export const NAME = 'manager';
|
|
17
21
|
|
|
18
22
|
export function init(store) {
|
|
@@ -219,4 +223,17 @@ export function init(store) {
|
|
|
219
223
|
defaultSort: true,
|
|
220
224
|
},
|
|
221
225
|
]);
|
|
226
|
+
|
|
227
|
+
// Configure custom count getter for cluster count (so we don't include Harvester clusters)
|
|
228
|
+
configureType(CAPI.RANCHER_CLUSTER, {
|
|
229
|
+
custom: {
|
|
230
|
+
countGetter: markRaw((getters) => {
|
|
231
|
+
const savedClusterCount = getters['management/getSavedCount'](SAVED_COUNTS.K8S_CLUSTERS);
|
|
232
|
+
const counts = getters[`management/all`](COUNT)?.[0]?.counts || {};
|
|
233
|
+
const clusterCount = counts[CAPI.RANCHER_CLUSTER]?.summary.count;
|
|
234
|
+
|
|
235
|
+
return savedClusterCount || clusterCount;
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
});
|
|
222
239
|
}
|
|
@@ -28,16 +28,16 @@ export function install(router, context) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Generate an object that includes both the
|
|
32
|
-
* @param {*}
|
|
31
|
+
* Generate an object that includes both the user and the me data
|
|
32
|
+
* @param {*} user User information
|
|
33
33
|
* @param {*} me Me user data
|
|
34
34
|
* @returns User info to be passed to `isLoggedIn`
|
|
35
35
|
*/
|
|
36
|
-
function getUserObject(
|
|
36
|
+
function getUserObject(user, me) {
|
|
37
37
|
return {
|
|
38
38
|
id: me.id,
|
|
39
39
|
me,
|
|
40
|
-
|
|
40
|
+
user,
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -59,10 +59,9 @@ export async function authenticate(to, from, next, { store }) {
|
|
|
59
59
|
if ( store.getters['auth/enabled'] !== false && !store.getters['auth/loggedIn'] ) {
|
|
60
60
|
// `await` so we have one successfully request whilst possibly logged in (ensures fromHeader is populated from `x-api-cattle-auth`)
|
|
61
61
|
await store.dispatch('auth/getUser');
|
|
62
|
+
const user = store.getters['auth/user'] || {};
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (v3User?.mustChangePassword) {
|
|
64
|
+
if (user?.mustChangePassword) {
|
|
66
65
|
return next({ name: 'auth-setup' });
|
|
67
66
|
}
|
|
68
67
|
|
|
@@ -75,7 +74,7 @@ export async function authenticate(to, from, next, { store }) {
|
|
|
75
74
|
} else if ( fromHeader === 'true' ) {
|
|
76
75
|
const me = await findMe(store);
|
|
77
76
|
|
|
78
|
-
await isLoggedIn(store, getUserObject(
|
|
77
|
+
await isLoggedIn(store, getUserObject(user, me));
|
|
79
78
|
handleOidcRedirectToCallbackUrl();
|
|
80
79
|
} else if ( fromHeader === 'false' ) {
|
|
81
80
|
notLoggedIn(store, next, to);
|
|
@@ -86,7 +85,7 @@ export async function authenticate(to, from, next, { store }) {
|
|
|
86
85
|
try {
|
|
87
86
|
const me = await findMe(store);
|
|
88
87
|
|
|
89
|
-
await isLoggedIn(store, getUserObject(
|
|
88
|
+
await isLoggedIn(store, getUserObject(user, me));
|
|
90
89
|
handleOidcRedirectToCallbackUrl();
|
|
91
90
|
} catch (e) {
|
|
92
91
|
const status = e?._status;
|
package/config/types.js
CHANGED
|
@@ -61,6 +61,7 @@ export const POD_DISRUPTION_BUDGET = 'policy.poddisruptionbudget';
|
|
|
61
61
|
export const PV = 'persistentvolume';
|
|
62
62
|
export const PVC = 'persistentvolumeclaim';
|
|
63
63
|
export const RESOURCE_QUOTA = 'resourcequota';
|
|
64
|
+
export const AUDIT_POLICY = 'auditlog.cattle.io.auditpolicy';
|
|
64
65
|
export const SCHEMA = 'schema';
|
|
65
66
|
export const SERVICE = 'service';
|
|
66
67
|
export const SECRET = 'secret';
|
|
@@ -263,8 +264,11 @@ export const BRAND = {
|
|
|
263
264
|
};
|
|
264
265
|
|
|
265
266
|
export const EXT = {
|
|
266
|
-
USER_ACTIVITY:
|
|
267
|
-
|
|
267
|
+
USER_ACTIVITY: 'ext.cattle.io.useractivity',
|
|
268
|
+
SELFUSER: 'ext.cattle.io.selfuser',
|
|
269
|
+
GROUP_MEMBERSHIP_REFRESH_REQUESTS: 'ext.cattle.io.groupmembershiprefreshrequest',
|
|
270
|
+
PASSWORD_CHANGE_REQUESTS: 'ext.cattle.io.passwordchangerequest',
|
|
271
|
+
KUBECONFIG: 'ext.cattle.io.kubeconfig',
|
|
268
272
|
};
|
|
269
273
|
|
|
270
274
|
export const CAPI = {
|
|
@@ -409,3 +413,7 @@ export const DEPRECATED = 'Deprecated';
|
|
|
409
413
|
export const EXPERIMENTAL = 'Experimental';
|
|
410
414
|
export const AUTOSCALER_CONFIG_MAP_ID = 'kube-system/cluster-autoscaler-status';
|
|
411
415
|
export const HOSTED_PROVIDER = 'hostedprovider';
|
|
416
|
+
|
|
417
|
+
// Named saved counts
|
|
418
|
+
|
|
419
|
+
export const SAVED_COUNTS = { K8S_CLUSTERS: 'k8sClusters' };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// Shared AuditPolicy interface for all audit log policy components
|
|
3
|
+
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
4
|
+
import ResourceTabs from '@shell/components/form/ResourceTabs/index.vue';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
name: 'DetailAuditPolicy',
|
|
8
|
+
components: { ResourceTabs },
|
|
9
|
+
mixins: [CreateEditView],
|
|
10
|
+
};
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<Loading v-if="$fetchState.pending" />
|
|
15
|
+
<ResourceTabs
|
|
16
|
+
:mode="mode"
|
|
17
|
+
:value="value"
|
|
18
|
+
/>
|
|
19
|
+
</template>
|
|
@@ -3,7 +3,7 @@ import CreateEditView from '@shell/mixins/create-edit-view';
|
|
|
3
3
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
4
4
|
import ResourceTabs from '@shell/components/form/ResourceTabs';
|
|
5
5
|
import SortableTable from '@shell/components/SortableTable';
|
|
6
|
-
import { MANAGEMENT
|
|
6
|
+
import { MANAGEMENT } from '@shell/config/types';
|
|
7
7
|
import Loading from '@shell/components/Loading';
|
|
8
8
|
import { NAME } from '@shell/config/table-headers';
|
|
9
9
|
|
|
@@ -31,7 +31,6 @@ export default {
|
|
|
31
31
|
if (this.canSeeRoleTemplates) {
|
|
32
32
|
// Upfront fetch, avoid async computes
|
|
33
33
|
await Promise.all([
|
|
34
|
-
await this.$store.dispatch('rancher/find', { type: NORMAN.USER, id: this.value.id }),
|
|
35
34
|
await this.$store.dispatch('management/findAll', { type: MANAGEMENT.ROLE_TEMPLATE }),
|
|
36
35
|
await this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING }),
|
|
37
36
|
await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING })
|
package/detail/node.vue
CHANGED
|
@@ -364,7 +364,8 @@ export default {
|
|
|
364
364
|
const machineFullName = machineNameFn(this.value.name, mp.name);
|
|
365
365
|
|
|
366
366
|
const machines = this.value.machines.filter((machine) => {
|
|
367
|
-
|
|
367
|
+
// elemental machines use an older version of CAPI CRDs that use apiVersion instead of apiGroup
|
|
368
|
+
const isElementalCluster = (machine.spec?.infrastructureRef?.apiGroup || machine.spec?.infrastructureRef?.apiVersion).startsWith('elemental.cattle.io');
|
|
368
369
|
const machinePoolInfName = machine.spec?.infrastructureRef?.name;
|
|
369
370
|
|
|
370
371
|
if (isElementalCluster) {
|
|
@@ -9,6 +9,13 @@ export default {
|
|
|
9
9
|
components: {
|
|
10
10
|
Card, AsyncButton, ChangePassword
|
|
11
11
|
},
|
|
12
|
+
props: {
|
|
13
|
+
user: {
|
|
14
|
+
type: Object,
|
|
15
|
+
default: () => null,
|
|
16
|
+
required: true
|
|
17
|
+
}
|
|
18
|
+
},
|
|
12
19
|
data() {
|
|
13
20
|
return { valid: false, password: '' };
|
|
14
21
|
},
|
|
@@ -45,6 +52,7 @@ export default {
|
|
|
45
52
|
<form @submit.prevent>
|
|
46
53
|
<ChangePassword
|
|
47
54
|
ref="changePassword"
|
|
55
|
+
:user="user"
|
|
48
56
|
@valid="valid = $event"
|
|
49
57
|
/>
|
|
50
58
|
</form>
|
package/dialog/GenericPrompt.vue
CHANGED
|
@@ -38,9 +38,24 @@ export default {
|
|
|
38
38
|
type: Function,
|
|
39
39
|
default: () => { }
|
|
40
40
|
},
|
|
41
|
+
actionColor: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: 'role-primary',
|
|
44
|
+
},
|
|
45
|
+
errors: {
|
|
46
|
+
type: Array,
|
|
47
|
+
default: () => []
|
|
48
|
+
}
|
|
41
49
|
},
|
|
50
|
+
|
|
42
51
|
data() {
|
|
43
|
-
return {
|
|
52
|
+
return { applyErrors: [] };
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
computed: {
|
|
56
|
+
allErrors() {
|
|
57
|
+
return [...this.errors, ...this.applyErrors];
|
|
58
|
+
}
|
|
44
59
|
},
|
|
45
60
|
|
|
46
61
|
methods: {
|
|
@@ -51,13 +66,14 @@ export default {
|
|
|
51
66
|
},
|
|
52
67
|
|
|
53
68
|
async apply(buttonDone) {
|
|
69
|
+
this.applyErrors = [];
|
|
54
70
|
try {
|
|
55
71
|
await this.applyAction(buttonDone);
|
|
56
72
|
this.confirm(true);
|
|
57
73
|
this.$emit('close');
|
|
58
74
|
} catch (err) {
|
|
59
75
|
console.error(err); // eslint-disable-line
|
|
60
|
-
this.
|
|
76
|
+
this.applyErrors = exceptionToErrorsArray(err);
|
|
61
77
|
buttonDone(false);
|
|
62
78
|
}
|
|
63
79
|
}
|
|
@@ -92,7 +108,7 @@ export default {
|
|
|
92
108
|
<template #actions>
|
|
93
109
|
<div class="bottom">
|
|
94
110
|
<Banner
|
|
95
|
-
v-for="(err, i) in
|
|
111
|
+
v-for="(err, i) in allErrors"
|
|
96
112
|
:key="i"
|
|
97
113
|
color="error"
|
|
98
114
|
:label="err"
|
|
@@ -107,6 +123,7 @@ export default {
|
|
|
107
123
|
|
|
108
124
|
<AsyncButton
|
|
109
125
|
:mode="applyMode"
|
|
126
|
+
:action-color="actionColor"
|
|
110
127
|
@click="apply"
|
|
111
128
|
/>
|
|
112
129
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { CAPI as CAPI_LABELS } from '@shell/config/labels-annotations';
|
|
3
3
|
import { MANAGEMENT, CAPI } from '@shell/config/types';
|
|
4
4
|
import GenericPrompt from './GenericPrompt';
|
|
5
|
-
|
|
5
|
+
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
6
6
|
export default {
|
|
7
7
|
emits: ['close'],
|
|
8
8
|
|
|
@@ -16,17 +16,26 @@ export default {
|
|
|
16
16
|
},
|
|
17
17
|
|
|
18
18
|
async fetch() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
this
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
this.loading = true;
|
|
20
|
+
try {
|
|
21
|
+
if (this.isRke2) {
|
|
22
|
+
await Promise.all([
|
|
23
|
+
this.$store.dispatch('management/findAll', { type: CAPI.MACHINE_DEPLOYMENT }),
|
|
24
|
+
this.$store.dispatch('management/findAll', { type: CAPI.MACHINE })
|
|
25
|
+
]);
|
|
26
|
+
const machineSetPromises = this.safeMachinesToDelete.filter((machine) => machine.isWorker).map((machine) => this.getMachineSets(machine));
|
|
27
|
+
|
|
28
|
+
this.workerMachineSets = await Promise.all(machineSetPromises);
|
|
29
|
+
} else {
|
|
30
|
+
await Promise.all([
|
|
31
|
+
this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_POOL }),
|
|
32
|
+
this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE })
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
this.errors = exceptionToErrorsArray(e);
|
|
29
37
|
}
|
|
38
|
+
this.loading = false;
|
|
30
39
|
},
|
|
31
40
|
|
|
32
41
|
data() {
|
|
@@ -51,11 +60,39 @@ export default {
|
|
|
51
60
|
title: this.t('promptRemove.title'),
|
|
52
61
|
applyMode: 'delete',
|
|
53
62
|
applyAction: this.remove,
|
|
54
|
-
}
|
|
63
|
+
},
|
|
64
|
+
workerMachineSets: [],
|
|
65
|
+
loading: false,
|
|
66
|
+
errors: []
|
|
55
67
|
};
|
|
56
68
|
},
|
|
69
|
+
computed: {
|
|
70
|
+
showScaling() {
|
|
71
|
+
for (const machineSet of this.workerMachineSets) {
|
|
72
|
+
const data = machineSet?.data || [];
|
|
73
|
+
|
|
74
|
+
for (const ms of data) {
|
|
75
|
+
if (!ms?.spec?.replicas || !ms?.status?.readyReplicas || ms.spec.replicas !== ms.status.readyReplicas) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
57
84
|
|
|
58
85
|
methods: {
|
|
86
|
+
getMachineSets(machine) {
|
|
87
|
+
const namespace = machine.namespace;
|
|
88
|
+
const labelSelector = { matchLabels: { [CAPI_LABELS.DEPLOYMENT_NAME]: machine.poolName } }; // machine.poolId
|
|
89
|
+
|
|
90
|
+
return this.$store.dispatch('management/findLabelSelector', {
|
|
91
|
+
type: CAPI.MACHINE_SET,
|
|
92
|
+
matching: { namespace, labelSelector },
|
|
93
|
+
opt: { transient: true }
|
|
94
|
+
});
|
|
95
|
+
},
|
|
59
96
|
deleteType(type, allToDelete, cluster, isRke2) {
|
|
60
97
|
const allToDeleteByType = allToDelete.reduce((res, m) => {
|
|
61
98
|
if (m[type]) {
|
|
@@ -117,15 +154,28 @@ export default {
|
|
|
117
154
|
<template>
|
|
118
155
|
<GenericPrompt
|
|
119
156
|
v-bind="config"
|
|
157
|
+
action-color="bg-error role-primary"
|
|
158
|
+
:errors="errors"
|
|
120
159
|
@close="$emit('close')"
|
|
121
160
|
>
|
|
122
161
|
<template #body>
|
|
123
162
|
<div class="pl-10 pr-10 mt-20 mb-20 body">
|
|
124
|
-
<div
|
|
125
|
-
|
|
163
|
+
<div
|
|
164
|
+
v-if="loading"
|
|
165
|
+
class="text-center"
|
|
166
|
+
>
|
|
167
|
+
<i class="icon icon-spinner icon-spin icon-lg" />
|
|
126
168
|
</div>
|
|
127
169
|
<div v-else>
|
|
128
|
-
|
|
170
|
+
<div v-if="showScaling">
|
|
171
|
+
<span v-clean-html="t('promptScaleMachineDown.scaling', { count: resources.length }, true)" />
|
|
172
|
+
</div>
|
|
173
|
+
<div v-else-if="safeMachinesToDelete.length === 1">
|
|
174
|
+
{{ t('promptRemove.attemptingToRemove', { type }) }} <b>{{ safeMachinesToDelete[0].nameDisplay }}</b>
|
|
175
|
+
</div>
|
|
176
|
+
<div v-else>
|
|
177
|
+
{{ t('promptScaleMachineDown.attemptingToRemove', { type, count: allToDelete.length }, true) }}
|
|
178
|
+
</div>
|
|
129
179
|
</div>
|
|
130
180
|
<div
|
|
131
181
|
v-if="ignored.length"
|
package/dialog/SearchDialog.vue
CHANGED
|
@@ -46,13 +46,21 @@ export default {
|
|
|
46
46
|
const counts = this.$store.getters[`${ product.inStore }/all`](COUNT)?.[0]?.counts || {};
|
|
47
47
|
|
|
48
48
|
out.forEach((o) => {
|
|
49
|
-
o.children?.
|
|
49
|
+
o.children = o.children?.reduce((res, t) => {
|
|
50
|
+
if (!this.$store.getters[`${ product.inStore }/canList`](t.name)) {
|
|
51
|
+
return res;
|
|
52
|
+
}
|
|
53
|
+
|
|
50
54
|
const count = counts[t.name];
|
|
51
55
|
|
|
52
56
|
t.count = count ? count.summary.count || 0 : null;
|
|
53
57
|
t.byNamespace = count ? count.namespaces : {};
|
|
54
58
|
t.revision = count ? count.revision : null;
|
|
55
|
-
|
|
59
|
+
|
|
60
|
+
res.push(t);
|
|
61
|
+
|
|
62
|
+
return res;
|
|
63
|
+
}, []);
|
|
56
64
|
});
|
|
57
65
|
|
|
58
66
|
this.groups = out;
|