@rancher/shell 0.3.16 → 0.3.18
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/images/wechat-qr-code.jpg +0 -0
- package/assets/translations/en-us.yaml +75 -16
- package/assets/translations/zh-hans.yaml +151 -15
- package/chart/__tests__/S3.test.ts +50 -0
- package/chart/rancher-backup/S3.vue +21 -0
- package/chart/rancher-backup/index.vue +4 -0
- package/components/AsyncButton.vue +1 -1
- package/components/CommunityLinks.vue +1 -0
- package/components/FileDiff.vue +92 -85
- package/components/Inactivity.vue +10 -0
- package/components/LazyImage.vue +2 -2
- package/components/PromptRestore.vue +7 -5
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceDetail/index.vue +8 -14
- package/components/ResourceList/index.vue +1 -1
- package/components/ResourceTable.vue +50 -2
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/PromptRestore.test.ts +72 -0
- package/components/auth/AzureWarning.vue +1 -1
- package/components/auth/RoleDetailEdit.vue +1 -0
- package/components/fleet/FleetResources.vue +3 -64
- package/components/form/FileImageSelector.vue +9 -0
- package/components/form/FileSelector.vue +2 -1
- package/components/form/MatchExpressions.vue +1 -3
- package/components/form/NameNsDescription.vue +28 -12
- package/components/form/NodeAffinity.vue +2 -2
- package/components/form/PodAffinity.vue +2 -2
- package/components/form/ResourceTabs/index.vue +8 -2
- package/components/form/Select.vue +16 -0
- package/components/form/__tests__/FileImageSelector.test.ts +42 -0
- package/components/form/__tests__/FileSelector.test.ts +76 -0
- package/components/form/__tests__/NodeAffinity.test.ts +38 -0
- package/components/form/__tests__/PodAffinity.test.ts +46 -0
- package/components/formatter/ClusterLink.vue +8 -4
- package/components/formatter/ClusterProvider.vue +3 -1
- package/components/formatter/ImageName.vue +23 -0
- package/components/formatter/PodImages.vue +7 -1
- package/components/formatter/__tests__/ClusterLink.test.ts +101 -0
- package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
- package/components/nav/Header.vue +2 -2
- package/components/nav/WindowManager/ContainerShell.vue +60 -36
- package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
- package/config/__test__/home-links.test.ts +62 -0
- package/config/home-links.js +15 -3
- package/config/labels-annotations.js +7 -2
- package/config/persistentVolume.ts +108 -0
- package/config/product/manager.js +5 -1
- package/config/router.js +0 -4
- package/config/settings.ts +4 -0
- package/config/table-headers.js +6 -5
- package/config/types.js +2 -0
- package/config/uiplugins.js +50 -5
- package/core/plugin-helpers.js +39 -15
- package/core/plugin.ts +9 -0
- package/core/plugins.js +1 -1
- package/core/types-provisioning.ts +253 -0
- package/core/types.ts +21 -3
- package/detail/autoscaling.horizontalpodautoscaler/index.vue +50 -1
- package/detail/fleet.cattle.io.gitrepo.vue +10 -2
- package/detail/node.vue +6 -6
- package/detail/pod.vue +38 -9
- package/detail/provisioning.cattle.io.cluster.vue +46 -7
- package/detail/workload/index.vue +49 -18
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +62 -0
- package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
- package/edit/auth/github.vue +1 -0
- package/edit/autoscaling.horizontalpodautoscaler/hpa-scaling-rule.vue +130 -0
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +79 -0
- package/edit/fleet.cattle.io.clustergroup.vue +14 -3
- package/edit/fleet.cattle.io.gitrepo.vue +18 -1
- package/edit/namespace.vue +9 -1
- package/edit/networking.k8s.io.ingress/RulePath.vue +0 -2
- package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
- package/edit/persistentvolume/index.vue +2 -1
- package/edit/persistentvolume/plugins/csi.vue +3 -1
- package/edit/persistentvolume/plugins/longhorn.vue +12 -12
- package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -30
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +79 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +53 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +335 -151
- package/edit/storage.k8s.io.storageclass/index.vue +1 -2
- package/edit/ui.cattle.io.navlink.vue +213 -186
- package/initialize/App.js +3 -13
- package/initialize/layouts.ts +26 -0
- package/layouts/default.vue +1 -1
- package/list/group.principal.vue +1 -1
- package/list/provisioning.cattle.io.cluster.vue +8 -1
- package/middleware/authenticated.js +101 -5
- package/mixins/brand.js +39 -3
- package/mixins/child-hook.js +2 -2
- package/mixins/create-edit-view/impl.js +4 -4
- package/models/chart.js +1 -1
- package/models/fleet.cattle.io.cluster.js +33 -4
- package/models/fleet.cattle.io.gitrepo.js +113 -38
- package/models/management.cattle.io.kontainerdriver.js +14 -0
- package/models/persistentvolume.js +2 -111
- package/models/pod.js +30 -0
- package/models/provisioning.cattle.io.cluster.js +9 -1
- package/models/rke.cattle.io.etcdsnapshot.js +10 -7
- package/package.json +2 -2
- package/pages/about.vue +8 -2
- package/pages/auth/login.vue +1 -1
- package/pages/auth/logout.vue +11 -3
- package/pages/c/_cluster/apps/charts/index.vue +5 -2
- package/pages/c/_cluster/apps/charts/install.vue +5 -0
- package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
- package/pages/c/_cluster/auth/roles/index.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +2 -11
- package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
- package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
- package/pages/c/_cluster/settings/brand.vue +11 -8
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +177 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +19 -3
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +90 -21
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +107 -37
- package/pages/c/_cluster/uiplugins/index.vue +160 -44
- package/pages/docs/_doc.vue +9 -3
- package/pages/home.vue +6 -6
- package/pages/support/index.vue +10 -4
- package/pkg/auto-import.js +1 -1
- package/plugins/clean-tooltip-directive.js +1 -1
- package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
- package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
- package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
- package/plugins/dashboard-store/actions.js +1 -1
- package/plugins/dashboard-store/resource-class.js +39 -2
- package/plugins/plugin.js +9 -1
- package/plugins/steve/__tests__/getters.spec.ts +93 -0
- package/plugins/steve/getters.js +21 -1
- package/plugins/steve/subscribe.js +1 -3
- package/rancher-components/BadgeState/BadgeState.vue +5 -1
- package/rancher-components/Banner/Banner.test.ts +51 -1
- package/rancher-components/Banner/Banner.vue +134 -53
- package/rancher-components/Card/Card.test.ts +37 -0
- package/rancher-components/Card/Card.vue +24 -7
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +20 -29
- package/rancher-components/Form/Checkbox/Checkbox.vue +45 -20
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +2 -8
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +22 -10
- package/rancher-components/Form/Radio/RadioButton.test.ts +31 -0
- package/rancher-components/Form/Radio/RadioButton.vue +30 -13
- package/rancher-components/Form/Radio/RadioGroup.vue +26 -7
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -6
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +25 -38
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +23 -11
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +19 -5
- package/rancher-components/StringList/StringList.test.ts +453 -49
- package/rancher-components/StringList/StringList.vue +44 -26
- package/scripts/extension/publish +2 -2
- package/scripts/typegen.sh +11 -2
- package/server/server-middleware.js +4 -12
- package/store/index.js +14 -3
- package/store/prefs.js +0 -3
- package/store/store-types.js +2 -0
- package/store/type-map.js +17 -29
- package/types/api.d.ts +1 -0
- package/types/fleet.d.ts +1 -0
- package/types/shell/index.d.ts +931 -85
- package/types/userPreferences.d.ts +1 -1
- package/utils/__mocks__/socket.js +21 -0
- package/utils/grafana.js +23 -11
- package/utils/kube.js +9 -0
- package/utils/object.js +27 -0
- package/utils/selector.js +2 -1
- package/utils/settings.ts +2 -2
- package/utils/validators/formRules/index.ts +3 -3
- package/vue.config.js +3 -2
- package/components/.DS_Store +0 -0
- package/components/__tests__/.DS_Store +0 -0
- package/creators/pkg/package-lock.json +0 -37
- package/pages/safeMode.vue +0 -17
- package/plugins/steve/urloptions.js +0 -47
- package/yarn-error.log +0 -196
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import PersistentVolume from '@shell/edit/persistentvolume/index';
|
|
3
|
+
import { ExtendedVue, Vue } from 'vue/types/vue';
|
|
4
|
+
|
|
5
|
+
describe('view: PersistentVolume', () => {
|
|
6
|
+
it('should list enabled PV storage option if supported', () => {
|
|
7
|
+
const plugin = {
|
|
8
|
+
labelKey: 'persistentVolume.csi.label', supported: true, value: 'csi'
|
|
9
|
+
};
|
|
10
|
+
const resource = 'PersistentVolume';
|
|
11
|
+
const wrapper = mount(PersistentVolume as ExtendedVue<Vue, {}, {}, {}, PersistentVolume>, {
|
|
12
|
+
propsData: { value: { spec: { } } },
|
|
13
|
+
mocks: {
|
|
14
|
+
$store: {
|
|
15
|
+
dispatch: () => jest.fn(),
|
|
16
|
+
getters: {
|
|
17
|
+
'i18n/t': jest.fn(),
|
|
18
|
+
'i18n/exists': jest.fn(),
|
|
19
|
+
currentStore: () => 'cluster',
|
|
20
|
+
'features/get': () => jest.fn(),
|
|
21
|
+
'prefs/get': () => resource,
|
|
22
|
+
'cluster/schemaFor': () => {},
|
|
23
|
+
'cluster/all': () => [{}],
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
$fetchState: {
|
|
27
|
+
pending: false, error: true, timestamp: Date.now()
|
|
28
|
+
},
|
|
29
|
+
$route: {
|
|
30
|
+
params: { resource },
|
|
31
|
+
query: { AS: '' },
|
|
32
|
+
hash: '',
|
|
33
|
+
},
|
|
34
|
+
$router: {
|
|
35
|
+
currentRoute: {},
|
|
36
|
+
replace: jest.fn(),
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
stubs: { LabeledSelect: true }
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const select = wrapper.find('[data-testid="persistent-volume-plugin-select"]');
|
|
43
|
+
|
|
44
|
+
expect((select.vm as unknown as any).options).toStrictEqual(expect.arrayContaining([plugin]));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should select current plugin', () => {
|
|
48
|
+
const plugin = 'csi';
|
|
49
|
+
const resource = 'PersistentVolume';
|
|
50
|
+
const wrapper = mount(PersistentVolume as ExtendedVue<Vue, {}, {}, {}, PersistentVolume>, {
|
|
51
|
+
propsData: { value: { spec: { [plugin]: { value: plugin } } } },
|
|
52
|
+
mocks: {
|
|
53
|
+
$store: {
|
|
54
|
+
dispatch: () => jest.fn(),
|
|
55
|
+
getters: {
|
|
56
|
+
'i18n/t': jest.fn(),
|
|
57
|
+
'i18n/exists': jest.fn(),
|
|
58
|
+
currentStore: () => 'cluster',
|
|
59
|
+
'features/get': () => jest.fn(),
|
|
60
|
+
'prefs/get': () => resource,
|
|
61
|
+
'cluster/schemaFor': () => {},
|
|
62
|
+
'cluster/all': () => [{}],
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
$fetchState: {
|
|
66
|
+
pending: false, error: true, timestamp: Date.now()
|
|
67
|
+
},
|
|
68
|
+
$route: {
|
|
69
|
+
params: { resource },
|
|
70
|
+
query: { AS: '' },
|
|
71
|
+
hash: '',
|
|
72
|
+
},
|
|
73
|
+
$router: {
|
|
74
|
+
currentRoute: {},
|
|
75
|
+
replace: jest.fn(),
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(wrapper.vm.plugin).toBe(plugin);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -13,9 +13,9 @@ import NodeAffinity from '@shell/components/form/NodeAffinity';
|
|
|
13
13
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
14
14
|
import uniq from 'lodash/uniq';
|
|
15
15
|
import UnitInput from '@shell/components/form/UnitInput';
|
|
16
|
+
import { VOLUME_PLUGINS, LONGHORN_PLUGIN } from '@shell/config/persistentVolume';
|
|
16
17
|
import { NODE, PVC, STORAGE_CLASS } from '@shell/config/types';
|
|
17
18
|
import Loading from '@shell/components/Loading';
|
|
18
|
-
import { LONGHORN_PLUGIN, VOLUME_PLUGINS } from '@shell/models/persistentvolume';
|
|
19
19
|
import { _CREATE, _VIEW } from '@shell/config/query-params';
|
|
20
20
|
import { clone } from '@shell/utils/object';
|
|
21
21
|
import InfoBox from '@shell/components/InfoBox';
|
|
@@ -258,6 +258,7 @@ export default {
|
|
|
258
258
|
:label="t('persistentVolume.plugin.label')"
|
|
259
259
|
:localized-label="true"
|
|
260
260
|
option-label="labelKey"
|
|
261
|
+
data-testid="persistent-volume-plugin-select"
|
|
261
262
|
:options="plugins"
|
|
262
263
|
:mode="modeOverride"
|
|
263
264
|
:required="true"
|
|
@@ -3,7 +3,7 @@ import KeyValue from '@shell/components/form/KeyValue';
|
|
|
3
3
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
4
4
|
import { RadioGroup } from '@components/Form/Radio';
|
|
5
5
|
import { _CREATE } from '@shell/config/query-params';
|
|
6
|
-
import { LONGHORN_DRIVER } from '@shell/
|
|
6
|
+
import { LONGHORN_DRIVER } from '@shell/config/types';
|
|
7
7
|
|
|
8
8
|
export default {
|
|
9
9
|
components: {
|
|
@@ -54,20 +54,20 @@ export default {
|
|
|
54
54
|
<div>
|
|
55
55
|
<div class="row mb-20">
|
|
56
56
|
<div class="col span-6">
|
|
57
|
-
<LabeledInput
|
|
58
|
-
v-model="value.spec.csi.fsType"
|
|
59
|
-
:mode="mode"
|
|
60
|
-
:label="t('persistentVolume.shared.filesystemType.label')"
|
|
61
|
-
:placeholder="t('persistentVolume.shared.filesystemType.placeholder')"
|
|
57
|
+
<LabeledInput
|
|
58
|
+
v-model="value.spec.csi.fsType"
|
|
59
|
+
:mode="mode"
|
|
60
|
+
:label="t('persistentVolume.shared.filesystemType.label')"
|
|
61
|
+
:placeholder="t('persistentVolume.shared.filesystemType.placeholder')"
|
|
62
62
|
/>
|
|
63
63
|
</div>
|
|
64
64
|
<div class="col span-6">
|
|
65
|
-
<LabeledInput
|
|
66
|
-
v-model="value.spec.csi.volumeHandle"
|
|
67
|
-
:mode="mode"
|
|
68
|
-
:label="t('persistentVolume.longhorn.volumeHandle.label')"
|
|
69
|
-
:placeholder="t('persistentVolume.longhorn.volumeHandle.placeholder')"
|
|
70
|
-
:required="true"
|
|
65
|
+
<LabeledInput
|
|
66
|
+
v-model="value.spec.csi.volumeHandle"
|
|
67
|
+
:mode="mode"
|
|
68
|
+
:label="t('persistentVolume.longhorn.volumeHandle.label')"
|
|
69
|
+
:placeholder="t('persistentVolume.longhorn.volumeHandle.placeholder')"
|
|
70
|
+
:required="true"
|
|
71
71
|
/>
|
|
72
72
|
</div>
|
|
73
73
|
</div>
|
|
@@ -9,35 +9,6 @@ import { cleanUp } from '@shell/utils/object';
|
|
|
9
9
|
import { fetchSetting } from '@shell/utils/settings';
|
|
10
10
|
import { RadioGroup } from '@components/Form/Radio';
|
|
11
11
|
|
|
12
|
-
export function cleanAgentConfiguration(model, key) {
|
|
13
|
-
if (!model || !model[key]) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const v = model[key];
|
|
18
|
-
|
|
19
|
-
if (Array.isArray(v) && v.length === 0) {
|
|
20
|
-
delete model[key];
|
|
21
|
-
} else if (v && typeof v === 'object') {
|
|
22
|
-
Object.keys(v).forEach((k) => {
|
|
23
|
-
// delete these auxiliary props used in podAffinity and nodeAffinity that shouldn't be sent to the server
|
|
24
|
-
if (k === '_namespaceOption' || k === '_namespaces' || k === '_anti' || k === '_id') {
|
|
25
|
-
delete v[k];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// prevent cleanup of "namespaceSelector" when an empty object because it represents all namespaces in pod/node affinity
|
|
29
|
-
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#podaffinityterm-v1-core
|
|
30
|
-
if (k !== 'namespaceSelector') {
|
|
31
|
-
cleanAgentConfiguration(v, k);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (Object.keys(v).length === 0) {
|
|
36
|
-
delete model[key];
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
12
|
// Affinity radio button choices
|
|
42
13
|
const DEFAULT = 'default';
|
|
43
14
|
const CUSTOM = 'custom';
|
|
@@ -215,7 +186,7 @@ export default {
|
|
|
215
186
|
</script>
|
|
216
187
|
|
|
217
188
|
<template>
|
|
218
|
-
<div
|
|
189
|
+
<div>
|
|
219
190
|
<Banner
|
|
220
191
|
:closable="false"
|
|
221
192
|
color="info"
|
|
@@ -43,14 +43,28 @@ export default {
|
|
|
43
43
|
const configMap = this.value.spec.rkeConfig?.registries?.configs || {};
|
|
44
44
|
const entries = [];
|
|
45
45
|
|
|
46
|
+
const defaultAddValue = {
|
|
47
|
+
hostname: '',
|
|
48
|
+
authConfigSecretName: null,
|
|
49
|
+
caBundle: '',
|
|
50
|
+
insecureSkipVerify: false,
|
|
51
|
+
tlsSecretName: null,
|
|
52
|
+
};
|
|
53
|
+
|
|
46
54
|
for ( const hostname in configMap ) {
|
|
55
|
+
if (configMap[hostname]) {
|
|
56
|
+
configMap[hostname].insecureSkipVerify = configMap[hostname].insecureSkipVerify ?? defaultAddValue.insecureSkipVerify;
|
|
57
|
+
configMap[hostname].authConfigSecretName = configMap[hostname].authConfigSecretName ?? defaultAddValue.authConfigSecretName;
|
|
58
|
+
configMap[hostname].caBundle = configMap[hostname].caBundle ?? defaultAddValue.caBundle;
|
|
59
|
+
configMap[hostname].tlsSecretName = configMap[hostname].tlsSecretName ?? defaultAddValue.tlsSecretName;
|
|
60
|
+
}
|
|
47
61
|
entries.push({
|
|
48
62
|
hostname,
|
|
49
63
|
...configMap[hostname],
|
|
50
64
|
});
|
|
51
65
|
}
|
|
52
66
|
|
|
53
|
-
return { entries };
|
|
67
|
+
return { entries, defaultAddValue };
|
|
54
68
|
},
|
|
55
69
|
|
|
56
70
|
computed: {
|
|
@@ -59,16 +73,6 @@ export default {
|
|
|
59
73
|
return TYPES.TLS;
|
|
60
74
|
},
|
|
61
75
|
},
|
|
62
|
-
|
|
63
|
-
defaultAddValue() {
|
|
64
|
-
return {
|
|
65
|
-
hostname: '',
|
|
66
|
-
authConfigSecretName: null,
|
|
67
|
-
caBundle: '',
|
|
68
|
-
insecureSkipVerify: false,
|
|
69
|
-
tlsSecretName: null,
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
76
|
},
|
|
73
77
|
|
|
74
78
|
mounted() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mount } from '@vue/test-utils';
|
|
1
|
+
import { mount, shallowMount } from '@vue/test-utils';
|
|
2
2
|
import rke2 from '@shell/edit/provisioning.cattle.io.cluster/rke2.vue';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -14,6 +14,7 @@ const defaultStubs = {
|
|
|
14
14
|
LabeledSelect: true,
|
|
15
15
|
ACE: true,
|
|
16
16
|
AgentEnv: true,
|
|
17
|
+
AgentConfiguration: true,
|
|
17
18
|
ArrayList: true,
|
|
18
19
|
ArrayListGrouped: true,
|
|
19
20
|
BadgeState: true,
|
|
@@ -267,4 +268,81 @@ describe('component: rke2', () => {
|
|
|
267
268
|
|
|
268
269
|
expect((wrapper.vm as any).validationPassed).toBe(true);
|
|
269
270
|
});
|
|
271
|
+
|
|
272
|
+
// TODO: Complete test after implementing fetch https://github.com/rancher/dashboard/issues/9322
|
|
273
|
+
// eslint-disable-next-line jest/no-disabled-tests
|
|
274
|
+
describe.skip('should initialize agent configuration values', () => {
|
|
275
|
+
it('adding default values if none', async() => {
|
|
276
|
+
const wrapper = shallowMount(rke2, {
|
|
277
|
+
propsData: {
|
|
278
|
+
mode: 'create',
|
|
279
|
+
value: { spec: { ...defaultSpec } },
|
|
280
|
+
provider: 'custom'
|
|
281
|
+
},
|
|
282
|
+
computed: defaultComputed,
|
|
283
|
+
mocks: {
|
|
284
|
+
...defaultMocks,
|
|
285
|
+
$store: {
|
|
286
|
+
getters: defaultGetters,
|
|
287
|
+
dispatch: {
|
|
288
|
+
'management/request': jest.fn(),
|
|
289
|
+
'management/find': jest.fn(),
|
|
290
|
+
'management/findAll': () => ([]),
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
stubs: defaultStubs
|
|
295
|
+
});
|
|
296
|
+
const defaultAgentConfig = {
|
|
297
|
+
clusterAgentDeploymentCustomization: {
|
|
298
|
+
overrideAffinity: {},
|
|
299
|
+
appendTolerations: [],
|
|
300
|
+
overrideResourceRequirements: {}
|
|
301
|
+
},
|
|
302
|
+
fleetAgentDeploymentCustomization: {
|
|
303
|
+
overrideAffinity: {},
|
|
304
|
+
appendTolerations: [],
|
|
305
|
+
overrideResourceRequirements: {}
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// Setting RKE to avoid calls
|
|
310
|
+
wrapper.setData({ rke2Versions: [] });
|
|
311
|
+
|
|
312
|
+
// await rke2.fetch.call(wrapper.vm);
|
|
313
|
+
|
|
314
|
+
expect(wrapper.props().value.spec).toContain(defaultAgentConfig);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should display agent configuration tab', async() => {
|
|
318
|
+
const wrapper = shallowMount(rke2, {
|
|
319
|
+
propsData: {
|
|
320
|
+
mode: 'create',
|
|
321
|
+
value: { spec: { ...defaultSpec } },
|
|
322
|
+
provider: 'custom'
|
|
323
|
+
},
|
|
324
|
+
computed: defaultComputed,
|
|
325
|
+
mocks: {
|
|
326
|
+
...defaultMocks,
|
|
327
|
+
$store: {
|
|
328
|
+
getters: defaultGetters,
|
|
329
|
+
dispatch: {
|
|
330
|
+
'management/request': jest.fn(),
|
|
331
|
+
'management/find': jest.fn(),
|
|
332
|
+
'management/findAll': () => ([]),
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
stubs: defaultStubs
|
|
337
|
+
});
|
|
338
|
+
const agent = wrapper.find('[data-testid="rke2-cluster-agent-config"]');
|
|
339
|
+
|
|
340
|
+
// Setting RKE to avoid calls
|
|
341
|
+
wrapper.setData({ rke2Versions: [] });
|
|
342
|
+
|
|
343
|
+
await rke2.fetch.call(wrapper.vm);
|
|
344
|
+
|
|
345
|
+
expect(agent.element).toBeDefined();
|
|
346
|
+
});
|
|
347
|
+
});
|
|
270
348
|
});
|
|
@@ -17,7 +17,7 @@ import { CATALOG } from '@shell/config/labels-annotations';
|
|
|
17
17
|
import { CAPI, MANAGEMENT, DEFAULT_WORKSPACE } from '@shell/config/types';
|
|
18
18
|
import { mapFeature, RKE2 as RKE2_FEATURE } from '@shell/store/features';
|
|
19
19
|
import { allHash } from '@shell/utils/promise';
|
|
20
|
-
import { BLANK_CLUSTER } from '@shell/store';
|
|
20
|
+
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
21
21
|
import { ELEMENTAL_PRODUCT_NAME, ELEMENTAL_CLUSTER_PROVIDER } from '../../config/elemental-types';
|
|
22
22
|
import Rke2Config from './rke2';
|
|
23
23
|
import Import from './import';
|
|
@@ -138,6 +138,27 @@ export default {
|
|
|
138
138
|
this.iconClasses[name] = `machine-driver ${ name }`;
|
|
139
139
|
}
|
|
140
140
|
});
|
|
141
|
+
|
|
142
|
+
// Custom Providers from extensions - initialize each with the store and the i18n service
|
|
143
|
+
// Wrap in try ... catch, to prevent errors in an extension breaking the page
|
|
144
|
+
try {
|
|
145
|
+
const extensionClasses = this.$plugin.listDynamic('provisioner').map((name) => this.$plugin.getDynamic('provisioner', name));
|
|
146
|
+
|
|
147
|
+
// We can't pass in this.$store as this leads to a circular-reference that causes Vue to freeze,
|
|
148
|
+
// so pass in specific services that the provisioner extension may need
|
|
149
|
+
this.extensions = extensionClasses.map((c) => new c({
|
|
150
|
+
dispatch: this.$store.dispatch,
|
|
151
|
+
getters: this.$store.getters,
|
|
152
|
+
axios: this.$store.$axios,
|
|
153
|
+
$plugin: this.$store.app.$plugin,
|
|
154
|
+
t: (...args) => this.t.apply(this, args),
|
|
155
|
+
isCreate: this.isCreate,
|
|
156
|
+
isEdit: this.isEdit,
|
|
157
|
+
isView: this.isView,
|
|
158
|
+
}));
|
|
159
|
+
} catch (e) {
|
|
160
|
+
console.error('Error loading provisioner(s) from extensions', e); // eslint-disable-line no-console
|
|
161
|
+
}
|
|
141
162
|
},
|
|
142
163
|
|
|
143
164
|
data() {
|
|
@@ -148,6 +169,7 @@ export default {
|
|
|
148
169
|
return {
|
|
149
170
|
nodeDrivers: [],
|
|
150
171
|
kontainerDrivers: [],
|
|
172
|
+
extensions: [],
|
|
151
173
|
subType,
|
|
152
174
|
chart,
|
|
153
175
|
isImport,
|
|
@@ -285,6 +307,11 @@ export default {
|
|
|
285
307
|
addType(id, 'rke2', false);
|
|
286
308
|
});
|
|
287
309
|
|
|
310
|
+
// Add from extensions
|
|
311
|
+
this.extensions.forEach((ext) => {
|
|
312
|
+
addExtensionType(ext, getters);
|
|
313
|
+
});
|
|
314
|
+
|
|
288
315
|
addType('custom', 'custom2', false);
|
|
289
316
|
|
|
290
317
|
if (isElementalActive) {
|
|
@@ -295,6 +322,31 @@ export default {
|
|
|
295
322
|
|
|
296
323
|
return out;
|
|
297
324
|
|
|
325
|
+
function addExtensionType(ext, getters) {
|
|
326
|
+
let iconClass = ext.iconClass;
|
|
327
|
+
let icon = ext.icon;
|
|
328
|
+
|
|
329
|
+
if (icon) {
|
|
330
|
+
iconClass = undefined;
|
|
331
|
+
} else if (!iconClass) {
|
|
332
|
+
icon = require('~shell/assets/images/generic-driver.svg');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const subtype = {
|
|
336
|
+
id: ext.id,
|
|
337
|
+
label: ext.label || getters['i18n/t'](`cluster.provider.${ ext.id }`),
|
|
338
|
+
description: ext.description,
|
|
339
|
+
icon,
|
|
340
|
+
iconClass,
|
|
341
|
+
group: ext.group || 'rke2',
|
|
342
|
+
disabled: ext.disabled || false,
|
|
343
|
+
link: ext.link,
|
|
344
|
+
tag: ext.tag
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
out.push(subtype);
|
|
348
|
+
}
|
|
349
|
+
|
|
298
350
|
function addType(id, group, disabled = false, link = null, iconClass = undefined) {
|
|
299
351
|
const label = getters['i18n/withFallback'](`cluster.provider."${ id }"`, null, id);
|
|
300
352
|
const description = getters['i18n/withFallback'](`cluster.providerDescription."${ id }"`, null, '');
|