@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.3
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/styles/base/_basic.scss +5 -7
- package/assets/styles/global/_button.scss +10 -0
- package/assets/styles/global/_tooltip.scss +2 -2
- package/assets/styles/themes/_dark.scss +14 -2
- package/assets/styles/themes/_light.scss +7 -2
- package/assets/styles/vendor/vue-select.scss +4 -0
- package/assets/translations/en-us.yaml +44 -5
- package/components/BannerGraphic.vue +0 -42
- package/components/ButtonMultiAction.vue +1 -1
- package/components/Carousel.vue +36 -29
- package/components/CommunityLinks.vue +6 -1
- package/components/GrowlManager.vue +9 -2
- package/components/LocaleSelector.vue +8 -1
- package/components/PaginatedResourceTable.vue +4 -7
- package/components/ProgressBarMulti.vue +14 -0
- package/components/Questions/Reference.vue +57 -28
- package/components/SelectIconGrid.vue +12 -1
- package/components/SideNav.vue +12 -38
- package/components/SortableTable/index.vue +1 -0
- package/components/Tabbed/index.vue +12 -1
- package/components/YamlEditor.vue +1 -0
- package/components/auth/Principal.vue +5 -3
- package/components/fleet/FleetClusters.vue +82 -1
- package/components/fleet/FleetRepos.vue +13 -30
- package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
- package/components/form/ChangePassword.vue +2 -0
- package/components/form/ColorInput.vue +24 -1
- package/components/form/FileSelector.vue +2 -0
- package/components/form/KeyValue.vue +230 -160
- package/components/form/LabeledSelect.vue +1 -1
- package/components/form/PlusMinus.vue +14 -2
- package/components/form/ResourceLabeledSelect.vue +13 -53
- package/components/form/ResourceSelector.vue +1 -0
- package/components/form/ResourceTabs/index.vue +79 -36
- package/components/form/SecretSelector.vue +2 -2
- package/components/form/__tests__/KeyValue.test.ts +1 -1
- package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +6 -7
- package/components/formatter/WorkloadHealthScale.vue +7 -0
- package/components/nav/Group.vue +30 -4
- package/components/nav/Header.vue +82 -114
- package/components/nav/HeaderPageActionMenu.vue +27 -131
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/Type.vue +15 -0
- package/config/home-links.js +21 -13
- package/config/labels-annotations.js +2 -0
- package/config/page-actions.js +1 -0
- package/config/pagination-table-headers.js +15 -1
- package/config/product/explorer.js +7 -17
- package/config/table-headers.js +6 -0
- package/config/version.js +5 -1
- package/core/plugin.ts +41 -1
- package/core/plugins.js +125 -72
- package/core/types-provisioning.ts +91 -2
- package/core/types.ts +55 -0
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/fleet.cattle.io.cluster.vue +3 -3
- package/detail/namespace.vue +13 -19
- package/detail/networking.k8s.io.ingress.vue +13 -53
- package/detail/provisioning.cattle.io.cluster.vue +12 -1
- package/detail/workload/index.vue +3 -3
- package/dialog/AddCustomBadgeDialog.vue +5 -1
- package/edit/auth/ldap/__tests__/config.test.ts +18 -0
- package/edit/auth/ldap/config.vue +24 -0
- package/edit/auth/saml.vue +8 -6
- package/edit/fleet.cattle.io.gitrepo.vue +7 -1
- package/edit/logging-flow/index.vue +4 -19
- package/edit/networking.k8s.io.ingress/index.vue +18 -65
- package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
- package/edit/provisioning.cattle.io.cluster/index.vue +13 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
- package/edit/service.vue +1 -2
- package/list/networking.k8s.io.ingress.vue +1 -1
- package/list/node.vue +15 -8
- package/list/persistentvolume.vue +12 -4
- package/list/service.vue +1 -1
- package/list/workload.vue +4 -0
- package/mixins/chart.js +4 -1
- package/models/catalog.cattle.io.app.js +3 -1
- package/models/catalog.cattle.io.clusterrepo.js +56 -7
- package/models/fleet.cattle.io.bundle.js +0 -11
- package/models/fleet.cattle.io.cluster.js +17 -1
- package/models/fleet.cattle.io.gitrepo.js +86 -50
- package/models/provisioning.cattle.io.cluster.js +47 -2
- package/models/service.js +1 -0
- package/models/workload.js +19 -1
- package/package.json +5 -4
- package/pages/c/_cluster/apps/charts/index.vue +4 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +8 -7
- package/pages/c/_cluster/explorer/index.vue +13 -6
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
- package/pages/c/_cluster/fleet/index.vue +75 -89
- package/pages/c/_cluster/settings/links.vue +2 -2
- package/pages/diagnostic.vue +17 -15
- package/pages/home.vue +32 -6
- package/plugins/clean-html.js +50 -0
- package/plugins/dashboard-store/resource-class.js +4 -0
- package/plugins/plugin.js +54 -49
- package/plugins/steve/mutations.js +1 -1
- package/plugins/steve/steve-class.js +8 -0
- package/plugins/steve/steve-pagination-utils.ts +3 -1
- package/rancher-components/Accordion/Accordion.vue +4 -4
- package/rancher-components/BadgeState/BadgeState.vue +7 -0
- package/rancher-components/Card/Card.vue +27 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +18 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
- package/rancher-components/RcButton/RcButton.vue +90 -0
- package/rancher-components/RcButton/index.ts +2 -0
- package/rancher-components/RcButton/types.ts +17 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +111 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
- package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +43 -0
- package/rancher-components/RcDropdown/index.ts +4 -0
- package/rancher-components/RcDropdown/types.ts +22 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +45 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +83 -0
- package/scripts/test-plugins-build.sh +2 -0
- package/scripts/typegen.sh +2 -0
- package/store/catalog.js +1 -1
- package/tsconfig.json +2 -1
- package/types/components/paginatedResourceTable.ts +25 -0
- package/types/components/resourceLabeledSelect.ts +48 -0
- package/types/resources/fleet.d.ts +17 -0
- package/types/shell/index.d.ts +61 -0
- package/utils/auth.js +5 -1
- package/utils/cluster.js +106 -0
- package/utils/fleet.ts +35 -3
- package/utils/ingress.ts +64 -0
- package/utils/uiplugins.ts +56 -44
- package/utils/validators/cron-schedule.js +7 -2
- package/utils/validators/formRules/__tests__/index.test.ts +53 -17
- package/utils/validators/formRules/index.ts +20 -5
- package/vue.config.js +1 -1
- package/components/RelatedWorkloadsTable.vue +0 -50
|
@@ -2,6 +2,7 @@ import { parse } from '@shell/utils/url';
|
|
|
2
2
|
import { CATALOG } from '@shell/config/labels-annotations';
|
|
3
3
|
import { insertAt } from '@shell/utils/array';
|
|
4
4
|
import { CATALOG as CATALOG_TYPE } from '@shell/config/types';
|
|
5
|
+
import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
5
6
|
|
|
6
7
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
7
8
|
|
|
@@ -12,18 +13,40 @@ export default class ClusterRepo extends SteveModel {
|
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
get _isClusterRepoDisabled() {
|
|
17
|
+
return this.spec?.enabled === false;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
get _availableActions() {
|
|
16
21
|
const out = super._availableActions;
|
|
17
22
|
|
|
18
23
|
insertAt(out, 0, { divider: true });
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
if (this._isClusterRepoDisabled) {
|
|
26
|
+
insertAt(out, 1, {
|
|
27
|
+
action: 'enableClusterRepo',
|
|
28
|
+
label: this.t('action.enable'),
|
|
29
|
+
icon: 'icon icon-play',
|
|
30
|
+
enabled: true,
|
|
31
|
+
bulkable: true,
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
insertAt(out, 1, {
|
|
35
|
+
action: 'disableClusterRepo',
|
|
36
|
+
label: this.t('action.disable'),
|
|
37
|
+
icon: 'icon icon-pause',
|
|
38
|
+
enabled: true,
|
|
39
|
+
bulkable: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
insertAt(out, 0, {
|
|
43
|
+
action: 'refresh',
|
|
44
|
+
label: this.t('action.refresh'),
|
|
45
|
+
icon: 'icon icon-refresh',
|
|
46
|
+
enabled: !!this.links.update,
|
|
47
|
+
bulkable: true,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
27
50
|
|
|
28
51
|
return out;
|
|
29
52
|
}
|
|
@@ -39,6 +62,16 @@ export default class ClusterRepo extends SteveModel {
|
|
|
39
62
|
this.$dispatch('catalog/load', { force: true, reset: true }, { root: true });
|
|
40
63
|
}
|
|
41
64
|
|
|
65
|
+
async disableClusterRepo() {
|
|
66
|
+
this.spec.enabled = false;
|
|
67
|
+
await this.save();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async enableClusterRepo() {
|
|
71
|
+
this.spec.enabled = true;
|
|
72
|
+
await this.save();
|
|
73
|
+
}
|
|
74
|
+
|
|
42
75
|
get isGit() {
|
|
43
76
|
return !!this.spec?.gitRepo;
|
|
44
77
|
}
|
|
@@ -157,6 +190,22 @@ export default class ClusterRepo extends SteveModel {
|
|
|
157
190
|
} : undefined;
|
|
158
191
|
}
|
|
159
192
|
|
|
193
|
+
get stateDisplay() {
|
|
194
|
+
if (this._isClusterRepoDisabled) {
|
|
195
|
+
return this.t('generic.disabled');
|
|
196
|
+
} else {
|
|
197
|
+
return stateDisplay(this.state);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get stateBackground() {
|
|
202
|
+
if (this._isClusterRepoDisabled) {
|
|
203
|
+
return 'badge-disabled';
|
|
204
|
+
} else {
|
|
205
|
+
return colorForState(this.state, this.stateObj?.error, this.stateObj?.transitioning).replace('text-', 'bg-');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
160
209
|
waitForOperation(operationId, timeout, interval = 2000) {
|
|
161
210
|
return this.waitForTestFn(() => {
|
|
162
211
|
if (!this.$getters['schemaFor'](CATALOG_TYPE.OPERATION)) {
|
|
@@ -6,17 +6,6 @@ import { FLEET } from '@shell/config/types';
|
|
|
6
6
|
import { convertSelectorObj, matching } from '@shell/utils/selector';
|
|
7
7
|
|
|
8
8
|
export default class FleetBundle extends SteveModel {
|
|
9
|
-
get deploymentInfo() {
|
|
10
|
-
const ready = this.status?.summary?.ready || 0;
|
|
11
|
-
const total = this.status?.summary?.desiredReady || 0;
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
ready,
|
|
15
|
-
unready: total - ready,
|
|
16
|
-
total
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
9
|
get lastUpdateTime() {
|
|
21
10
|
return this.status?.conditions?.[0].lastUpdateTime;
|
|
22
11
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LOCAL_CLUSTER, MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
2
|
-
import { CAPI, FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
|
|
2
|
+
import { CAPI, FLEET as FLEET_LABELS, SYSTEM_LABELS } from '@shell/config/labels-annotations';
|
|
3
3
|
import { _RKE2 } from '@shell/store/prefs';
|
|
4
4
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
5
5
|
import { escapeHtml } from '@shell/utils/string';
|
|
@@ -190,6 +190,22 @@ export default class FleetCluster extends SteveModel {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
get customLabels() {
|
|
194
|
+
const parsedLabels = [];
|
|
195
|
+
|
|
196
|
+
if (this.labels) {
|
|
197
|
+
for (const k in this.labels) {
|
|
198
|
+
const [prefix] = k.split('/');
|
|
199
|
+
|
|
200
|
+
if (!SYSTEM_LABELS.includes(prefix) && k !== CAPI.PROVIDER) {
|
|
201
|
+
parsedLabels.push(`${ k }=${ this.labels[k] }`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return parsedLabels;
|
|
207
|
+
}
|
|
208
|
+
|
|
193
209
|
async saveYaml(yaml) {
|
|
194
210
|
await this._saveYaml(yaml);
|
|
195
211
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { convert, matching, convertSelectorObj } from '@shell/utils/selector';
|
|
2
2
|
import jsyaml from 'js-yaml';
|
|
3
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
4
|
import { escapeHtml } from '@shell/utils/string';
|
|
4
5
|
import { FLEET } from '@shell/config/types';
|
|
5
6
|
import { FLEET as FLEET_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
@@ -7,7 +8,7 @@ import { addObject, addObjects, findBy, insertAt } from '@shell/utils/array';
|
|
|
7
8
|
import { set } from '@shell/utils/object';
|
|
8
9
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
9
10
|
import {
|
|
10
|
-
colorForState, mapStateToEnum, primaryDisplayStatusFromCount, stateDisplay, stateSort
|
|
11
|
+
colorForState, mapStateToEnum, primaryDisplayStatusFromCount, stateDisplay, STATES_ENUM, stateSort,
|
|
11
12
|
} from '@shell/plugins/dashboard-store/resource-class';
|
|
12
13
|
import { NAME } from '@shell/config/product/explorer';
|
|
13
14
|
import FleetUtils from '@shell/utils/fleet';
|
|
@@ -20,6 +21,26 @@ function quacksLikeAHash(str) {
|
|
|
20
21
|
return false;
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
function normalizeStateCounts(data) {
|
|
25
|
+
if (isEmpty(data)) {
|
|
26
|
+
return {
|
|
27
|
+
total: 0,
|
|
28
|
+
states: {},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const { desiredReady, ...rest } = data ;
|
|
32
|
+
const states = Object.entries(rest).reduce((res, [key, value]) => {
|
|
33
|
+
res[mapStateToEnum(key)] = value;
|
|
34
|
+
|
|
35
|
+
return res;
|
|
36
|
+
}, {});
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
total: desiredReady,
|
|
40
|
+
states,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
23
44
|
export default class GitRepo extends SteveModel {
|
|
24
45
|
applyDefaults() {
|
|
25
46
|
const spec = this.spec || {};
|
|
@@ -305,18 +326,7 @@ export default class GitRepo extends SteveModel {
|
|
|
305
326
|
}
|
|
306
327
|
|
|
307
328
|
get bundles() {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return all.filter((bundle) => bundle.repoName === this.name &&
|
|
311
|
-
bundle.namespace === this.namespace &&
|
|
312
|
-
bundle.namespacedName.startsWith(`${ this.namespace }:${ this.name }`));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Bundles with state of active
|
|
317
|
-
*/
|
|
318
|
-
get bundlesReady() {
|
|
319
|
-
return this.bundles?.filter((bundle) => bundle.state === 'active');
|
|
329
|
+
return this.$getters['matching'](FLEET.BUNDLE, { 'fleet.cattle.io/repo-name': this.name }, this.namespace);
|
|
320
330
|
}
|
|
321
331
|
|
|
322
332
|
get bundleDeployments() {
|
|
@@ -325,6 +335,65 @@ export default class GitRepo extends SteveModel {
|
|
|
325
335
|
return bds.filter((bd) => bd.metadata?.labels?.['fleet.cattle.io/repo-name'] === this.name);
|
|
326
336
|
}
|
|
327
337
|
|
|
338
|
+
get allBundlesStatuses() {
|
|
339
|
+
const bundleDeploymentCountsPerBundle = this.bundleDeployments.reduce((acc, bd) => {
|
|
340
|
+
const bundleId = FleetUtils.bundleIdFromBundleDeploymentLabels(bd.metadata?.labels);
|
|
341
|
+
const state = mapStateToEnum(FleetUtils.bundleDeploymentState(bd));
|
|
342
|
+
|
|
343
|
+
if (!acc[bundleId]) {
|
|
344
|
+
acc[bundleId] = {
|
|
345
|
+
total: 0,
|
|
346
|
+
states: { [STATES_ENUM.READY]: 0 },
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
acc[bundleId].total++;
|
|
350
|
+
|
|
351
|
+
if (!acc[bundleId].states[state]) {
|
|
352
|
+
acc[bundleId].states[state] = 0;
|
|
353
|
+
}
|
|
354
|
+
acc[bundleId].states[state]++;
|
|
355
|
+
|
|
356
|
+
return acc;
|
|
357
|
+
}, {});
|
|
358
|
+
const bundleIds = Object.keys(bundleDeploymentCountsPerBundle);
|
|
359
|
+
|
|
360
|
+
return bundleIds.reduce((acc, bundleId) => {
|
|
361
|
+
const state = primaryDisplayStatusFromCount(bundleDeploymentCountsPerBundle[bundleId].states);
|
|
362
|
+
|
|
363
|
+
if (!acc.states[state]) {
|
|
364
|
+
acc.states[state] = 0;
|
|
365
|
+
}
|
|
366
|
+
acc.states[state]++;
|
|
367
|
+
|
|
368
|
+
return acc;
|
|
369
|
+
}, { total: bundleIds.length, states: { [STATES_ENUM.READY]: 0 } } );
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
get allResourceStatuses() {
|
|
373
|
+
return normalizeStateCounts(this.status?.resourceCounts || {});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
statusResourceCountsForCluster(clusterId) {
|
|
377
|
+
if (!this.targetClusters.some((c) => c.id === clusterId)) {
|
|
378
|
+
return {};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return this.bundleDeployments
|
|
382
|
+
.filter((bd) => FleetUtils.clusterIdFromBundleDeploymentLabels(bd.metadata?.labels) === clusterId)
|
|
383
|
+
.map((bd) => FleetUtils.resourcesFromBundleDeploymentStatus(bd.status))
|
|
384
|
+
.flat()
|
|
385
|
+
.map((r) => r.state)
|
|
386
|
+
.reduce((prev, state) => {
|
|
387
|
+
if (!prev[state]) {
|
|
388
|
+
prev[state] = 0;
|
|
389
|
+
}
|
|
390
|
+
prev[state]++;
|
|
391
|
+
prev.desiredReady++;
|
|
392
|
+
|
|
393
|
+
return prev;
|
|
394
|
+
}, { desiredReady: 0 });
|
|
395
|
+
}
|
|
396
|
+
|
|
328
397
|
get resourcesStatuses() {
|
|
329
398
|
const bundleDeployments = this.bundleDeployments || [];
|
|
330
399
|
const clusters = (this.targetClusters || []).reduce((res, c) => {
|
|
@@ -357,7 +426,7 @@ export default class GitRepo extends SteveModel {
|
|
|
357
426
|
name: `c-cluster-product-resource${ r.namespace ? '-namespace' : '' }-id`,
|
|
358
427
|
params: {
|
|
359
428
|
product: NAME,
|
|
360
|
-
cluster: c.metadata.labels[FLEET_ANNOTATIONS.CLUSTER_NAME],
|
|
429
|
+
cluster: c.metadata.labels[FLEET_ANNOTATIONS.CLUSTER_NAME], // explorer uses the "management" Cluster name, which differs from the Fleet Cluster name
|
|
361
430
|
resource: type,
|
|
362
431
|
namespace: r.namespace,
|
|
363
432
|
id: r.name,
|
|
@@ -385,7 +454,6 @@ export default class GitRepo extends SteveModel {
|
|
|
385
454
|
creationTimestamp: r.createdAt,
|
|
386
455
|
|
|
387
456
|
// other properties
|
|
388
|
-
clusterLabel: c.metadata.labels[FLEET_ANNOTATIONS.CLUSTER_NAME],
|
|
389
457
|
stateBackground: color,
|
|
390
458
|
stateDisplay: display,
|
|
391
459
|
stateSort: stateSort(color, display),
|
|
@@ -408,42 +476,10 @@ export default class GitRepo extends SteveModel {
|
|
|
408
476
|
};
|
|
409
477
|
}
|
|
410
478
|
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
const { clusterId, clusterLabel, state } = curr;
|
|
414
|
-
|
|
415
|
-
if (!prev[clusterId]) {
|
|
416
|
-
prev[clusterId] = {
|
|
417
|
-
clusterLabel,
|
|
418
|
-
resourceCounts: { [state]: 0, desiredReady: 0 }
|
|
419
|
-
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (!prev[clusterId].resourceCounts[state]) {
|
|
424
|
-
prev[clusterId].resourceCounts[state] = 0;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
prev[clusterId].resourceCounts[state] += 1;
|
|
428
|
-
prev[clusterId].resourceCounts.desiredReady += 1;
|
|
429
|
-
|
|
430
|
-
return prev;
|
|
431
|
-
}, {});
|
|
432
|
-
|
|
433
|
-
const values = Object.keys(clusterStatuses).map((key) => {
|
|
434
|
-
const { clusterLabel, resourceCounts } = clusterStatuses[key];
|
|
435
|
-
|
|
436
|
-
return {
|
|
437
|
-
clusterId: key,
|
|
438
|
-
clusterLabel, // FLEET LABEL
|
|
439
|
-
status: {
|
|
440
|
-
displayStatus: primaryDisplayStatusFromCount(resourceCounts),
|
|
441
|
-
resourceCounts: { ...resourceCounts }
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
});
|
|
479
|
+
clusterState(clusterId) {
|
|
480
|
+
const resourceCounts = this.statusResourceCountsForCluster(clusterId);
|
|
445
481
|
|
|
446
|
-
return
|
|
482
|
+
return primaryDisplayStatusFromCount(resourceCounts) || STATES_ENUM.ACTIVE;
|
|
447
483
|
}
|
|
448
484
|
|
|
449
485
|
get clustersList() {
|
|
@@ -5,7 +5,7 @@ import SteveModel from '@shell/plugins/steve/steve-class';
|
|
|
5
5
|
import { findBy } from '@shell/utils/array';
|
|
6
6
|
import { get, set } from '@shell/utils/object';
|
|
7
7
|
import { sortBy } from '@shell/utils/sort';
|
|
8
|
-
import { ucFirst } from '@shell/utils/string';
|
|
8
|
+
import { escapeHtml, ucFirst } from '@shell/utils/string';
|
|
9
9
|
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';
|
|
@@ -178,7 +178,15 @@ export default class ProvCluster extends SteveModel {
|
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
const all = actions.concat(out);
|
|
182
|
+
|
|
183
|
+
// If we have a helper that wants to modify the available actions, let it do it
|
|
184
|
+
if (this.customProvisionerHelper?.availableActions) {
|
|
185
|
+
// Provider can either modify the provided list or return one of its own
|
|
186
|
+
return this.customProvisionerHelper?.availableActions(this, all) || all;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return all;
|
|
182
190
|
}
|
|
183
191
|
|
|
184
192
|
get normanCluster() {
|
|
@@ -401,6 +409,11 @@ export default class ProvCluster extends SteveModel {
|
|
|
401
409
|
}
|
|
402
410
|
|
|
403
411
|
get provisionerDisplay() {
|
|
412
|
+
// Allow a model extension to override the display of the provisioner
|
|
413
|
+
if (this.customProvisionerHelper?.provisionerDisplay) {
|
|
414
|
+
return this.customProvisionerHelper?.provisionerDisplay(this);
|
|
415
|
+
}
|
|
416
|
+
|
|
404
417
|
let provisioner = (this.provisioner || '').toLowerCase();
|
|
405
418
|
|
|
406
419
|
// RKE provisioner can actually do K3s too...
|
|
@@ -496,6 +509,10 @@ export default class ProvCluster extends SteveModel {
|
|
|
496
509
|
}
|
|
497
510
|
|
|
498
511
|
get machineProviderDisplay() {
|
|
512
|
+
if (this.customProvisionerHelper?.machineProviderDisplay) {
|
|
513
|
+
return this.customProvisionerHelper?.machineProviderDisplay(this);
|
|
514
|
+
}
|
|
515
|
+
|
|
499
516
|
if ( this.isImported ) {
|
|
500
517
|
return null;
|
|
501
518
|
}
|
|
@@ -954,6 +971,34 @@ export default class ProvCluster extends SteveModel {
|
|
|
954
971
|
if ( res?._status === 204 ) {
|
|
955
972
|
await this.$dispatch('ws.resource.remove', { data: this });
|
|
956
973
|
}
|
|
974
|
+
|
|
975
|
+
// If this cluster has a custom provisioner, allow it to do custom deletion
|
|
976
|
+
if (this.customProvisionerHelper?.postDelete) {
|
|
977
|
+
return this.customProvisionerHelper?.postDelete(this);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Get the custom provisioner helper for this model
|
|
983
|
+
*/
|
|
984
|
+
get customProvisionerHelper() {
|
|
985
|
+
// Find the first model extension that says it can be used for this model
|
|
986
|
+
return this.modelExtensions.find((modelExt) => modelExt.useFor ? modelExt.useFor(this) : false);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
get groupByParent() {
|
|
990
|
+
// Customer helper can report if the cluster has a parent cluster
|
|
991
|
+
return this.customProvisionerHelper?.parentCluster?.(this);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
get groupByLabel() {
|
|
995
|
+
const name = this.groupByParent;
|
|
996
|
+
|
|
997
|
+
if (name) {
|
|
998
|
+
return this.$rootGetters['i18n/t']('resourceTable.groupLabel.cluster', { name: escapeHtml(name) });
|
|
999
|
+
} else {
|
|
1000
|
+
return this.$rootGetters['i18n/t']('resourceTable.groupLabel.notInACluster');
|
|
1001
|
+
}
|
|
957
1002
|
}
|
|
958
1003
|
|
|
959
1004
|
get hasError() {
|
package/models/service.js
CHANGED
|
@@ -138,6 +138,7 @@ export default class extends SteveModel {
|
|
|
138
138
|
|
|
139
139
|
async fetchPods() {
|
|
140
140
|
if (this.podRelationship) {
|
|
141
|
+
// Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
|
|
141
142
|
await this.$dispatch('cluster/findMatching', {
|
|
142
143
|
type: POD,
|
|
143
144
|
selector: this.podRelationship.selector,
|
package/models/workload.js
CHANGED
|
@@ -554,6 +554,7 @@ export default class Workload extends WorkloadService {
|
|
|
554
554
|
if (podRelationship) {
|
|
555
555
|
const pods = this.$getters['podsByNamespace'](this.metadata.namespace);
|
|
556
556
|
|
|
557
|
+
// Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
|
|
557
558
|
return pods.filter((obj) => {
|
|
558
559
|
return matches(obj, podRelationship.selector);
|
|
559
560
|
});
|
|
@@ -594,6 +595,23 @@ export default class Workload extends WorkloadService {
|
|
|
594
595
|
return (get(this, 'metadata.relationships') || []).filter((relationship) => relationship.toType === WORKLOAD_TYPES.JOB);
|
|
595
596
|
}
|
|
596
597
|
|
|
598
|
+
/**
|
|
599
|
+
* Ensure the store has all matching jobs
|
|
600
|
+
*/
|
|
601
|
+
async matchingJobs() {
|
|
602
|
+
if (this.type !== WORKLOAD_TYPES.CRON_JOB) {
|
|
603
|
+
return undefined;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// This will be 1 request per relationship, though there's not likely to be many per cron job
|
|
607
|
+
return Promise.all(this.jobRelationships.map((obj) => {
|
|
608
|
+
return this.$dispatch('find', { type: WORKLOAD_TYPES.JOB, id: obj.toId });
|
|
609
|
+
}));
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Expects all required pods are fetched upfront
|
|
614
|
+
*/
|
|
597
615
|
get jobs() {
|
|
598
616
|
if (this.type !== WORKLOAD_TYPES.CRON_JOB) {
|
|
599
617
|
return undefined;
|
|
@@ -643,12 +661,12 @@ export default class Workload extends WorkloadService {
|
|
|
643
661
|
}
|
|
644
662
|
|
|
645
663
|
async matchingPods() {
|
|
664
|
+
// Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix
|
|
646
665
|
const all = await this.$dispatch('findAll', { type: POD });
|
|
647
666
|
const allInNamespace = all.filter((pod) => pod.metadata.namespace === this.metadata.namespace);
|
|
648
667
|
|
|
649
668
|
const selector = convertSelectorObj(this.spec.selector);
|
|
650
669
|
|
|
651
|
-
// See https://github.com/rancher/dashboard/issues/10417, all pods bad, need to replace local selector somehow
|
|
652
670
|
return matching(allInNamespace, selector);
|
|
653
671
|
}
|
|
654
672
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.2-rc.
|
|
3
|
+
"version": "3.0.2-rc.3",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancherlabs/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@aws-sdk/client-eks": "3.1.0",
|
|
32
32
|
"@aws-sdk/client-iam": "3.658.1",
|
|
33
33
|
"@aws-sdk/client-kms": "3.8.1",
|
|
34
|
-
"@babel/plugin-proposal-optional-chaining": "7.
|
|
34
|
+
"@babel/plugin-proposal-optional-chaining": "7.21.0",
|
|
35
35
|
"@babel/plugin-proposal-private-methods": "7.18.6",
|
|
36
36
|
"@babel/plugin-proposal-private-property-in-object": "7.14.5",
|
|
37
37
|
"@babel/preset-typescript": "7.16.7",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"cookie": "0.7.0",
|
|
65
65
|
"core-js": "3.40.0",
|
|
66
66
|
"cron-validator": "1.3.1",
|
|
67
|
-
"cronstrue": "2.
|
|
67
|
+
"cronstrue": "2.53.0",
|
|
68
68
|
"cross-env": "7.0.3",
|
|
69
69
|
"css-loader": "6.7.3",
|
|
70
70
|
"csv-loader": "3.0.3",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"express": "4.17.1",
|
|
92
92
|
"file-saver": "2.0.2",
|
|
93
93
|
"floating-vue": "5.2.2",
|
|
94
|
+
"focus-trap": "7.6.2",
|
|
94
95
|
"frontmatter-markdown-loader": "3.7.0",
|
|
95
96
|
"identicon.js": "2.3.3",
|
|
96
97
|
"intl-messageformat": "7.8.4",
|
|
@@ -120,7 +121,7 @@
|
|
|
120
121
|
"set-cookie-parser": "2.4.6",
|
|
121
122
|
"shell-quote": "1.7.3",
|
|
122
123
|
"sinon": "8.1.1",
|
|
123
|
-
"start-server-and-test": "
|
|
124
|
+
"start-server-and-test": "2.0.10",
|
|
124
125
|
"style-loader": "1.2.1",
|
|
125
126
|
"ts-node": "8.10.2",
|
|
126
127
|
"typescript": "5.6.3",
|
|
@@ -455,6 +455,8 @@ export default {
|
|
|
455
455
|
class="input-sm"
|
|
456
456
|
:placeholder="t('catalog.charts.search')"
|
|
457
457
|
data-testid="charts-filter-input"
|
|
458
|
+
:aria-label="t('catalog.charts.search')"
|
|
459
|
+
role="textbox"
|
|
458
460
|
>
|
|
459
461
|
|
|
460
462
|
<button
|
|
@@ -463,6 +465,8 @@ export default {
|
|
|
463
465
|
@shortkey="focusSearch()"
|
|
464
466
|
/>
|
|
465
467
|
<AsyncButton
|
|
468
|
+
role="button"
|
|
469
|
+
:aria-label="t('catalog.charts.refresh')"
|
|
466
470
|
class="refresh-btn"
|
|
467
471
|
mode="refresh"
|
|
468
472
|
size="sm"
|
|
@@ -24,18 +24,23 @@ export default {
|
|
|
24
24
|
</script>
|
|
25
25
|
|
|
26
26
|
<template>
|
|
27
|
-
<div
|
|
27
|
+
<div
|
|
28
|
+
class="config-badge"
|
|
29
|
+
>
|
|
28
30
|
<div>
|
|
29
|
-
<
|
|
31
|
+
<button
|
|
30
32
|
class="badge-install btn btn-sm role-secondary"
|
|
31
33
|
data-testid="add-custom-cluster-badge"
|
|
34
|
+
role="button"
|
|
35
|
+
tabindex="0"
|
|
32
36
|
@click="customBadgeDialog"
|
|
37
|
+
@keyup.space="customBadgeDialog"
|
|
33
38
|
>
|
|
34
39
|
<i
|
|
35
40
|
v-clean-tooltip="tooltip"
|
|
36
41
|
class="icon icon-brush-icon"
|
|
37
42
|
/>
|
|
38
|
-
</
|
|
43
|
+
</button>
|
|
39
44
|
</div>
|
|
40
45
|
</div>
|
|
41
46
|
</template>
|
|
@@ -55,10 +60,6 @@ export default {
|
|
|
55
60
|
> I {
|
|
56
61
|
line-height: inherit;
|
|
57
62
|
}
|
|
58
|
-
|
|
59
|
-
&:focus {
|
|
60
|
-
outline: 0;
|
|
61
|
-
}
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
</style>
|
|
@@ -641,12 +641,14 @@ export default {
|
|
|
641
641
|
<div data-testid="clusterProvider__label">
|
|
642
642
|
<label>{{ t('glance.provider') }}: </label>
|
|
643
643
|
<span v-if="isHarvesterCluster">
|
|
644
|
-
<
|
|
644
|
+
<button
|
|
645
|
+
class="btn role-link harvester-cluster-link"
|
|
645
646
|
role="button"
|
|
647
|
+
:aria-label="displayProvider"
|
|
646
648
|
@click="goToHarvesterCluster"
|
|
647
649
|
>
|
|
648
650
|
{{ displayProvider }}
|
|
649
|
-
</
|
|
651
|
+
</button>
|
|
650
652
|
</span>
|
|
651
653
|
<span v-else>
|
|
652
654
|
{{ displayProvider }}
|
|
@@ -682,6 +684,8 @@ export default {
|
|
|
682
684
|
<router-link
|
|
683
685
|
:to="{name: 'c-cluster-explorer-tools'}"
|
|
684
686
|
class="cluster-tools-link"
|
|
687
|
+
role="link"
|
|
688
|
+
:aria-label="t('nav.clusterTools')"
|
|
685
689
|
>
|
|
686
690
|
<span>{{ t('nav.clusterTools') }}</span>
|
|
687
691
|
</router-link>
|
|
@@ -871,6 +875,13 @@ export default {
|
|
|
871
875
|
grid-row-gap: 20px;
|
|
872
876
|
}
|
|
873
877
|
|
|
878
|
+
.harvester-cluster-link {
|
|
879
|
+
line-height: inherit;
|
|
880
|
+
min-height: inherit;
|
|
881
|
+
padding: 0;
|
|
882
|
+
vertical-align: bottom;
|
|
883
|
+
}
|
|
884
|
+
|
|
874
885
|
@media only screen and (max-width: map-get($breakpoints, "--viewport-9")) {
|
|
875
886
|
.extension-card-container {
|
|
876
887
|
grid-template-columns: 1fr !important;
|
|
@@ -935,10 +946,6 @@ export default {
|
|
|
935
946
|
line-height: inherit;
|
|
936
947
|
margin-right: 4px;
|
|
937
948
|
}
|
|
938
|
-
|
|
939
|
-
&:focus {
|
|
940
|
-
outline: 0;
|
|
941
|
-
}
|
|
942
949
|
}
|
|
943
950
|
|
|
944
951
|
.cert-table-link {
|
|
@@ -77,7 +77,7 @@ export const gitRepoGraphConfig = {
|
|
|
77
77
|
id: bd.id,
|
|
78
78
|
matchingId: bd.id,
|
|
79
79
|
type: bd.type,
|
|
80
|
-
|
|
80
|
+
clusterLabel: cluster ? cluster.namespacedName : undefined,
|
|
81
81
|
clusterDetailLocation: cluster ? cluster.detailLocation : undefined,
|
|
82
82
|
state: bd.state,
|
|
83
83
|
stateLabel: bd.stateDisplay,
|
|
@@ -210,7 +210,7 @@ export const gitRepoGraphConfig = {
|
|
|
210
210
|
type: 'title-link',
|
|
211
211
|
labelKey: 'fleet.fdc.id',
|
|
212
212
|
valueObj: {
|
|
213
|
-
|
|
213
|
+
label: data.id,
|
|
214
214
|
detailLocation: data.detailLocation
|
|
215
215
|
}
|
|
216
216
|
}
|
|
@@ -221,7 +221,7 @@ export const gitRepoGraphConfig = {
|
|
|
221
221
|
type: 'title-link',
|
|
222
222
|
labelKey: 'fleet.fdc.cluster',
|
|
223
223
|
valueObj: {
|
|
224
|
-
|
|
224
|
+
label: data.clusterLabel,
|
|
225
225
|
detailLocation: data.clusterDetailLocation
|
|
226
226
|
}
|
|
227
227
|
});
|