@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.4
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 +7 -8
- package/assets/styles/global/_button.scss +10 -0
- package/assets/styles/global/_form.scss +2 -1
- package/assets/styles/global/_tooltip.scss +2 -2
- package/assets/styles/themes/_dark.scss +15 -3
- package/assets/styles/themes/_light.scss +7 -2
- package/assets/styles/vendor/vue-select.scss +4 -0
- package/assets/translations/en-us.yaml +66 -9
- package/assets/translations/zh-hans.yaml +2 -3
- package/components/AppModal.vue +50 -0
- package/components/BannerGraphic.vue +0 -42
- package/components/ButtonMultiAction.vue +1 -1
- package/components/Carousel.vue +88 -74
- package/components/CommunityLinks.vue +6 -1
- package/components/CopyToClipboardText.vue +3 -0
- package/components/Dialog.vue +20 -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/PromptChangePassword.vue +3 -0
- package/components/Questions/Reference.vue +57 -28
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/SelectIconGrid.vue +12 -1
- package/components/SideNav.vue +12 -38
- package/components/SortableTable/index.vue +1 -0
- package/components/Tabbed/index.vue +9 -1
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/Carousel.test.ts +56 -27
- 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 +2 -2
- 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/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
- package/components/form/SSHKnownHosts/index.vue +101 -0
- package/components/form/SecretSelector.vue +2 -2
- package/components/form/Select.vue +1 -1
- package/components/form/SelectOrCreateAuthSecret.vue +43 -11
- package/components/form/__tests__/KeyValue.test.ts +1 -1
- package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
- 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/composables/focusTrap.ts +68 -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/secret.vue +25 -0
- 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 +34 -23
- 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 +27 -8
- 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/secret/index.vue +1 -1
- package/edit/secret/ssh.vue +21 -3
- 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/provisioning.cattle.io.cluster.vue +1 -0
- 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 +88 -52
- package/models/provisioning.cattle.io.cluster.js +36 -1
- package/models/secret.js +5 -0
- package/models/service.js +1 -0
- package/models/workload.js +19 -1
- package/package.json +5 -4
- package/pages/account/index.vue +4 -0
- package/pages/c/_cluster/apps/charts/index.vue +4 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
- 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/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
- package/pages/c/_cluster/uiplugins/index.vue +50 -12
- 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 +12 -0
- 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 +19 -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 +122 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
- package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
- package/rancher-components/RcDropdown/index.ts +4 -0
- package/rancher-components/RcDropdown/types.ts +22 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +110 -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
|
@@ -3,6 +3,7 @@ import { _EDIT } from '@shell/config/query-params';
|
|
|
3
3
|
import { Banner } from '@components/Banner';
|
|
4
4
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
5
5
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
6
|
+
import SSHKnownHosts from '@shell/components/form/SSHKnownHosts';
|
|
6
7
|
import { AUTH_TYPE, NORMAN, SECRET } from '@shell/config/types';
|
|
7
8
|
import { SECRET_TYPES } from '@shell/config/secret';
|
|
8
9
|
import { base64Encode } from '@shell/utils/crypto';
|
|
@@ -23,6 +24,7 @@ export default {
|
|
|
23
24
|
Banner,
|
|
24
25
|
LabeledInput,
|
|
25
26
|
LabeledSelect,
|
|
27
|
+
SSHKnownHosts,
|
|
26
28
|
},
|
|
27
29
|
|
|
28
30
|
props: {
|
|
@@ -142,6 +144,11 @@ export default {
|
|
|
142
144
|
type: Boolean,
|
|
143
145
|
default: false,
|
|
144
146
|
},
|
|
147
|
+
|
|
148
|
+
showSshKnownHosts: {
|
|
149
|
+
type: Boolean,
|
|
150
|
+
default: true,
|
|
151
|
+
},
|
|
145
152
|
},
|
|
146
153
|
|
|
147
154
|
async fetch() {
|
|
@@ -172,6 +179,7 @@ export default {
|
|
|
172
179
|
if ( !this.value ) {
|
|
173
180
|
this.publicKey = this.preSelect?.publicKey || '';
|
|
174
181
|
this.privateKey = this.preSelect?.privateKey || '';
|
|
182
|
+
this.sshKnownHosts = this.preSelect?.sshKnownHosts || '';
|
|
175
183
|
}
|
|
176
184
|
|
|
177
185
|
this.updateSelectedFromValue();
|
|
@@ -189,9 +197,10 @@ export default {
|
|
|
189
197
|
|
|
190
198
|
filterByNamespace: this.namespace && this.limitToNamespace,
|
|
191
199
|
|
|
192
|
-
publicKey:
|
|
193
|
-
privateKey:
|
|
194
|
-
|
|
200
|
+
publicKey: '',
|
|
201
|
+
privateKey: '',
|
|
202
|
+
sshKnownHosts: '',
|
|
203
|
+
uniqueId: new Date().getTime(), // Allows form state to be individually tracked if the form is in a list
|
|
195
204
|
|
|
196
205
|
SSH: AUTH_TYPE._SSH,
|
|
197
206
|
BASIC: AUTH_TYPE._BASIC,
|
|
@@ -372,15 +381,16 @@ export default {
|
|
|
372
381
|
return 'mt-20';
|
|
373
382
|
}
|
|
374
383
|
|
|
375
|
-
return 'col span-4';
|
|
384
|
+
return (this.selected === AUTH_TYPE._SSH) && this.showSshKnownHosts ? 'col span-3' : 'col span-4';
|
|
376
385
|
}
|
|
377
386
|
},
|
|
378
387
|
|
|
379
388
|
watch: {
|
|
380
|
-
selected:
|
|
381
|
-
publicKey:
|
|
382
|
-
privateKey:
|
|
383
|
-
|
|
389
|
+
selected: 'update',
|
|
390
|
+
publicKey: 'updateKeyVal',
|
|
391
|
+
privateKey: 'updateKeyVal',
|
|
392
|
+
sshKnownHosts: 'updateKeyVal',
|
|
393
|
+
value: 'updateSelectedFromValue',
|
|
384
394
|
|
|
385
395
|
async namespace(ns) {
|
|
386
396
|
if (ns && !this.selected.startsWith(`${ ns }/`)) {
|
|
@@ -463,13 +473,20 @@ export default {
|
|
|
463
473
|
if ( ![AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE].includes(this.selected) ) {
|
|
464
474
|
this.privateKey = '';
|
|
465
475
|
this.publicKey = '';
|
|
476
|
+
this.sshKnownHosts = '';
|
|
466
477
|
}
|
|
467
478
|
|
|
468
|
-
|
|
479
|
+
const value = {
|
|
469
480
|
selected: this.selected,
|
|
470
481
|
privateKey: this.privateKey,
|
|
471
|
-
publicKey: this.publicKey
|
|
472
|
-
}
|
|
482
|
+
publicKey: this.publicKey,
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
if (this.sshKnownHosts) {
|
|
486
|
+
value.sshKnownHosts = this.sshKnownHosts;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
this.$emit('inputauthval', value);
|
|
473
490
|
},
|
|
474
491
|
|
|
475
492
|
update() {
|
|
@@ -550,6 +567,12 @@ export default {
|
|
|
550
567
|
[publicField]: base64Encode(this.publicKey),
|
|
551
568
|
[privateField]: base64Encode(this.privateKey),
|
|
552
569
|
};
|
|
570
|
+
|
|
571
|
+
// Add ssh known hosts data key - we will add a key with an empty value if the inout field was left blank
|
|
572
|
+
// This ensures on edit of the secret, we allow the user to edit the known_hosts field
|
|
573
|
+
if ((this.selected === AUTH_TYPE._SSH) && this.showSshKnownHosts) {
|
|
574
|
+
secret.data.known_hosts = base64Encode(this.sshKnownHosts || '');
|
|
575
|
+
}
|
|
553
576
|
}
|
|
554
577
|
}
|
|
555
578
|
|
|
@@ -603,6 +626,15 @@ export default {
|
|
|
603
626
|
label-key="selectOrCreateAuthSecret.ssh.privateKey"
|
|
604
627
|
/>
|
|
605
628
|
</div>
|
|
629
|
+
<div
|
|
630
|
+
v-if="showSshKnownHosts"
|
|
631
|
+
class="col span-2"
|
|
632
|
+
>
|
|
633
|
+
<SSHKnownHosts
|
|
634
|
+
v-model:value="sshKnownHosts"
|
|
635
|
+
:mode="mode"
|
|
636
|
+
/>
|
|
637
|
+
</div>
|
|
606
638
|
</template>
|
|
607
639
|
<template v-else-if="selected === BASIC || selected === RKE">
|
|
608
640
|
<Banner
|
|
@@ -127,7 +127,7 @@ describe('component: KeyValue', () => {
|
|
|
127
127
|
expect(secondKeyInput.exists()).toBe(false);
|
|
128
128
|
expect(secondValueInput.exists()).toBe(false);
|
|
129
129
|
|
|
130
|
-
const addButton = wrapper.find('[data-testid="
|
|
130
|
+
const addButton = wrapper.find('[data-testid="add_row_item_button"]');
|
|
131
131
|
|
|
132
132
|
addButton.trigger('click');
|
|
133
133
|
await nextTick();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { _EDIT, _VIEW } from '@shell/config/query-params';
|
|
3
|
+
import SSHKnownHosts from '@shell/components/form/SSHKnownHosts/index.vue';
|
|
4
|
+
|
|
5
|
+
describe('component: SSHKnownHosts', () => {
|
|
6
|
+
it.each([
|
|
7
|
+
['0 entities', '', 0],
|
|
8
|
+
['0 entities (multiple empty lines)', '\n \n \n', 0],
|
|
9
|
+
['1 entity', 'line1\n', 1],
|
|
10
|
+
['1 entity (multiple empty lines)', 'line1\n\n\n', 1],
|
|
11
|
+
['2 entities', 'line1\nline2\n', 2],
|
|
12
|
+
['2 entities (multiple empty lines)', 'line1\n \n line2\n \n', 2],
|
|
13
|
+
])('mode view: summary should be: %p', (_, value, entities) => {
|
|
14
|
+
const wrapper = mount(SSHKnownHosts, {
|
|
15
|
+
props: {
|
|
16
|
+
mode: _VIEW,
|
|
17
|
+
value,
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const knownSshHostsSummary = wrapper.find('[data-testid="input-known-ssh-hosts_summary"]');
|
|
22
|
+
const knownSshHostsOpenDialog = wrapper.findAll('[data-testid="input-known-ssh-hosts_open-dialog"]');
|
|
23
|
+
|
|
24
|
+
expect(wrapper.vm.entries).toBe(entities);
|
|
25
|
+
expect(knownSshHostsSummary.element).toBeDefined();
|
|
26
|
+
expect(knownSshHostsOpenDialog).toHaveLength(0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('mode edit: should display summary and edit button', () => {
|
|
30
|
+
const wrapper = mount(SSHKnownHosts, {
|
|
31
|
+
props: {
|
|
32
|
+
mode: _EDIT,
|
|
33
|
+
value: 'line1\nline2\n',
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const knownSshHostsSummary = wrapper.find('[data-testid="input-known-ssh-hosts_summary"]');
|
|
38
|
+
const knownSshHostsOpenDialog = wrapper.find('[data-testid="input-known-ssh-hosts_open-dialog"]');
|
|
39
|
+
|
|
40
|
+
expect(knownSshHostsSummary.element).toBeDefined();
|
|
41
|
+
expect(knownSshHostsOpenDialog.element).toBeDefined();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('mode edit: should open edit dialog', async() => {
|
|
45
|
+
const wrapper = mount(SSHKnownHosts, {
|
|
46
|
+
props: {
|
|
47
|
+
mode: _EDIT,
|
|
48
|
+
value: '',
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const knownSshHostsOpenDialog = wrapper.find('[data-testid="input-known-ssh-hosts_open-dialog"]');
|
|
53
|
+
const editDialog = wrapper.vm.$refs['editDialog'] as any;
|
|
54
|
+
|
|
55
|
+
await knownSshHostsOpenDialog.trigger('click');
|
|
56
|
+
|
|
57
|
+
expect(editDialog.showModal).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
required: true
|
|
12
12
|
},
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
clusterId: {
|
|
15
15
|
type: String,
|
|
16
16
|
required: true
|
|
17
17
|
}
|
|
@@ -22,6 +22,6 @@ export default {
|
|
|
22
22
|
<template>
|
|
23
23
|
<FleetSummaryGraph
|
|
24
24
|
:row="row"
|
|
25
|
-
:
|
|
25
|
+
:clusterId="clusterId"
|
|
26
26
|
/>
|
|
27
27
|
</template>
|
|
@@ -14,7 +14,7 @@ export default {
|
|
|
14
14
|
required: true
|
|
15
15
|
},
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
clusterId: {
|
|
18
18
|
type: String,
|
|
19
19
|
required: false,
|
|
20
20
|
default: null,
|
|
@@ -23,10 +23,8 @@ export default {
|
|
|
23
23
|
|
|
24
24
|
computed: {
|
|
25
25
|
summary() {
|
|
26
|
-
if (this.
|
|
27
|
-
return this.row.
|
|
28
|
-
return x.clusterLabel === this.clusterLabel;
|
|
29
|
-
})?.status.resourceCounts || {};
|
|
26
|
+
if (this.clusterId) {
|
|
27
|
+
return this.row.statusResourceCountsForCluster(this.clusterId);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
return this.row.status?.resourceCounts || {};
|
|
@@ -37,7 +35,8 @@ export default {
|
|
|
37
35
|
},
|
|
38
36
|
|
|
39
37
|
stateParts() {
|
|
40
|
-
const
|
|
38
|
+
const summary = this.summary;
|
|
39
|
+
const keys = Object.keys(summary).filter((x) => !x.startsWith('desired'));
|
|
41
40
|
|
|
42
41
|
const out = keys.map((key) => {
|
|
43
42
|
const textColor = colorForState(key);
|
|
@@ -46,7 +45,7 @@ export default {
|
|
|
46
45
|
label: ucFirst(key),
|
|
47
46
|
color: textColor.replace(/text-/, 'bg-'),
|
|
48
47
|
textColor,
|
|
49
|
-
value:
|
|
48
|
+
value: summary[key],
|
|
50
49
|
sort: stateSort(textColor, key),
|
|
51
50
|
};
|
|
52
51
|
}).filter((x) => x.value > 0);
|
|
@@ -182,14 +182,21 @@ export default {
|
|
|
182
182
|
<div
|
|
183
183
|
id="trigger"
|
|
184
184
|
class="hs-popover__trigger"
|
|
185
|
+
aria-role="button"
|
|
186
|
+
tabindex="0"
|
|
185
187
|
:class="{expanded}"
|
|
188
|
+
:aria-roledescription="t('workload.scaleWorkloads')"
|
|
189
|
+
:aria-label="t('workload.healthScaleToggle')"
|
|
190
|
+
:aria-expanded="expanded"
|
|
186
191
|
@click="expanded = !expanded"
|
|
192
|
+
@keyup.enter.space="expanded = !expanded"
|
|
187
193
|
>
|
|
188
194
|
<ProgressBarMulti
|
|
189
195
|
v-if="parts"
|
|
190
196
|
class="health"
|
|
191
197
|
:values="parts"
|
|
192
198
|
:show-zeros="true"
|
|
199
|
+
:aria-describedby="t('workload.healthWorkloads')"
|
|
193
200
|
/>
|
|
194
201
|
<i :class="{icon: true, 'icon-chevron-up': expanded, 'icon-chevron-down': !expanded}" />
|
|
195
202
|
</div>
|
package/components/nav/Group.vue
CHANGED
|
@@ -211,26 +211,40 @@ export default {
|
|
|
211
211
|
v-if="showHeader"
|
|
212
212
|
class="header"
|
|
213
213
|
:class="{'active': isOverview, 'noHover': !canCollapse}"
|
|
214
|
+
role="button"
|
|
215
|
+
tabindex="0"
|
|
216
|
+
:aria-label="group.labelDisplay || group.label || ''"
|
|
214
217
|
@click="groupSelected()"
|
|
218
|
+
@keyup.enter="groupSelected()"
|
|
219
|
+
@keyup.space="groupSelected()"
|
|
215
220
|
>
|
|
216
221
|
<slot name="header">
|
|
217
222
|
<router-link
|
|
218
223
|
v-if="hasOverview"
|
|
219
224
|
:to="group.children[0].route"
|
|
220
225
|
:exact="group.children[0].exact"
|
|
226
|
+
:tabindex="-1"
|
|
221
227
|
>
|
|
222
|
-
<h6
|
|
228
|
+
<h6>
|
|
229
|
+
<span v-clean-html="group.labelDisplay || group.label" />
|
|
230
|
+
</h6>
|
|
223
231
|
</router-link>
|
|
224
232
|
<h6
|
|
225
233
|
v-else
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
>
|
|
235
|
+
<span v-clean-html="group.labelDisplay || group.label" />
|
|
236
|
+
</h6>
|
|
228
237
|
</slot>
|
|
229
238
|
<i
|
|
230
239
|
v-if="!onlyHasOverview && canCollapse"
|
|
231
|
-
class="icon toggle"
|
|
240
|
+
class="icon toggle toggle-accordion"
|
|
232
241
|
:class="{'icon-chevron-right': !isExpanded, 'icon-chevron-down': isExpanded}"
|
|
242
|
+
role="button"
|
|
243
|
+
tabindex="0"
|
|
244
|
+
:aria-label="t('nav.ariaLabel.collapseExpand')"
|
|
233
245
|
@click="peek($event, true)"
|
|
246
|
+
@keyup.enter="peek($event, true)"
|
|
247
|
+
@keyup.space="peek($event, true)"
|
|
234
248
|
/>
|
|
235
249
|
</div>
|
|
236
250
|
<ul
|
|
@@ -288,6 +302,7 @@ export default {
|
|
|
288
302
|
cursor: pointer;
|
|
289
303
|
color: var(--body-text);
|
|
290
304
|
height: 33px;
|
|
305
|
+
outline: none;
|
|
291
306
|
|
|
292
307
|
H6 {
|
|
293
308
|
color: var(--body-text);
|
|
@@ -315,6 +330,17 @@ export default {
|
|
|
315
330
|
|
|
316
331
|
.accordion {
|
|
317
332
|
.header {
|
|
333
|
+
&:focus-visible {
|
|
334
|
+
h6 span {
|
|
335
|
+
@include focus-outline;
|
|
336
|
+
outline-offset: 2px;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
.toggle-accordion:focus-visible {
|
|
340
|
+
@include focus-outline;
|
|
341
|
+
outline-offset: -6px;
|
|
342
|
+
}
|
|
343
|
+
|
|
318
344
|
&.active {
|
|
319
345
|
color: var(--primary-hover-text);
|
|
320
346
|
background-color: var(--primary-hover-bg);
|
|
@@ -24,6 +24,12 @@ import IconOrSvg from '@shell/components/IconOrSvg';
|
|
|
24
24
|
import { wait } from '@shell/utils/async';
|
|
25
25
|
import { configType } from '@shell/models/management.cattle.io.authconfig';
|
|
26
26
|
import HeaderPageActionMenu from './HeaderPageActionMenu.vue';
|
|
27
|
+
import {
|
|
28
|
+
RcDropdown,
|
|
29
|
+
RcDropdownItem,
|
|
30
|
+
RcDropdownSeparator,
|
|
31
|
+
RcDropdownTrigger
|
|
32
|
+
} from '@components/RcDropdown';
|
|
27
33
|
|
|
28
34
|
export default {
|
|
29
35
|
|
|
@@ -39,6 +45,10 @@ export default {
|
|
|
39
45
|
IconOrSvg,
|
|
40
46
|
AppModal,
|
|
41
47
|
HeaderPageActionMenu,
|
|
48
|
+
RcDropdown,
|
|
49
|
+
RcDropdownItem,
|
|
50
|
+
RcDropdownSeparator,
|
|
51
|
+
RcDropdownTrigger,
|
|
42
52
|
},
|
|
43
53
|
|
|
44
54
|
props: {
|
|
@@ -641,27 +651,18 @@ export default {
|
|
|
641
651
|
</button>
|
|
642
652
|
</div>
|
|
643
653
|
|
|
644
|
-
<
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
class="user user-menu"
|
|
650
|
-
data-testid="nav_header_showUserMenu"
|
|
651
|
-
tabindex="0"
|
|
652
|
-
@blur="showMenu(false)"
|
|
653
|
-
@click="showMenu(true)"
|
|
654
|
-
@focus.capture="showMenu(true)"
|
|
655
|
-
>
|
|
656
|
-
<v-dropdown
|
|
657
|
-
:triggers="[]"
|
|
658
|
-
:shown="isUserMenuOpen"
|
|
659
|
-
:autoHide="false"
|
|
660
|
-
:flip="false"
|
|
661
|
-
:container="false"
|
|
662
|
-
:placement="'bottom-end'"
|
|
654
|
+
<div class="center-self">
|
|
655
|
+
<header-page-action-menu v-if="showPageActions" />
|
|
656
|
+
<rc-dropdown
|
|
657
|
+
v-if="showUserMenu"
|
|
658
|
+
:aria-label="t('nav.userMenu.label')"
|
|
663
659
|
>
|
|
664
|
-
<
|
|
660
|
+
<rc-dropdown-trigger
|
|
661
|
+
ghost
|
|
662
|
+
small
|
|
663
|
+
data-testid="nav_header_showUserMenu"
|
|
664
|
+
:aria-label="t('nav.userMenu.button.label')"
|
|
665
|
+
>
|
|
665
666
|
<img
|
|
666
667
|
v-if="principal && principal.avatarSrc"
|
|
667
668
|
:src="principal.avatarSrc"
|
|
@@ -673,88 +674,47 @@ export default {
|
|
|
673
674
|
v-else
|
|
674
675
|
class="icon icon-user icon-3x avatar"
|
|
675
676
|
/>
|
|
676
|
-
</
|
|
677
|
-
<template #
|
|
678
|
-
<
|
|
679
|
-
class="user-
|
|
677
|
+
</rc-dropdown-trigger>
|
|
678
|
+
<template #dropdownCollection>
|
|
679
|
+
<template v-if="authEnabled">
|
|
680
|
+
<div class="user-info">
|
|
681
|
+
<div class="user-name">
|
|
682
|
+
<i class="icon icon-lg icon-user" /> {{ principal.loginName }}
|
|
683
|
+
</div>
|
|
684
|
+
<div class="text-small">
|
|
685
|
+
<template v-if="principal.loginName !== principal.name">
|
|
686
|
+
{{ principal.name }}
|
|
687
|
+
</template>
|
|
688
|
+
</div>
|
|
689
|
+
</div>
|
|
690
|
+
<rc-dropdown-separator />
|
|
691
|
+
</template>
|
|
692
|
+
<rc-dropdown-item
|
|
693
|
+
v-if="showPreferencesLink"
|
|
694
|
+
@click="$router.push({ name: 'prefs'})"
|
|
680
695
|
>
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
v-slot="{ href, navigate }"
|
|
702
|
-
custom
|
|
703
|
-
:to="{name: 'prefs'}"
|
|
704
|
-
>
|
|
705
|
-
<li
|
|
706
|
-
class="user-menu-item"
|
|
707
|
-
@click="navigate"
|
|
708
|
-
@keypress.enter="navigate"
|
|
709
|
-
>
|
|
710
|
-
<a :href="href">{{ t('nav.userMenu.preferences') }}</a>
|
|
711
|
-
</li>
|
|
712
|
-
</router-link>
|
|
713
|
-
<router-link
|
|
714
|
-
v-if="showAccountAndApiKeyLink"
|
|
715
|
-
v-slot="{ href, navigate }"
|
|
716
|
-
custom
|
|
717
|
-
:to="{name: 'account'}"
|
|
718
|
-
>
|
|
719
|
-
<li
|
|
720
|
-
class="user-menu-item"
|
|
721
|
-
@click="navigate"
|
|
722
|
-
@keypress.enter="navigate"
|
|
723
|
-
>
|
|
724
|
-
<a :href="href">{{ t('nav.userMenu.accountAndKeys', {}, true) }}</a>
|
|
725
|
-
</li>
|
|
726
|
-
</router-link>
|
|
727
|
-
<!-- SLO modal -->
|
|
728
|
-
<li
|
|
729
|
-
v-if="authEnabled && shouldShowSloLogoutModal"
|
|
730
|
-
class="user-menu-item no-link"
|
|
731
|
-
@click="showSloModal"
|
|
732
|
-
@keypress.enter="showSloModal"
|
|
733
|
-
>
|
|
734
|
-
<span>{{ t('nav.userMenu.logOut') }}</span>
|
|
735
|
-
</li>
|
|
736
|
-
<!-- logout -->
|
|
737
|
-
<router-link
|
|
738
|
-
v-else-if="authEnabled"
|
|
739
|
-
v-slot="{ href, navigate }"
|
|
740
|
-
custom
|
|
741
|
-
:to="generateLogoutRoute"
|
|
742
|
-
>
|
|
743
|
-
<li
|
|
744
|
-
class="user-menu-item"
|
|
745
|
-
@click="navigate"
|
|
746
|
-
@keypress.enter="navigate"
|
|
747
|
-
>
|
|
748
|
-
<a
|
|
749
|
-
:href="href"
|
|
750
|
-
@blur="showMenu(false)"
|
|
751
|
-
>{{ t('nav.userMenu.logOut') }}</a>
|
|
752
|
-
</li>
|
|
753
|
-
</router-link>
|
|
754
|
-
</ul>
|
|
755
|
-
</div>
|
|
696
|
+
{{ t('nav.userMenu.preferences') }}
|
|
697
|
+
</rc-dropdown-item>
|
|
698
|
+
<rc-dropdown-item
|
|
699
|
+
v-if="showAccountAndApiKeyLink"
|
|
700
|
+
@click="$router.push({ name: 'account'})"
|
|
701
|
+
>
|
|
702
|
+
{{ t('nav.userMenu.accountAndKeys', {}, true) }}
|
|
703
|
+
</rc-dropdown-item>
|
|
704
|
+
<rc-dropdown-item
|
|
705
|
+
v-if="authEnabled && shouldShowSloLogoutModal"
|
|
706
|
+
@click="showSloModal"
|
|
707
|
+
>
|
|
708
|
+
{{ t('nav.userMenu.logOut') }}
|
|
709
|
+
</rc-dropdown-item>
|
|
710
|
+
<rc-dropdown-item
|
|
711
|
+
v-else-if="authEnabled"
|
|
712
|
+
@click="$router.push(generateLogoutRoute)"
|
|
713
|
+
>
|
|
714
|
+
{{ t('nav.userMenu.logOut') }}
|
|
715
|
+
</rc-dropdown-item>
|
|
756
716
|
</template>
|
|
757
|
-
</
|
|
717
|
+
</rc-dropdown>
|
|
758
718
|
</div>
|
|
759
719
|
</div>
|
|
760
720
|
</header>
|
|
@@ -957,7 +917,7 @@ export default {
|
|
|
957
917
|
width: 40px;
|
|
958
918
|
}
|
|
959
919
|
|
|
960
|
-
:deep()
|
|
920
|
+
:deep() div .btn.role-tertiary {
|
|
961
921
|
border: 1px solid var(--header-btn-bg);
|
|
962
922
|
border: none;
|
|
963
923
|
background: var(--header-btn-bg);
|
|
@@ -1010,8 +970,9 @@ export default {
|
|
|
1010
970
|
position: relative;
|
|
1011
971
|
}
|
|
1012
972
|
|
|
1013
|
-
.
|
|
1014
|
-
|
|
973
|
+
.avatar-round {
|
|
974
|
+
border: 0;
|
|
975
|
+
border-radius: 50%;
|
|
1015
976
|
}
|
|
1016
977
|
|
|
1017
978
|
> .user {
|
|
@@ -1047,11 +1008,14 @@ export default {
|
|
|
1047
1008
|
}
|
|
1048
1009
|
|
|
1049
1010
|
background-color: var(--header-bg);
|
|
1011
|
+
}
|
|
1050
1012
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1013
|
+
> .center-self {
|
|
1014
|
+
align-self: center;
|
|
1015
|
+
display: flex;
|
|
1016
|
+
gap: 1rem;
|
|
1017
|
+
align-items: center;
|
|
1018
|
+
padding-right: 1rem;
|
|
1055
1019
|
}
|
|
1056
1020
|
}
|
|
1057
1021
|
}
|
|
@@ -1063,14 +1027,17 @@ export default {
|
|
|
1063
1027
|
justify-content: space-between;
|
|
1064
1028
|
padding: 10px;
|
|
1065
1029
|
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1066
1032
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1033
|
+
div {
|
|
1034
|
+
&.user-info {
|
|
1035
|
+
padding: 0 8px;
|
|
1036
|
+
margin: 0 9px;
|
|
1037
|
+
min-width: 200px;
|
|
1038
|
+
display: flex;
|
|
1039
|
+
gap: 5px;
|
|
1040
|
+
flex-direction: column;
|
|
1074
1041
|
}
|
|
1075
1042
|
}
|
|
1076
1043
|
|
|
@@ -1152,4 +1119,5 @@ export default {
|
|
|
1152
1119
|
}
|
|
1153
1120
|
}
|
|
1154
1121
|
}
|
|
1122
|
+
|
|
1155
1123
|
</style>
|