@rancher/shell 3.0.0-rc.8 → 3.0.0
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 +12 -11
- package/assets/translations/zh-hans.yaml +1 -4
- package/components/EmberPage.vue +0 -8
- package/components/ResourceTable.vue +26 -1
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +17 -1
- package/components/SortableTable/selection.js +1 -1
- package/components/SortableTable/sorting.js +11 -3
- package/components/fleet/FleetClusters.vue +0 -3
- package/components/form/ColorInput.vue +13 -2
- package/components/form/HookOption.vue +31 -29
- package/components/form/LabeledSelect.vue +0 -1
- package/components/form/LifecycleHooks.vue +2 -2
- package/components/form/__tests__/ColorInput.test.ts +27 -0
- package/components/formatter/SecretData.vue +1 -1
- package/components/nav/Header.vue +10 -13
- package/components/nav/TopLevelMenu.vue +0 -40
- package/components/nav/WorkspaceSwitcher.vue +0 -1
- package/config/private-label.js +2 -1
- package/config/router/routes.js +2 -26
- package/config/settings.ts +5 -0
- package/config/version.js +2 -0
- package/detail/catalog.cattle.io.app.vue +17 -4
- package/detail/fleet.cattle.io.cluster.vue +11 -9
- package/detail/fleet.cattle.io.gitrepo.vue +1 -1
- package/edit/cis.cattle.io.clusterscan.vue +4 -3
- package/edit/cis.cattle.io.clusterscanbenchmark.vue +2 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +2 -0
- package/edit/fleet.cattle.io.cluster.vue +4 -0
- package/edit/fleet.cattle.io.gitrepo.vue +11 -8
- package/edit/helm.cattle.io.projecthelmchart.vue +2 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +2 -0
- package/edit/kontainerDriver.vue +2 -0
- package/edit/logging-flow/index.vue +2 -0
- package/edit/management.cattle.io.project.vue +2 -1
- package/edit/management.cattle.io.projectroletemplatebinding.vue +2 -1
- package/edit/management.cattle.io.user.vue +3 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +2 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -0
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +5 -5
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +3 -1
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -0
- package/edit/monitoring.coreos.com.route.vue +2 -0
- package/edit/networking.istio.io.destinationrule/index.vue +2 -0
- package/edit/nodeDriver.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +26 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +63 -149
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +4 -1
- package/edit/provisioning.cattle.io.cluster/import.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -3
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +7 -2
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +108 -35
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +1 -1
- package/edit/ui.cattle.io.navlink.vue +4 -3
- package/edit/workload/mixins/workload.js +1 -1
- package/mixins/browser-tab-visibility.js +1 -1
- package/mixins/chart.js +6 -2
- package/mixins/metric-poller.js +1 -1
- package/mixins/resource-fetch.js +1 -1
- package/models/catalog.cattle.io.app.js +108 -21
- package/models/cloudcredential.js +4 -4
- package/models/fleet.cattle.io.gitrepo.js +8 -13
- package/models/management.cattle.io.cluster.js +13 -2
- package/models/management.cattle.io.project.js +4 -0
- package/models/provisioning.cattle.io.cluster.js +1 -2
- package/models/workload.js +1 -1
- package/package.json +11 -4
- package/pages/auth/logout.vue +7 -9
- package/pages/auth/setup.vue +3 -0
- package/pages/c/_cluster/apps/charts/install.vue +11 -3
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +7 -4
- package/pages/c/_cluster/explorer/index.vue +45 -24
- package/pages/c/_cluster/fleet/index.vue +11 -5
- package/pages/c/_cluster/uiplugins/index.vue +4 -2
- package/pages/diagnostic.vue +1 -0
- package/plugins/steve/mutations.js +4 -1
- package/plugins/steve/subscribe.js +3 -4
- package/types/shell/index.d.ts +13 -0
- package/utils/__tests__/object.test.ts +152 -1
- package/utils/object.js +37 -0
- package/utils/string.js +9 -0
- package/utils/validators/formRules/index.ts +1 -1
- package/config/product/multi-cluster-apps.js +0 -61
package/mixins/chart.js
CHANGED
|
@@ -291,6 +291,8 @@ export default {
|
|
|
291
291
|
id: `${ this.query.appNamespace }/${ this.query.appName }`,
|
|
292
292
|
});
|
|
293
293
|
|
|
294
|
+
await this.existing?.fetchValues(true);
|
|
295
|
+
|
|
294
296
|
this.mode = _EDIT;
|
|
295
297
|
} catch (e) {
|
|
296
298
|
this.mode = _CREATE;
|
|
@@ -450,10 +452,12 @@ export default {
|
|
|
450
452
|
}
|
|
451
453
|
}
|
|
452
454
|
if (existingCRDApp) {
|
|
455
|
+
await existingCRDApp.fetchValues(true);
|
|
456
|
+
|
|
453
457
|
// spec.values are any non-default values the user configured
|
|
454
458
|
// the installation form should show these, as well as any default values from the chart
|
|
455
|
-
const existingValues = clone(existingCRDApp.
|
|
456
|
-
const defaultValues = clone(existingCRDApp.
|
|
459
|
+
const existingValues = clone(existingCRDApp.values || {});
|
|
460
|
+
const defaultValues = clone(existingCRDApp.chartValues || {});
|
|
457
461
|
|
|
458
462
|
crdVersionInfo.existingValues = existingValues;
|
|
459
463
|
crdVersionInfo.allValues = merge(defaultValues, existingValues);
|
package/mixins/metric-poller.js
CHANGED
package/mixins/resource-fetch.js
CHANGED
|
@@ -48,7 +48,7 @@ export default {
|
|
|
48
48
|
};
|
|
49
49
|
},
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
beforeUnmount() {
|
|
52
52
|
// make sure this only runs once, for the initialized instance
|
|
53
53
|
if (this.init) {
|
|
54
54
|
// clear up the store to make sure we aren't storing anything that might interfere with the next rendered list view
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import { CATALOG as CATALOG_ANNOTATIONS, FLEET } from '@shell/config/labels-annotations';
|
|
5
5
|
import { compare, isPrerelease, sortable } from '@shell/utils/version';
|
|
6
6
|
import { filterBy } from '@shell/utils/array';
|
|
7
|
-
import { CATALOG, MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
7
|
+
import { CATALOG, MANAGEMENT, NORMAN, SECRET } from '@shell/config/types';
|
|
8
8
|
import { SHOW_PRE_RELEASE } from '@shell/store/prefs';
|
|
9
9
|
import { set } from '@shell/utils/object';
|
|
10
10
|
|
|
@@ -280,28 +280,115 @@ export default class CatalogApp extends SteveModel {
|
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
}
|
|
283
|
+
async deployedAsLegacy() {
|
|
284
|
+
await this.fetchValues();
|
|
285
|
+
|
|
286
|
+
if (this.values?.global) {
|
|
287
|
+
const { clusterName, projectName } = this.values.global;
|
|
288
|
+
|
|
289
|
+
if (clusterName && projectName) {
|
|
290
|
+
try {
|
|
291
|
+
const legacyApp = await this.$dispatch('rancher/find', {
|
|
292
|
+
type: NORMAN.APP,
|
|
293
|
+
id: `${ projectName }:${ this.metadata?.name }`,
|
|
294
|
+
opt: { url: `/v3/project/${ clusterName }:${ projectName }/apps/${ projectName }:${ this.metadata?.name }` }
|
|
295
|
+
}, { root: true });
|
|
296
|
+
|
|
297
|
+
if (legacyApp) {
|
|
298
|
+
return legacyApp;
|
|
299
|
+
}
|
|
300
|
+
} catch (e) {}
|
|
301
301
|
}
|
|
302
|
+
}
|
|
302
303
|
|
|
303
|
-
|
|
304
|
-
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* User and Chart values live in a helm secret, so fetch it (with special param)
|
|
309
|
+
*/
|
|
310
|
+
async fetchValues(force = false) {
|
|
311
|
+
if (!this.secretId) {
|
|
312
|
+
// If there's no secret id this isn't ever going to work, no need to carry on
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const haveValues = !!this._values && !!this._chartValues;
|
|
317
|
+
|
|
318
|
+
if (haveValues && !force) {
|
|
319
|
+
// If we already have the required values and we're not forced to re-fetch, no need to carry on
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
await this.$dispatch('find', {
|
|
325
|
+
type: SECRET,
|
|
326
|
+
id: this.secretId,
|
|
327
|
+
opt: {
|
|
328
|
+
force: force || (!!this._secret && !haveValues), // force if explicitly requested or there's ean existing secret without the required values we have a secret without the values in (Secret has been fetched another way)
|
|
329
|
+
watch: false, // Cannot watch with custom params (they are dropped on calls made when resyncing over socket)
|
|
330
|
+
params: { includeHelmData: true }
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
} catch (e) {
|
|
334
|
+
console.error(`Cannot find values for ${ this.id } (unable to fetch)`, e); // eslint-disable-line no-console
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
get secretId() {
|
|
339
|
+
const metadata = this.metadata;
|
|
340
|
+
const secretReference = metadata.ownerReferences?.find((ow) => ow.kind.toLowerCase() === SECRET);
|
|
341
|
+
|
|
342
|
+
const secretId = secretReference?.name;
|
|
343
|
+
const secretNamespace = metadata.namespace;
|
|
344
|
+
|
|
345
|
+
if (!secretNamespace || !secretId) {
|
|
346
|
+
console.warn(`Cannot find values for ${ this.id } (cannot find related secret namespace or id)`); // eslint-disable-line no-console
|
|
347
|
+
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return `${ secretNamespace }/${ secretId }`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
get _secret() {
|
|
355
|
+
return this.secretId ? this.$getters['byId'](SECRET, this.secretId) : null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
_validateSecret(noun) {
|
|
359
|
+
if (this._secret === undefined) {
|
|
360
|
+
throw new Error(`Cannot find ${ noun } for ${ this.id } (chart secret has not been fetched via app \`fetchValues\`)`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (this._secret === null) {
|
|
364
|
+
throw new Error(`Cannot find ${ noun } for ${ this.id } (chart secret cannot or has failed to fetch) `);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* The user's helm values
|
|
370
|
+
*/
|
|
371
|
+
get values() {
|
|
372
|
+
this._validateSecret('values');
|
|
373
|
+
|
|
374
|
+
return this._values;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
get _values() {
|
|
378
|
+
return this._secret?.data?.release?.config;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* The Charts default helm values
|
|
383
|
+
*/
|
|
384
|
+
get chartValues() {
|
|
385
|
+
this._validateSecret('chartValues');
|
|
386
|
+
|
|
387
|
+
return this._chartValues;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
get _chartValues() {
|
|
391
|
+
return this._secret?.data?.release?.chart?.values;
|
|
305
392
|
}
|
|
306
393
|
}
|
|
307
394
|
|
|
@@ -241,9 +241,9 @@ export default class CloudCredential extends NormanModel {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
get expiresForSort() {
|
|
244
|
-
// Why not just `expires`? Ensures the correct sort order of
|
|
245
|
-
// (instead of expired -->
|
|
246
|
-
return this.expires
|
|
244
|
+
// Why not just `expires`? Ensures the correct sort order of expired --> expiring --> never expires
|
|
245
|
+
// (instead of 'never expired' --> 'expired' --> 'expiring')
|
|
246
|
+
return this.expires !== undefined ? this.expires : Number.MAX_SAFE_INTEGER;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
get expires() {
|
|
@@ -296,7 +296,7 @@ export default class CloudCredential extends NormanModel {
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
get expiresIn() {
|
|
299
|
-
if (
|
|
299
|
+
if (this.expires === undefined) {
|
|
300
300
|
return null;
|
|
301
301
|
}
|
|
302
302
|
|
|
@@ -176,6 +176,10 @@ export default class GitRepo extends SteveModel {
|
|
|
176
176
|
get repoDisplay() {
|
|
177
177
|
let repo = this.spec.repo;
|
|
178
178
|
|
|
179
|
+
if (!repo) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
|
|
179
183
|
repo = repo.replace(/.git$/, '');
|
|
180
184
|
repo = repo.replace(/^https:\/\//, '');
|
|
181
185
|
repo = repo.replace(/\/+$/, '');
|
|
@@ -307,20 +311,11 @@ export default class GitRepo extends SteveModel {
|
|
|
307
311
|
bundle.namespacedName.startsWith(`${ this.namespace }:${ this.name }`));
|
|
308
312
|
}
|
|
309
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Bundles with state of active
|
|
316
|
+
*/
|
|
310
317
|
get bundlesReady() {
|
|
311
|
-
|
|
312
|
-
return this.bundles.filter((bundle) => bundle.state === 'active');
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return 0;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
get targetClustersReady() {
|
|
319
|
-
if (this.targetClusters && this.targetClusters.length) {
|
|
320
|
-
return this.targetClusters.filter((cluster) => cluster.state === 'active');
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return 0;
|
|
318
|
+
return this.bundles?.filter((bundle) => bundle.state === 'active');
|
|
324
319
|
}
|
|
325
320
|
|
|
326
321
|
get bundleDeployments() {
|
|
@@ -16,6 +16,8 @@ import { KONTAINER_TO_DRIVER } from './management.cattle.io.kontainerdriver';
|
|
|
16
16
|
import { PINNED_CLUSTERS } from '@shell/store/prefs';
|
|
17
17
|
import { copyTextToClipboard } from '@shell/utils/clipboard';
|
|
18
18
|
|
|
19
|
+
const DEFAULT_BADGE_COLOR = '#707070';
|
|
20
|
+
|
|
19
21
|
// See translation file cluster.providers for list of providers
|
|
20
22
|
// If the logo is not named with the provider name, add an override here
|
|
21
23
|
const PROVIDER_LOGO_OVERRIDE = {};
|
|
@@ -306,13 +308,22 @@ export default class MgmtCluster extends SteveModel {
|
|
|
306
308
|
return undefined;
|
|
307
309
|
}
|
|
308
310
|
|
|
309
|
-
|
|
311
|
+
let color = this.metadata?.annotations[CLUSTER_BADGE.COLOR] || DEFAULT_BADGE_COLOR;
|
|
310
312
|
const iconText = this.metadata?.annotations[CLUSTER_BADGE.ICON_TEXT] || '';
|
|
313
|
+
let foregroundColor;
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
foregroundColor = textColor(parseColor(color.trim())); // Remove any whitespace
|
|
317
|
+
} catch (_e) {
|
|
318
|
+
// If we could not parse the badge color, use the defaults
|
|
319
|
+
color = DEFAULT_BADGE_COLOR;
|
|
320
|
+
foregroundColor = textColor(parseColor(color));
|
|
321
|
+
}
|
|
311
322
|
|
|
312
323
|
return {
|
|
313
324
|
text: comment || undefined,
|
|
314
325
|
color,
|
|
315
|
-
textColor:
|
|
326
|
+
textColor: foregroundColor,
|
|
316
327
|
iconText: iconText.substr(0, 3)
|
|
317
328
|
};
|
|
318
329
|
}
|
|
@@ -10,7 +10,6 @@ import { compare } from '@shell/utils/version';
|
|
|
10
10
|
import { AS, MODE, _VIEW, _YAML } from '@shell/config/query-params';
|
|
11
11
|
import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
|
|
12
12
|
import { CAPI as CAPI_ANNOTATIONS, NODE_ARCHITECTURE } from '@shell/config/labels-annotations';
|
|
13
|
-
import capitalize from 'lodash/capitalize';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Class representing Cluster resource.
|
|
@@ -424,7 +423,7 @@ export default class ProvCluster extends SteveModel {
|
|
|
424
423
|
if (!node.metadata?.state?.transitioning) {
|
|
425
424
|
const architecture = node.status?.nodeLabels?.[NODE_ARCHITECTURE];
|
|
426
425
|
|
|
427
|
-
const key = architecture
|
|
426
|
+
const key = architecture || this.t('cluster.architecture.label.unknown');
|
|
428
427
|
|
|
429
428
|
obj[key] = (obj[key] || 0) + 1;
|
|
430
429
|
}
|
package/models/workload.js
CHANGED
|
@@ -110,7 +110,7 @@ export default class Workload extends WorkloadService {
|
|
|
110
110
|
spec.template = {
|
|
111
111
|
spec: {
|
|
112
112
|
restartPolicy: this.type === WORKLOAD_TYPES.JOB ? 'Never' : 'Always',
|
|
113
|
-
containers: [{ ...defaultContainer }],
|
|
113
|
+
containers: [{ ...structuredClone(defaultContainer) }],
|
|
114
114
|
initContainers: []
|
|
115
115
|
}
|
|
116
116
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancherlabs/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"@rancher/icons": "2.0.29",
|
|
42
42
|
"@types/is-url": "1.2.30",
|
|
43
43
|
"@types/node": "16.4.3",
|
|
44
|
+
"@types/semver": "^7.5.8",
|
|
44
45
|
"@typescript-eslint/eslint-plugin": "~5.4.0",
|
|
45
46
|
"@typescript-eslint/parser": "~5.4.0",
|
|
46
47
|
"@vue/cli-plugin-babel": "~5.0.0",
|
|
@@ -53,7 +54,9 @@
|
|
|
53
54
|
"babel-eslint": "10.1.0",
|
|
54
55
|
"babel-plugin-module-resolver": "4.0.0",
|
|
55
56
|
"babel-preset-vue": "2.0.2",
|
|
57
|
+
"cache-loader": "4.1.0",
|
|
56
58
|
"clipboard-polyfill": "4.0.1",
|
|
59
|
+
"color": "4.2.3",
|
|
57
60
|
"codemirror": ">=5.64.0 <6",
|
|
58
61
|
"codemirror-editor-vue3": "2.7.1",
|
|
59
62
|
"cookie": "0.5.0",
|
|
@@ -71,7 +74,7 @@
|
|
|
71
74
|
"dagre-d3": "0.6.4",
|
|
72
75
|
"dayjs": "1.8.29",
|
|
73
76
|
"diff2html": "3.4.24",
|
|
74
|
-
"dompurify": "2.4
|
|
77
|
+
"dompurify": "2.5.4",
|
|
75
78
|
"element-matches": "^0.1.2",
|
|
76
79
|
"eslint": "7.32.0",
|
|
77
80
|
"eslint-config-standard": "16.0.3",
|
|
@@ -89,6 +92,7 @@
|
|
|
89
92
|
"frontmatter-markdown-loader": "3.7.0",
|
|
90
93
|
"identicon.js": "2.3.3",
|
|
91
94
|
"intl-messageformat": "7.8.4",
|
|
95
|
+
"ip": "2.0.1",
|
|
92
96
|
"is-url": "1.2.4",
|
|
93
97
|
"jest": "27.5.1",
|
|
94
98
|
"jest-serializer-vue": "2.0.2",
|
|
@@ -98,13 +102,14 @@
|
|
|
98
102
|
"js-yaml": "4.1.0",
|
|
99
103
|
"js-yaml-loader": "1.2.2",
|
|
100
104
|
"jsdiff": "1.1.1",
|
|
101
|
-
"jsonpath-plus": "
|
|
105
|
+
"jsonpath-plus": "10.0.0",
|
|
102
106
|
"jsrsasign": "10.5.25",
|
|
103
107
|
"jszip": "3.8.0",
|
|
104
108
|
"lodash": "4.17.21",
|
|
105
109
|
"marked": "4.0.17",
|
|
106
110
|
"nodemon": "2.0.22",
|
|
107
111
|
"nyc": "15.1.0",
|
|
112
|
+
"node-polyfill-webpack-plugin": "3.0.0",
|
|
108
113
|
"papaparse": "5.3.0",
|
|
109
114
|
"portal-vue": "~3.0.0",
|
|
110
115
|
"sass": "1.51.0",
|
|
@@ -153,7 +158,9 @@
|
|
|
153
158
|
"qs": "6.11.1",
|
|
154
159
|
"roarr": "7.0.4",
|
|
155
160
|
"semver": "7.5.4",
|
|
156
|
-
"@
|
|
161
|
+
"@types/lodash": "4.17.5",
|
|
162
|
+
"@types/node": "~20.10.0",
|
|
163
|
+
"@vue/cli-service/html-webpack-plugin": "^5.0.0"
|
|
157
164
|
},
|
|
158
165
|
"nyc": {
|
|
159
166
|
"extension": [
|
package/pages/auth/logout.vue
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import {
|
|
2
|
+
import { configType } from '@shell/models/management.cattle.io.authconfig';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
async fetch() {
|
|
6
|
-
const
|
|
6
|
+
const publicAuthProviders = await this.$store.dispatch('auth/getAuthProviders');
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
const authProvider = authInfo.enabled[0];
|
|
8
|
+
const samlAuthProvider = publicAuthProviders.find((authProvider) => configType[authProvider.id] === 'saml');
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} = authProvider;
|
|
10
|
+
if (!!samlAuthProvider) {
|
|
11
|
+
const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = samlAuthProvider;
|
|
14
12
|
|
|
15
|
-
if (
|
|
13
|
+
if (logoutAllSupported && logoutAllEnabled && logoutAllForced) {
|
|
16
14
|
// SAML - force SLO (logout from all apps)
|
|
17
15
|
await this.$store.dispatch('auth/logout', {
|
|
18
|
-
force: true, slo: true, provider:
|
|
16
|
+
force: true, slo: true, provider: samlAuthProvider
|
|
19
17
|
}, { root: true });
|
|
20
18
|
} else {
|
|
21
19
|
// simple logout
|
package/pages/auth/setup.vue
CHANGED
|
@@ -496,6 +496,7 @@ export default {
|
|
|
496
496
|
|
|
497
497
|
.span-6 {
|
|
498
498
|
padding: 0 60px;
|
|
499
|
+
margin: 0;
|
|
499
500
|
}
|
|
500
501
|
|
|
501
502
|
.landscape {
|
|
@@ -503,6 +504,7 @@ export default {
|
|
|
503
504
|
margin: 0;
|
|
504
505
|
object-fit: cover;
|
|
505
506
|
padding: 0;
|
|
507
|
+
width: 49%;
|
|
506
508
|
}
|
|
507
509
|
}
|
|
508
510
|
|
|
@@ -512,6 +514,7 @@ export default {
|
|
|
512
514
|
overflow-y: auto;
|
|
513
515
|
position: relative;
|
|
514
516
|
height: 100vh;
|
|
517
|
+
width: 51%;
|
|
515
518
|
|
|
516
519
|
& > div:first-of-type {
|
|
517
520
|
flex:3;
|
|
@@ -294,8 +294,9 @@ export default {
|
|
|
294
294
|
*/
|
|
295
295
|
userValues = diff(this.loadedVersionValues, this.chartValues);
|
|
296
296
|
} else if ( this.existing ) {
|
|
297
|
+
await this.existing.fetchValues(); // In theory this has already been called, but do again to be safe
|
|
297
298
|
/* For an already installed app, use the values from the previous install. */
|
|
298
|
-
userValues = clone(this.existing.
|
|
299
|
+
userValues = clone(this.existing.values || {});
|
|
299
300
|
} else {
|
|
300
301
|
/* For an new app, start empty. */
|
|
301
302
|
userValues = {};
|
|
@@ -1457,6 +1458,7 @@ export default {
|
|
|
1457
1458
|
<Banner
|
|
1458
1459
|
v-if="isNamespaceNew && value.metadata.namespace.length"
|
|
1459
1460
|
color="info"
|
|
1461
|
+
class="namespace-create-banner"
|
|
1460
1462
|
>
|
|
1461
1463
|
<div v-clean-html="t('catalog.install.steps.basics.createNamespace', {namespace: value.metadata.namespace}, true) " />
|
|
1462
1464
|
</Banner>
|
|
@@ -1661,9 +1663,10 @@ export default {
|
|
|
1661
1663
|
class="mt-10"
|
|
1662
1664
|
>
|
|
1663
1665
|
<UnitInput
|
|
1664
|
-
v-model
|
|
1666
|
+
v-model:value="customCmdOpts.timeout"
|
|
1665
1667
|
:label="t('catalog.install.helm.timeout.label')"
|
|
1666
1668
|
:suffix="t('catalog.install.helm.timeout.unit', {value: customCmdOpts.timeout})"
|
|
1669
|
+
type="number"
|
|
1667
1670
|
/>
|
|
1668
1671
|
</div>
|
|
1669
1672
|
<div
|
|
@@ -1672,9 +1675,10 @@ export default {
|
|
|
1672
1675
|
>
|
|
1673
1676
|
<UnitInput
|
|
1674
1677
|
v-if="existing"
|
|
1675
|
-
v-model
|
|
1678
|
+
v-model:value="customCmdOpts.historyMax"
|
|
1676
1679
|
:label="t('catalog.install.helm.historyMax.label')"
|
|
1677
1680
|
:suffix="t('catalog.install.helm.historyMax.unit', {value: customCmdOpts.historyMax})"
|
|
1681
|
+
type="number"
|
|
1678
1682
|
/>
|
|
1679
1683
|
</div>
|
|
1680
1684
|
<div
|
|
@@ -1852,6 +1856,10 @@ export default {
|
|
|
1852
1856
|
.spacer {
|
|
1853
1857
|
line-height: 2;
|
|
1854
1858
|
}
|
|
1859
|
+
|
|
1860
|
+
.namespace-create-banner {
|
|
1861
|
+
margin-bottom: 70px;
|
|
1862
|
+
}
|
|
1855
1863
|
}
|
|
1856
1864
|
&__values {
|
|
1857
1865
|
&__controls {
|
|
@@ -25,9 +25,12 @@ describe('page: cluster dashboard', () => {
|
|
|
25
25
|
'cluster/inError': () => false,
|
|
26
26
|
'cluster/schemaFor': jest.fn(),
|
|
27
27
|
'cluster/canList': jest.fn(),
|
|
28
|
-
'cluster/
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
'cluster/byId': () => {
|
|
29
|
+
return {};
|
|
30
|
+
},
|
|
31
|
+
'cluster/all': jest.fn(),
|
|
32
|
+
'i18n/exists': jest.fn(),
|
|
33
|
+
'i18n/t': (label: string) => label === 'generic.provisioning' ? '—' : jest.fn()(),
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
},
|
|
@@ -161,7 +164,7 @@ describe('page: cluster dashboard', () => {
|
|
|
161
164
|
['created', 'glance.created', []],
|
|
162
165
|
['architecture', 'mixed', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }, { labels: { [NODE_ARCHITECTURE]: 'intel' } }]],
|
|
163
166
|
['architecture', 'mixed', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }, { labels: { } }]],
|
|
164
|
-
['architecture', '
|
|
167
|
+
['architecture', 'amd64', [{ labels: { [NODE_ARCHITECTURE]: 'amd64' } }]],
|
|
165
168
|
['architecture', 'unknown', [{ labels: { } }]],
|
|
166
169
|
['architecture', 'glance.architecture', [{ metadata: { state: { transitioning: true } } }]],
|
|
167
170
|
])('should show %p label %p', (label, text, nodes) => {
|
|
@@ -47,7 +47,6 @@ import Certificates from '@shell/components/Certificates';
|
|
|
47
47
|
import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
48
48
|
import TabTitle from '@shell/components/TabTitle';
|
|
49
49
|
import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
50
|
-
import capitalize from 'lodash/capitalize';
|
|
51
50
|
|
|
52
51
|
export const RESOURCES = [NAMESPACE, INGRESS, PV, WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET, WORKLOAD_TYPES.JOB, WORKLOAD_TYPES.DAEMON_SET, SERVICE];
|
|
53
52
|
|
|
@@ -115,12 +114,6 @@ export default {
|
|
|
115
114
|
if (this.currentCluster.isLocal && this.$store.getters['management/schemaFor'](MANAGEMENT.NODE)) {
|
|
116
115
|
this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE });
|
|
117
116
|
}
|
|
118
|
-
|
|
119
|
-
this.canViewAgents = this.$store.getters['cluster/canList'](WORKLOAD_TYPES.DEPLOYMENT) && this.$store.getters['cluster/canList'](WORKLOAD_TYPES.STATEFUL_SET);
|
|
120
|
-
|
|
121
|
-
if (this.canViewAgents) {
|
|
122
|
-
this.loadAgents();
|
|
123
|
-
}
|
|
124
117
|
}
|
|
125
118
|
},
|
|
126
119
|
|
|
@@ -138,7 +131,6 @@ export default {
|
|
|
138
131
|
cattleDeployment: 'loading',
|
|
139
132
|
fleetDeployment: 'loading',
|
|
140
133
|
fleetStatefulSet: 'loading',
|
|
141
|
-
canViewAgents: false,
|
|
142
134
|
disconnected: false,
|
|
143
135
|
events: [],
|
|
144
136
|
nodeMetrics: [],
|
|
@@ -172,6 +164,17 @@ export default {
|
|
|
172
164
|
clearInterval(this.interval);
|
|
173
165
|
},
|
|
174
166
|
|
|
167
|
+
watch: {
|
|
168
|
+
canViewAgents: {
|
|
169
|
+
handler(neu, old) {
|
|
170
|
+
if (neu && !old) {
|
|
171
|
+
this.loadAgents();
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
immediate: true
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
175
178
|
computed: {
|
|
176
179
|
...mapGetters(['currentCluster']),
|
|
177
180
|
...monitoringStatus(),
|
|
@@ -184,6 +187,22 @@ export default {
|
|
|
184
187
|
return this.$store.getters['management/all'](MANAGEMENT.CLUSTER);
|
|
185
188
|
},
|
|
186
189
|
|
|
190
|
+
fleetAgentNamespace() {
|
|
191
|
+
return this.$store.getters['cluster/byId'](NAMESPACE, 'cattle-fleet-system');
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
cattleAgentNamespace() {
|
|
195
|
+
if (this.currentCluster.isLocal) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return this.$store.getters['cluster/byId'](NAMESPACE, 'cattle-system');
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
canViewAgents() {
|
|
203
|
+
return !!this.fleetAgentNamespace || (!this.currentCluster.isLocal && this.cattleAgentNamespace);
|
|
204
|
+
},
|
|
205
|
+
|
|
187
206
|
showClusterTools() {
|
|
188
207
|
return this.$store.getters['cluster/canList'](CATALOG.CLUSTER_REPO) &&
|
|
189
208
|
this.$store.getters['cluster/canList'](CATALOG.APP);
|
|
@@ -212,7 +231,7 @@ export default {
|
|
|
212
231
|
if (!node.metadata?.state?.transitioning) {
|
|
213
232
|
const architecture = node.labels?.[NODE_ARCHITECTURE];
|
|
214
233
|
|
|
215
|
-
const key = architecture
|
|
234
|
+
const key = architecture || this.t('cluster.architecture.label.unknown');
|
|
216
235
|
|
|
217
236
|
obj[key] = (obj[key] || 0) + 1;
|
|
218
237
|
}
|
|
@@ -268,15 +287,15 @@ export default {
|
|
|
268
287
|
});
|
|
269
288
|
});
|
|
270
289
|
|
|
271
|
-
if (this.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
290
|
+
if (this.cattleAgentNamespace) {
|
|
291
|
+
services.push({
|
|
292
|
+
name: 'cattle',
|
|
293
|
+
status: this.cattleStatus,
|
|
294
|
+
labelKey: 'clusterIndexPage.sections.componentStatus.cattle',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
279
297
|
|
|
298
|
+
if (this.fleetAgentNamespace) {
|
|
280
299
|
services.push({
|
|
281
300
|
name: 'fleet',
|
|
282
301
|
status: this.fleetStatus,
|
|
@@ -485,14 +504,16 @@ export default {
|
|
|
485
504
|
|
|
486
505
|
methods: {
|
|
487
506
|
loadAgents() {
|
|
488
|
-
if (this.
|
|
489
|
-
this.
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
507
|
+
if (this.fleetAgentNamespace) {
|
|
508
|
+
if (this.currentCluster.isLocal) {
|
|
509
|
+
this.setAgentResource('fleetDeployment', WORKLOAD_TYPES.DEPLOYMENT, 'cattle-fleet-system/fleet-controller');
|
|
510
|
+
this.setAgentResource('fleetStatefulSet', WORKLOAD_TYPES.STATEFUL_SET, 'cattle-fleet-local-system/fleet-agent');
|
|
511
|
+
} else {
|
|
512
|
+
this.setAgentResource('fleetStatefulSet', WORKLOAD_TYPES.STATEFUL_SET, 'cattle-fleet-system/fleet-agent');
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (this.cattleAgentNamespace) {
|
|
493
516
|
this.setAgentResource('cattleDeployment', WORKLOAD_TYPES.DEPLOYMENT, 'cattle-system/cattle-cluster-agent');
|
|
494
|
-
|
|
495
|
-
// Scaling Up/Down cattle deployment causes web sockets disconnection;
|
|
496
517
|
this.interval = setInterval(() => {
|
|
497
518
|
this.disconnected = !!this.$store.getters['cluster/inError']({ type: NODE });
|
|
498
519
|
}, 1000);
|