@rancher/shell 3.0.6 → 3.0.8-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/assets/images/pl/dark/rancher-logo.svg +131 -44
- package/assets/images/pl/rancher-logo.svg +120 -44
- package/assets/images/vendor/githubapp.svg +13 -0
- package/assets/styles/base/_basic.scss +2 -2
- package/assets/styles/base/_color-classic.scss +51 -0
- package/assets/styles/base/_color.scss +3 -3
- package/assets/styles/base/_mixins.scss +1 -1
- package/assets/styles/base/_typography.scss +1 -1
- package/assets/styles/base/_variables-classic.scss +47 -0
- package/assets/styles/global/_button.scss +49 -17
- package/assets/styles/global/_form.scss +1 -1
- package/assets/styles/themes/_dark.scss +4 -0
- package/assets/styles/themes/_light.scss +3 -69
- package/assets/styles/themes/_modern.scss +194 -50
- package/assets/styles/vendor/vue-select.scss +1 -2
- package/assets/translations/en-us.yaml +124 -32
- package/assets/translations/zh-hans.yaml +0 -4
- package/components/ClusterIconMenu.vue +1 -1
- package/components/ClusterProviderIcon.vue +1 -1
- package/components/CodeMirror.vue +1 -1
- package/components/IconOrSvg.vue +40 -29
- package/components/Inactivity.vue +222 -106
- package/components/InstallHelmCharts.vue +2 -2
- package/components/ResourceDetail/index.vue +2 -1
- package/components/SortableTable/index.vue +17 -2
- package/components/SortableTable/sorting.js +3 -1
- package/components/Tabbed/index.vue +5 -5
- package/components/fleet/FleetConfigMapSelector.vue +117 -0
- package/components/fleet/FleetSecretSelector.vue +127 -0
- package/components/fleet/__tests__/FleetConfigMapSelector.test.ts +125 -0
- package/components/fleet/__tests__/FleetSecretSelector.test.ts +82 -0
- package/components/form/FileImageSelector.vue +13 -4
- package/components/form/FileSelector.vue +11 -2
- package/components/form/ResourceLabeledSelect.vue +1 -0
- package/components/form/ResourceTabs/index.vue +37 -18
- package/components/form/SecretSelector.vue +6 -2
- package/components/form/__tests__/ResourceLabeledSelect.test.ts +90 -0
- package/components/nav/Group.vue +29 -9
- package/components/nav/Header.vue +7 -8
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +47 -20
- package/components/nav/TopLevelMenu.vue +44 -14
- package/components/nav/Type.vue +0 -5
- package/components/nav/__tests__/TopLevelMenu.test.ts +2 -0
- package/config/pagination-table-headers.js +10 -2
- package/config/product/auth.js +1 -0
- package/config/product/explorer.js +4 -3
- package/config/query-params.js +1 -0
- package/config/settings.ts +8 -1
- package/config/table-headers.js +9 -0
- package/config/types.js +2 -0
- package/core/plugin.ts +18 -6
- package/core/types.ts +8 -0
- package/detail/provisioning.cattle.io.cluster.vue +1 -0
- package/dialog/AddonConfigConfirmationDialog.vue +45 -1
- package/dialog/InstallExtensionDialog.vue +71 -45
- package/dialog/UninstallExtensionDialog.vue +2 -1
- package/dialog/__tests__/InstallExtensionDialog.test.ts +111 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +52 -11
- package/edit/auth/AuthProviderWarningBanners.vue +14 -1
- package/edit/auth/github-app-steps.vue +97 -0
- package/edit/auth/github-steps.vue +75 -0
- package/edit/auth/github.vue +94 -65
- package/edit/auth/oidc.vue +86 -16
- package/edit/fleet.cattle.io.helmop.vue +51 -2
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +15 -5
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +11 -9
- package/edit/provisioning.cattle.io.cluster/rke2.vue +56 -9
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +28 -2
- package/list/projectsecret.vue +1 -1
- package/machine-config/azure.vue +1 -1
- package/mixins/__tests__/chart.test.ts +1 -1
- package/mixins/chart.js +2 -2
- package/models/__tests__/chart.test.ts +17 -9
- package/models/__tests__/compliance.cattle.io.clusterscanprofile.spec.js +30 -0
- package/models/catalog.cattle.io.app.js +1 -1
- package/models/chart.js +3 -1
- package/models/compliance.cattle.io.clusterscanprofile.js +1 -1
- package/models/event.js +7 -0
- package/models/management.cattle.io.authconfig.js +1 -0
- package/models/provisioning.cattle.io.cluster.js +9 -0
- package/package.json +2 -2
- package/pages/auth/login.vue +5 -2
- package/pages/auth/verify.vue +1 -1
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +3 -2
- package/pages/c/_cluster/apps/charts/chart.vue +2 -2
- package/pages/c/_cluster/explorer/EventsTable.vue +92 -9
- package/pages/c/_cluster/explorer/tools/index.vue +3 -3
- package/pages/c/_cluster/settings/performance.vue +13 -26
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +159 -62
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +102 -0
- package/pages/c/_cluster/uiplugins/__tests__/{index.spec.ts → index.test.ts} +121 -55
- package/pages/c/_cluster/uiplugins/index.vue +110 -94
- package/pages/home.vue +313 -12
- package/plugins/__tests__/subscribe.events.test.ts +194 -0
- package/plugins/axios.js +2 -1
- package/plugins/dashboard-store/actions.js +4 -1
- package/plugins/dashboard-store/getters.js +1 -1
- package/plugins/dashboard-store/resource-class.js +20 -5
- package/plugins/steve/__tests__/subscribe.spec.ts +27 -24
- package/plugins/steve/index.js +18 -10
- package/plugins/steve/mutations.js +2 -2
- package/plugins/steve/resourceWatcher.js +2 -2
- package/plugins/steve/steve-pagination-utils.ts +12 -9
- package/plugins/steve/subscribe.js +113 -85
- package/plugins/subscribe-events.ts +211 -0
- package/rancher-components/BadgeState/BadgeState.vue +8 -6
- package/rancher-components/Banner/Banner.vue +2 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
- package/rancher-components/Form/Radio/RadioButton.vue +3 -3
- package/scripts/extension/publish +1 -1
- package/store/auth.js +8 -3
- package/store/aws.js +8 -6
- package/store/features.js +1 -0
- package/store/index.js +21 -25
- package/store/prefs.js +6 -0
- package/types/extension-manager.ts +8 -1
- package/types/kube/kube-api.ts +2 -1
- package/types/rancher/index.d.ts +1 -0
- package/types/resources/settings.d.ts +52 -23
- package/types/shell/index.d.ts +412 -336
- package/types/store/subscribe-events.types.ts +70 -0
- package/types/store/subscribe.types.ts +6 -22
- package/utils/__tests__/cluster.test.ts +379 -1
- package/utils/cluster.js +157 -3
- package/utils/dynamic-content/__tests__/config.test.ts +187 -0
- package/utils/dynamic-content/__tests__/index.test.ts +390 -0
- package/utils/dynamic-content/__tests__/info.test.ts +263 -0
- package/utils/dynamic-content/__tests__/new-release.test.ts +216 -0
- package/utils/dynamic-content/__tests__/support-notice.test.ts +262 -0
- package/utils/dynamic-content/__tests__/util.test.ts +235 -0
- package/utils/dynamic-content/config.ts +55 -0
- package/utils/dynamic-content/index.ts +273 -0
- package/utils/dynamic-content/info.ts +219 -0
- package/utils/dynamic-content/new-release.ts +126 -0
- package/utils/dynamic-content/support-notice.ts +169 -0
- package/utils/dynamic-content/types.d.ts +101 -0
- package/utils/dynamic-content/util.ts +122 -0
- package/utils/inactivity.ts +104 -0
- package/utils/pagination-utils.ts +105 -31
- package/utils/pagination-wrapper.ts +6 -8
- package/utils/release-notes.ts +1 -1
- package/utils/sort.js +5 -0
- package/utils/unit-tests/pagination-utils.spec.ts +283 -0
- package/utils/validators/formRules/__tests__/index.test.ts +7 -0
- package/utils/validators/formRules/index.ts +2 -2
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import AsyncButton from '@shell/components/AsyncButton';
|
|
3
3
|
import { Card } from '@components/Card';
|
|
4
|
+
import { mapGetters } from 'vuex';
|
|
5
|
+
|
|
6
|
+
import { labelForAddon } from '@shell/utils/cluster';
|
|
7
|
+
import { resourceNames } from '@shell/utils/string';
|
|
4
8
|
|
|
5
9
|
export default {
|
|
6
10
|
emits: ['close'],
|
|
@@ -17,11 +21,45 @@ export default {
|
|
|
17
21
|
registerBackgroundClosing: {
|
|
18
22
|
type: Function,
|
|
19
23
|
required: true
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* The names of the addons that have configuration conflicts.
|
|
27
|
+
*/
|
|
28
|
+
addonNames: {
|
|
29
|
+
type: Array,
|
|
30
|
+
default: () => []
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* The Kubernetes version the user is upgrading from.
|
|
34
|
+
*/
|
|
35
|
+
previousKubeVersion: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: ''
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* The Kubernetes version the user is upgrading to.
|
|
41
|
+
*/
|
|
42
|
+
newKubeVersion: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: ''
|
|
20
45
|
}
|
|
21
46
|
},
|
|
22
47
|
created() {
|
|
23
48
|
this.registerBackgroundClosing(this.closing);
|
|
24
49
|
},
|
|
50
|
+
computed: {
|
|
51
|
+
...mapGetters({ t: 'i18n/t' }),
|
|
52
|
+
|
|
53
|
+
formattedAddons() {
|
|
54
|
+
if (!this.addonNames || this.addonNames.length === 0) {
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const translatedNames = this.addonNames.map((name) => labelForAddon(this.$store, name, true));
|
|
59
|
+
|
|
60
|
+
return resourceNames(translatedNames, null, this.t, false);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
25
63
|
methods: {
|
|
26
64
|
continue(value) {
|
|
27
65
|
if (this.resources[0]) {
|
|
@@ -59,7 +97,13 @@ export default {
|
|
|
59
97
|
|
|
60
98
|
<template #body>
|
|
61
99
|
<slot name="body">
|
|
62
|
-
|
|
100
|
+
<span
|
|
101
|
+
v-clean-html="t('addonConfigConfirmation.body', {
|
|
102
|
+
addons: formattedAddons,
|
|
103
|
+
previousKubeVersion,
|
|
104
|
+
newKubeVersion
|
|
105
|
+
}, true)"
|
|
106
|
+
/>
|
|
63
107
|
</slot>
|
|
64
108
|
</template>
|
|
65
109
|
|
|
@@ -3,12 +3,12 @@ import AsyncButton from '@shell/components/AsyncButton';
|
|
|
3
3
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
4
4
|
import { CATALOG, MANAGEMENT } from '@shell/config/types';
|
|
5
5
|
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
6
|
-
import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
|
|
6
|
+
import { UI_PLUGIN_NAMESPACE, isChartVersionHigher } from '@shell/config/uiplugins';
|
|
7
7
|
import Banner from '@components/Banner/Banner.vue';
|
|
8
8
|
import { SETTING } from '@shell/config/settings';
|
|
9
|
-
import {
|
|
9
|
+
import { getPluginChartVersionLabel } from '@shell/utils/uiplugins';
|
|
10
10
|
|
|
11
|
-
// Note: This dialog handles installation and
|
|
11
|
+
// Note: This dialog handles installation, upgrade and downgrade of a plugin
|
|
12
12
|
|
|
13
13
|
export default {
|
|
14
14
|
emits: ['close'],
|
|
@@ -29,7 +29,14 @@ export default {
|
|
|
29
29
|
required: true
|
|
30
30
|
},
|
|
31
31
|
/**
|
|
32
|
-
* The
|
|
32
|
+
* The pre-selected version in the dropdown
|
|
33
|
+
*/
|
|
34
|
+
initialVersion: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: null
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* The action to perform (install, upgrade, downgrade)
|
|
33
40
|
*/
|
|
34
41
|
action: {
|
|
35
42
|
type: String,
|
|
@@ -63,33 +70,32 @@ export default {
|
|
|
63
70
|
},
|
|
64
71
|
|
|
65
72
|
async fetch() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (this.action === 'update') {
|
|
72
|
-
this.currentVersion = chartVersion;
|
|
73
|
-
|
|
74
|
-
// Update to latest version, so take the first version
|
|
75
|
-
if (this.plugin?.installableVersions?.length > 0) {
|
|
76
|
-
this.version = this.plugin?.installableVersions?.[0]?.version;
|
|
77
|
-
}
|
|
78
|
-
} else if (this.action === 'rollback') {
|
|
79
|
-
// Find the newest version once we remove the current version
|
|
80
|
-
const versionNames = this.plugin.installableVersions.filter((v) => v.version !== chartVersion);
|
|
73
|
+
// Determine the currently installed version, if any
|
|
74
|
+
if (this.plugin.installed) {
|
|
75
|
+
this.currentVersion = this.plugin.installedVersion;
|
|
76
|
+
}
|
|
81
77
|
|
|
82
|
-
|
|
78
|
+
// Determine the initial version to select in the dropdown
|
|
79
|
+
if (this.initialVersion) {
|
|
80
|
+
this.version = this.initialVersion;
|
|
81
|
+
} else if (this.action === 'upgrade') {
|
|
82
|
+
// Upgrade to the latest version, so take the first version
|
|
83
|
+
this.version = this.plugin?.installableVersions?.[0]?.version;
|
|
84
|
+
} else if (this.action === 'downgrade') {
|
|
85
|
+
const versions = this.plugin.installableVersions;
|
|
86
|
+
const currentIndex = versions.findIndex((v) => v.version === this.currentVersion);
|
|
83
87
|
|
|
84
|
-
if (
|
|
85
|
-
|
|
88
|
+
if (currentIndex !== -1 && currentIndex < versions.length - 1) {
|
|
89
|
+
// Select the version just below the current version
|
|
90
|
+
this.version = versions[currentIndex + 1].version;
|
|
86
91
|
}
|
|
92
|
+
} else {
|
|
93
|
+
// Default to the latest installable version for new installs
|
|
94
|
+
this.version = this.plugin?.installableVersions?.[0]?.version;
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (!versionChart) {
|
|
97
|
+
// Fallback if no version could be determined
|
|
98
|
+
if (!this.version) {
|
|
93
99
|
this.version = this.plugin?.installableVersions?.[0]?.version;
|
|
94
100
|
}
|
|
95
101
|
|
|
@@ -119,37 +125,39 @@ export default {
|
|
|
119
125
|
},
|
|
120
126
|
|
|
121
127
|
versionOptions() {
|
|
122
|
-
if (!this.plugin) {
|
|
128
|
+
if (!this.plugin?.installableVersions) {
|
|
123
129
|
return [];
|
|
124
130
|
}
|
|
125
131
|
|
|
126
|
-
// Don't allow
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return v.version !== this.currentVersion;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return true;
|
|
133
|
-
});
|
|
132
|
+
// Don't allow upgrade/downgrade to current version by disabling the option
|
|
133
|
+
return this.plugin.installableVersions.map((v) => {
|
|
134
|
+
const isCurrent = v.version === this.currentVersion;
|
|
134
135
|
|
|
135
|
-
return versions.map((version) => {
|
|
136
136
|
return {
|
|
137
|
-
label:
|
|
138
|
-
value:
|
|
137
|
+
label: getPluginChartVersionLabel(v) + (isCurrent ? ` (${ this.t('plugins.labels.current') })` : ''),
|
|
138
|
+
value: v.version,
|
|
139
|
+
disabled: isCurrent,
|
|
139
140
|
};
|
|
140
141
|
});
|
|
141
142
|
},
|
|
142
143
|
|
|
143
144
|
buttonMode() {
|
|
144
|
-
if (this.action === '
|
|
145
|
-
return '
|
|
145
|
+
if (this.action === 'install') {
|
|
146
|
+
return 'install';
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
if (this.
|
|
149
|
-
|
|
149
|
+
if (this.currentVersion && this.version) {
|
|
150
|
+
if (isChartVersionHigher(this.version, this.currentVersion)) {
|
|
151
|
+
return 'upgrade';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (isChartVersionHigher(this.currentVersion, this.version)) {
|
|
155
|
+
return 'downgrade';
|
|
156
|
+
}
|
|
150
157
|
}
|
|
151
158
|
|
|
152
|
-
|
|
159
|
+
// Fallback for safety, though should not be reached if version is selected
|
|
160
|
+
return this.action;
|
|
153
161
|
},
|
|
154
162
|
|
|
155
163
|
chartVersionLoadsWithoutAuth() {
|
|
@@ -158,6 +166,23 @@ export default {
|
|
|
158
166
|
|
|
159
167
|
returnFocusSelector() {
|
|
160
168
|
return `[data-testid="extension-card-${ this.action }-btn-${ this.plugin?.name }"]`;
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
buttonIcon() {
|
|
172
|
+
if (this.busy) {
|
|
173
|
+
return '';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
switch (this.buttonMode) {
|
|
177
|
+
case 'install':
|
|
178
|
+
return 'icon-plus';
|
|
179
|
+
case 'upgrade':
|
|
180
|
+
return 'icon-upgrade-alt';
|
|
181
|
+
case 'downgrade':
|
|
182
|
+
return 'icon-downgrade-alt';
|
|
183
|
+
default:
|
|
184
|
+
return '';
|
|
185
|
+
}
|
|
161
186
|
}
|
|
162
187
|
},
|
|
163
188
|
|
|
@@ -295,12 +320,12 @@ export default {
|
|
|
295
320
|
<template>
|
|
296
321
|
<div class="plugin-install-dialog">
|
|
297
322
|
<h4 class="mt-10">
|
|
298
|
-
{{ t(`plugins.${
|
|
323
|
+
{{ t(`plugins.${ buttonMode }.title`, { name: `"${plugin?.label}"` }, true) }}
|
|
299
324
|
</h4>
|
|
300
325
|
<div class="custom mt-10">
|
|
301
326
|
<div class="dialog-panel">
|
|
302
327
|
<p>
|
|
303
|
-
{{ t(`plugins.${
|
|
328
|
+
{{ t(`plugins.${ buttonMode }.prompt`) }}
|
|
304
329
|
</p>
|
|
305
330
|
<Banner
|
|
306
331
|
v-if="chartVersionLoadsWithoutAuth"
|
|
@@ -335,6 +360,7 @@ export default {
|
|
|
335
360
|
</button>
|
|
336
361
|
<AsyncButton
|
|
337
362
|
:mode="buttonMode"
|
|
363
|
+
:icon="buttonIcon"
|
|
338
364
|
data-testid="install-ext-modal-install-btn"
|
|
339
365
|
@click="install"
|
|
340
366
|
/>
|
|
@@ -103,7 +103,7 @@ export default {
|
|
|
103
103
|
<template>
|
|
104
104
|
<div class="plugin-install-dialog">
|
|
105
105
|
<h4 class="mt-10">
|
|
106
|
-
{{ t('plugins.uninstall.title', { name: plugin?.label }) }}
|
|
106
|
+
{{ t('plugins.uninstall.title', { name: `"${plugin?.label}"` }, true) }}
|
|
107
107
|
</h4>
|
|
108
108
|
<div class="mt-10 dialog-panel">
|
|
109
109
|
<div class="dialog-info">
|
|
@@ -122,6 +122,7 @@ export default {
|
|
|
122
122
|
</button>
|
|
123
123
|
<AsyncButton
|
|
124
124
|
mode="uninstall"
|
|
125
|
+
:icon="busy ? '' : 'icon-delete'"
|
|
125
126
|
data-testid="uninstall-ext-modal-uninstall-btn"
|
|
126
127
|
@click="uninstall()"
|
|
127
128
|
/>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { shallowMount, VueWrapper } from '@vue/test-utils';
|
|
2
|
+
import InstallExtensionDialog from '@shell/dialog/InstallExtensionDialog.vue';
|
|
3
|
+
|
|
4
|
+
jest.mock('@shell/config/uiplugins', () => ({
|
|
5
|
+
...jest.requireActual('@shell/config/uiplugins'),
|
|
6
|
+
isChartVersionHigher: jest.fn((v1: string, v2: string) => v1 > v2),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
const t = (key: string): string => key;
|
|
10
|
+
|
|
11
|
+
describe('component: InstallExtensionDialog', () => {
|
|
12
|
+
let wrapper: VueWrapper<any>;
|
|
13
|
+
|
|
14
|
+
const mountComponent = (propsData = {}) => {
|
|
15
|
+
const store = { dispatch: () => Promise.resolve() };
|
|
16
|
+
|
|
17
|
+
const defaultProps = {
|
|
18
|
+
plugin: { installableVersions: [] },
|
|
19
|
+
action: 'install',
|
|
20
|
+
updateStatus: jest.fn(),
|
|
21
|
+
closed: jest.fn(),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return shallowMount(InstallExtensionDialog, {
|
|
25
|
+
propsData: {
|
|
26
|
+
...defaultProps,
|
|
27
|
+
...propsData,
|
|
28
|
+
},
|
|
29
|
+
global: {
|
|
30
|
+
mocks: {
|
|
31
|
+
$store: store,
|
|
32
|
+
t,
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
describe('fetch', () => {
|
|
39
|
+
it('should set currentVersion if plugin is installed', async() => {
|
|
40
|
+
wrapper = mountComponent({ plugin: { installed: true, installedVersion: '1.0.0' } });
|
|
41
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
42
|
+
expect(wrapper.vm.currentVersion).toBe('1.0.0');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should set version from initialVersion if provided', async() => {
|
|
46
|
+
wrapper = mountComponent({ initialVersion: '1.2.3', plugin: { installed: false } });
|
|
47
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
48
|
+
expect(wrapper.vm.version).toBe('1.2.3');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should set version to latest for upgrade action', async() => {
|
|
52
|
+
const plugin = { installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }] };
|
|
53
|
+
|
|
54
|
+
wrapper = mountComponent({ plugin, action: 'upgrade' });
|
|
55
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
56
|
+
expect(wrapper.vm.version).toBe('1.1.0');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should set version to next oldest for downgrade action', async() => {
|
|
60
|
+
const plugin = {
|
|
61
|
+
installed: true,
|
|
62
|
+
installedVersion: '1.1.0',
|
|
63
|
+
installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }]
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
wrapper = mountComponent({ plugin, action: 'downgrade' });
|
|
67
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
68
|
+
expect(wrapper.vm.version).toBe('1.0.0');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('versionOptions', () => {
|
|
73
|
+
it('should include and disable the current version', () => {
|
|
74
|
+
const plugin = {
|
|
75
|
+
installableVersions: [
|
|
76
|
+
{ version: '1.1.0' },
|
|
77
|
+
{ version: '1.0.0' },
|
|
78
|
+
]
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
wrapper = mountComponent({ plugin });
|
|
82
|
+
wrapper.vm.currentVersion = '1.0.0';
|
|
83
|
+
|
|
84
|
+
const options = wrapper.vm.versionOptions;
|
|
85
|
+
const currentOption = options.find((o: any) => o.value === '1.0.0');
|
|
86
|
+
|
|
87
|
+
expect(currentOption).toBeDefined();
|
|
88
|
+
expect(currentOption.disabled).toBe(true);
|
|
89
|
+
expect(currentOption.label).toContain('(plugins.labels.current)');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('buttonMode', () => {
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
wrapper = mountComponent({ action: 'upgrade' });
|
|
96
|
+
wrapper.vm.currentVersion = '1.0.0';
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should be "upgrade" if selected version is higher', async() => {
|
|
100
|
+
wrapper.vm.version = '1.1.0';
|
|
101
|
+
await wrapper.vm.$nextTick();
|
|
102
|
+
expect(wrapper.vm.buttonMode).toBe('upgrade');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should be "downgrade" if selected version is lower', async() => {
|
|
106
|
+
wrapper.vm.version = '0.9.0';
|
|
107
|
+
await wrapper.vm.$nextTick();
|
|
108
|
+
expect(wrapper.vm.buttonMode).toBe('downgrade');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -2,18 +2,22 @@ import { mount } from '@vue/test-utils';
|
|
|
2
2
|
import { _CREATE, _EDIT, _VIEW } from '@shell/config/query-params';
|
|
3
3
|
import HelmOp from '@shell/models/fleet.cattle.io.helmop';
|
|
4
4
|
import HelmOpComponent from '@shell/edit/fleet.cattle.io.helmop.vue';
|
|
5
|
+
import FleetSecretSelector from '@shell/components/fleet/FleetSecretSelector.vue';
|
|
6
|
+
import FleetConfigMapSelector from '@shell/components/fleet/FleetConfigMapSelector.vue';
|
|
5
7
|
|
|
6
8
|
const mockStore = {
|
|
7
9
|
dispatch: jest.fn(),
|
|
8
10
|
commit: jest.fn(),
|
|
9
11
|
getters: {
|
|
10
|
-
'i18n/t':
|
|
11
|
-
'i18n/exists':
|
|
12
|
-
t:
|
|
13
|
-
currentStore:
|
|
14
|
-
'current_store/schemaFor':
|
|
15
|
-
'current_store/all':
|
|
16
|
-
workspace:
|
|
12
|
+
'i18n/t': (text: string) => text,
|
|
13
|
+
'i18n/exists': jest.fn(),
|
|
14
|
+
t: (text: string) => text,
|
|
15
|
+
currentStore: () => 'current_store',
|
|
16
|
+
'current_store/schemaFor': jest.fn(),
|
|
17
|
+
'current_store/all': jest.fn(),
|
|
18
|
+
workspace: 'test',
|
|
19
|
+
'management/paginationEnabled': () => false,
|
|
20
|
+
'management/all': () => [],
|
|
17
21
|
},
|
|
18
22
|
rootGetters: { 'i18n/t': jest.fn() },
|
|
19
23
|
};
|
|
@@ -63,19 +67,22 @@ const mockHelmOp = {
|
|
|
63
67
|
currentRoute: () => {},
|
|
64
68
|
};
|
|
65
69
|
|
|
66
|
-
const initHelmOp = (props: any,
|
|
67
|
-
const
|
|
70
|
+
const initHelmOp = (props: any, options = {}) => {
|
|
71
|
+
const value = new HelmOp({
|
|
68
72
|
...mockHelmOp,
|
|
69
|
-
...
|
|
73
|
+
...options
|
|
70
74
|
}, {
|
|
71
75
|
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
72
76
|
dispatch: jest.fn(),
|
|
73
77
|
rootGetters: { 'i18n/t': jest.fn() },
|
|
74
78
|
});
|
|
75
79
|
|
|
80
|
+
value.applyDefaults = () => {};
|
|
81
|
+
value.metadata = { namespace: '' };
|
|
82
|
+
|
|
76
83
|
return {
|
|
77
84
|
props: {
|
|
78
|
-
value
|
|
85
|
+
value,
|
|
79
86
|
...props
|
|
80
87
|
},
|
|
81
88
|
computed: mockComputed,
|
|
@@ -221,4 +228,38 @@ describe.each([
|
|
|
221
228
|
|
|
222
229
|
expect(pollingIntervalInput.value).toBe(displayValue);
|
|
223
230
|
});
|
|
231
|
+
|
|
232
|
+
it('should update downstreamResources with new Secrets when FleetSecretSelector emits update event', async() => {
|
|
233
|
+
const wrapper = mount(HelmOpComponent, initHelmOp({ realMode: mode }));
|
|
234
|
+
|
|
235
|
+
const fleetConfigMapSelector = wrapper.findComponent(FleetConfigMapSelector);
|
|
236
|
+
const fleetSecretSelector = wrapper.findComponent(FleetSecretSelector);
|
|
237
|
+
|
|
238
|
+
expect(fleetSecretSelector.exists()).toBe(true);
|
|
239
|
+
expect(fleetConfigMapSelector.exists()).toBe(true);
|
|
240
|
+
|
|
241
|
+
await fleetSecretSelector.vm.$emit('update:value', []);
|
|
242
|
+
await fleetConfigMapSelector.vm.$emit('update:value', []);
|
|
243
|
+
|
|
244
|
+
await fleetSecretSelector.vm.$emit('update:value', ['secret2', 'secret3']);
|
|
245
|
+
|
|
246
|
+
expect(wrapper.vm.value.spec.helm.downstreamResources).toStrictEqual([{ name: 'secret2', kind: 'Secret' }, { name: 'secret3', kind: 'Secret' }]);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should update downstreamResources with new ConfigMaps when FleetConfigMapSelector emits update event', async() => {
|
|
250
|
+
const wrapper = mount(HelmOpComponent, initHelmOp({ realMode: mode }));
|
|
251
|
+
|
|
252
|
+
const fleetConfigMapSelector = wrapper.findComponent(FleetConfigMapSelector);
|
|
253
|
+
const fleetSecretSelector = wrapper.findComponent(FleetSecretSelector);
|
|
254
|
+
|
|
255
|
+
expect(fleetSecretSelector.exists()).toBe(true);
|
|
256
|
+
expect(fleetConfigMapSelector.exists()).toBe(true);
|
|
257
|
+
|
|
258
|
+
await fleetSecretSelector.vm.$emit('update:value', []);
|
|
259
|
+
await fleetConfigMapSelector.vm.$emit('update:value', []);
|
|
260
|
+
|
|
261
|
+
await fleetConfigMapSelector.vm.$emit('update:value', ['configMap2', 'configMap3']);
|
|
262
|
+
|
|
263
|
+
expect(wrapper.vm.value.spec.helm.downstreamResources).toStrictEqual([{ name: 'configMap2', kind: 'ConfigMap' }, { name: 'configMap3', kind: 'ConfigMap' }]);
|
|
264
|
+
});
|
|
224
265
|
});
|
|
@@ -28,7 +28,20 @@ export default defineComponent({
|
|
|
28
28
|
color="warning"
|
|
29
29
|
data-testid="auth-provider-admin-permissions-warning-banner"
|
|
30
30
|
>
|
|
31
|
-
<span
|
|
31
|
+
<span class="banner-content">
|
|
32
|
+
<span v-clean-html="t('authConfig.associatedWarning', tArgs, true)" />
|
|
33
|
+
<slot name="additional-warning">
|
|
34
|
+
<!--Empty slot content-->
|
|
35
|
+
</slot>
|
|
36
|
+
</span>
|
|
32
37
|
</Banner>
|
|
33
38
|
</div>
|
|
34
39
|
</template>
|
|
40
|
+
|
|
41
|
+
<style lang="scss" scoped>
|
|
42
|
+
.banner-content {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: 1rem;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import InfoBox from '@shell/components/InfoBox';
|
|
3
|
+
import CopyToClipboard from '@shell/components/CopyToClipboard';
|
|
4
|
+
|
|
5
|
+
type TArgs = {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
serverUrl: string;
|
|
8
|
+
provider: string;
|
|
9
|
+
username: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
defineProps<{
|
|
13
|
+
name: string;
|
|
14
|
+
tArgs: TArgs;
|
|
15
|
+
}>();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<InfoBox
|
|
21
|
+
:step="1"
|
|
22
|
+
class="step-box"
|
|
23
|
+
>
|
|
24
|
+
<ul class="step-list">
|
|
25
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.1`, tArgs, true)" />
|
|
26
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.2`, tArgs, true)" />
|
|
27
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.3`, tArgs, true)" />
|
|
28
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.4`, tArgs, true)" />
|
|
29
|
+
</ul>
|
|
30
|
+
</InfoBox>
|
|
31
|
+
<InfoBox
|
|
32
|
+
:step="2"
|
|
33
|
+
class="step-box"
|
|
34
|
+
>
|
|
35
|
+
<ul class="step-list">
|
|
36
|
+
<li>
|
|
37
|
+
{{ t(`authConfig.${name}.form.instruction`, tArgs, true) }}
|
|
38
|
+
<ul class="mt-10">
|
|
39
|
+
<li>
|
|
40
|
+
<b>
|
|
41
|
+
{{ t(`authConfig.${name}.form.app.label`) }}
|
|
42
|
+
</b>:
|
|
43
|
+
<span v-clean-html="t(`authConfig.${name}.form.app.value`, tArgs, true)" />
|
|
44
|
+
</li>
|
|
45
|
+
<li>
|
|
46
|
+
<b>
|
|
47
|
+
{{ t(`authConfig.${name}.form.homepage.label`) }}
|
|
48
|
+
</b>: {{ tArgs.serverUrl }}
|
|
49
|
+
<CopyToClipboard
|
|
50
|
+
label-as="tooltip"
|
|
51
|
+
:text="tArgs.serverUrl"
|
|
52
|
+
class="icon-btn"
|
|
53
|
+
action-color="bg-transparent"
|
|
54
|
+
/>
|
|
55
|
+
</li>
|
|
56
|
+
<li>
|
|
57
|
+
<b>
|
|
58
|
+
{{ t(`authConfig.${name}.form.description.label`) }}
|
|
59
|
+
</b>:
|
|
60
|
+
<span v-clean-html="t(`authConfig.${name}.form.description.value`, tArgs, true)" />
|
|
61
|
+
</li>
|
|
62
|
+
<li>
|
|
63
|
+
<b>
|
|
64
|
+
{{ t(`authConfig.${name}.form.callback.label`) }}
|
|
65
|
+
</b>:
|
|
66
|
+
{{ t(`authConfig.${name}.form.callback.value`, tArgs, true) }}
|
|
67
|
+
<CopyToClipboard
|
|
68
|
+
:text="t(`authConfig.${name}.form.callback.value`, tArgs, true)"
|
|
69
|
+
label-as="tooltip"
|
|
70
|
+
class="icon-btn"
|
|
71
|
+
action-color="bg-transparent"
|
|
72
|
+
/>
|
|
73
|
+
</li>
|
|
74
|
+
</ul>
|
|
75
|
+
</li>
|
|
76
|
+
<li>
|
|
77
|
+
{{ t(`authConfig.${name}.form.create`, tArgs, true) }}
|
|
78
|
+
</li>
|
|
79
|
+
</ul>
|
|
80
|
+
</InfoBox>
|
|
81
|
+
<InfoBox
|
|
82
|
+
:step="3"
|
|
83
|
+
class="mb-20"
|
|
84
|
+
>
|
|
85
|
+
<ul class="step-list">
|
|
86
|
+
<li v-clean-html="t(`authConfig.${name}.form.suffix.1`, tArgs, true)" />
|
|
87
|
+
<li v-clean-html="t(`authConfig.${name}.form.suffix.2`, tArgs, true)" />
|
|
88
|
+
<li v-clean-html="t(`authConfig.${name}.form.suffix.3`, tArgs, true)" />
|
|
89
|
+
</ul>
|
|
90
|
+
</InfoBox>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<style lang="scss" scoped>
|
|
94
|
+
.step-list li:not(:last-child) {
|
|
95
|
+
margin-bottom: 8px;
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import InfoBox from '@shell/components/InfoBox';
|
|
3
|
+
import CopyToClipboard from '@shell/components/CopyToClipboard';
|
|
4
|
+
|
|
5
|
+
type TArgs = {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
serverUrl: string;
|
|
8
|
+
provider: string;
|
|
9
|
+
username: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
defineProps<{
|
|
13
|
+
name: string;
|
|
14
|
+
tArgs: TArgs;
|
|
15
|
+
}>();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<InfoBox
|
|
21
|
+
:step="1"
|
|
22
|
+
class="step-box"
|
|
23
|
+
>
|
|
24
|
+
<ul class="step-list">
|
|
25
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.1`, tArgs, true)" />
|
|
26
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.2`, tArgs, true)" />
|
|
27
|
+
<li v-clean-html="t(`authConfig.${name}.form.prefix.3`, tArgs, true)" />
|
|
28
|
+
</ul>
|
|
29
|
+
</InfoBox>
|
|
30
|
+
<InfoBox
|
|
31
|
+
:step="2"
|
|
32
|
+
class="step-box"
|
|
33
|
+
>
|
|
34
|
+
<ul class="step-list">
|
|
35
|
+
<li>
|
|
36
|
+
{{ t(`authConfig.${name}.form.instruction`, tArgs, true) }}
|
|
37
|
+
<ul class="mt-10">
|
|
38
|
+
<li><b>{{ t(`authConfig.${name}.form.app.label`) }}</b>: <span v-clean-html="t(`authConfig.${name}.form.app.value`, tArgs, true)" /></li>
|
|
39
|
+
<li>
|
|
40
|
+
<b>{{ t(`authConfig.${name}.form.homepage.label`) }}</b>: {{ tArgs.serverUrl }} <CopyToClipboard
|
|
41
|
+
label-as="tooltip"
|
|
42
|
+
:text="tArgs.serverUrl"
|
|
43
|
+
class="icon-btn"
|
|
44
|
+
action-color="bg-transparent"
|
|
45
|
+
/>
|
|
46
|
+
</li>
|
|
47
|
+
<li><b>{{ t(`authConfig.${name}.form.description.label`) }}</b>: <span v-clean-html="t(`authConfig.${name}.form.description.value`, tArgs, true)" /></li>
|
|
48
|
+
<li>
|
|
49
|
+
<b>{{ t(`authConfig.${name}.form.callback.label`) }}</b>: {{ tArgs.serverUrl }} <CopyToClipboard
|
|
50
|
+
:text="tArgs.serverUrl"
|
|
51
|
+
label-as="tooltip"
|
|
52
|
+
class="icon-btn"
|
|
53
|
+
action-color="bg-transparent"
|
|
54
|
+
/>
|
|
55
|
+
</li>
|
|
56
|
+
</ul>
|
|
57
|
+
</li>
|
|
58
|
+
</ul>
|
|
59
|
+
</InfoBox>
|
|
60
|
+
<InfoBox
|
|
61
|
+
:step="3"
|
|
62
|
+
class="mb-20"
|
|
63
|
+
>
|
|
64
|
+
<ul class="step-list">
|
|
65
|
+
<li v-clean-html="t(`authConfig.${name}.form.suffix.1`, tArgs, true)" />
|
|
66
|
+
<li v-clean-html="t(`authConfig.${name}.form.suffix.2`, tArgs, true)" />
|
|
67
|
+
</ul>
|
|
68
|
+
</InfoBox>
|
|
69
|
+
</template>
|
|
70
|
+
|
|
71
|
+
<style lang="scss" scoped>
|
|
72
|
+
.step-list li:not(:last-child) {
|
|
73
|
+
margin-bottom: 8px;
|
|
74
|
+
}
|
|
75
|
+
</style>
|