@rancher/shell 3.0.5-rc.9 → 3.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/translations/en-us.yaml +11 -5
- package/components/FilterPanel.vue +8 -1
- package/components/PaginatedResourceTable.vue +7 -2
- package/components/PodSecurityAdmission.vue +2 -0
- package/components/PromptRemove.vue +5 -0
- package/components/ResourceTable.vue +30 -20
- package/components/form/ProjectMemberEditor.vue +2 -0
- package/components/nav/Header.vue +6 -5
- package/config/product/explorer.js +5 -5
- package/config/store.js +2 -0
- package/config/uiplugins.js +1 -1
- package/core/plugin.ts +15 -3
- package/core/types.ts +30 -7
- package/dialog/SloDialog.vue +1 -1
- package/edit/auth/oidc.vue +106 -6
- package/edit/auth/saml.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +6 -0
- package/initialize/install-plugins.js +1 -3
- package/list/catalog.cattle.io.clusterrepo.vue +2 -2
- package/mixins/__tests__/auth-config.test.ts +4 -6
- package/mixins/__tests__/chart.test.ts +1 -1
- package/mixins/auth-config.js +33 -10
- package/mixins/chart.js +1 -1
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/workload.js +1 -1
- package/package.json +2 -2
- package/pages/auth/login.vue +8 -3
- package/pages/auth/logout.vue +6 -5
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +6 -0
- package/pages/c/_cluster/apps/charts/StatusLabel.vue +4 -3
- package/pages/c/_cluster/apps/charts/index.vue +12 -11
- package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/tools/index.vue +1 -1
- package/plugins/axios.js +3 -2
- package/plugins/dashboard-store/resource-class.js +12 -1
- package/plugins/ember-cookie.js +7 -3
- package/plugins/steve/steve-pagination-utils.ts +14 -22
- package/plugins/steve/subscribe.js +4 -2
- package/scripts/test-plugins-build.sh +4 -6
- package/scripts/typegen.sh +2 -0
- package/store/__tests__/cookies.test.ts +72 -0
- package/store/auth.js +34 -11
- package/store/cookies.ts +30 -0
- package/store/prefs.js +10 -5
- package/types/shell/index.d.ts +183 -11
- package/types/store/vuex.d.ts +2 -1
- package/types/vue-shim.d.ts +2 -5
- package/utils/auth.js +1 -1
- package/utils/pagination-utils.ts +11 -2
- package/utils/cookie-universal.js +0 -10
|
@@ -78,6 +78,7 @@ export default {
|
|
|
78
78
|
<div class="row">
|
|
79
79
|
<Checkbox
|
|
80
80
|
:value="showCustomRegistryInput"
|
|
81
|
+
:mode="mode"
|
|
81
82
|
:label="t('cluster.privateRegistry.label')"
|
|
82
83
|
data-testid="registries-enable-checkbox"
|
|
83
84
|
@update:value="$emit('custom-registry-changed', $event)"
|
|
@@ -90,6 +91,7 @@ export default {
|
|
|
90
91
|
<div class="col span-6">
|
|
91
92
|
<LabeledInput
|
|
92
93
|
:value="registryHost"
|
|
94
|
+
:mode="mode"
|
|
93
95
|
label-key="catalog.chart.registry.custom.inputLabel"
|
|
94
96
|
placeholder-key="catalog.chart.registry.custom.placeholder"
|
|
95
97
|
:min-height="30"
|
|
@@ -102,6 +102,7 @@ export default {
|
|
|
102
102
|
<div class="mt-20">
|
|
103
103
|
<Checkbox
|
|
104
104
|
v-model:value="deleteEmptyDirData"
|
|
105
|
+
:mode="mode"
|
|
105
106
|
label-key="cluster.rke2.drain.deleteEmptyDir.label"
|
|
106
107
|
tooltip-key="cluster.rke2.drain.deleteEmptyDir.tooltip"
|
|
107
108
|
@update:value="update"
|
|
@@ -110,6 +111,7 @@ export default {
|
|
|
110
111
|
<div>
|
|
111
112
|
<Checkbox
|
|
112
113
|
v-model:value="force"
|
|
114
|
+
:mode="mode"
|
|
113
115
|
label="Delete standalone pods"
|
|
114
116
|
label-key="cluster.rke2.drain.force.label"
|
|
115
117
|
tooltip="Delete standalone pods which are not managed by a Workload controller (Deployment, Job, etc). Draining will fail if this is not set and there are standalone pods."
|
|
@@ -120,12 +122,14 @@ export default {
|
|
|
120
122
|
<div>
|
|
121
123
|
<Checkbox
|
|
122
124
|
v-model:value="customGracePeriod"
|
|
125
|
+
:mode="mode"
|
|
123
126
|
label-key="cluster.rke2.drain.gracePeriod.checkboxLabel"
|
|
124
127
|
@update:value="update"
|
|
125
128
|
/>
|
|
126
129
|
<UnitInput
|
|
127
130
|
v-if="customGracePeriod"
|
|
128
131
|
v-model:value="gracePeriod"
|
|
132
|
+
:mode="mode"
|
|
129
133
|
label-key="cluster.rke2.drain.gracePeriod.inputLabel"
|
|
130
134
|
:suffix="t('suffix.seconds', {count: timeout})"
|
|
131
135
|
class="mb-10"
|
|
@@ -135,12 +139,14 @@ export default {
|
|
|
135
139
|
<div>
|
|
136
140
|
<Checkbox
|
|
137
141
|
v-model:value="customTimeout"
|
|
142
|
+
:mode="mode"
|
|
138
143
|
label-key="cluster.rke2.drain.timeout.checkboxLabel"
|
|
139
144
|
@update:value="update"
|
|
140
145
|
/>
|
|
141
146
|
<UnitInput
|
|
142
147
|
v-if="customTimeout"
|
|
143
148
|
v-model:value="timeout"
|
|
149
|
+
:mode="mode"
|
|
144
150
|
label-key="cluster.rke2.drain.timeout.inputLabel"
|
|
145
151
|
:suffix="t('suffix.seconds', {count: timeout})"
|
|
146
152
|
class="drain-timeout"
|
|
@@ -12,7 +12,6 @@ import i18n from '@shell/plugins/i18n';
|
|
|
12
12
|
import globalFormatters from '@shell/plugins/global-formatters';
|
|
13
13
|
|
|
14
14
|
import axios from '@shell/utils/axios';
|
|
15
|
-
import cookieUniversal from '@shell/utils/cookie-universal';
|
|
16
15
|
import config from '@shell/utils/config';
|
|
17
16
|
import axiosShell from '@shell/plugins/axios';
|
|
18
17
|
import codeMirror from '@shell/plugins/codemirror-loader';
|
|
@@ -47,7 +46,7 @@ export async function installPlugins(vueApp) {
|
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
export async function installInjectedPlugins(app, vueApp) {
|
|
50
|
-
const pluginDefinitions = [config,
|
|
49
|
+
const pluginDefinitions = [config, axios, plugins, pluginsLoader, axiosShell, intNumber, codeMirror, nuxtClientInit, replaceAll, plugin, steveCreateWorker, emberCookie, internalApiPlugin];
|
|
51
50
|
|
|
52
51
|
const installations = pluginDefinitions.map(async(pluginDefinition) => {
|
|
53
52
|
if (typeof pluginDefinition === 'function') {
|
|
@@ -64,7 +63,6 @@ export async function installInjectedPlugins(app, vueApp) {
|
|
|
64
63
|
// If there's any performance reasons this can be done concurrently with all of the installation promises above but I felt it was organizationally better to keep both i18n items together.
|
|
65
64
|
await app.store.dispatch('i18n/init');
|
|
66
65
|
|
|
67
|
-
// Order matters here. This is coming after the other plugins specifically so $cookies can be installed. i18n/init relies on prefs/get which relies on $cookies.
|
|
68
66
|
vueApp.use(i18n, { store: app.store });
|
|
69
67
|
}
|
|
70
68
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import PaginatedResourceTable from '@shell/components/PaginatedResourceTable.vue';
|
|
3
3
|
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
4
|
-
import
|
|
4
|
+
import { RancherKubeMetadata } from '@shell/types/kube/kube-api';
|
|
5
5
|
import { PaginationArgs, PaginationParamFilter } from '@shell/types/store/pagination.types';
|
|
6
6
|
import { defineComponent } from 'vue';
|
|
7
7
|
|
|
@@ -25,7 +25,7 @@ export default defineComponent({
|
|
|
25
25
|
/**
|
|
26
26
|
* Filter out hidden repos from list of all repos
|
|
27
27
|
*/
|
|
28
|
-
filterRowsLocal(rows:
|
|
28
|
+
filterRowsLocal(rows: { metadata: RancherKubeMetadata}[]) {
|
|
29
29
|
return rows.filter((repo) => !(repo?.metadata?.annotations?.[CATALOG_ANNOTATIONS.HIDDEN_REPO] === 'true'));
|
|
30
30
|
},
|
|
31
31
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import authConfigMixin from '@shell/mixins/auth-config';
|
|
3
|
-
|
|
3
|
+
import childHook from '@shell/mixins/child-hook';
|
|
4
|
+
//
|
|
4
5
|
describe('mixin: authConfigMixin', () => {
|
|
5
6
|
describe('method: save', () => {
|
|
6
7
|
const componentMock = (model: any) => ({
|
|
@@ -11,10 +12,7 @@ describe('mixin: authConfigMixin', () => {
|
|
|
11
12
|
computed: { principal: () => ({ me: {} }) },
|
|
12
13
|
global: {
|
|
13
14
|
mocks: {
|
|
14
|
-
$store: {
|
|
15
|
-
dispatch: () => model,
|
|
16
|
-
commit: () => ({ 'auth/loggedInAs': jest.fn() }),
|
|
17
|
-
},
|
|
15
|
+
$store: { dispatch: () => model },
|
|
18
16
|
$route: {
|
|
19
17
|
params: { id: '123' },
|
|
20
18
|
query: { mode: 'edit' },
|
|
@@ -24,7 +22,7 @@ describe('mixin: authConfigMixin', () => {
|
|
|
24
22
|
});
|
|
25
23
|
const FakeComponent = {
|
|
26
24
|
render() {},
|
|
27
|
-
mixins: [authConfigMixin],
|
|
25
|
+
mixins: [authConfigMixin, childHook],
|
|
28
26
|
methods: { applyHooks: jest.fn() },
|
|
29
27
|
};
|
|
30
28
|
|
package/mixins/auth-config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _EDIT } from '@shell/config/query-params';
|
|
2
2
|
import { NORMAN, MANAGEMENT } from '@shell/config/types';
|
|
3
3
|
import { AFTER_SAVE_HOOKS, BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
|
|
4
|
-
import { BASE_SCOPES } from '@shell/store/auth';
|
|
4
|
+
import { BASE_SCOPES, SLO_AUTH_PROVIDERS } from '@shell/store/auth';
|
|
5
5
|
import { addObject, findBy } from '@shell/utils/array';
|
|
6
6
|
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
7
7
|
import difference from 'lodash/difference';
|
|
@@ -30,6 +30,10 @@ export default {
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
|
|
33
|
+
created() {
|
|
34
|
+
this.registerAfterHook(this.updateAuthProviders, 'force-update-auth-providers');
|
|
35
|
+
},
|
|
36
|
+
|
|
33
37
|
async fetch() {
|
|
34
38
|
await this.mixinFetch();
|
|
35
39
|
},
|
|
@@ -88,6 +92,23 @@ export default {
|
|
|
88
92
|
},
|
|
89
93
|
|
|
90
94
|
methods: {
|
|
95
|
+
updateAuthProviders() {
|
|
96
|
+
// we need to forcefully re-fetch the authProviders list so that we can update the logout method
|
|
97
|
+
// this is to satisfy the SLO usecase where after setting an auth provider the logout method
|
|
98
|
+
// wasn't being updated because the resource is not watchable
|
|
99
|
+
this.$store.dispatch('auth/getAuthProviders', { force: true });
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
setSloType(selectedModel) {
|
|
103
|
+
if (!selectedModel.logoutAllEnabled && !selectedModel.logoutAllForced) {
|
|
104
|
+
this.sloType = SLO_OPTION_VALUES.rancher;
|
|
105
|
+
} else if (selectedModel.logoutAllEnabled && selectedModel.logoutAllForced) {
|
|
106
|
+
this.sloType = SLO_OPTION_VALUES.all;
|
|
107
|
+
} else if (selectedModel.logoutAllEnabled && !selectedModel.logoutAllForced) {
|
|
108
|
+
this.sloType = SLO_OPTION_VALUES.both;
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
91
112
|
async mixinFetch() {
|
|
92
113
|
this.authConfigName = this.$route.params.id;
|
|
93
114
|
|
|
@@ -115,20 +136,16 @@ export default {
|
|
|
115
136
|
if (this.model.openLdapConfig) {
|
|
116
137
|
this.showLdap = true;
|
|
117
138
|
}
|
|
118
|
-
|
|
139
|
+
|
|
140
|
+
// Logic for Single Logout/SLO for auth providers
|
|
141
|
+
if (this.value?.configType && SLO_AUTH_PROVIDERS.includes(this.value?.configType)) {
|
|
119
142
|
if (!this.model.rancherApiHost || !this.model.rancherApiHost.length) {
|
|
120
143
|
this.model['rancherApiHost'] = this.serverUrl;
|
|
121
144
|
}
|
|
122
145
|
|
|
123
146
|
// setting data for SLO
|
|
124
147
|
if (this.model && Object.keys(this.model).includes('logoutAllSupported')) {
|
|
125
|
-
|
|
126
|
-
this.sloType = SLO_OPTION_VALUES.rancher;
|
|
127
|
-
} else if (this.model.logoutAllEnabled && this.model.logoutAllForced) {
|
|
128
|
-
this.sloType = SLO_OPTION_VALUES.all;
|
|
129
|
-
} else if (this.model.logoutAllEnabled && !this.model.logoutAllForced) {
|
|
130
|
-
this.sloType = SLO_OPTION_VALUES.both;
|
|
131
|
-
}
|
|
148
|
+
this.setSloType(this.model);
|
|
132
149
|
}
|
|
133
150
|
}
|
|
134
151
|
|
|
@@ -220,7 +237,7 @@ export default {
|
|
|
220
237
|
addObject(this.model.allowedPrincipalIds, this.principal.id);
|
|
221
238
|
}
|
|
222
239
|
// Session has switched to new 'me', ensure we react
|
|
223
|
-
this.$store.
|
|
240
|
+
this.$store.dispatch('auth/loggedInAs', this.principal.id);
|
|
224
241
|
} else {
|
|
225
242
|
console.warn(`Unable to find principal marked as 'me'`); // eslint-disable-line no-console
|
|
226
243
|
}
|
|
@@ -292,6 +309,12 @@ export default {
|
|
|
292
309
|
// must be cancelling edit of an enabled config; reset any changes and return to add users/groups view for that config
|
|
293
310
|
this.$store.dispatch(`rancher/clone`, { resource: this.originalModel }).then((cloned) => {
|
|
294
311
|
this.model = cloned;
|
|
312
|
+
|
|
313
|
+
// reset SLO type (radio option)
|
|
314
|
+
if (cloned && Object.keys(cloned).includes('logoutAllSupported')) {
|
|
315
|
+
this.setSloType(cloned);
|
|
316
|
+
}
|
|
317
|
+
|
|
295
318
|
this.editConfig = false;
|
|
296
319
|
});
|
|
297
320
|
}
|
package/mixins/chart.js
CHANGED
|
@@ -278,7 +278,7 @@ export default class MgmtCluster extends SteveModel {
|
|
|
278
278
|
|
|
279
279
|
// Color to use as the underline for the icon in the app bar
|
|
280
280
|
get iconColor() {
|
|
281
|
-
return this.metadata?.annotations[CLUSTER_BADGE.COLOR];
|
|
281
|
+
return this.metadata?.annotations?.[CLUSTER_BADGE.COLOR];
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
// Custom badge to show for the Cluster (if the appropriate annotations are set)
|
package/models/workload.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.6",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancherlabs/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"express": "4.17.1",
|
|
94
94
|
"file-saver": "2.0.2",
|
|
95
95
|
"floating-vue": "5.2.2",
|
|
96
|
-
"focus-trap": "7.6.
|
|
96
|
+
"focus-trap": "7.6.5",
|
|
97
97
|
"frontmatter-markdown-loader": "3.7.0",
|
|
98
98
|
"identicon.js": "2.3.3",
|
|
99
99
|
"intl-messageformat": "7.8.4",
|
package/pages/auth/login.vue
CHANGED
|
@@ -134,7 +134,8 @@ export default {
|
|
|
134
134
|
},
|
|
135
135
|
|
|
136
136
|
async fetch() {
|
|
137
|
-
const
|
|
137
|
+
const cookie = this.$store.getters['cookies/get']({ key: USERNAME, options: { parseJSON: false } });
|
|
138
|
+
const username = cookie || '';
|
|
138
139
|
|
|
139
140
|
this.username = username;
|
|
140
141
|
this.remember = !!username;
|
|
@@ -272,15 +273,19 @@ export default {
|
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
if ( this.remember ) {
|
|
275
|
-
|
|
276
|
+
const options = {
|
|
276
277
|
encode: (x) => x,
|
|
277
278
|
maxAge: 86400 * 365,
|
|
278
279
|
path: '/',
|
|
279
280
|
sameSite: true,
|
|
280
281
|
secure: true,
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
this.$store.commit('cookies/set', {
|
|
285
|
+
key: USERNAME, value: this.username, options
|
|
281
286
|
});
|
|
282
287
|
} else {
|
|
283
|
-
this.$cookies
|
|
288
|
+
this.$store.commit('cookies/remove', { key: USERNAME });
|
|
284
289
|
}
|
|
285
290
|
|
|
286
291
|
// User logged with local login - we don't do any redirect/reload, so the boot-time plugin will not run again to laod the plugins
|
package/pages/auth/logout.vue
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { configType } from '@shell/models/management.cattle.io.authconfig';
|
|
3
|
+
import { SLO_AUTH_PROVIDERS } from '@shell/store/auth';
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
6
|
async fetch() {
|
|
6
7
|
const publicAuthProviders = await this.$store.dispatch('auth/getAuthProviders');
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
+
const sloAuthProvider = publicAuthProviders.find((authProvider) => SLO_AUTH_PROVIDERS.includes(configType[authProvider?.id]));
|
|
9
10
|
|
|
10
|
-
if (!!
|
|
11
|
-
const { logoutAllSupported, logoutAllEnabled, logoutAllForced } =
|
|
11
|
+
if (!!sloAuthProvider) {
|
|
12
|
+
const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = sloAuthProvider;
|
|
12
13
|
|
|
13
14
|
if (logoutAllSupported && logoutAllEnabled && logoutAllForced) {
|
|
14
|
-
//
|
|
15
|
+
// force SLO (logout from all apps)
|
|
15
16
|
await this.$store.dispatch('auth/logout', {
|
|
16
|
-
force: true, slo: true, provider:
|
|
17
|
+
force: true, slo: true, provider: sloAuthProvider
|
|
17
18
|
}, { root: true });
|
|
18
19
|
} else {
|
|
19
20
|
// simple logout
|
|
@@ -80,6 +80,12 @@ function onClickItem(type: string, label: string) {
|
|
|
80
80
|
&-text {
|
|
81
81
|
text-transform: capitalize;
|
|
82
82
|
margin-right: 8px;
|
|
83
|
+
display: -webkit-box;
|
|
84
|
+
-webkit-line-clamp: 1;
|
|
85
|
+
-webkit-box-orient: vertical;
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
text-overflow: ellipsis;
|
|
88
|
+
word-break: break-all;
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
&-icon {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
defineProps<{
|
|
4
4
|
label: string;
|
|
5
|
-
icon
|
|
5
|
+
icon?: string;
|
|
6
6
|
iconColor?: string;
|
|
7
|
-
|
|
7
|
+
iconTooltip?: string;
|
|
8
8
|
}>();
|
|
9
9
|
|
|
10
10
|
</script>
|
|
@@ -13,7 +13,8 @@ defineProps<{
|
|
|
13
13
|
<div class="status-label">
|
|
14
14
|
{{ label }}
|
|
15
15
|
<i
|
|
16
|
-
v-
|
|
16
|
+
v-if="!!icon"
|
|
17
|
+
v-clean-tooltip.right="iconTooltip"
|
|
17
18
|
:class="['icon', icon, iconColor]"
|
|
18
19
|
/>
|
|
19
20
|
</div>
|
|
@@ -82,10 +82,10 @@ export default {
|
|
|
82
82
|
label: {
|
|
83
83
|
component: markRaw(StatusLabel),
|
|
84
84
|
componentProps: {
|
|
85
|
-
label:
|
|
86
|
-
icon:
|
|
87
|
-
iconColor:
|
|
88
|
-
|
|
85
|
+
label: this.t('generic.installed'),
|
|
86
|
+
icon: 'icon-warning',
|
|
87
|
+
iconColor: 'warning',
|
|
88
|
+
iconTooltip: this.t('catalog.charts.statusFilterCautions.installation')
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
},
|
|
@@ -98,10 +98,10 @@ export default {
|
|
|
98
98
|
label: {
|
|
99
99
|
component: markRaw(StatusLabel),
|
|
100
100
|
componentProps: {
|
|
101
|
-
label:
|
|
102
|
-
icon:
|
|
103
|
-
iconColor:
|
|
104
|
-
|
|
101
|
+
label: this.t('generic.upgradeable'),
|
|
102
|
+
icon: 'icon-warning',
|
|
103
|
+
iconColor: 'warning',
|
|
104
|
+
iconTooltip: this.t('catalog.charts.statusFilterCautions.upgradeable')
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -125,9 +125,10 @@ export default {
|
|
|
125
125
|
repoOptions() {
|
|
126
126
|
let out = this.$store.getters['catalog/repos'].map((r) => {
|
|
127
127
|
return {
|
|
128
|
-
value:
|
|
129
|
-
label:
|
|
130
|
-
|
|
128
|
+
value: r._key,
|
|
129
|
+
label: r.nameDisplay,
|
|
130
|
+
labelTooltip: r.nameDisplay,
|
|
131
|
+
weight: ( r.isRancher ? 1 : ( r.isPartner ? 2 : 3 ) ),
|
|
131
132
|
};
|
|
132
133
|
});
|
|
133
134
|
|
|
@@ -117,7 +117,7 @@ describe('page: cluster tools', () => {
|
|
|
117
117
|
});
|
|
118
118
|
expect(actions[2]).toStrictEqual({
|
|
119
119
|
label: 'catalog.tools.action.downgrade',
|
|
120
|
-
icon: 'icon-
|
|
120
|
+
icon: 'icon-downgrade-alt',
|
|
121
121
|
action: 'downgrade'
|
|
122
122
|
});
|
|
123
123
|
expect(actions[3]).toStrictEqual({ divider: true });
|
|
@@ -158,7 +158,7 @@ export default {
|
|
|
158
158
|
if (currentIndex !== -1 && currentIndex < versions.length - 1) {
|
|
159
159
|
actions.push({
|
|
160
160
|
label: this.t('catalog.tools.action.downgrade'),
|
|
161
|
-
icon: 'icon-
|
|
161
|
+
icon: 'icon-downgrade-alt',
|
|
162
162
|
action: 'downgrade',
|
|
163
163
|
});
|
|
164
164
|
}
|
package/plugins/axios.js
CHANGED
|
@@ -2,13 +2,14 @@ import https from 'https';
|
|
|
2
2
|
import { CSRF } from '@shell/config/cookies';
|
|
3
3
|
|
|
4
4
|
export default function({
|
|
5
|
-
$axios,
|
|
5
|
+
$axios, store, isDev, req
|
|
6
6
|
}) {
|
|
7
7
|
$axios.defaults.headers.common['Accept'] = 'application/json';
|
|
8
8
|
$axios.defaults.withCredentials = true;
|
|
9
9
|
|
|
10
10
|
$axios.onRequest((config) => {
|
|
11
|
-
const
|
|
11
|
+
const options = { parseJSON: false };
|
|
12
|
+
const csrf = store.getters['cookies/get']({ key: CSRF, options });
|
|
12
13
|
|
|
13
14
|
if ( csrf ) {
|
|
14
15
|
config.headers['x-api-csrf'] = csrf;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { NORMAN_NAME } from '@shell/config/labels-annotations';
|
|
2
|
+
import { getVersionData } from '@shell/config/version';
|
|
3
|
+
import { parseRancherVersion } from '@shell/config/uiplugins';
|
|
4
|
+
import semver from 'semver';
|
|
2
5
|
import {
|
|
3
6
|
_CLONE,
|
|
4
7
|
_CONFIG,
|
|
@@ -929,12 +932,20 @@ export default class Resource {
|
|
|
929
932
|
const currentRoute = this.currentRouter().currentRoute.value;
|
|
930
933
|
const extensionMenuActions = getApplicableExtensionEnhancements(this.$rootState, ExtensionPoint.ACTION, ActionLocation.TABLE, currentRoute, this);
|
|
931
934
|
|
|
935
|
+
const currRancherVersionData = getVersionData();
|
|
936
|
+
const parsedRancherVersion = parseRancherVersion(currRancherVersionData.Version);
|
|
937
|
+
|
|
938
|
+
// "showConfiguration" table action is only compatible with Rancher 2.13 and onwards
|
|
939
|
+
// defence against extension issue https://github.com/rancher/dashboard/issues/15564
|
|
940
|
+
// where mostly likely extension CRD model is extending from resource-class
|
|
941
|
+
const isResourceDetailDrawerCompatibleWithRancherSystem = semver.satisfies(parsedRancherVersion, '>= 2.13.0');
|
|
942
|
+
|
|
932
943
|
const all = [
|
|
933
944
|
{
|
|
934
945
|
action: 'showConfiguration',
|
|
935
946
|
label: this.t('action.showConfiguration'),
|
|
936
947
|
icon: 'icon icon-document',
|
|
937
|
-
enabled: this.disableResourceDetailDrawer !== true && (this.canCustomEdit || this.canYaml), // If the resource can't show an edit or a yaml we don't want to show the configuration drawer
|
|
948
|
+
enabled: isResourceDetailDrawerCompatibleWithRancherSystem && this.disableResourceDetailDrawer !== true && (this.canCustomEdit || this.canYaml), // If the resource can't show an edit or a yaml we don't want to show the configuration drawer
|
|
938
949
|
},
|
|
939
950
|
{ divider: true },
|
|
940
951
|
{
|
package/plugins/ember-cookie.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { REDIRECTED } from '@shell/config/cookies';
|
|
2
2
|
|
|
3
|
-
export default function({
|
|
3
|
+
export default function({ store }) {
|
|
4
4
|
// This tells Ember not to redirect back to us once you've already been to dashboard once.
|
|
5
5
|
// TODO: Remove this once the ember portion of the app is no longer needed
|
|
6
|
-
if (
|
|
7
|
-
|
|
6
|
+
if ( !store.getters['cookies/get']({ key: REDIRECTED })) {
|
|
7
|
+
const options = {
|
|
8
8
|
path: '/',
|
|
9
9
|
sameSite: true,
|
|
10
10
|
secure: true,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
store.commit('cookies/set', {
|
|
14
|
+
key: REDIRECTED, value: 'true', options
|
|
11
15
|
});
|
|
12
16
|
}
|
|
13
17
|
}
|
|
@@ -15,9 +15,7 @@ import {
|
|
|
15
15
|
HPA,
|
|
16
16
|
SECRET
|
|
17
17
|
} from '@shell/config/types';
|
|
18
|
-
import {
|
|
19
|
-
CAPI as CAPI_LAB_AND_ANO, CATTLE_PUBLIC_ENDPOINTS, STORAGE, UI_PROJECT_SECRET, UI_PROJECT_SECRET_COPY
|
|
20
|
-
} from '@shell/config/labels-annotations';
|
|
18
|
+
import { CAPI as CAPI_LAB_AND_ANO, CATTLE_PUBLIC_ENDPOINTS, STORAGE, UI_PROJECT_SECRET_COPY } from '@shell/config/labels-annotations';
|
|
21
19
|
import { Schema } from '@shell/plugins/steve/schema';
|
|
22
20
|
import { PaginationSettingsStore } from '@shell/types/resources/settings';
|
|
23
21
|
import paginationUtils from '@shell/utils/pagination-utils';
|
|
@@ -158,6 +156,7 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
158
156
|
{ field: 'id' },
|
|
159
157
|
{ field: 'metadata.state.name' },
|
|
160
158
|
{ field: 'metadata.creationTimestamp' },
|
|
159
|
+
{ field: 'metadata.labels', startsWith: true },
|
|
161
160
|
],
|
|
162
161
|
[NODE]: [
|
|
163
162
|
{ field: 'status.nodeInfo.kubeletVersion' },
|
|
@@ -180,18 +179,12 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
180
179
|
{ field: 'spec.internal' },
|
|
181
180
|
{ field: 'spec.displayName' },
|
|
182
181
|
{ field: `status.provider` },
|
|
183
|
-
{ field: `metadata.labels["${ CAPI_LAB_AND_ANO.PROVIDER }]` },
|
|
184
182
|
{ field: `status.connected` },
|
|
185
183
|
],
|
|
186
|
-
[CONFIG_MAP]: [
|
|
187
|
-
{ field: 'metadata.labels[harvesterhci.io/cloud-init-template]' }
|
|
188
|
-
],
|
|
189
184
|
[SECRET]: [
|
|
190
|
-
{ field: `metadata.labels[${ UI_PROJECT_SECRET }]` },
|
|
191
185
|
{ field: `metadata.annotations[${ UI_PROJECT_SECRET_COPY }]` },
|
|
192
186
|
],
|
|
193
187
|
[NAMESPACE]: [
|
|
194
|
-
{ field: 'metadata.labels[field.cattle.io/projectId]' }
|
|
195
188
|
],
|
|
196
189
|
[CAPI.MACHINE]: [
|
|
197
190
|
{ field: 'spec.clusterName' }
|
|
@@ -214,7 +207,6 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
214
207
|
{ field: 'status.releaseName' },
|
|
215
208
|
],
|
|
216
209
|
[CAPI.RANCHER_CLUSTER]: [
|
|
217
|
-
{ field: `metadata.labels[${ CAPI_LAB_AND_ANO.PROVIDER }]` },
|
|
218
210
|
{ field: `status.provider` },
|
|
219
211
|
{ field: 'status.clusterName' },
|
|
220
212
|
{ field: `metadata.annotations[${ CAPI_LAB_AND_ANO.HUMAN_NAME }]` }
|
|
@@ -224,14 +216,14 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
224
216
|
{ field: 'spec.clusterIP' },
|
|
225
217
|
],
|
|
226
218
|
[INGRESS]: [
|
|
227
|
-
{ field: 'spec.rules.host' },
|
|
219
|
+
{ field: 'spec.rules.host' },
|
|
228
220
|
{ field: 'spec.ingressClassName' },
|
|
229
221
|
],
|
|
230
222
|
[HPA]: [
|
|
231
|
-
{ field: 'spec.scaleTargetRef.name' },
|
|
232
|
-
{ field: 'spec.minReplicas' },
|
|
233
|
-
{ field: 'spec.maxReplicas' },
|
|
234
|
-
{ field: 'spec.currentReplicas' },
|
|
223
|
+
{ field: 'spec.scaleTargetRef.name' },
|
|
224
|
+
{ field: 'spec.minReplicas' },
|
|
225
|
+
{ field: 'spec.maxReplicas' },
|
|
226
|
+
{ field: 'spec.currentReplicas' },
|
|
235
227
|
],
|
|
236
228
|
[PVC]: [
|
|
237
229
|
{ field: 'spec.volumeName' },
|
|
@@ -249,29 +241,29 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
249
241
|
],
|
|
250
242
|
[WORKLOAD_TYPES.CRON_JOB]: [
|
|
251
243
|
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
252
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
244
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
253
245
|
],
|
|
254
246
|
[WORKLOAD_TYPES.DAEMON_SET]: [
|
|
255
247
|
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
256
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
248
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
257
249
|
],
|
|
258
250
|
[WORKLOAD_TYPES.DEPLOYMENT]: [
|
|
259
251
|
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
260
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
252
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
261
253
|
],
|
|
262
254
|
[WORKLOAD_TYPES.JOB]: [
|
|
263
255
|
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
264
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
256
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
265
257
|
],
|
|
266
258
|
[WORKLOAD_TYPES.STATEFUL_SET]: [
|
|
267
259
|
{ field: `metadata.annotations[${ CATTLE_PUBLIC_ENDPOINTS }]` },
|
|
268
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
260
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
269
261
|
],
|
|
270
262
|
[WORKLOAD_TYPES.REPLICA_SET]: [
|
|
271
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
263
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
272
264
|
],
|
|
273
265
|
[WORKLOAD_TYPES.REPLICATION_CONTROLLER]: [
|
|
274
|
-
{ field: 'spec.template.spec.containers.image' },
|
|
266
|
+
{ field: 'spec.template.spec.containers.image' },
|
|
275
267
|
],
|
|
276
268
|
}
|
|
277
269
|
|
|
@@ -369,13 +369,15 @@ const sharedActions = {
|
|
|
369
369
|
if (!this.$workers[getters.storeName]) {
|
|
370
370
|
await createWorker(this, ctx);
|
|
371
371
|
}
|
|
372
|
+
const options = { parseJSON: false };
|
|
373
|
+
const csrf = rootGetters['cookies/get']({ key: CSRF, options });
|
|
372
374
|
|
|
373
375
|
// if the worker is in advanced mode then it'll contain it's own socket which it calls a 'watcher'
|
|
374
376
|
this.$workers[getters.storeName].postMessage({
|
|
375
377
|
createWatcher: {
|
|
376
378
|
metadata,
|
|
377
|
-
url:
|
|
378
|
-
csrf
|
|
379
|
+
url: `${ state.config.baseUrl }/subscribe`,
|
|
380
|
+
csrf,
|
|
379
381
|
maxTries
|
|
380
382
|
}
|
|
381
383
|
});
|