@rancher/shell 3.0.9-rc.4 → 3.0.9-rc.6
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/images/providers/oci-open-containers.svg +22 -0
- package/assets/images/providers/traefik.png +0 -0
- package/assets/styles/themes/_dark.scss +2 -0
- package/assets/styles/themes/_light.scss +2 -0
- package/assets/styles/themes/_modern.scss +6 -0
- package/assets/translations/en-us.yaml +218 -26
- package/components/ActionMenuShell.vue +1 -1
- package/components/CruResource.vue +3 -1
- package/components/ExplorerProjectsNamespaces.vue +12 -12
- package/components/Inactivity.vue +2 -2
- package/components/Resource/Detail/Card/ExtrasCard.vue +49 -15
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +109 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +21 -4
- 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/__tests__/identifying-fields.test.ts +19 -2
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +19 -11
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +3 -1
- package/components/Resource/Detail/Metadata/index.vue +1 -1
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +12 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +2 -0
- package/components/Resource/Detail/ResourceRow.vue +3 -3
- package/components/ResourceDetail/Masthead/latest.vue +12 -2
- package/components/ResourceList/index.vue +12 -0
- package/components/ResourceTable.vue +38 -4
- package/components/Tabbed/Tab.vue +4 -0
- package/components/Tabbed/index.vue +4 -1
- package/components/Window/ContainerLogs.vue +48 -37
- package/components/fleet/FleetClusterTargets/TargetsList.vue +2 -2
- package/components/fleet/FleetClusterTargets/index.vue +6 -1
- package/components/fleet/GitRepoAdvancedTab.vue +333 -0
- package/components/fleet/GitRepoMetadataTab.vue +43 -0
- package/components/fleet/GitRepoRepositoryTab.vue +101 -0
- package/components/fleet/GitRepoTargetTab.vue +77 -0
- package/components/fleet/HelmOpAdvancedTab.vue +247 -0
- package/components/fleet/HelmOpChartTab.vue +158 -0
- package/components/fleet/HelmOpMetadataTab.vue +46 -0
- package/components/fleet/HelmOpTargetTab.vue +84 -0
- package/components/fleet/HelmOpValuesTab.vue +147 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +119 -70
- package/components/form/ChangePassword.vue +41 -35
- package/components/form/NodeScheduling.vue +81 -7
- package/components/form/PodAffinity.vue +1 -36
- package/components/form/ResourceLabeledSelect.vue +8 -4
- package/components/form/ResourceQuota/Namespace.vue +30 -9
- package/components/form/ResourceQuota/NamespaceRow.vue +25 -7
- package/components/form/ResourceQuota/Project.vue +150 -51
- package/components/form/ResourceQuota/ResourceQuotaEntry.vue +145 -0
- package/components/form/ResourceQuota/__tests__/Namespace.test.ts +307 -0
- package/components/form/ResourceQuota/__tests__/NamespaceRow.test.ts +281 -0
- package/components/form/ResourceQuota/__tests__/Project.test.ts +310 -0
- package/components/form/ResourceQuota/__tests__/ResourceQuotaEntry.test.ts +215 -0
- package/components/form/SchedulingCustomization.vue +14 -6
- package/components/form/SelectOrCreateAuthSecret.vue +113 -19
- package/components/form/__tests__/NodeScheduling.test.ts +12 -9
- package/components/form/__tests__/PodAffinity.test.ts +21 -2
- package/components/form/__tests__/SchedulingCustomization.test.ts +240 -0
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +35 -0
- package/components/formatter/ClusterLink.vue +8 -0
- package/components/formatter/MachineSummaryGraph.vue +10 -2
- package/components/formatter/SecretOrigin.vue +79 -0
- 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/labels-annotations.js +7 -6
- package/config/pagination-table-headers.js +6 -4
- package/config/product/explorer.js +5 -14
- package/config/product/manager.js +18 -1
- package/config/query-params.js +3 -0
- package/config/router/navigation-guards/authentication.js +8 -9
- package/config/settings.ts +15 -2
- package/config/table-headers.js +21 -17
- package/config/types.js +33 -10
- 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/detail/workload/index.vue +11 -16
- package/dialog/ChangePasswordDialog.vue +8 -0
- package/dialog/DeactivateDriverDialog.vue +1 -1
- package/dialog/GenericPrompt.vue +20 -3
- package/dialog/Ipv6NetworkingDialog.vue +156 -0
- package/dialog/ScaleMachineDownDialog.vue +65 -15
- package/dialog/ScalePoolDownDialog.vue +2 -2
- 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__/fleet.cattle.io.helmop.test.ts +1 -0
- package/edit/__tests__/management.cattle.io.project.test.js +81 -98
- 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/auth/oidc.vue +1 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +155 -25
- package/edit/fleet.cattle.io.gitrepo.vue +161 -276
- package/edit/fleet.cattle.io.helmop.vue +190 -332
- package/edit/management.cattle.io.project.vue +11 -42
- package/edit/management.cattle.io.setting.vue +6 -0
- package/edit/management.cattle.io.user.vue +29 -34
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +55 -24
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +1 -103
- package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +13 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2-fleet-cluster-agent.test.ts +283 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +196 -2
- package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +112 -0
- package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +184 -66
- package/edit/provisioning.cattle.io.cluster/shared.ts +39 -0
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +56 -7
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +319 -0
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +13 -1
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +10 -44
- package/edit/secret/index.vue +1 -1
- package/edit/token.vue +68 -29
- package/edit/workload/__tests__/index.test.ts +2 -37
- package/edit/workload/index.vue +6 -2
- package/edit/workload/mixins/workload.js +0 -32
- package/list/__tests__/management.cattle.io.setting.test.ts +198 -0
- package/list/auditlog.cattle.io.auditpolicy.vue +63 -0
- package/list/group.principal.vue +11 -15
- package/list/management.cattle.io.setting.vue +13 -0
- package/list/management.cattle.io.user.vue +11 -21
- package/list/provisioning.cattle.io.cluster.vue +50 -1
- package/list/secret.vue +4 -9
- package/list/service.vue +6 -8
- package/machine-config/amazonec2.vue +11 -4
- package/machine-config/azure.vue +14 -0
- package/machine-config/components/EC2Networking.vue +46 -30
- package/machine-config/components/__tests__/EC2Networking.test.ts +7 -7
- package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +0 -9
- package/machine-config/digitalocean.vue +3 -3
- 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__/namespace.test.ts +11 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +96 -0
- package/models/__tests__/workload.test.ts +90 -6
- package/models/auditlog.cattle.io.auditpolicy.js +46 -0
- package/models/catalog.cattle.io.clusterrepo.js +30 -4
- 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/ext.cattle.io.token.js +48 -0
- package/models/fleet-application.js +17 -7
- package/models/kontainerdriver.js +2 -2
- package/models/management.cattle.io.user.js +28 -31
- package/models/namespace.js +7 -1
- package/models/nodedriver.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +28 -7
- package/models/schema.js +18 -0
- package/models/secret.js +27 -41
- package/models/service.js +44 -1
- package/models/steve-schema.ts +39 -2
- package/models/token.js +4 -0
- package/models/workload.js +13 -6
- package/package.json +1 -1
- package/pages/account/index.vue +108 -72
- package/pages/auth/login.vue +15 -8
- package/pages/auth/setup.vue +55 -27
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
- package/pages/c/_cluster/apps/charts/index.vue +93 -4
- package/pages/c/_cluster/apps/charts/install.vue +317 -42
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
- package/pages/c/_cluster/settings/index.vue +3 -1
- package/pages/home.vue +9 -3
- package/plugins/dashboard-store/__tests__/getters.test.ts +108 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +28 -3
- package/plugins/dashboard-store/actions.js +10 -8
- package/plugins/dashboard-store/getters.js +30 -6
- package/plugins/dashboard-store/index.js +3 -2
- package/plugins/dashboard-store/mutations.js +8 -1
- package/plugins/dashboard-store/resource-class.js +15 -8
- package/plugins/steve/__tests__/steve-class.test.ts +128 -0
- package/plugins/steve/schema.d.ts +5 -0
- package/plugins/steve/steve-class.js +28 -0
- package/plugins/steve/steve-pagination-utils.ts +7 -2
- package/rancher-components/RcIcon/types.ts +2 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +64 -19
- package/store/auth.js +57 -19
- package/store/notifications.ts +1 -1
- package/store/prefs.js +3 -0
- package/store/type-map.js +12 -1
- package/types/aws-sdk.d.ts +121 -0
- package/types/resources/node.ts +15 -0
- package/types/shell/index.d.ts +542 -516
- package/types/store/dashboard-store.types.ts +7 -0
- package/types/store/pagination.types.ts +5 -5
- package/utils/__tests__/array.test.ts +1 -29
- package/utils/__tests__/cluster-agent-configuration.test.ts +203 -0
- package/utils/array.ts +0 -11
- package/utils/aws.ts +21 -0
- package/utils/cluster.js +22 -2
- package/utils/pagination-wrapper.ts +11 -3
- package/utils/selector-typed.ts +1 -1
- package/vue.config.js +26 -13
- package/components/__tests__/ProjectRow.test.ts +0 -146
- package/components/form/ResourceQuota/ProjectRow.vue +0 -210
- package/edit/provisioning.cattle.io.cluster/defaults.ts +0 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import AuditPolicy from '@shell/models/auditlog.cattle.io.auditpolicy';
|
|
2
|
+
|
|
3
|
+
describe('auditPolicy Model', () => {
|
|
4
|
+
let mockDispatch: jest.Mock;
|
|
5
|
+
let mockT: jest.Mock;
|
|
6
|
+
let auditPolicy: any;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockDispatch = jest.fn();
|
|
10
|
+
mockT = jest.fn();
|
|
11
|
+
|
|
12
|
+
const mockResource = {
|
|
13
|
+
id: 'test-policy',
|
|
14
|
+
spec: { enabled: false },
|
|
15
|
+
metadata: { name: 'test-policy' }
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
auditPolicy = new AuditPolicy(mockResource, {
|
|
19
|
+
dispatch: mockDispatch,
|
|
20
|
+
rootGetters: { 'i18n/t': mockT },
|
|
21
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) }
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('enable method', () => {
|
|
26
|
+
it('should call enableOrDisable with "enable"', () => {
|
|
27
|
+
const spy = jest.spyOn(auditPolicy, 'enableOrDisable').mockImplementation();
|
|
28
|
+
|
|
29
|
+
auditPolicy.enable();
|
|
30
|
+
|
|
31
|
+
expect(spy).toHaveBeenCalledWith('enable');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('disable method', () => {
|
|
36
|
+
it('should call enableOrDisable with "disable"', () => {
|
|
37
|
+
const spy = jest.spyOn(auditPolicy, 'enableOrDisable').mockImplementation();
|
|
38
|
+
|
|
39
|
+
auditPolicy.disable();
|
|
40
|
+
|
|
41
|
+
expect(spy).toHaveBeenCalledWith('disable');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('enableOrDisable method', () => {
|
|
46
|
+
let mockClone: any;
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
mockClone = {
|
|
50
|
+
spec: { enabled: false },
|
|
51
|
+
save: jest.fn()
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
mockDispatch.mockImplementation((action: string) => {
|
|
55
|
+
if (action === 'rancher/clone') {
|
|
56
|
+
return Promise.resolve(mockClone);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return Promise.resolve();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should enable policy when flag is "enable"', async() => {
|
|
64
|
+
mockClone.save.mockResolvedValue({});
|
|
65
|
+
|
|
66
|
+
await auditPolicy.enableOrDisable('enable');
|
|
67
|
+
|
|
68
|
+
expect(mockClone.spec.enabled).toBe(true);
|
|
69
|
+
expect(mockClone.save).toHaveBeenCalledWith();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should disable policy when flag is "disable"', async() => {
|
|
73
|
+
mockClone.save.mockResolvedValue({});
|
|
74
|
+
|
|
75
|
+
await auditPolicy.enableOrDisable('disable');
|
|
76
|
+
|
|
77
|
+
expect(mockClone.spec.enabled).toBe(false);
|
|
78
|
+
expect(mockClone.save).toHaveBeenCalledWith();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should handle save errors and show growl notification', async() => {
|
|
82
|
+
const saveError = new Error('Save failed');
|
|
83
|
+
|
|
84
|
+
mockClone.save.mockRejectedValue(saveError);
|
|
85
|
+
mockT.mockReturnValue('Error when enabling - test-policy');
|
|
86
|
+
|
|
87
|
+
await auditPolicy.enableOrDisable('enable');
|
|
88
|
+
|
|
89
|
+
expect(mockDispatch).toHaveBeenCalledWith('growl/fromError', {
|
|
90
|
+
title: 'Error when enabling - test-policy',
|
|
91
|
+
err: saveError,
|
|
92
|
+
timeout: 5000
|
|
93
|
+
}, { root: true });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should call translation with correct parameters', async() => {
|
|
97
|
+
const saveError = new Error('Save failed');
|
|
98
|
+
|
|
99
|
+
mockClone.save.mockRejectedValue(saveError);
|
|
100
|
+
|
|
101
|
+
await auditPolicy.enableOrDisable('enable');
|
|
102
|
+
|
|
103
|
+
expect(mockT).toHaveBeenCalledWith('auditPolicy.error.enableOrDisable', {
|
|
104
|
+
flag: 'enable',
|
|
105
|
+
id: 'test-policy'
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should dispatch rancher/clone with correct parameters', async() => {
|
|
110
|
+
mockClone.save.mockResolvedValue({});
|
|
111
|
+
|
|
112
|
+
await auditPolicy.enableOrDisable('enable');
|
|
113
|
+
|
|
114
|
+
expect(mockDispatch).toHaveBeenCalledWith('rancher/clone', { resource: auditPolicy }, { root: true });
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -187,6 +187,17 @@ describe('class Namespace', () => {
|
|
|
187
187
|
it.todo('should set the resourceQuota as reactive Vue property');
|
|
188
188
|
it.todo('should reset project with cleanForNew');
|
|
189
189
|
|
|
190
|
+
describe('hideDetailLocation', () => {
|
|
191
|
+
it('should not throw when currentProduct is undefined', () => {
|
|
192
|
+
const namespace = new Namespace({});
|
|
193
|
+
|
|
194
|
+
jest.spyOn(namespace, '$rootGetters', 'get').mockReturnValue({ currentProduct: undefined });
|
|
195
|
+
|
|
196
|
+
expect(() => namespace.hideDetailLocation).not.toThrow();
|
|
197
|
+
expect(namespace.hideDetailLocation).toBe(true);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
190
201
|
describe('glance', () => {
|
|
191
202
|
it('should return projectGlance instead of namespace when namespace is in a project', () => {
|
|
192
203
|
const t = jest.fn((key) => key);
|
|
@@ -275,4 +275,100 @@ describe('class ProvCluster', () => {
|
|
|
275
275
|
}
|
|
276
276
|
);
|
|
277
277
|
});
|
|
278
|
+
|
|
279
|
+
describe('supportsWindows', () => {
|
|
280
|
+
const testCases = [
|
|
281
|
+
{
|
|
282
|
+
description: 'should return false for k3s',
|
|
283
|
+
clusterData: { isK3s: true },
|
|
284
|
+
expected: false
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
description: 'should return false for imported k3s',
|
|
288
|
+
clusterData: { isImportedK3s: true },
|
|
289
|
+
expected: false
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
description: 'should return windowsPreferedCluster for rke1',
|
|
293
|
+
clusterData: { isRke1: true, mgmt: { spec: { windowsPreferedCluster: true } } },
|
|
294
|
+
expected: true
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
description: 'should return false for rke1 if windowsPreferedCluster is false/missing',
|
|
298
|
+
clusterData: { isRke1: true, mgmt: { spec: { windowsPreferedCluster: false } } },
|
|
299
|
+
expected: false
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
description: 'should return false if not rke2 (and not rke1 or k3s)',
|
|
303
|
+
clusterData: { isRke2: false },
|
|
304
|
+
expected: false
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
description: 'should return false if kubernetesVersion is missing',
|
|
308
|
+
clusterData: { isRke2: true, kubernetesVersion: undefined },
|
|
309
|
+
expected: false
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
description: 'should return false if kubernetesVersion is less than v1.21.0',
|
|
313
|
+
clusterData: { isRke2: true, kubernetesVersion: 'v1.20.9' },
|
|
314
|
+
expected: false
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
description: 'should return false if cni is not calico or flannel',
|
|
318
|
+
clusterData: {
|
|
319
|
+
isRke2: true, kubernetesVersion: 'v1.34.0', spec: { rkeConfig: { machineGlobalConfig: { cni: 'cilium' } } }
|
|
320
|
+
},
|
|
321
|
+
expected: false
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
description: 'should return true if cni is calico',
|
|
325
|
+
clusterData: {
|
|
326
|
+
isRke2: true, kubernetesVersion: 'v1.34.0', spec: { rkeConfig: { machineGlobalConfig: { cni: 'calico' } } }
|
|
327
|
+
},
|
|
328
|
+
expected: true
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
description: 'should return false if cni is flannel and kubernetesVersion is less than v1.29.2 (e.g. v1.29.1)',
|
|
332
|
+
clusterData: {
|
|
333
|
+
isRke2: true, kubernetesVersion: 'v1.29.1', spec: { rkeConfig: { machineGlobalConfig: { cni: 'flannel' } } }
|
|
334
|
+
},
|
|
335
|
+
expected: false
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
description: 'should return true if cni is flannel and kubernetesVersion is exactly v1.29.2',
|
|
339
|
+
clusterData: {
|
|
340
|
+
isRke2: true, kubernetesVersion: 'v1.29.2', spec: { rkeConfig: { machineGlobalConfig: { cni: 'flannel' } } }
|
|
341
|
+
},
|
|
342
|
+
expected: true
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
description: 'should return true if cni is flannel and kubernetesVersion is >= v1.29.2 (e.g. v1.35.0)',
|
|
346
|
+
clusterData: {
|
|
347
|
+
isRke2: true, kubernetesVersion: 'v1.35.0', spec: { rkeConfig: { machineGlobalConfig: { cni: 'flannel' } } }
|
|
348
|
+
},
|
|
349
|
+
expected: true
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
description: 'should return true if cni is empty/undefined',
|
|
353
|
+
clusterData: {
|
|
354
|
+
isRke2: true, kubernetesVersion: 'v1.34.0', spec: { rkeConfig: { machineGlobalConfig: {} } }
|
|
355
|
+
},
|
|
356
|
+
expected: true
|
|
357
|
+
},
|
|
358
|
+
];
|
|
359
|
+
|
|
360
|
+
it.each(testCases)('$description', ({ clusterData, expected }) => {
|
|
361
|
+
const cluster = new ProvCluster({ spec: clusterData.spec });
|
|
362
|
+
|
|
363
|
+
jest.spyOn(cluster, 'mgmt', 'get').mockReturnValue(clusterData.mgmt);
|
|
364
|
+
jest.spyOn(cluster, 'isK3s', 'get').mockReturnValue(clusterData.isK3s || false);
|
|
365
|
+
jest.spyOn(cluster, 'isImportedK3s', 'get').mockReturnValue(clusterData.isImportedK3s || false);
|
|
366
|
+
jest.spyOn(cluster, 'isRke1', 'get').mockReturnValue(clusterData.isRke1 || false);
|
|
367
|
+
jest.spyOn(cluster, 'isRke2', 'get').mockReturnValue(clusterData.isRke2 || false);
|
|
368
|
+
jest.spyOn(cluster, 'kubernetesVersion', 'get').mockReturnValue(clusterData.kubernetesVersion);
|
|
369
|
+
|
|
370
|
+
expect(cluster.supportsWindows).toBe(expected);
|
|
371
|
+
jest.clearAllMocks();
|
|
372
|
+
});
|
|
373
|
+
});
|
|
278
374
|
});
|
|
@@ -253,6 +253,8 @@ describe('class: Workload', () => {
|
|
|
253
253
|
});
|
|
254
254
|
|
|
255
255
|
describe('getter: podsCard', () => {
|
|
256
|
+
const mockPod = { metadata: { name: 'pod-1', namespace: 'default' } };
|
|
257
|
+
|
|
256
258
|
it('should return card for Deployment type', () => {
|
|
257
259
|
const workload = new Workload({
|
|
258
260
|
type: WORKLOAD_TYPES.DEPLOYMENT,
|
|
@@ -264,7 +266,7 @@ describe('class: Workload', () => {
|
|
|
264
266
|
rootGetters: { 'i18n/t': (key: string) => key },
|
|
265
267
|
});
|
|
266
268
|
|
|
267
|
-
Object.defineProperty(workload, 'pods', { get: () => [] });
|
|
269
|
+
Object.defineProperty(workload, 'pods', { get: () => [mockPod] });
|
|
268
270
|
Object.defineProperty(workload, 'canUpdate', { get: () => true });
|
|
269
271
|
|
|
270
272
|
const card = workload.podsCard;
|
|
@@ -272,6 +274,7 @@ describe('class: Workload', () => {
|
|
|
272
274
|
expect(card).not.toBeNull();
|
|
273
275
|
expect(card.props.title).toBe('component.resource.detail.card.podsCard.title');
|
|
274
276
|
expect(card.props.showScaling).toBe(true);
|
|
277
|
+
expect(card.props.noResourcesMessage).toBe('component.resource.detail.card.podsCard.noPods');
|
|
275
278
|
});
|
|
276
279
|
|
|
277
280
|
it('should return card for DaemonSet type without scaling', () => {
|
|
@@ -285,7 +288,7 @@ describe('class: Workload', () => {
|
|
|
285
288
|
rootGetters: { 'i18n/t': (key: string) => key },
|
|
286
289
|
});
|
|
287
290
|
|
|
288
|
-
Object.defineProperty(workload, 'pods', { get: () => [] });
|
|
291
|
+
Object.defineProperty(workload, 'pods', { get: () => [mockPod] });
|
|
289
292
|
Object.defineProperty(workload, 'canUpdate', { get: () => true });
|
|
290
293
|
|
|
291
294
|
const card = workload.podsCard;
|
|
@@ -310,7 +313,7 @@ describe('class: Workload', () => {
|
|
|
310
313
|
expect(card).toBeNull();
|
|
311
314
|
});
|
|
312
315
|
|
|
313
|
-
it('should
|
|
316
|
+
it('should return card when pods array is empty (scaled to 0)', () => {
|
|
314
317
|
const workload = new Workload({
|
|
315
318
|
type: WORKLOAD_TYPES.DEPLOYMENT,
|
|
316
319
|
metadata: { name: 'test', namespace: 'default' },
|
|
@@ -322,6 +325,64 @@ describe('class: Workload', () => {
|
|
|
322
325
|
});
|
|
323
326
|
|
|
324
327
|
Object.defineProperty(workload, 'pods', { get: () => [] });
|
|
328
|
+
Object.defineProperty(workload, 'canUpdate', { get: () => true });
|
|
329
|
+
|
|
330
|
+
const card = workload.podsCard;
|
|
331
|
+
|
|
332
|
+
expect(card).not.toBeNull();
|
|
333
|
+
expect(card.props.resources).toStrictEqual([]);
|
|
334
|
+
expect(card.props.noResourcesMessage).toBe('component.resource.detail.card.podsCard.noPods');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('should return null for non-scalable type with empty pods', () => {
|
|
338
|
+
const workload = new Workload({
|
|
339
|
+
type: WORKLOAD_TYPES.DAEMON_SET,
|
|
340
|
+
metadata: { name: 'test', namespace: 'default' },
|
|
341
|
+
spec: {}
|
|
342
|
+
}, {
|
|
343
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
344
|
+
dispatch: jest.fn(),
|
|
345
|
+
rootGetters: { 'i18n/t': (key: string) => key },
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
Object.defineProperty(workload, 'pods', { get: () => [] });
|
|
349
|
+
Object.defineProperty(workload, 'canUpdate', { get: () => true });
|
|
350
|
+
|
|
351
|
+
const card = workload.podsCard;
|
|
352
|
+
|
|
353
|
+
expect(card).toBeNull();
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should return null when pods is undefined', () => {
|
|
357
|
+
const workload = new Workload({
|
|
358
|
+
type: WORKLOAD_TYPES.DEPLOYMENT,
|
|
359
|
+
metadata: { name: 'test', namespace: 'default' },
|
|
360
|
+
spec: {}
|
|
361
|
+
}, {
|
|
362
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
363
|
+
dispatch: jest.fn(),
|
|
364
|
+
rootGetters: { 'i18n/t': (key: string) => key },
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
Object.defineProperty(workload, 'pods', { get: () => undefined });
|
|
368
|
+
|
|
369
|
+
const card = workload.podsCard;
|
|
370
|
+
|
|
371
|
+
expect(card).toBeNull();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('should hide scaling when canUpdate is false', () => {
|
|
375
|
+
const workload = new Workload({
|
|
376
|
+
type: WORKLOAD_TYPES.DEPLOYMENT,
|
|
377
|
+
metadata: { name: 'test', namespace: 'default' },
|
|
378
|
+
spec: {}
|
|
379
|
+
}, {
|
|
380
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
381
|
+
dispatch: jest.fn(),
|
|
382
|
+
rootGetters: { 'i18n/t': (key: string) => key },
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
Object.defineProperty(workload, 'pods', { get: () => [mockPod] });
|
|
325
386
|
Object.defineProperty(workload, 'canUpdate', { get: () => false });
|
|
326
387
|
|
|
327
388
|
const card = workload.podsCard;
|
|
@@ -331,6 +392,8 @@ describe('class: Workload', () => {
|
|
|
331
392
|
});
|
|
332
393
|
|
|
333
394
|
describe('getter: jobsCard', () => {
|
|
395
|
+
const mockJob = { metadata: { name: 'job-1', namespace: 'default' } };
|
|
396
|
+
|
|
334
397
|
it('should return card for CronJob type', () => {
|
|
335
398
|
const workload = new Workload({
|
|
336
399
|
type: WORKLOAD_TYPES.CRON_JOB,
|
|
@@ -342,7 +405,7 @@ describe('class: Workload', () => {
|
|
|
342
405
|
rootGetters: { 'i18n/t': (key: string) => key },
|
|
343
406
|
});
|
|
344
407
|
|
|
345
|
-
Object.defineProperty(workload, 'jobs', { get: () => [] });
|
|
408
|
+
Object.defineProperty(workload, 'jobs', { get: () => [mockJob] });
|
|
346
409
|
|
|
347
410
|
const card = workload.jobsCard;
|
|
348
411
|
|
|
@@ -366,9 +429,30 @@ describe('class: Workload', () => {
|
|
|
366
429
|
|
|
367
430
|
expect(card).toBeNull();
|
|
368
431
|
});
|
|
432
|
+
|
|
433
|
+
it('should return null when jobs array is empty', () => {
|
|
434
|
+
const workload = new Workload({
|
|
435
|
+
type: WORKLOAD_TYPES.CRON_JOB,
|
|
436
|
+
metadata: { name: 'test', namespace: 'default' },
|
|
437
|
+
spec: {}
|
|
438
|
+
}, {
|
|
439
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
440
|
+
dispatch: jest.fn(),
|
|
441
|
+
rootGetters: { 'i18n/t': (key: string) => key },
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
Object.defineProperty(workload, 'jobs', { get: () => [] });
|
|
445
|
+
|
|
446
|
+
const card = workload.jobsCard;
|
|
447
|
+
|
|
448
|
+
expect(card).toBeNull();
|
|
449
|
+
});
|
|
369
450
|
});
|
|
370
451
|
|
|
371
452
|
describe('getter: cards', () => {
|
|
453
|
+
const mockPod = { metadata: { name: 'pod-1', namespace: 'default' } };
|
|
454
|
+
const mockJob = { metadata: { name: 'job-1', namespace: 'default' } };
|
|
455
|
+
|
|
372
456
|
it('should include podsCard for Deployment', () => {
|
|
373
457
|
const workload = new Workload({
|
|
374
458
|
type: WORKLOAD_TYPES.DEPLOYMENT,
|
|
@@ -384,7 +468,7 @@ describe('class: Workload', () => {
|
|
|
384
468
|
},
|
|
385
469
|
});
|
|
386
470
|
|
|
387
|
-
Object.defineProperty(workload, 'pods', { get: () => [] });
|
|
471
|
+
Object.defineProperty(workload, 'pods', { get: () => [mockPod] });
|
|
388
472
|
Object.defineProperty(workload, 'canUpdate', { get: () => true });
|
|
389
473
|
|
|
390
474
|
const cards = workload.cards;
|
|
@@ -411,7 +495,7 @@ describe('class: Workload', () => {
|
|
|
411
495
|
},
|
|
412
496
|
});
|
|
413
497
|
|
|
414
|
-
Object.defineProperty(workload, 'jobs', { get: () => [] });
|
|
498
|
+
Object.defineProperty(workload, 'jobs', { get: () => [mockJob] });
|
|
415
499
|
|
|
416
500
|
const cards = workload.cards;
|
|
417
501
|
const nonNullCards = cards.filter((c: any) => c !== null);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { insertAt } from '@shell/utils/array';
|
|
2
|
+
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
3
|
+
|
|
4
|
+
export default class AuditPolicy extends SteveModel {
|
|
5
|
+
get _availableActions() {
|
|
6
|
+
const out = super._availableActions;
|
|
7
|
+
|
|
8
|
+
insertAt(out, 0, {
|
|
9
|
+
action: 'enable',
|
|
10
|
+
label: this.t('action.enable'),
|
|
11
|
+
icon: 'icon icon-play',
|
|
12
|
+
enabled: (this.canEdit || this.canEditYaml) && !this.spec.enabled,
|
|
13
|
+
bulkable: true,
|
|
14
|
+
weight: 2,
|
|
15
|
+
});
|
|
16
|
+
insertAt(out, 0, {
|
|
17
|
+
action: 'disable',
|
|
18
|
+
label: this.t('action.disable'),
|
|
19
|
+
icon: 'icon icon-pause',
|
|
20
|
+
enabled: (this.canEdit || this.canEditYaml) && this.spec.enabled,
|
|
21
|
+
bulkable: true,
|
|
22
|
+
weight: 1,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
enable() {
|
|
29
|
+
this.enableOrDisable('enable');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
disable() {
|
|
33
|
+
this.enableOrDisable('disable');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async enableOrDisable(flag) {
|
|
37
|
+
const clone = await this.$dispatch('rancher/clone', { resource: this }, { root: true });
|
|
38
|
+
|
|
39
|
+
clone.spec.enabled = flag === 'enable';
|
|
40
|
+
await clone.save().catch((err) => {
|
|
41
|
+
this.$dispatch('growl/fromError', {
|
|
42
|
+
title: this.t('auditPolicy.error.enableOrDisable', { flag, id: this.id }), err, timeout: 5000
|
|
43
|
+
}, { root: true });
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parse } from '@shell/utils/url';
|
|
2
2
|
import { CATALOG } from '@shell/config/labels-annotations';
|
|
3
3
|
import { insertAt } from '@shell/utils/array';
|
|
4
|
-
import { CATALOG as CATALOG_TYPE } from '@shell/config/types';
|
|
4
|
+
import { CLUSTER_REPO_APPCO_AUTH_GENERATE_NAME, CATALOG as CATALOG_TYPE } from '@shell/config/types';
|
|
5
5
|
import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
6
6
|
|
|
7
7
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
@@ -143,14 +143,27 @@ export default class ClusterRepo extends SteveModel {
|
|
|
143
143
|
return this.metadata?.state?.name === 'active';
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
get isSuseAppCollectionFromUI() {
|
|
147
|
+
return this.metadata?.annotations?.[CATALOG.SUSE_APP_COLLECTION];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get isSuseAppCollection() {
|
|
151
|
+
// Check annotation set by the UI or if the URL points to the SUSE App Collection registry
|
|
152
|
+
return this.isSuseAppCollectionFromUI || this.spec?.url?.startsWith('oci://dp.apps.rancher.io/charts');
|
|
153
|
+
}
|
|
154
|
+
|
|
146
155
|
get typeDisplay() {
|
|
156
|
+
if (this.isSuseAppCollectionFromUI) {
|
|
157
|
+
return 'SUSE AppCo';
|
|
158
|
+
}
|
|
147
159
|
if ( this.spec.gitRepo ) {
|
|
148
160
|
return 'git';
|
|
149
|
-
}
|
|
161
|
+
}
|
|
162
|
+
if ( this.spec.url ) {
|
|
150
163
|
return this.isOciType ? 'oci' : 'http';
|
|
151
|
-
} else {
|
|
152
|
-
return '?';
|
|
153
164
|
}
|
|
165
|
+
|
|
166
|
+
return '?';
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
get nameDisplay() {
|
|
@@ -220,4 +233,17 @@ export default class ClusterRepo extends SteveModel {
|
|
|
220
233
|
});
|
|
221
234
|
}, `catalog operation fetch`, timeout, interval);
|
|
222
235
|
}
|
|
236
|
+
|
|
237
|
+
async save() {
|
|
238
|
+
// Add annotation only if the type is SUSE_APP_COLLECTION
|
|
239
|
+
if (this.spec.clientSecret?.name?.search(CLUSTER_REPO_APPCO_AUTH_GENERATE_NAME) === 0) {
|
|
240
|
+
if (!this.metadata.annotations) {
|
|
241
|
+
this.metadata.annotations = {};
|
|
242
|
+
}
|
|
243
|
+
this.metadata.annotations[CATALOG.SUSE_APP_COLLECTION] = 'true';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Call the parent save method
|
|
247
|
+
return super.save();
|
|
248
|
+
}
|
|
223
249
|
}
|
|
@@ -138,7 +138,7 @@ export default class CapiMachine extends SteveModel {
|
|
|
138
138
|
|
|
139
139
|
async machineRef() {
|
|
140
140
|
const ref = this.spec.infrastructureRef;
|
|
141
|
-
const id = `${
|
|
141
|
+
const id = `${ this.metadata.namespace }/${ ref.name }`;
|
|
142
142
|
const kind = `rke-machine.cattle.io.${ ref.kind.toLowerCase() }`;
|
|
143
143
|
|
|
144
144
|
return await this.$dispatch('find', { type: kind, id });
|
|
@@ -41,12 +41,12 @@ export default class CapiMachineDeployment extends SteveModel {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
get templateType() {
|
|
44
|
-
return this.
|
|
44
|
+
return this.infrastructureRefKind ? `rke-machine.cattle.io.${ this.infrastructureRefKind.toLowerCase() }` : null;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
get template() {
|
|
48
48
|
const ref = this.spec.template.spec.infrastructureRef;
|
|
49
|
-
const id = `${
|
|
49
|
+
const id = `${ this.metadata.namespace }/${ ref.name }`;
|
|
50
50
|
const template = this.$rootGetters['management/byId'](this.templateType, id);
|
|
51
51
|
|
|
52
52
|
return template;
|
|
@@ -92,15 +92,15 @@ export default class CapiMachineDeployment extends SteveModel {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
get outdated() {
|
|
95
|
-
return Math.max(0, (this.status?.replicas || 0) - (this.status?.
|
|
95
|
+
return Math.max(0, (this.status?.replicas || 0) - (this.status?.upToDateReplicas || 0));
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
get ready() {
|
|
99
|
-
return
|
|
99
|
+
return this.status?.availableReplicas || 0;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
get unavailable() {
|
|
103
|
-
return this.status?.
|
|
103
|
+
return Math.max(0, (this.status?.replicas || 0) - (this.status?.availableReplicas || 0));
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
get isControlPlane() {
|
package/models/event.js
CHANGED
|
@@ -38,4 +38,9 @@ export default class K8sEvent extends SteveModel {
|
|
|
38
38
|
|
|
39
39
|
return schema && rowValueGetter ? rowValueGetter(schema, 'Last Seen')(this) : null;
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
// Because we're using eventType which is a non-standard state we don't have a reliable way to provide a state color anymore and have therefore disabled the color.
|
|
43
|
+
get insightsColor() {
|
|
44
|
+
return 'disabled';
|
|
45
|
+
}
|
|
41
46
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
2
|
+
|
|
3
|
+
export default class GroupMembershipRefreshRequest extends SteveModel {
|
|
4
|
+
get canRefreshMemberships() {
|
|
5
|
+
return this.schema?.collectionMethods.find((x) => x.toLowerCase() === 'post');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
cleanForSave(data) {
|
|
9
|
+
const val = super.cleanForSave(data);
|
|
10
|
+
|
|
11
|
+
delete val.type;
|
|
12
|
+
|
|
13
|
+
return val;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
2
|
+
|
|
3
|
+
export default class PasswordChangeRequest extends SteveModel {
|
|
4
|
+
get canChangePassword() {
|
|
5
|
+
return this.schema?.collectionMethods.find((x) => x.toLowerCase() === 'post');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
cleanForSave(data) {
|
|
9
|
+
const val = super.cleanForSave(data);
|
|
10
|
+
|
|
11
|
+
delete val.type;
|
|
12
|
+
|
|
13
|
+
return val;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
2
|
+
|
|
3
|
+
export default class SelfUser extends SteveModel {
|
|
4
|
+
get canGetUser() {
|
|
5
|
+
return this.schema?.collectionMethods.find((x) => x.toLowerCase() === 'post');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
cleanForSave(data) {
|
|
9
|
+
const val = super.cleanForSave(data);
|
|
10
|
+
|
|
11
|
+
delete val.type;
|
|
12
|
+
|
|
13
|
+
return val;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
2
|
+
|
|
3
|
+
export default class SteveToken extends SteveModel {
|
|
4
|
+
// for now, we are only showing the new tokens in the UI. Later we will be able to edit a few of it's fields
|
|
5
|
+
get _availableActions() {
|
|
6
|
+
return super._availableActions.filter((a) => ['viewInApi', 'promptRemove'].includes(a.action));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
cleanForSave(data) {
|
|
10
|
+
const val = super.cleanForSave(data);
|
|
11
|
+
|
|
12
|
+
delete val.type;
|
|
13
|
+
|
|
14
|
+
return val;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get isDeprecated() {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get state() {
|
|
22
|
+
return this.isExpired ? 'expired' : !this.spec?.enabled ? 'inactive' : 'active';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get isExpired() {
|
|
26
|
+
return this.status?.expired;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get expiresAt() {
|
|
30
|
+
return this.status?.expiresAt || '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get lastUsedAt() {
|
|
34
|
+
return this.status?.lastUsedAt || '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get description() {
|
|
38
|
+
return this.spec?.description || '';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get clusterId() {
|
|
42
|
+
return this.spec?.clusterName || '';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get created() {
|
|
46
|
+
return this.metadata?.creationTimestamp;
|
|
47
|
+
}
|
|
48
|
+
}
|