@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/global/_layout.scss +4 -0
- package/assets/translations/en-us.yaml +144 -41
- package/assets/translations/zh-hans.yaml +1 -7
- package/chart/monitoring/ClusterSelector.vue +0 -21
- package/chart/monitoring/prometheus/index.vue +6 -3
- package/components/CruResource.vue +161 -14
- package/components/ExplorerMembers.vue +8 -4
- package/components/ExplorerProjectsNamespaces.vue +10 -6
- package/components/GrowlManager.vue +4 -0
- package/components/MgmtNodeList.vue +184 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
- package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
- package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
- package/components/ResourceDetail/index.vue +1 -1
- package/components/ResourceList/Masthead.vue +7 -1
- package/components/ResourceList/index.vue +82 -1
- package/components/RichTranslation.vue +5 -2
- package/components/Setting.vue +1 -0
- package/components/SubtleLink.vue +31 -6
- package/components/Tabbed/Tab.vue +29 -3
- package/components/Tabbed/index.vue +25 -3
- package/components/TableOfContents/TableOfContents.vue +109 -0
- package/components/TableOfContents/composables.ts +258 -0
- package/components/Window/ContainerShell.vue +21 -11
- package/components/Window/__tests__/ContainerShell.test.ts +107 -37
- package/components/Wizard.vue +9 -4
- package/components/fleet/AppCoChartGrid.vue +401 -0
- package/components/fleet/AppCoEmptyState.vue +127 -0
- package/components/fleet/AppCoPageHeader.vue +119 -0
- package/components/fleet/AppCoVersionSelect.vue +70 -0
- package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
- package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
- package/components/fleet/FleetClusterTargets/index.vue +189 -146
- package/components/fleet/FleetIntro.vue +7 -3
- package/components/fleet/FleetNoWorkspaces.vue +7 -3
- package/components/fleet/FleetSecretSelector.vue +5 -3
- package/components/fleet/FleetValuesFrom.vue +8 -2
- package/components/fleet/GitRepoTargetTab.vue +0 -2
- package/components/fleet/HelmOpAdvancedTab.vue +19 -53
- package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
- package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
- package/components/fleet/HelmOpResourcesSection.vue +82 -0
- package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
- package/components/fleet/HelmOpTargetTab.vue +64 -60
- package/components/fleet/HelmOpValuesTab.vue +129 -105
- package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
- package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
- package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
- package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
- package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
- package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
- package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
- package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
- package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
- package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
- package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
- package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
- package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
- package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
- package/components/fleet/dashboard/Empty.vue +8 -4
- package/components/fleet/dashboard/ResourceCard.vue +28 -0
- package/components/fleet/dashboard/ResourceDetails.vue +28 -0
- package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
- package/components/form/ArrayList.vue +61 -4
- package/components/form/KeyValue.vue +23 -2
- package/components/form/LabeledSelect.vue +39 -1
- package/components/form/Labels.vue +22 -3
- package/components/form/NameNsDescription.vue +13 -5
- package/components/form/ResourceTabs/index.vue +1 -0
- package/components/form/__tests__/NameNsDescription.test.ts +75 -0
- package/components/formatter/InternalExternalIP.vue +10 -4
- package/components/formatter/ServiceTargets.vue +26 -7
- package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
- package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
- package/components/nav/Header.vue +4 -0
- package/components/nav/TopLevelMenu.vue +7 -2
- package/components/nav/__tests__/Header.test.ts +15 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
- package/components/templates/default.vue +9 -4
- package/components/templates/home.vue +9 -4
- package/components/templates/plain.vue +9 -4
- package/composables/useHelmOpResources.test.ts +56 -0
- package/composables/useHelmOpResources.ts +32 -0
- package/composables/useStateColor.test.ts +325 -0
- package/composables/useStateColor.ts +128 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +17 -4
- package/config/product/manager.js +2 -0
- package/config/router/index.js +16 -0
- package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
- package/config/router/navigation-guards/authentication.js +10 -4
- package/config/router/routes.js +20 -6
- package/config/settings.ts +0 -2
- package/config/table-headers.js +3 -4
- package/config/types.js +9 -0
- package/core/plugin-products-base.ts +3 -3
- package/core/plugin-types.ts +83 -30
- package/core/plugin.ts +3 -0
- package/core/types-provisioning.ts +34 -1
- package/core/types.ts +15 -2
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
- package/detail/__tests__/workload.test.ts +3 -152
- package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +30 -4
- package/detail/workload/index.vue +12 -55
- package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
- package/edit/auth/__tests__/azuread.test.ts +34 -9
- package/edit/auth/__tests__/github.test.ts +234 -0
- package/edit/auth/__tests__/oidc.test.ts +26 -6
- package/edit/auth/__tests__/saml.test.ts +196 -0
- package/edit/auth/azuread.vue +128 -95
- package/edit/auth/github.vue +72 -13
- package/edit/auth/ldap/__tests__/index.test.ts +206 -0
- package/edit/auth/ldap/config.vue +8 -0
- package/edit/auth/ldap/index.vue +75 -1
- package/edit/auth/oidc.vue +119 -73
- package/edit/auth/saml.vue +76 -12
- package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
- package/edit/fleet.cattle.io.helmop.vue +491 -136
- package/edit/management.cattle.io.user.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/rke2.vue +84 -10
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/list/group.principal.vue +5 -4
- package/list/harvesterhci.io.management.cluster.vue +8 -9
- package/list/management.cattle.io.user.vue +12 -9
- package/list/provisioning.cattle.io.cluster.vue +16 -10
- package/mixins/__tests__/auth-config.test.ts +90 -0
- package/mixins/__tests__/chart.test.ts +94 -0
- package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
- package/mixins/auth-config.js +7 -0
- package/mixins/chart.js +11 -2
- package/mixins/child-hook.js +12 -6
- package/mixins/create-edit-view/impl.js +5 -3
- package/mixins/resource-fetch-api-pagination.js +21 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
- package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
- package/models/__tests__/fleet-application.test.ts +175 -0
- package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
- package/models/__tests__/management.cattle.io.node.ts +22 -0
- package/models/__tests__/namespace.test.ts +36 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +49 -0
- package/models/__tests__/workload.test.ts +401 -26
- package/models/catalog.cattle.io.clusterrepo.js +28 -4
- package/models/compliance.cattle.io.clusterscan.js +39 -4
- package/models/fleet-application.js +4 -0
- package/models/fleet.cattle.io.helmop.js +20 -1
- package/models/management.cattle.io.cluster.js +18 -2
- package/models/management.cattle.io.node.js +44 -3
- package/models/namespace.js +1 -1
- package/models/pod.js +33 -1
- package/models/provisioning.cattle.io.cluster.js +5 -5
- package/models/workload.js +108 -13
- package/models/workload.service.js +5 -0
- package/package.json +14 -13
- package/pages/about.vue +5 -6
- package/pages/auth/login.vue +0 -35
- package/pages/auth/setup.vue +11 -0
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
- package/pages/c/_cluster/apps/charts/chart.vue +2 -1
- package/pages/c/_cluster/apps/charts/index.vue +48 -10
- package/pages/c/_cluster/apps/charts/install.vue +122 -116
- package/pages/c/_cluster/auth/roles/index.vue +5 -4
- package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
- package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
- package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
- package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
- package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
- package/pages/c/_cluster/fleet/application/create.vue +187 -136
- package/pages/c/_cluster/fleet/application/index.vue +5 -3
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
- package/pages/c/_cluster/fleet/index.vue +2 -2
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
- package/pages/c/_cluster/uiplugins/index.vue +15 -0
- package/pages/fail-whale.vue +16 -11
- package/pages/home.vue +16 -46
- package/plugins/clean-html.d.ts +9 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +93 -0
- package/plugins/dashboard-store/resource-class.js +62 -7
- package/plugins/steve/__tests__/actions.test.ts +212 -0
- package/plugins/steve/actions.js +96 -0
- package/plugins/steve/steve-pagination-utils.ts +1 -1
- package/rancher-components/Accordion/Accordion.vue +53 -9
- package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
- package/rancher-components/Form/Radio/RadioButton.vue +17 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
- package/rancher-components/RcButton/RcButton.test.ts +103 -0
- package/rancher-components/RcButton/RcButton.vue +94 -15
- package/rancher-components/RcButton/types.ts +3 -0
- package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
- package/rancher-components/RcSection/RcSection.vue +28 -3
- package/scripts/extension/helm/package/Dockerfile +1 -1
- package/scripts/test-plugins-build.sh +2 -1
- package/store/__tests__/notifications.test.ts +434 -0
- package/store/catalog.js +57 -0
- package/store/plugins.js +7 -4
- package/types/components/buttonGroup.ts +5 -0
- package/types/shell/index.d.ts +104 -70
- package/utils/__tests__/auth.test.ts +273 -0
- package/utils/__tests__/computed.test.ts +193 -0
- package/utils/__tests__/cspAdaptor.test.ts +163 -0
- package/utils/__tests__/dom.test.ts +81 -0
- package/utils/__tests__/duration.test.ts +37 -1
- package/utils/__tests__/dynamic-importer.test.ts +102 -0
- package/utils/__tests__/fleet-appco.test.ts +312 -0
- package/utils/__tests__/monitoring.test.ts +130 -0
- package/utils/__tests__/object.test.ts +22 -0
- package/utils/__tests__/platform.test.ts +91 -0
- package/utils/__tests__/position.test.ts +237 -0
- package/utils/__tests__/provider.test.ts +51 -1
- package/utils/__tests__/queue.test.ts +232 -0
- package/utils/__tests__/release-notes.test.ts +221 -0
- package/utils/__tests__/router.test.js +254 -1
- package/utils/__tests__/select.test.ts +208 -0
- package/utils/__tests__/time.test.ts +265 -1
- package/utils/__tests__/title.test.ts +47 -0
- package/utils/__tests__/width.test.ts +53 -0
- package/utils/__tests__/window.test.ts +158 -0
- package/utils/__tests__/xccdf.test.ts +126 -6
- package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
- package/utils/crypto/__tests__/index.test.ts +144 -0
- package/utils/duration.ts +104 -0
- package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
- package/utils/dynamic-content/info.ts +2 -1
- package/utils/error.js +13 -0
- package/utils/fleet-appco.ts +323 -0
- package/utils/object.js +22 -2
- package/utils/provider.ts +12 -0
- package/utils/validators/__tests__/container-images.test.ts +104 -0
- package/utils/validators/__tests__/flow-output.test.ts +91 -0
- package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
- package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
- package/utils/xccdf.ts +39 -42
- package/vue.config.js +1 -1
- package/pages/support/index.vue +0 -264
- package/utils/duration.js +0 -43
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import FleetBundle from '@shell/models/fleet.cattle.io.bundle.js';
|
|
2
|
+
|
|
3
|
+
describe('class FleetBundle', () => {
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
jest.restoreAllMocks();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe('targetClusters', () => {
|
|
9
|
+
function createFleetBundle(targets: any[], clusters: any[], workspaceId = 'fleet-default', groups: any[] = []) {
|
|
10
|
+
const workspace = {
|
|
11
|
+
id: workspaceId,
|
|
12
|
+
clusters,
|
|
13
|
+
clusterGroups: groups,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
jest.spyOn(FleetBundle.prototype, '$getters', 'get').mockReturnValue({ byId: () => workspace });
|
|
17
|
+
|
|
18
|
+
return new FleetBundle({
|
|
19
|
+
metadata: { namespace: workspaceId },
|
|
20
|
+
spec: { targets },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
it.each([
|
|
25
|
+
[
|
|
26
|
+
'metadata.name',
|
|
27
|
+
[{ clusterName: 'c-m-abc123' }],
|
|
28
|
+
[{
|
|
29
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-cluster'
|
|
30
|
+
}],
|
|
31
|
+
[{
|
|
32
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-cluster'
|
|
33
|
+
}],
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
'nameDisplay when metadata.name does not match',
|
|
37
|
+
[{ clusterName: 'my-display-name' }],
|
|
38
|
+
[{
|
|
39
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-display-name'
|
|
40
|
+
}],
|
|
41
|
+
[{
|
|
42
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-display-name'
|
|
43
|
+
}],
|
|
44
|
+
],
|
|
45
|
+
])('should find cluster by %s', (_label, targets, clusters, expected) => {
|
|
46
|
+
const bundle = createFleetBundle(targets, clusters);
|
|
47
|
+
|
|
48
|
+
expect(bundle.targetClusters).toStrictEqual(expected);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should prefer metadata.name match over nameDisplay match', () => {
|
|
52
|
+
const clusters = [
|
|
53
|
+
{
|
|
54
|
+
id: 'fleet-default/exact-match',
|
|
55
|
+
metadata: { name: 'exact-match' },
|
|
56
|
+
nameDisplay: 'display-a',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'fleet-default/c-m-other',
|
|
60
|
+
metadata: { name: 'c-m-other' },
|
|
61
|
+
nameDisplay: 'exact-match',
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const bundle = createFleetBundle([{ clusterName: 'exact-match' }], clusters);
|
|
66
|
+
|
|
67
|
+
expect(bundle.targetClusters).toStrictEqual([clusters[0]]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should return empty array when no cluster matches by name or nameDisplay', () => {
|
|
71
|
+
const clusters = [
|
|
72
|
+
{
|
|
73
|
+
id: 'fleet-default/c-m-abc123',
|
|
74
|
+
metadata: { name: 'c-m-abc123' },
|
|
75
|
+
nameDisplay: 'my-cluster',
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const bundle = createFleetBundle([{ clusterName: 'non-existent' }], clusters);
|
|
80
|
+
|
|
81
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle multiple targets with mixed name and nameDisplay matches', () => {
|
|
85
|
+
const clusters = [
|
|
86
|
+
{
|
|
87
|
+
id: 'fleet-default/c-m-abc123',
|
|
88
|
+
metadata: { name: 'c-m-abc123' },
|
|
89
|
+
nameDisplay: 'cluster-alpha',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'fleet-default/c-m-def456',
|
|
93
|
+
metadata: { name: 'c-m-def456' },
|
|
94
|
+
nameDisplay: 'cluster-beta',
|
|
95
|
+
}
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const targets = [
|
|
99
|
+
{ clusterName: 'c-m-abc123' },
|
|
100
|
+
{ clusterName: 'cluster-beta' },
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const bundle = createFleetBundle(targets, clusters);
|
|
104
|
+
|
|
105
|
+
expect(bundle.targetClusters).toStrictEqual([clusters[0], clusters[1]]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should return empty array when workspace has no clusters', () => {
|
|
109
|
+
const bundle = createFleetBundle([{ clusterName: 'any-name' }], []);
|
|
110
|
+
|
|
111
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should handle cluster with undefined nameDisplay gracefully', () => {
|
|
115
|
+
const clusters = [
|
|
116
|
+
{
|
|
117
|
+
id: 'fleet-default/c-m-abc123',
|
|
118
|
+
metadata: { name: 'c-m-abc123' },
|
|
119
|
+
nameDisplay: undefined,
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const bundle = createFleetBundle([{ clusterName: 'c-m-abc123' }], clusters);
|
|
124
|
+
|
|
125
|
+
expect(bundle.targetClusters).toStrictEqual([clusters[0]]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should not match by nameDisplay when nameDisplay is undefined and target uses a different name', () => {
|
|
129
|
+
const clusters = [
|
|
130
|
+
{
|
|
131
|
+
id: 'fleet-default/c-m-abc123',
|
|
132
|
+
metadata: { name: 'c-m-abc123' },
|
|
133
|
+
nameDisplay: undefined,
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const bundle = createFleetBundle([{ clusterName: 'some-other-name' }], clusters);
|
|
138
|
+
|
|
139
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should return local cluster targets when workspace is fleet-local', () => {
|
|
143
|
+
const localTargetClusters = [
|
|
144
|
+
{
|
|
145
|
+
id: 'fleet-local/local',
|
|
146
|
+
metadata: { name: 'local' },
|
|
147
|
+
nameDisplay: 'local',
|
|
148
|
+
}
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
const groups = [
|
|
152
|
+
{
|
|
153
|
+
id: 'fleet-local/default',
|
|
154
|
+
targetClusters: localTargetClusters,
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
const bundle = createFleetBundle([], [], 'fleet-local', groups);
|
|
159
|
+
|
|
160
|
+
expect(bundle.targetClusters).toStrictEqual(localTargetClusters);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should return empty array when workspace is fleet-local and default group is missing', () => {
|
|
164
|
+
const bundle = createFleetBundle([], [], 'fleet-local', []);
|
|
165
|
+
|
|
166
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import HelmOp from '@shell/models/fleet.cattle.io.helmop.js';
|
|
2
|
+
import { SUSE_APP_COLLECTION_REPO_URL } from '@shell/utils/fleet-appco';
|
|
3
|
+
|
|
4
|
+
const mockIsRancherPrime = jest.fn(() => true);
|
|
5
|
+
|
|
6
|
+
jest.mock('@shell/config/version', () => ({ isRancherPrime: () => mockIsRancherPrime() }));
|
|
2
7
|
|
|
3
8
|
describe('class HelmOp', () => {
|
|
4
9
|
let instance;
|
|
5
10
|
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
mockIsRancherPrime.mockReturnValue(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
6
15
|
describe('source getter', () => {
|
|
7
16
|
it('should return correct source for SOURCE_TYPE.REPO (HTTPS)', () => {
|
|
8
17
|
instance = new HelmOp({
|
|
@@ -221,4 +230,79 @@ describe('class HelmOp', () => {
|
|
|
221
230
|
expect(sourceSub.display).toBe('');
|
|
222
231
|
});
|
|
223
232
|
});
|
|
233
|
+
|
|
234
|
+
describe('isSuseAppCollectionFromUI', () => {
|
|
235
|
+
it('should return true when annotation is set', () => {
|
|
236
|
+
instance = new HelmOp({ metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } }, spec: { helm: {} } });
|
|
237
|
+
|
|
238
|
+
expect(instance.isSuseAppCollectionFromUI).toBe(true);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should return false when annotation is missing', () => {
|
|
242
|
+
instance = new HelmOp({ metadata: { annotations: {} }, spec: { helm: {} } });
|
|
243
|
+
|
|
244
|
+
expect(instance.isSuseAppCollectionFromUI).toBe(false);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe('isSuseAppCollection', () => {
|
|
249
|
+
it('should return true even when not Rancher Prime if annotation is set', () => {
|
|
250
|
+
mockIsRancherPrime.mockReturnValue(false);
|
|
251
|
+
instance = new HelmOp({
|
|
252
|
+
metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } },
|
|
253
|
+
spec: { helm: {} }
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(instance.isSuseAppCollection).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should return true when annotation is set and Rancher Prime', () => {
|
|
260
|
+
instance = new HelmOp({
|
|
261
|
+
metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } },
|
|
262
|
+
spec: { helm: {} }
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(instance.isSuseAppCollection).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('should return true when repo URL starts with SUSE_APP_COLLECTION_REPO_URL', () => {
|
|
269
|
+
instance = new HelmOp({
|
|
270
|
+
metadata: {},
|
|
271
|
+
spec: { helm: { repo: `${ SUSE_APP_COLLECTION_REPO_URL }/my-chart` } }
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(instance.isSuseAppCollection).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should return false when no annotation and different repo URL', () => {
|
|
278
|
+
instance = new HelmOp({
|
|
279
|
+
metadata: {},
|
|
280
|
+
spec: { helm: { repo: 'oci://other-registry.io/charts' } }
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
expect(instance.isSuseAppCollection).toBe(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('applicationType', () => {
|
|
288
|
+
it('should return "SUSE AppCo" when isSuseAppCollectionFromUI is true', () => {
|
|
289
|
+
instance = new HelmOp({
|
|
290
|
+
metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } },
|
|
291
|
+
spec: { helm: {} },
|
|
292
|
+
kind: 'HelmOp'
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
expect(instance.applicationType).toStrictEqual('SUSE AppCo');
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should return kind when not SUSE App Collection from UI', () => {
|
|
299
|
+
instance = new HelmOp({
|
|
300
|
+
metadata: {},
|
|
301
|
+
spec: { helm: {} },
|
|
302
|
+
kind: 'HelmOp'
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(instance.applicationType).toStrictEqual('HelmOp');
|
|
306
|
+
});
|
|
307
|
+
});
|
|
224
308
|
});
|
|
@@ -94,6 +94,28 @@ describe('class MgmtNode', () => {
|
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
describe('pool', () => {
|
|
98
|
+
it('should return undefined if nodePoolName is not set', () => {
|
|
99
|
+
const mgmtNode = new MgmtNode({ spec: {} });
|
|
100
|
+
|
|
101
|
+
expect(mgmtNode.pool).toBeUndefined();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should return the node pool when nodePoolName is set', () => {
|
|
105
|
+
const nodePool = { id: 'fleet-local/np1' };
|
|
106
|
+
const mgmtNodeCtx = {
|
|
107
|
+
rootGetters: {
|
|
108
|
+
'i18n/t': t,
|
|
109
|
+
'management/byId': jest.fn(() => nodePool)
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const mgmtNode = new MgmtNode({ spec: { nodePoolName: 'fleet-local:np1' } }, mgmtNodeCtx);
|
|
113
|
+
|
|
114
|
+
expect(mgmtNode.pool).toStrictEqual(nodePool);
|
|
115
|
+
expect(mgmtNodeCtx.rootGetters['management/byId']).toHaveBeenCalledWith('management.cattle.io.nodepool', 'fleet-local/np1');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
97
119
|
describe('canScaleDown', () => {
|
|
98
120
|
const mgmtClusterId = 'test';
|
|
99
121
|
const nodeId = 'test/id';
|
|
@@ -150,6 +150,42 @@ describe('class Namespace', () => {
|
|
|
150
150
|
it.todo('should disableAutoInjection');
|
|
151
151
|
it.todo('should check if confirmRemove');
|
|
152
152
|
|
|
153
|
+
describe('move action availability', () => {
|
|
154
|
+
const SteveModelProto = Object.getPrototypeOf(Namespace.prototype);
|
|
155
|
+
|
|
156
|
+
const makeNamespace = ({ canUpdate }: { canUpdate: boolean }) => {
|
|
157
|
+
const namespace = new Namespace({});
|
|
158
|
+
|
|
159
|
+
jest.spyOn(namespace, '$rootGetters', 'get').mockReturnValue({
|
|
160
|
+
isRancher: true,
|
|
161
|
+
isSingleProduct: false,
|
|
162
|
+
'i18n/t': (key: string) => key,
|
|
163
|
+
});
|
|
164
|
+
Object.defineProperty(namespace, 'istioInstalled', { get: () => false, configurable: true });
|
|
165
|
+
Object.defineProperty(namespace, 'canUpdate', { get: () => canUpdate, configurable: true });
|
|
166
|
+
jest.spyOn(SteveModelProto, '_availableActions', 'get').mockReturnValue([]);
|
|
167
|
+
|
|
168
|
+
return namespace;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
it('should include the move action when user can update the namespace', () => {
|
|
172
|
+
const namespace = makeNamespace({ canUpdate: true });
|
|
173
|
+
|
|
174
|
+
const moveAction = namespace.availableActions.find((a: any) => a.action === 'move');
|
|
175
|
+
|
|
176
|
+
expect(moveAction).toBeDefined();
|
|
177
|
+
expect(moveAction.enabled).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should exclude the move action when user cannot update the namespace', () => {
|
|
181
|
+
const namespace = makeNamespace({ canUpdate: false });
|
|
182
|
+
|
|
183
|
+
const moveAction = namespace.availableActions.find((a: any) => a.action === 'move');
|
|
184
|
+
|
|
185
|
+
expect(moveAction).toBeUndefined();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
153
189
|
describe('handling listLocation', () => {
|
|
154
190
|
it.each([
|
|
155
191
|
['c-cluster-product-projectsnamespaces', true],
|
|
@@ -4,6 +4,9 @@ import MgmtCluster from '@shell/models/management.cattle.io.cluster';
|
|
|
4
4
|
jest.mock('@shell/utils/provider', () => ({
|
|
5
5
|
isHostedProvider: jest.fn().mockImplementation((context, provider) => {
|
|
6
6
|
return ['GKE', 'EKS', 'AKS'].includes(provider);
|
|
7
|
+
}),
|
|
8
|
+
isCAPIProvider: jest.fn().mockImplementation((context, provider) => {
|
|
9
|
+
return ['capa', 'capv'].includes(provider.toLowerCase());
|
|
7
10
|
})
|
|
8
11
|
}));
|
|
9
12
|
|
|
@@ -392,4 +395,50 @@ describe('class ProvCluster', () => {
|
|
|
392
395
|
jest.clearAllMocks();
|
|
393
396
|
});
|
|
394
397
|
});
|
|
398
|
+
|
|
399
|
+
describe('isCapiWithoutExtension', () => {
|
|
400
|
+
const testCases = [
|
|
401
|
+
{
|
|
402
|
+
description: 'should return undefined when mgmt is undefined',
|
|
403
|
+
isCapiHybrid: undefined,
|
|
404
|
+
isCAPIProvider: undefined,
|
|
405
|
+
expected: undefined,
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
description: 'should return false when not a CAPI cluster',
|
|
409
|
+
isCapiHybrid: false,
|
|
410
|
+
isCAPIProvider: false,
|
|
411
|
+
expected: false,
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
description: 'should return false when CAPI cluster and a registered CAPI provider extension exists',
|
|
415
|
+
isCapiHybrid: true,
|
|
416
|
+
isCAPIProvider: true,
|
|
417
|
+
expected: false,
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
description: 'should return true when CAPI cluster but no registered CAPI provider extension',
|
|
421
|
+
isCapiHybrid: true,
|
|
422
|
+
isCAPIProvider: false,
|
|
423
|
+
expected: true,
|
|
424
|
+
},
|
|
425
|
+
];
|
|
426
|
+
|
|
427
|
+
it.each(testCases)('$description', ({ isCapiHybrid, isCAPIProvider, expected }) => {
|
|
428
|
+
const cluster = new ProvCluster({});
|
|
429
|
+
|
|
430
|
+
if (isCapiHybrid === undefined) {
|
|
431
|
+
jest.spyOn(cluster, 'mgmt', 'get').mockReturnValue(undefined);
|
|
432
|
+
} else {
|
|
433
|
+
const mgmtCluster = new MgmtCluster({});
|
|
434
|
+
|
|
435
|
+
jest.spyOn(mgmtCluster, 'isCapiHybrid', 'get').mockReturnValue(isCapiHybrid);
|
|
436
|
+
jest.spyOn(mgmtCluster, 'isCAPIProvider', 'get').mockReturnValue(isCAPIProvider);
|
|
437
|
+
jest.spyOn(cluster, 'mgmt', 'get').mockReturnValue(mgmtCluster);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
expect(cluster.isCapiWithoutExtension).toStrictEqual(expected);
|
|
441
|
+
jest.clearAllMocks();
|
|
442
|
+
});
|
|
443
|
+
});
|
|
395
444
|
});
|