@rancher/shell 3.0.8-rc.9 → 3.0.9-rc.1
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/apis/impl/apis.ts +61 -0
- package/apis/index.ts +40 -0
- package/apis/intf/modal.ts +128 -0
- package/apis/intf/shell.ts +36 -0
- package/apis/intf/slide-in.ts +100 -0
- package/apis/intf/system.ts +41 -0
- package/apis/shell/__tests__/modal.test.ts +80 -0
- package/apis/shell/__tests__/notifications.test.ts +71 -0
- package/apis/shell/__tests__/slide-in.test.ts +90 -0
- package/apis/shell/__tests__/system.test.ts +129 -0
- package/apis/shell/index.ts +38 -0
- package/apis/shell/modal.ts +41 -0
- package/apis/shell/notifications.ts +65 -0
- package/apis/shell/slide-in.ts +37 -0
- package/apis/shell/system.ts +65 -0
- package/apis/vue-shim.d.ts +11 -0
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +5 -0
- package/components/ActionMenuShell.vue +3 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +3 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/ResourceDetail/Masthead/latest.vue +23 -21
- package/components/ResourceDetail/index.vue +3 -0
- package/components/ResourceTable.vue +54 -21
- package/components/SlideInPanelManager.vue +16 -11
- package/components/SortableTable/THead.vue +2 -1
- package/components/SortableTable/index.vue +20 -2
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +4 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/fleet/FleetSecretSelector.vue +1 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +2 -2
- package/components/form/ResourceTabs/composable.ts +2 -2
- package/components/form/ResourceTabs/index.vue +0 -2
- package/components/form/__tests__/NameNsDescription.test.ts +42 -0
- package/components/formatter/LinkName.vue +5 -0
- package/components/nav/Group.vue +25 -7
- package/components/nav/Header.vue +1 -1
- package/components/nav/NamespaceFilter.vue +1 -0
- package/components/nav/Type.vue +17 -6
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/product/fleet.js +1 -1
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +1 -5
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +6 -27
- package/core/plugin-helpers.ts +2 -2
- package/core/plugin.ts +9 -1
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +4 -0
- package/core/types.ts +35 -0
- package/detail/catalog.cattle.io.app.vue +1 -0
- package/detail/provisioning.cattle.io.cluster.vue +8 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +1 -1
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/SearchDialog.vue +1 -0
- package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
- package/directives/__tests__/clean-tooltip.test.ts +298 -0
- package/directives/clean-tooltip.ts +234 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +98 -1
- package/edit/fleet.cattle.io.helmop.vue +5 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/__tests__/index.test.ts +123 -85
- package/edit/workload/index.vue +2 -2
- package/edit/workload/mixins/workload.js +19 -1
- package/initialize/install-plugins.js +4 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +18 -13
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +16 -0
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/provisioning.cattle.io.cluster.js +11 -3
- package/package.json +7 -7
- package/pages/auth/login.vue +3 -3
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/index.vue +122 -24
- package/pages/c/_cluster/apps/charts/install.vue +33 -0
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/fleet/index.vue +7 -10
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +1 -1
- package/pkg/import.js +1 -1
- package/plugins/__tests__/mutations.tests.ts +179 -0
- package/plugins/dashboard-store/getters.js +1 -1
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +8 -3
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +301 -128
- package/plugins/steve/mutations.js +9 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +108 -43
- package/plugins/steve/subscribe.js +23 -2
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/scripts/publish-shell.sh +25 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/auth.js +23 -11
- package/store/i18n.js +3 -3
- package/store/index.js +5 -3
- package/store/notifications.ts +2 -0
- package/store/prefs.js +2 -2
- package/store/type-map.js +17 -7
- package/types/internal-api/shell/modal.d.ts +6 -6
- package/types/notifications/index.ts +126 -15
- package/types/rancher/index.d.ts +9 -0
- package/types/shell/index.d.ts +16 -1
- package/types/store/dashboard-store.types.ts +29 -7
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/router.test.js +238 -0
- package/utils/cluster.js +4 -1
- package/utils/cspAdaptor.ts +32 -14
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +4 -4
- package/utils/router.js +50 -0
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- package/core/__test__/extension-manager-impl.test.js +0 -236
- package/core/plugins.js +0 -38
- package/directives/clean-tooltip.js +0 -32
- package/plugins/internal-api/index.ts +0 -37
- package/plugins/internal-api/shared/base-api.ts +0 -13
- package/plugins/internal-api/shell/shell.api.ts +0 -108
- package/types/internal-api/shell/growl.d.ts +0 -25
- package/types/internal-api/shell/slideIn.d.ts +0 -15
|
@@ -4,100 +4,138 @@ import Workload from '@shell/edit/workload/index.vue';
|
|
|
4
4
|
jest.mock('@shell/models/secret', () => ({ onmessage: jest.fn() }));
|
|
5
5
|
|
|
6
6
|
describe('component: Workload', () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
isJob: jest.fn(),
|
|
48
|
-
podFsGroup: jest.fn(),
|
|
49
|
-
namespacedSecrets: jest.fn(),
|
|
50
|
-
registerBeforeHook: jest.fn(),
|
|
51
|
-
pvcs: jest.fn(),
|
|
52
|
-
// tabWeightMap: jest.fn(),
|
|
53
|
-
}
|
|
54
|
-
};
|
|
7
|
+
const baseMockedValidationMixin = {
|
|
8
|
+
methods: {
|
|
9
|
+
fvFormIsValid: jest.fn(),
|
|
10
|
+
type: jest.fn(),
|
|
11
|
+
fvGetAndReportPathRules: jest.fn(),
|
|
12
|
+
},
|
|
13
|
+
computed: { fvUnreportedValidationErrors: jest.fn().mockReturnValue([]) }
|
|
14
|
+
};
|
|
15
|
+
const baseMockedCREMixin = {};
|
|
16
|
+
const baseMockedWorkloadMixin = {
|
|
17
|
+
methods: {
|
|
18
|
+
doneRoute: jest.fn(),
|
|
19
|
+
workloadSubTypes: jest.fn(),
|
|
20
|
+
applyHooks: jest.fn(),
|
|
21
|
+
save: jest.fn(),
|
|
22
|
+
selectType: jest.fn(),
|
|
23
|
+
isCronJob: jest.fn(),
|
|
24
|
+
spec: jest.fn(),
|
|
25
|
+
isReplicable: jest.fn(),
|
|
26
|
+
isStatefulSet: jest.fn(),
|
|
27
|
+
headlessServices: jest.fn(),
|
|
28
|
+
defaultTab: jest.fn(),
|
|
29
|
+
allContainers: jest.fn(),
|
|
30
|
+
isPod: jest.fn(),
|
|
31
|
+
tabWeightMap: jest.fn(),
|
|
32
|
+
podLabels: jest.fn(),
|
|
33
|
+
podTemplateSpec: jest.fn(),
|
|
34
|
+
isLoadingSecondaryResources: jest.fn(),
|
|
35
|
+
allNodes: jest.fn(),
|
|
36
|
+
clearPvcFormState: jest.fn(),
|
|
37
|
+
savePvcHookName: jest.fn(),
|
|
38
|
+
namespacedConfigMaps: jest.fn(),
|
|
39
|
+
podAnnotations: jest.fn(),
|
|
40
|
+
isJob: jest.fn(),
|
|
41
|
+
podFsGroup: jest.fn(),
|
|
42
|
+
namespacedSecrets: jest.fn(),
|
|
43
|
+
registerBeforeHook: jest.fn(),
|
|
44
|
+
pvcs: jest.fn(),
|
|
45
|
+
}
|
|
46
|
+
};
|
|
55
47
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
48
|
+
describe('component: Workload', () => {
|
|
49
|
+
it.each([
|
|
50
|
+
[
|
|
51
|
+
`pods \"test\" is forbidden: violates PodSecurity \"restricted:latest\": allowPrivilegeEscalation != false (container \"container-0\" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container \"container-0\" must set securityContext.capabilities.drop=[\"ALL\"]), runAsNonRoot != true (container \"container-0\" must not set securityContext.runAsNonRoot=false), seccompProfile (pod or container \"container-0\" must set securityContext.seccompProfile.type to \"RuntimeDefault\" or \"Localhost\")`,
|
|
52
|
+
`workload.error, \"test\",\"restricted:latest\"`
|
|
53
|
+
]
|
|
54
|
+
])('should map error message into object', (oldMessage, newMessage) => {
|
|
55
|
+
// For this test, allNodeObjects is just a jest.fn() in the base mixin
|
|
56
|
+
const MockedWorkload = { ...Workload, mixins: [baseMockedValidationMixin, baseMockedCREMixin, { ...baseMockedWorkloadMixin, computed: { allNodeObjects: jest.fn() } }] };
|
|
57
|
+
const wrapper = shallowMount(MockedWorkload, {
|
|
58
|
+
props: {
|
|
59
|
+
value: { metadata: {}, spec: { template: {} } },
|
|
60
|
+
params: {},
|
|
61
|
+
fvFormIsValid: {}
|
|
62
|
+
},
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
global: {
|
|
65
|
+
mocks: {
|
|
66
|
+
$route: { params: {}, query: {} },
|
|
67
|
+
$router: { applyQuery: jest.fn() },
|
|
68
|
+
$fetchState: { pending: false },
|
|
69
|
+
$store: {
|
|
70
|
+
getters: {
|
|
71
|
+
'cluster/schemaFor': jest.fn(),
|
|
72
|
+
'type-map/labelFor': jest.fn(),
|
|
73
|
+
'i18n/t': (text: string, v: {[key:string]: string}) => {
|
|
74
|
+
return `${ text }, ${ Object.values(v || {}) }`;
|
|
75
|
+
},
|
|
75
76
|
},
|
|
76
77
|
},
|
|
77
78
|
},
|
|
78
|
-
},
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
stubs: {
|
|
81
|
+
Tab: true,
|
|
82
|
+
LabeledInput: true,
|
|
83
|
+
VolumeClaimTemplate: true,
|
|
84
|
+
Networking: true,
|
|
85
|
+
Job: true,
|
|
86
|
+
NodeScheduling: true,
|
|
87
|
+
PodAffinity: true,
|
|
88
|
+
Tolerations: true,
|
|
89
|
+
Storage: true,
|
|
90
|
+
Tabbed: true,
|
|
91
|
+
LabeledSelect: true,
|
|
92
|
+
NameNsDescription: true,
|
|
93
|
+
CruResource: true,
|
|
94
|
+
KeyValue: true
|
|
95
|
+
},
|
|
95
96
|
},
|
|
96
|
-
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const result = (wrapper.vm as any).mapError(oldMessage).message;
|
|
100
|
+
|
|
101
|
+
expect(result).toStrictEqual(newMessage);
|
|
97
102
|
});
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
describe('secondaryResourceDataConfig', () => {
|
|
105
|
+
it('should filter out nodes with control-plane or etcd taints from workerNodes parsingFunc', () => {
|
|
106
|
+
const allNodeObjects = [
|
|
107
|
+
{
|
|
108
|
+
id: 'node-1',
|
|
109
|
+
spec: { taints: [{ key: 'node-role.kubernetes.io/control-plane', effect: 'NoSchedule' }] }
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'node-2',
|
|
113
|
+
spec: { taints: [{ key: 'node-role.kubernetes.io/etcd', effect: 'NoSchedule' }] }
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'node-3',
|
|
117
|
+
spec: { taints: [{ key: 'node-role.kubernetes.io/worker', effect: 'NoSchedule' }] }
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 'node-4',
|
|
121
|
+
spec: { taints: [] }
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'node-5',
|
|
125
|
+
spec: {}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: 'node-6',
|
|
129
|
+
spec: null
|
|
130
|
+
}
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
const { data } = (Workload.mixins[2] as any).methods.secondaryResourceDataConfig.apply({ value: { metadata: { namespace: 'test' } } });
|
|
134
|
+
const workerNodesParsingFunc = data.node.applyTo.find((r: any) => r.var === 'workerNodes').parsingFunc;
|
|
135
|
+
const result = workerNodesParsingFunc(allNodeObjects);
|
|
100
136
|
|
|
101
|
-
|
|
137
|
+
expect(result).toStrictEqual(['node-3', 'node-4', 'node-5', 'node-6']);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
102
140
|
});
|
|
103
141
|
});
|
package/edit/workload/index.vue
CHANGED
|
@@ -155,7 +155,7 @@ export default {
|
|
|
155
155
|
:default-tab="defaultTab || defaultWorkloadTab"
|
|
156
156
|
:flat="true"
|
|
157
157
|
:use-hash="useTabbedHash"
|
|
158
|
-
|
|
158
|
+
:showExtensionTabs="false"
|
|
159
159
|
data-testid="workload-horizontal-tabs"
|
|
160
160
|
@changed="changed"
|
|
161
161
|
>
|
|
@@ -494,7 +494,7 @@ export default {
|
|
|
494
494
|
<NodeScheduling
|
|
495
495
|
:mode="mode"
|
|
496
496
|
:value="podTemplateSpec"
|
|
497
|
-
:nodes="
|
|
497
|
+
:nodes="workerNodes"
|
|
498
498
|
:loading="isLoadingSecondaryResources"
|
|
499
499
|
/>
|
|
500
500
|
</Tab>
|
|
@@ -258,6 +258,7 @@ export default {
|
|
|
258
258
|
secondaryResourceData: this.secondaryResourceDataConfig(),
|
|
259
259
|
namespacedConfigMaps: [],
|
|
260
260
|
allNodes: null,
|
|
261
|
+
workerNodes: null,
|
|
261
262
|
allNodeObjects: [],
|
|
262
263
|
namespacedSecrets: [],
|
|
263
264
|
imagePullNamespacedSecrets: [],
|
|
@@ -647,7 +648,24 @@ export default {
|
|
|
647
648
|
parsingFunc: (data) => {
|
|
648
649
|
return data.map((node) => node.id);
|
|
649
650
|
}
|
|
650
|
-
}
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
var: 'workerNodes',
|
|
654
|
+
parsingFunc: (data) => {
|
|
655
|
+
const keys = [
|
|
656
|
+
`node-role.kubernetes.io/control-plane`,
|
|
657
|
+
`node-role.kubernetes.io/etcd`
|
|
658
|
+
];
|
|
659
|
+
|
|
660
|
+
return data
|
|
661
|
+
.filter((node) => {
|
|
662
|
+
const taints = node?.spec?.taints || [];
|
|
663
|
+
|
|
664
|
+
return taints.every((taint) => !keys.includes(taint.key));
|
|
665
|
+
})
|
|
666
|
+
.map((node) => node.id);
|
|
667
|
+
}
|
|
668
|
+
},
|
|
651
669
|
]
|
|
652
670
|
},
|
|
653
671
|
[SERVICE]: {
|
|
@@ -19,13 +19,12 @@ import { InstallCodeMirror } from 'codemirror-editor-vue3';
|
|
|
19
19
|
import * as intNumber from '@shell/directives/int-number';
|
|
20
20
|
import dashboardClientInit from '@shell/plugins/dashboard-client-init';
|
|
21
21
|
import plugin from '@shell/plugins/plugin';
|
|
22
|
-
import plugins from '@shell/core/plugins.js';
|
|
23
22
|
import pluginsLoader from '@shell/core/plugins-loader.js';
|
|
24
23
|
import replaceAll from '@shell/plugins/replaceall';
|
|
25
24
|
import steveCreateWorker from '@shell/plugins/steve-create-worker';
|
|
26
25
|
import emberCookie from '@shell/plugins/ember-cookie';
|
|
27
26
|
import ShortKey from '@shell/plugins/shortkey';
|
|
28
|
-
import
|
|
27
|
+
import { initUiApis } from '@shell/apis/impl/apis';
|
|
29
28
|
|
|
30
29
|
import 'floating-vue/dist/style.css';
|
|
31
30
|
import { floatingVueOptions } from '@shell/plugins/floating-vue';
|
|
@@ -51,7 +50,7 @@ export async function installInjectedPlugins(app, vueApp) {
|
|
|
51
50
|
const pluginDefinitions = [
|
|
52
51
|
config,
|
|
53
52
|
axios,
|
|
54
|
-
|
|
53
|
+
initUiApis,
|
|
55
54
|
pluginsLoader,
|
|
56
55
|
axiosShell,
|
|
57
56
|
intNumber,
|
|
@@ -61,7 +60,6 @@ export async function installInjectedPlugins(app, vueApp) {
|
|
|
61
60
|
plugin,
|
|
62
61
|
steveCreateWorker,
|
|
63
62
|
emberCookie,
|
|
64
|
-
internalApiPlugin,
|
|
65
63
|
dynamicContent,
|
|
66
64
|
];
|
|
67
65
|
|
|
@@ -69,7 +67,8 @@ export async function installInjectedPlugins(app, vueApp) {
|
|
|
69
67
|
if (typeof pluginDefinition === 'function') {
|
|
70
68
|
await pluginDefinition(
|
|
71
69
|
app.context,
|
|
72
|
-
(key, value) => inject(key, value, app.context, vueApp)
|
|
70
|
+
(key, value) => inject(key, value, app.context, vueApp),
|
|
71
|
+
vueApp
|
|
73
72
|
);
|
|
74
73
|
}
|
|
75
74
|
});
|
package/machine-config/azure.vue
CHANGED
|
@@ -8,7 +8,7 @@ import { getGKEImageFamilies, getGKEFamiliesFromProject } from '@shell/component
|
|
|
8
8
|
import debounce from 'lodash/debounce';
|
|
9
9
|
import { mapGetters } from 'vuex';
|
|
10
10
|
|
|
11
|
-
const DEFAULT_PROJECTS = '
|
|
11
|
+
const DEFAULT_PROJECTS = 'ubuntu-os-cloud';
|
|
12
12
|
const DEFAULT_MIN_DISK = 10;
|
|
13
13
|
|
|
14
14
|
export default {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import { CATALOG, MANAGEMENT } from '@shell/config/types';
|
|
3
3
|
import Brand from '@shell/mixins/brand';
|
|
4
|
+
import CspAdapterUtils from '@shell/utils/cspAdaptor';
|
|
4
5
|
|
|
5
6
|
describe('brandMixin', () => {
|
|
6
7
|
const createWrapper = (vaiOn = false) => {
|
|
@@ -54,45 +55,47 @@ describe('brandMixin', () => {
|
|
|
54
55
|
data: () => data,
|
|
55
56
|
global: { mocks: { $store: store } }
|
|
56
57
|
});
|
|
57
|
-
const
|
|
58
|
+
const spyManagementDispatch = jest.spyOn(store, 'dispatch');
|
|
59
|
+
|
|
60
|
+
CspAdapterUtils.resetState();
|
|
58
61
|
|
|
59
62
|
return {
|
|
60
63
|
wrapper,
|
|
61
64
|
store,
|
|
62
|
-
|
|
65
|
+
spyManagementDispatch,
|
|
63
66
|
};
|
|
64
67
|
};
|
|
65
68
|
|
|
66
69
|
describe('should make correct requests', () => {
|
|
67
70
|
it('vai off', async() => {
|
|
68
|
-
const { wrapper,
|
|
71
|
+
const { wrapper, spyManagementDispatch } = createWrapper(false);
|
|
69
72
|
|
|
70
73
|
// NOTE - wrapper.vm.$options.fetch() doesn't work
|
|
71
74
|
await wrapper.vm.$options.fetch.apply(wrapper.vm);
|
|
72
75
|
|
|
73
76
|
// wrapper.vm.$nextTick();
|
|
74
|
-
expect(
|
|
77
|
+
expect(spyManagementDispatch).toHaveBeenNthCalledWith(1, 'management/findAll', {
|
|
75
78
|
type: MANAGEMENT.SETTING,
|
|
76
79
|
opt: {
|
|
77
80
|
load: 'multi', redirectUnauthorized: false, url: `/v1/${ MANAGEMENT.SETTING }s`
|
|
78
81
|
}
|
|
79
82
|
});
|
|
80
|
-
expect(
|
|
83
|
+
expect(spyManagementDispatch).toHaveBeenNthCalledWith(2, 'management/findAll', { type: CATALOG.APP });
|
|
81
84
|
});
|
|
82
85
|
|
|
83
86
|
it('vai on', async() => {
|
|
84
|
-
const { wrapper,
|
|
87
|
+
const { wrapper, spyManagementDispatch } = createWrapper(true);
|
|
85
88
|
|
|
86
89
|
// NOTE - wrapper.vm.$options.fetch() doesn't work
|
|
87
90
|
await wrapper.vm.$options.fetch.apply(wrapper.vm);
|
|
88
91
|
|
|
89
|
-
expect(
|
|
92
|
+
expect(spyManagementDispatch).toHaveBeenNthCalledWith(1, 'management/findAll', {
|
|
90
93
|
type: MANAGEMENT.SETTING,
|
|
91
94
|
opt: {
|
|
92
95
|
load: 'multi', url: `/v1/${ MANAGEMENT.SETTING }s`, redirectUnauthorized: false
|
|
93
96
|
}
|
|
94
97
|
});
|
|
95
|
-
expect(
|
|
98
|
+
expect(spyManagementDispatch).toHaveBeenNthCalledWith(2, 'management/findPage', {
|
|
96
99
|
type: CATALOG.APP,
|
|
97
100
|
opt: {
|
|
98
101
|
pagination: {
|
|
@@ -110,7 +113,9 @@ describe('brandMixin', () => {
|
|
|
110
113
|
pageSize: null,
|
|
111
114
|
projectsOrNamespaces: [],
|
|
112
115
|
sort: []
|
|
113
|
-
}
|
|
116
|
+
},
|
|
117
|
+
transient: true,
|
|
118
|
+
watch: false
|
|
114
119
|
}
|
|
115
120
|
});
|
|
116
121
|
});
|
|
@@ -120,7 +125,7 @@ describe('brandMixin', () => {
|
|
|
120
125
|
it('should have correct csp values (off)', async() => {
|
|
121
126
|
const { wrapper, store } = createWrapper();
|
|
122
127
|
|
|
123
|
-
const
|
|
128
|
+
const spyManagementDispatch = jest.spyOn(store, 'dispatch').mockImplementation((_, options) => {
|
|
124
129
|
const { type } = options as any;
|
|
125
130
|
|
|
126
131
|
if (type === MANAGEMENT.SETTING) {
|
|
@@ -136,7 +141,7 @@ describe('brandMixin', () => {
|
|
|
136
141
|
// NOTE - wrapper.vm.$options.fetch() doesn't work
|
|
137
142
|
await wrapper.vm.$options.fetch.apply(wrapper.vm, []);
|
|
138
143
|
|
|
139
|
-
expect(
|
|
144
|
+
expect(spyManagementDispatch).toHaveBeenCalledTimes(2);
|
|
140
145
|
|
|
141
146
|
expect(wrapper.vm.canCalcCspAdapter).toBeTruthy();
|
|
142
147
|
expect(wrapper.vm.cspAdapter).toBeFalsy();
|
|
@@ -145,7 +150,7 @@ describe('brandMixin', () => {
|
|
|
145
150
|
it.each(['rancher-csp-adapter', 'rancher-csp-billing-adapter'])('should have correct csp values (on - %p )', async(chartName) => {
|
|
146
151
|
const { wrapper, store } = createWrapper();
|
|
147
152
|
|
|
148
|
-
const
|
|
153
|
+
const spyManagementDispatch = jest.spyOn(store, 'dispatch').mockImplementation((_, options) => {
|
|
149
154
|
const { type } = options as any;
|
|
150
155
|
|
|
151
156
|
if (type === MANAGEMENT.SETTING) {
|
|
@@ -161,7 +166,7 @@ describe('brandMixin', () => {
|
|
|
161
166
|
// NOTE - wrapper.vm.$options.fetch() doesn't work
|
|
162
167
|
await wrapper.vm.$options.fetch.apply(wrapper.vm, []);
|
|
163
168
|
|
|
164
|
-
expect(
|
|
169
|
+
expect(spyManagementDispatch).toHaveBeenCalledTimes(2);
|
|
165
170
|
|
|
166
171
|
expect(wrapper.vm.canCalcCspAdapter).toBeTruthy();
|
|
167
172
|
expect(wrapper.vm.cspAdapter).toBeTruthy();
|
|
@@ -69,6 +69,22 @@ describe('class ProvCluster', () => {
|
|
|
69
69
|
},
|
|
70
70
|
expected: true
|
|
71
71
|
},
|
|
72
|
+
{
|
|
73
|
+
description: 'should return true for an imported k3s cluster in waiting state',
|
|
74
|
+
clusterData: {
|
|
75
|
+
isLocal: false,
|
|
76
|
+
mgmt: { status: { provider: undefined, driver: 'k3s' } }
|
|
77
|
+
},
|
|
78
|
+
expected: true
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
description: 'should return true for an imported rke2 cluster in waiting state',
|
|
82
|
+
clusterData: {
|
|
83
|
+
isLocal: false,
|
|
84
|
+
mgmt: { status: { provider: undefined, driver: 'rke2' } }
|
|
85
|
+
},
|
|
86
|
+
expected: true
|
|
87
|
+
},
|
|
72
88
|
{
|
|
73
89
|
description: 'should return false for a provisioned k3s cluster',
|
|
74
90
|
clusterData: {
|
package/models/chart.js
CHANGED
|
@@ -136,91 +136,87 @@ export default class Chart extends SteveModel {
|
|
|
136
136
|
* @returns {Object} Card content object with `subHeaderItems`, `footerItems`, and `statuses` arrays.
|
|
137
137
|
*/
|
|
138
138
|
get cardContent() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
if (hasZeroTime) {
|
|
159
|
-
lastUpdatedItem.labelTooltip = this.t('catalog.charts.appChartCard.subHeaderItem.missingVersionDate');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
subHeaderItems.push(lastUpdatedItem);
|
|
163
|
-
}
|
|
139
|
+
const latestVersion = this.latestCompatibleVersion;
|
|
140
|
+
const subHeaderItems = [];
|
|
141
|
+
|
|
142
|
+
if (latestVersion) {
|
|
143
|
+
const hasZeroTime = latestVersion.created === ZERO_TIME;
|
|
144
|
+
|
|
145
|
+
subHeaderItems.push({
|
|
146
|
+
icon: 'icon-version-alt',
|
|
147
|
+
iconTooltip: { key: 'tableHeaders.version' },
|
|
148
|
+
label: latestVersion.version
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const lastUpdatedItem = {
|
|
152
|
+
icon: 'icon-refresh-alt',
|
|
153
|
+
iconTooltip: { key: 'tableHeaders.lastUpdated' },
|
|
154
|
+
label: hasZeroTime ? this.t('generic.na') : day(latestVersion.created).format('MMM D, YYYY')
|
|
155
|
+
};
|
|
164
156
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
type: REPO,
|
|
168
|
-
icon: 'icon-repository-alt',
|
|
169
|
-
iconTooltip: { key: 'tableHeaders.repoName' },
|
|
170
|
-
labels: [this.repoNameDisplay],
|
|
171
|
-
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.repo') }, true)
|
|
172
|
-
}
|
|
173
|
-
];
|
|
174
|
-
|
|
175
|
-
if (this.categories.length) {
|
|
176
|
-
footerItems.push( {
|
|
177
|
-
type: CATEGORY,
|
|
178
|
-
icon: 'icon-category-alt',
|
|
179
|
-
iconTooltip: { key: 'generic.category' },
|
|
180
|
-
labels: this.categories,
|
|
181
|
-
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.category') }, true)
|
|
182
|
-
});
|
|
157
|
+
if (hasZeroTime) {
|
|
158
|
+
lastUpdatedItem.labelTooltip = this.t('catalog.charts.appChartCard.subHeaderItem.missingVersionDate');
|
|
183
159
|
}
|
|
184
160
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
161
|
+
subHeaderItems.push(lastUpdatedItem);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const footerItems = [
|
|
165
|
+
{
|
|
166
|
+
type: REPO,
|
|
167
|
+
icon: 'icon-repository-alt',
|
|
168
|
+
iconTooltip: { key: 'tableHeaders.repoName' },
|
|
169
|
+
labels: [this.repoNameDisplay],
|
|
170
|
+
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.repo') }, true)
|
|
193
171
|
}
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
if (this.categories.length) {
|
|
175
|
+
footerItems.push( {
|
|
176
|
+
type: CATEGORY,
|
|
177
|
+
icon: 'icon-category-alt',
|
|
178
|
+
iconTooltip: { key: 'generic.category' },
|
|
179
|
+
labels: this.categories,
|
|
180
|
+
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.category') }, true)
|
|
181
|
+
});
|
|
182
|
+
}
|
|
194
183
|
|
|
195
|
-
|
|
184
|
+
if (this.tags.length) {
|
|
185
|
+
footerItems.push({
|
|
186
|
+
type: TAG,
|
|
187
|
+
icon: 'icon-tag-alt',
|
|
188
|
+
iconTooltip: { key: 'generic.tags' },
|
|
189
|
+
labels: this.tags,
|
|
190
|
+
labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.tag') }, true)
|
|
191
|
+
});
|
|
192
|
+
}
|
|
196
193
|
|
|
197
|
-
|
|
198
|
-
statuses.push({
|
|
199
|
-
icon: 'icon-alert-alt', color: 'error', tooltip: { key: 'generic.deprecated' }
|
|
200
|
-
});
|
|
201
|
-
}
|
|
194
|
+
const statuses = [];
|
|
202
195
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
196
|
+
if (this.deprecated) {
|
|
197
|
+
statuses.push({
|
|
198
|
+
icon: 'icon-alert-alt', color: 'error', tooltip: { key: 'generic.deprecated' }
|
|
199
|
+
});
|
|
200
|
+
}
|
|
208
201
|
|
|
209
|
-
|
|
210
|
-
|
|
202
|
+
if (this.upgradeable) {
|
|
203
|
+
statuses.push({
|
|
204
|
+
icon: 'icon-upgrade-alt', color: 'info', tooltip: { key: 'generic.upgradeable' }
|
|
205
|
+
});
|
|
206
|
+
}
|
|
211
207
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
215
|
-
}
|
|
208
|
+
if (this.isInstalled) {
|
|
209
|
+
const installedVersion = this.matchingInstalledApps[0]?.spec?.chart?.metadata?.version;
|
|
216
210
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
statuses
|
|
221
|
-
};
|
|
211
|
+
statuses.push({
|
|
212
|
+
icon: 'icon-confirmation-alt', color: 'success', tooltip: { text: `${ this.t('generic.installed') } (${ installedVersion })` }
|
|
213
|
+
});
|
|
222
214
|
}
|
|
223
215
|
|
|
224
|
-
return
|
|
216
|
+
return {
|
|
217
|
+
subHeaderItems,
|
|
218
|
+
footerItems,
|
|
219
|
+
statuses
|
|
220
|
+
};
|
|
225
221
|
}
|
|
226
222
|
}
|
|
@@ -255,7 +255,7 @@ export default class MgmtCluster extends SteveModel {
|
|
|
255
255
|
dispatch: this.$dispatch,
|
|
256
256
|
getters: this.$getters,
|
|
257
257
|
axios: this.$axios,
|
|
258
|
-
$extension: this.$
|
|
258
|
+
$extension: this.$extension,
|
|
259
259
|
t: (...args) => this.t.apply(this, args),
|
|
260
260
|
};
|
|
261
261
|
|