@rancher/shell 3.0.2-rc.5 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/images/providers/nutanix.svg +12 -1
- package/assets/styles/base/_basic.scss +2 -1
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/global/_labeled-input.scss +5 -13
- package/assets/styles/global/_layout.scss +4 -1
- package/assets/styles/global/_select.scss +5 -0
- package/assets/styles/themes/_dark.scss +1 -3
- package/assets/styles/themes/_light.scss +5 -1
- package/assets/translations/en-us.yaml +130 -23
- package/assets/translations/zh-hans.yaml +0 -3
- package/cloud-credential/azure.vue +1 -1
- package/components/ActionMenuShell.vue +105 -0
- package/components/AppModal.vue +2 -2
- package/components/AsyncButton.vue +2 -0
- package/components/ButtonGroup.vue +9 -2
- package/components/ClusterBadge.vue +1 -0
- package/components/ClusterIconMenu.vue +3 -0
- package/components/ClusterProviderIcon.vue +14 -1
- package/components/CodeMirror.vue +96 -5
- package/components/Collapse.vue +16 -3
- package/components/CruResource.vue +9 -0
- package/components/CruResourceFooter.vue +1 -1
- package/components/ExplorerMembers.vue +2 -1
- package/components/FixedBanner.vue +19 -12
- package/components/Import.vue +14 -1
- package/components/LandingPagePreference.vue +4 -2
- package/components/PodSecurityAdmission.vue +8 -6
- package/components/PromptChangePassword.vue +1 -0
- package/components/PromptRemove.vue +23 -21
- package/components/ResourceDetail/Masthead.vue +30 -11
- package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
- package/components/ResourceDetail/index.vue +6 -0
- package/components/ResourceTable.vue +6 -1
- package/components/ResourceYaml.vue +1 -0
- package/components/Setting.vue +115 -0
- package/components/SortableTable/THead.vue +2 -0
- package/components/SortableTable/index.vue +7 -12
- package/components/StatusBadge.vue +71 -0
- package/components/Tabbed/index.vue +16 -15
- package/components/Wizard.vue +108 -104
- package/components/YamlEditor.vue +12 -2
- package/components/__tests__/Collapse.test.ts +2 -2
- package/components/__tests__/FixedBanner.test.ts +3 -3
- package/components/auth/Principal.vue +29 -17
- package/components/auth/__tests__/Principal.test.ts +40 -0
- package/components/auth/login/ldap.vue +7 -0
- package/components/fleet/FleetBundles.vue +1 -1
- package/components/fleet/FleetRepos.vue +1 -1
- package/components/fleet/FleetResources.vue +0 -2
- package/components/fleet/FleetSummary.vue +60 -65
- package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
- package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
- package/components/form/ArrayList.vue +6 -2
- package/components/form/ColorInput.vue +1 -0
- package/components/form/KeyValue.vue +11 -12
- package/components/form/LabeledSelect.vue +15 -3
- package/components/form/Labels.vue +8 -1
- package/components/form/Members/MembershipEditor.vue +230 -222
- package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
- package/components/form/Password.vue +3 -0
- package/components/form/ProjectMemberEditor.vue +6 -3
- package/components/form/ResourceTabs/index.vue +15 -13
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
- package/components/form/SchedulingCustomization.vue +85 -0
- package/components/form/Select.vue +3 -2
- package/components/form/SelectOrCreateAuthSecret.vue +2 -1
- package/components/form/UnitInput.vue +3 -4
- package/components/form/__tests__/ArrayList.test.ts +9 -6
- package/components/form/__tests__/LabeledSelect.test.ts +37 -0
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
- package/components/form/__tests__/UnitInput.test.ts +4 -5
- package/components/formatter/LiveDate.vue +3 -1
- package/components/formatter/ServiceType.vue +12 -4
- package/components/formatter/WorkloadHealthScale.vue +2 -1
- package/components/nav/Header.vue +35 -2
- package/components/nav/HeaderPageActionMenu.vue +11 -40
- package/components/nav/Jump.vue +8 -2
- package/components/nav/NamespaceFilter.vue +5 -4
- package/components/nav/Pinned.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +5 -5
- package/components/nav/TopLevelMenu.vue +1 -12
- package/components/nav/WindowManager/ContainerLogs.vue +96 -58
- package/components/nav/WindowManager/ContainerShell.vue +99 -18
- package/components/nav/WindowManager/index.vue +74 -6
- package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
- package/components/templates/default.vue +2 -47
- package/config/features.js +1 -0
- package/config/labels-annotations.js +11 -1
- package/config/router/navigation-guards/index.js +2 -1
- package/config/router/navigation-guards/record-last-route.js +24 -0
- package/config/settings.ts +66 -98
- package/config/version.js +1 -1
- package/core/types-provisioning.ts +7 -0
- package/detail/fleet.cattle.io.bundle.vue +7 -0
- package/detail/fleet.cattle.io.cluster.vue +0 -3
- package/detail/fleet.cattle.io.gitrepo.vue +8 -15
- package/detail/provisioning.cattle.io.cluster.vue +8 -2
- package/dialog/DeactivateDriverDialog.vue +5 -5
- package/dialog/GitRepoForceUpdateDialog.vue +132 -0
- package/directives/strip-html-aria-label.js +19 -0
- package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
- package/edit/auth/__tests__/oidc.test.ts +60 -12
- package/edit/auth/ldap/__tests__/config.test.ts +40 -0
- package/edit/auth/ldap/config.vue +67 -89
- package/edit/auth/oidc.vue +16 -2
- package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
- package/edit/cis.cattle.io.clusterscan.vue +13 -1
- package/edit/fleet.cattle.io.gitrepo.vue +198 -72
- package/edit/logging-flow/Match.vue +0 -21
- package/edit/management.cattle.io.project.vue +1 -1
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
- package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +0 -2
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
- package/edit/provisioning.cattle.io.cluster/index.vue +28 -30
- package/edit/provisioning.cattle.io.cluster/rke2.vue +64 -13
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
- package/edit/resources.cattle.io.backup.vue +150 -15
- package/edit/secret/__tests__/ssh.test.ts +79 -0
- package/edit/secret/ssh.vue +7 -1
- package/edit/service.vue +0 -3
- package/edit/workload/Job.vue +8 -8
- package/edit/workload/__tests__/Job.test.ts +0 -1
- package/edit/workload/index.vue +3 -1
- package/initialize/install-directives.js +2 -0
- package/initialize/install-plugins.js +6 -1
- package/list/catalog.cattle.io.app.vue +21 -4
- package/list/fleet.cattle.io.bundle.vue +1 -1
- package/list/management.cattle.io.setting.vue +34 -132
- package/list/provisioning.cattle.io.cluster.vue +11 -3
- package/machine-config/vmwarevsphere.vue +15 -8
- package/mixins/__tests__/auth-config.test.ts +74 -0
- package/mixins/__tests__/chart.test.ts +5 -4
- package/mixins/__tests__/create-edit-view.test.ts +38 -0
- package/mixins/auth-config.js +8 -0
- package/mixins/chart.js +2 -2
- package/mixins/create-edit-view/impl.js +4 -1
- package/mixins/vue-select-overrides.js +10 -0
- package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
- package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
- package/models/__tests__/secret.test.ts +56 -13
- package/models/catalog.cattle.io.app.js +112 -37
- package/models/cluster.js +11 -0
- package/models/fleet.cattle.io.bundle.js +40 -2
- package/models/fleet.cattle.io.gitrepo.js +169 -109
- package/models/management.cattle.io.fleetworkspace.js +4 -0
- package/models/management.cattle.io.kontainerdriver.js +7 -0
- package/models/nodedriver.js +4 -1
- package/models/provisioning.cattle.io.cluster.js +24 -0
- package/models/secret.js +1 -1
- package/package.json +5 -5
- package/pages/auth/login.vue +5 -11
- package/pages/auth/verify.vue +11 -1
- package/pages/c/_cluster/apps/charts/index.vue +6 -4
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
- package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
- package/pages/c/_cluster/explorer/index.vue +33 -35
- package/pages/c/_cluster/explorer/tools/index.vue +3 -3
- package/pages/c/_cluster/fleet/index.vue +0 -5
- package/pages/c/_cluster/legacy/project/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +52 -53
- package/pages/c/_cluster/uiplugins/index.vue +19 -22
- package/pages/home.vue +17 -12
- package/pages/prefs.vue +5 -1
- package/plugins/shortkey.js +10 -1
- package/plugins/steve/steve-pagination-utils.ts +58 -8
- package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
- package/promptRemove/management.cattle.io.globalrole.vue +1 -1
- package/promptRemove/management.cattle.io.project.vue +2 -8
- package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
- package/promptRemove/mixin/roleDeletionCheck.js +1 -7
- package/promptRemove/pod.vue +7 -28
- package/rancher-components/Card/Card.vue +9 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
- package/rancher-components/Form/Radio/RadioButton.vue +18 -3
- package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
- package/rancher-components/RcButton/RcButton.test.ts +97 -0
- package/rancher-components/RcButton/RcButton.vue +14 -9
- package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
- package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -2
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
- package/rancher-components/RcDropdown/index.ts +1 -0
- package/rancher-components/RcDropdown/types.ts +27 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
- package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +2 -2
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/auth.test.ts +120 -0
- package/store/action-menu.js +13 -3
- package/store/auth.js +14 -9
- package/store/aws.js +9 -2
- package/store/catalog.js +14 -7
- package/store/features.js +1 -0
- package/store/prefs.js +9 -28
- package/store/type-map.utils.ts +4 -0
- package/types/resources/settings.d.ts +27 -20
- package/types/shell/index.d.ts +18 -12
- package/utils/__tests__/array.test.ts +13 -1
- package/utils/__tests__/string.test.ts +80 -1
- package/utils/array.ts +13 -0
- package/utils/auth.js +4 -0
- package/utils/banners.js +0 -45
- package/utils/cluster.js +1 -1
- package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
- package/utils/object.js +0 -3
- package/utils/pagination-utils.ts +15 -2
- package/utils/string.js +31 -7
- package/utils/validators/formRules/__tests__/index.test.ts +27 -0
- package/utils/validators/formRules/index.ts +16 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
|
@@ -14,7 +14,6 @@ import { SETTING } from '@shell/config/settings';
|
|
|
14
14
|
import { getProductFromRoute } from '@shell/utils/router';
|
|
15
15
|
import { isRancherPrime } from '@shell/config/version';
|
|
16
16
|
import Pinned from '@shell/components/nav/Pinned';
|
|
17
|
-
import { getGlobalBannerFontSizes } from '@shell/utils/banners';
|
|
18
17
|
import { TopLevelMenuHelperPagination, TopLevelMenuHelperLegacy } from '@shell/components/nav/TopLevelMenu.helper';
|
|
19
18
|
import { debounce } from 'lodash';
|
|
20
19
|
import { sameContents } from '@shell/utils/array';
|
|
@@ -82,15 +81,6 @@ export default {
|
|
|
82
81
|
return this.$store.getters['prefs/get'](PINNED_CLUSTERS);
|
|
83
82
|
},
|
|
84
83
|
|
|
85
|
-
sideMenuStyle() {
|
|
86
|
-
const globalBannerSettings = getGlobalBannerFontSizes(this.$store);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
marginBottom: globalBannerSettings?.footerFont,
|
|
90
|
-
marginTop: globalBannerSettings?.headerFont
|
|
91
|
-
};
|
|
92
|
-
},
|
|
93
|
-
|
|
94
84
|
showClusterSearch() {
|
|
95
85
|
return this.allClustersCount > this.maxClustersToShow;
|
|
96
86
|
},
|
|
@@ -483,7 +473,6 @@ export default {
|
|
|
483
473
|
data-testid="side-menu"
|
|
484
474
|
class="side-menu"
|
|
485
475
|
:class="{'menu-open': shown, 'menu-close':!shown}"
|
|
486
|
-
:style="sideMenuStyle"
|
|
487
476
|
tabindex="-1"
|
|
488
477
|
role="navigation"
|
|
489
478
|
:aria-label="t('nav.ariaLabel.topLevelMenu')"
|
|
@@ -1002,7 +991,7 @@ export default {
|
|
|
1002
991
|
}
|
|
1003
992
|
}
|
|
1004
993
|
|
|
1005
|
-
position:
|
|
994
|
+
position: absolute;
|
|
1006
995
|
top: 0;
|
|
1007
996
|
left: 0px;
|
|
1008
997
|
bottom: 0;
|
|
@@ -132,19 +132,20 @@ export default {
|
|
|
132
132
|
|
|
133
133
|
data() {
|
|
134
134
|
return {
|
|
135
|
-
container:
|
|
136
|
-
socket:
|
|
137
|
-
isOpen:
|
|
138
|
-
isFollowing:
|
|
139
|
-
scrollThreshold:
|
|
140
|
-
timestamps:
|
|
141
|
-
wrap:
|
|
142
|
-
previous:
|
|
143
|
-
search:
|
|
144
|
-
backlog:
|
|
145
|
-
lines:
|
|
146
|
-
now:
|
|
147
|
-
logItem:
|
|
135
|
+
container: this.initialContainer || this.pod?.defaultContainerName,
|
|
136
|
+
socket: null,
|
|
137
|
+
isOpen: false,
|
|
138
|
+
isFollowing: true,
|
|
139
|
+
scrollThreshold: 80,
|
|
140
|
+
timestamps: this.$store.getters['prefs/get'](LOGS_TIME),
|
|
141
|
+
wrap: this.$store.getters['prefs/get'](LOGS_WRAP),
|
|
142
|
+
previous: false,
|
|
143
|
+
search: '',
|
|
144
|
+
backlog: [],
|
|
145
|
+
lines: [],
|
|
146
|
+
now: new Date(),
|
|
147
|
+
logItem: shallowRef(LogItem),
|
|
148
|
+
isContainerMenuOpen: false
|
|
148
149
|
};
|
|
149
150
|
},
|
|
150
151
|
|
|
@@ -302,6 +303,14 @@ export default {
|
|
|
302
303
|
},
|
|
303
304
|
|
|
304
305
|
methods: {
|
|
306
|
+
openContainerMenu() {
|
|
307
|
+
this.isContainerMenuOpen = true;
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
closeContainerMenu() {
|
|
311
|
+
this.isContainerMenuOpen = false;
|
|
312
|
+
},
|
|
313
|
+
|
|
305
314
|
async connect() {
|
|
306
315
|
if ( this.socket ) {
|
|
307
316
|
await this.socket.disconnect();
|
|
@@ -581,7 +590,10 @@ export default {
|
|
|
581
590
|
</Select>
|
|
582
591
|
<div class="log-action log-action-group ml-5">
|
|
583
592
|
<button
|
|
584
|
-
class="btn
|
|
593
|
+
class="btn role-primary wm-btn"
|
|
594
|
+
role="button"
|
|
595
|
+
:aria-label="t('wm.containerLogs.follow')"
|
|
596
|
+
:aria-disabled="isFollowing"
|
|
585
597
|
:disabled="isFollowing"
|
|
586
598
|
@click="follow"
|
|
587
599
|
>
|
|
@@ -592,7 +604,9 @@ export default {
|
|
|
592
604
|
<i class="wm-btn-small icon icon-chevron-end" />
|
|
593
605
|
</button>
|
|
594
606
|
<button
|
|
595
|
-
class="btn
|
|
607
|
+
class="btn role-primary wm-btn"
|
|
608
|
+
role="button"
|
|
609
|
+
:aria-label="t('wm.containerLogs.clear')"
|
|
596
610
|
@click="clear"
|
|
597
611
|
>
|
|
598
612
|
<t
|
|
@@ -603,6 +617,8 @@ export default {
|
|
|
603
617
|
</button>
|
|
604
618
|
<AsyncButton
|
|
605
619
|
mode="download"
|
|
620
|
+
role="button"
|
|
621
|
+
:aria-label="t('asyncButton.download.action')"
|
|
606
622
|
@click="download"
|
|
607
623
|
/>
|
|
608
624
|
</div>
|
|
@@ -620,54 +636,72 @@ export default {
|
|
|
620
636
|
</div>
|
|
621
637
|
|
|
622
638
|
<div class="log-action log-action-group ml-5">
|
|
623
|
-
<
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
639
|
+
<div
|
|
640
|
+
role="menu"
|
|
641
|
+
tabindex="0"
|
|
642
|
+
:aria-label="t('wm.containerLogs.logActionMenu')"
|
|
643
|
+
@click="openContainerMenu"
|
|
644
|
+
@blur.capture="closeContainerMenu"
|
|
645
|
+
@keyup.enter="openContainerMenu"
|
|
646
|
+
@keyup.space="openContainerMenu"
|
|
627
647
|
>
|
|
628
|
-
<
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
648
|
+
<v-dropdown
|
|
649
|
+
:triggers="[]"
|
|
650
|
+
:shown="isContainerMenuOpen"
|
|
651
|
+
placement="top"
|
|
652
|
+
popperClass="containerLogsDropdown"
|
|
653
|
+
:autoHide="false"
|
|
654
|
+
:flip="false"
|
|
655
|
+
:container="false"
|
|
656
|
+
@focus.capture="openContainerMenu"
|
|
632
657
|
>
|
|
633
|
-
<
|
|
634
|
-
class="
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
</button>
|
|
642
|
-
|
|
643
|
-
<template #popper>
|
|
644
|
-
<div class="filter-popup">
|
|
645
|
-
<LabeledSelect
|
|
646
|
-
v-model:value="range"
|
|
647
|
-
class="range"
|
|
648
|
-
:label="t('wm.containerLogs.range.label')"
|
|
649
|
-
:options="rangeOptions"
|
|
650
|
-
:clearable="false"
|
|
651
|
-
placement="top"
|
|
652
|
-
@update:value="toggleRange($event)"
|
|
658
|
+
<button
|
|
659
|
+
class="btn role-primary btn-cog"
|
|
660
|
+
role="button"
|
|
661
|
+
:aria-label="t('wm.containerLogs.options')"
|
|
662
|
+
>
|
|
663
|
+
<i
|
|
664
|
+
class="icon icon-gear"
|
|
665
|
+
:alt="t('wm.containerLogs.options')"
|
|
653
666
|
/>
|
|
654
|
-
<
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
<div>
|
|
662
|
-
<
|
|
663
|
-
:
|
|
664
|
-
|
|
665
|
-
|
|
667
|
+
<i
|
|
668
|
+
class="icon icon-chevron-up"
|
|
669
|
+
:alt="t('wm.containerLogs.expand')"
|
|
670
|
+
/>
|
|
671
|
+
</button>
|
|
672
|
+
|
|
673
|
+
<template #popper>
|
|
674
|
+
<div class="filter-popup">
|
|
675
|
+
<LabeledSelect
|
|
676
|
+
v-model:value="range"
|
|
677
|
+
class="range"
|
|
678
|
+
:label="t('wm.containerLogs.range.label')"
|
|
679
|
+
:options="rangeOptions"
|
|
680
|
+
:clearable="false"
|
|
681
|
+
placement="top"
|
|
682
|
+
role="menuitem"
|
|
683
|
+
@update:value="toggleRange($event)"
|
|
666
684
|
/>
|
|
685
|
+
<div>
|
|
686
|
+
<Checkbox
|
|
687
|
+
:label="t('wm.containerLogs.wrap')"
|
|
688
|
+
:value="wrap"
|
|
689
|
+
role="menuitem"
|
|
690
|
+
@update:value="toggleWrap"
|
|
691
|
+
/>
|
|
692
|
+
</div>
|
|
693
|
+
<div>
|
|
694
|
+
<Checkbox
|
|
695
|
+
:label="t('wm.containerLogs.timestamps')"
|
|
696
|
+
:value="timestamps"
|
|
697
|
+
role="menuitem"
|
|
698
|
+
@update:value="toggleTimestamps"
|
|
699
|
+
/>
|
|
700
|
+
</div>
|
|
667
701
|
</div>
|
|
668
|
-
</
|
|
669
|
-
</
|
|
670
|
-
</
|
|
702
|
+
</template>
|
|
703
|
+
</v-dropdown>
|
|
704
|
+
</div>
|
|
671
705
|
</div>
|
|
672
706
|
|
|
673
707
|
<div class="log-action log-action-group ml-5">
|
|
@@ -675,6 +709,8 @@ export default {
|
|
|
675
709
|
v-model="search"
|
|
676
710
|
class="input-sm"
|
|
677
711
|
type="search"
|
|
712
|
+
role="textbox"
|
|
713
|
+
:aria-label="t('wm.containerLogs.searchLogs')"
|
|
678
714
|
:placeholder="t('wm.containerLogs.search')"
|
|
679
715
|
>
|
|
680
716
|
</div>
|
|
@@ -768,6 +804,7 @@ export default {
|
|
|
768
804
|
border: 0 !important;
|
|
769
805
|
min-height: 30px;
|
|
770
806
|
line-height: 30px;
|
|
807
|
+
margin: 0 2px;
|
|
771
808
|
}
|
|
772
809
|
|
|
773
810
|
> input {
|
|
@@ -799,6 +836,7 @@ export default {
|
|
|
799
836
|
text-overflow : ellipsis;
|
|
800
837
|
overflow : hidden;
|
|
801
838
|
white-space : nowrap;
|
|
839
|
+
padding-left: 4px;
|
|
802
840
|
}
|
|
803
841
|
|
|
804
842
|
.status {
|
|
@@ -74,22 +74,24 @@ export default {
|
|
|
74
74
|
|
|
75
75
|
data() {
|
|
76
76
|
return {
|
|
77
|
-
container:
|
|
78
|
-
socket:
|
|
79
|
-
terminal:
|
|
80
|
-
fitAddon:
|
|
81
|
-
searchAddon:
|
|
82
|
-
webglAddon:
|
|
83
|
-
canvasAddon:
|
|
84
|
-
isOpen:
|
|
85
|
-
isOpening:
|
|
86
|
-
backlog:
|
|
87
|
-
node:
|
|
88
|
-
keepAliveTimer:
|
|
89
|
-
errorMsg:
|
|
90
|
-
backupShells:
|
|
91
|
-
os:
|
|
92
|
-
retries:
|
|
77
|
+
container: this.initialContainer || this.pod?.defaultContainerName,
|
|
78
|
+
socket: null,
|
|
79
|
+
terminal: null,
|
|
80
|
+
fitAddon: null,
|
|
81
|
+
searchAddon: null,
|
|
82
|
+
webglAddon: null,
|
|
83
|
+
canvasAddon: null,
|
|
84
|
+
isOpen: false,
|
|
85
|
+
isOpening: false,
|
|
86
|
+
backlog: [],
|
|
87
|
+
node: null,
|
|
88
|
+
keepAliveTimer: null,
|
|
89
|
+
errorMsg: '',
|
|
90
|
+
backupShells: ['linux', 'windows'],
|
|
91
|
+
os: undefined,
|
|
92
|
+
retries: 0,
|
|
93
|
+
currFocusedElem: undefined,
|
|
94
|
+
xtermContainerRef: undefined
|
|
93
95
|
};
|
|
94
96
|
},
|
|
95
97
|
|
|
@@ -106,7 +108,20 @@ export default {
|
|
|
106
108
|
containerChoices() {
|
|
107
109
|
return this.pod?.spec?.containers?.map((x) => x.name) || [];
|
|
108
110
|
},
|
|
109
|
-
|
|
111
|
+
|
|
112
|
+
...mapGetters({ t: 'i18n/t' }),
|
|
113
|
+
|
|
114
|
+
isXtermFocused() {
|
|
115
|
+
return this.currFocusedElem === this.terminal?.textarea;
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
isXtermContainerFocused() {
|
|
119
|
+
return this.currFocusedElem === this.xtermContainerRef;
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
xTermContainerTabIndex() {
|
|
123
|
+
return this.isXtermFocused ? 0 : -1;
|
|
124
|
+
}
|
|
110
125
|
},
|
|
111
126
|
|
|
112
127
|
watch: {
|
|
@@ -121,14 +136,33 @@ export default {
|
|
|
121
136
|
width() {
|
|
122
137
|
this.fit();
|
|
123
138
|
},
|
|
139
|
+
|
|
140
|
+
isXtermContainerFocused: {
|
|
141
|
+
handler(neu) {
|
|
142
|
+
const shellEl = this.terminal?.textarea;
|
|
143
|
+
|
|
144
|
+
if (shellEl) {
|
|
145
|
+
shellEl.tabIndex = neu ? -1 : 0;
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
immediate: true
|
|
149
|
+
}
|
|
124
150
|
},
|
|
125
151
|
|
|
126
152
|
beforeUnmount() {
|
|
153
|
+
document.removeEventListener('keyup', this.handleKeyPress);
|
|
154
|
+
this.$refs?.containerShell?.$el?.removeEventListener('focusin', this.focusInHandler);
|
|
155
|
+
this.$refs?.xterm.removeEventListener('focusout', this.focusOutHandler);
|
|
156
|
+
|
|
127
157
|
clearInterval(this.keepAliveTimer);
|
|
128
158
|
this.cleanup();
|
|
129
159
|
},
|
|
130
160
|
|
|
131
161
|
async mounted() {
|
|
162
|
+
document.addEventListener('keyup', this.handleKeyPress);
|
|
163
|
+
this.$refs?.containerShell?.$el?.addEventListener('focusin', this.focusInHandler);
|
|
164
|
+
this.$refs?.xterm.addEventListener('focusout', this.focusOutHandler);
|
|
165
|
+
|
|
132
166
|
const nodeId = this.pod.spec?.nodeName;
|
|
133
167
|
|
|
134
168
|
try {
|
|
@@ -146,9 +180,36 @@ export default {
|
|
|
146
180
|
this.keepAliveTimer = setInterval(() => {
|
|
147
181
|
this.fit();
|
|
148
182
|
}, 60 * 1000);
|
|
183
|
+
|
|
184
|
+
this.xtermContainerRef = this.$refs?.xterm;
|
|
149
185
|
},
|
|
150
186
|
|
|
151
187
|
methods: {
|
|
188
|
+
focusInHandler(ev) {
|
|
189
|
+
this.currFocusedElem = ev.target;
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
focusOutHandler(ev) {
|
|
193
|
+
this.currFocusedElem = undefined;
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
handleKeyPress(ev) {
|
|
197
|
+
ev.preventDefault();
|
|
198
|
+
ev.stopPropagation();
|
|
199
|
+
|
|
200
|
+
// make focus leave the shell for it's parent container so that we can tab
|
|
201
|
+
const didPressEscapeSequence = ev.shiftKey && ev.code === 'Escape';
|
|
202
|
+
|
|
203
|
+
if (this.isXtermFocused && didPressEscapeSequence) {
|
|
204
|
+
this.$refs.xterm.focus();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// if parent container is focused and we press a trigger, focus goes to the shell inside
|
|
208
|
+
if (this.isXtermContainerFocused && (ev.code === 'Enter' || ev.code === 'Space')) {
|
|
209
|
+
this.terminal?.textarea?.focus();
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
|
|
152
213
|
async setupTerminal() {
|
|
153
214
|
const docStyle = getComputedStyle(document.querySelector('body'));
|
|
154
215
|
const xterm = await import(/* webpackChunkName: "xterm" */ 'xterm');
|
|
@@ -388,6 +449,7 @@ export default {
|
|
|
388
449
|
|
|
389
450
|
<template>
|
|
390
451
|
<Window
|
|
452
|
+
ref="containerShell"
|
|
391
453
|
:active="active"
|
|
392
454
|
:before-close="cleanup"
|
|
393
455
|
class="container-shell"
|
|
@@ -412,7 +474,9 @@ export default {
|
|
|
412
474
|
</Select>
|
|
413
475
|
<div class="pull-left ml-5">
|
|
414
476
|
<button
|
|
415
|
-
class="btn btn-sm
|
|
477
|
+
class="btn btn-sm role-primary"
|
|
478
|
+
role="button"
|
|
479
|
+
:aria-label="t('wm.containerShell.clear')"
|
|
416
480
|
@click="clear"
|
|
417
481
|
>
|
|
418
482
|
<t
|
|
@@ -439,6 +503,12 @@ export default {
|
|
|
439
503
|
class="text-error"
|
|
440
504
|
data-testid="shell-status-disconnected"
|
|
441
505
|
/>
|
|
506
|
+
<span
|
|
507
|
+
v-show="isXtermFocused"
|
|
508
|
+
class="escape-text"
|
|
509
|
+
role="alert"
|
|
510
|
+
:aria-describedby="t('wm.containerShell.escapeText')"
|
|
511
|
+
>{{ t('wm.containerShell.escapeText') }}</span>
|
|
442
512
|
</div>
|
|
443
513
|
</template>
|
|
444
514
|
<template #body>
|
|
@@ -448,6 +518,7 @@ export default {
|
|
|
448
518
|
>
|
|
449
519
|
<div
|
|
450
520
|
ref="xterm"
|
|
521
|
+
:tabindex="xTermContainerTabIndex"
|
|
451
522
|
class="shell-body"
|
|
452
523
|
/>
|
|
453
524
|
<resize-observer @notify="fit" />
|
|
@@ -466,6 +537,11 @@ export default {
|
|
|
466
537
|
animation: flasher 2.5s linear infinite;
|
|
467
538
|
}
|
|
468
539
|
|
|
540
|
+
.escape-text {
|
|
541
|
+
font-size: 12px;
|
|
542
|
+
margin-left: 20px;
|
|
543
|
+
}
|
|
544
|
+
|
|
469
545
|
@keyframes flasher {
|
|
470
546
|
50% {
|
|
471
547
|
opacity: 0;
|
|
@@ -483,6 +559,11 @@ export default {
|
|
|
483
559
|
.shell-body {
|
|
484
560
|
padding: calc(2 * var(--outline-width));
|
|
485
561
|
height: 100%;
|
|
562
|
+
|
|
563
|
+
&:focus-visible, &:focus {
|
|
564
|
+
@include focus-outline;
|
|
565
|
+
outline-offset: -2px;
|
|
566
|
+
}
|
|
486
567
|
}
|
|
487
568
|
|
|
488
569
|
.containerPicker.unlabeled-select {
|
|
@@ -261,15 +261,15 @@ export default {
|
|
|
261
261
|
this.reportedWidth = this.width;
|
|
262
262
|
},
|
|
263
263
|
|
|
264
|
-
setWmDimensions() {
|
|
264
|
+
setWmDimensions(forceValue) {
|
|
265
265
|
switch (this.userPin) {
|
|
266
266
|
case RIGHT:
|
|
267
267
|
case LEFT:
|
|
268
268
|
document.documentElement.style.setProperty('--wm-height', `${ window.innerHeight - 55 }px`);
|
|
269
|
-
document.documentElement.style.setProperty('--wm-width', `${ this.width }px`);
|
|
269
|
+
document.documentElement.style.setProperty('--wm-width', `${ forceValue || this.width }px`);
|
|
270
270
|
break;
|
|
271
271
|
case BOTTOM:
|
|
272
|
-
document.documentElement.style.setProperty('--wm-height', `${ this.height }px`);
|
|
272
|
+
document.documentElement.style.setProperty('--wm-height', `${ forceValue || this.height }px`);
|
|
273
273
|
break;
|
|
274
274
|
}
|
|
275
275
|
},
|
|
@@ -293,6 +293,32 @@ export default {
|
|
|
293
293
|
|
|
294
294
|
emitDraggable(event) {
|
|
295
295
|
this.$emit('draggable', event);
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
resizeVertical(arrowUp) {
|
|
299
|
+
const resizeStep = 20;
|
|
300
|
+
const height = arrowUp ? this.height + resizeStep : this.height - resizeStep;
|
|
301
|
+
|
|
302
|
+
this.height = height;
|
|
303
|
+
|
|
304
|
+
this.setWmDimensions(height);
|
|
305
|
+
this.setReportedHeight(height);
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
resizeHorizontal(arrowLeft) {
|
|
309
|
+
const resizeStep = 20;
|
|
310
|
+
let width;
|
|
311
|
+
|
|
312
|
+
if (this.userPin === 'left') {
|
|
313
|
+
width = arrowLeft ? this.width - resizeStep : this.width + resizeStep;
|
|
314
|
+
} else {
|
|
315
|
+
width = arrowLeft ? this.width + resizeStep : this.width - resizeStep;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
this.width = width;
|
|
319
|
+
|
|
320
|
+
this.setWmDimensions(width);
|
|
321
|
+
this.setReportedWidth(width);
|
|
296
322
|
}
|
|
297
323
|
}
|
|
298
324
|
};
|
|
@@ -311,18 +337,27 @@ export default {
|
|
|
311
337
|
:class="{
|
|
312
338
|
'resizer-left': userPin == 'left',
|
|
313
339
|
}"
|
|
340
|
+
role="tablist"
|
|
341
|
+
@keyup.right.prevent="selectNext(1)"
|
|
342
|
+
@keyup.left.prevent="selectNext(-1)"
|
|
314
343
|
@mousedown="emitDraggable(true)"
|
|
315
344
|
@mouseup="emitDraggable(false)"
|
|
316
345
|
>
|
|
317
346
|
<div
|
|
318
347
|
v-if="userPin == 'right'"
|
|
319
348
|
class="resizer resizer-x"
|
|
349
|
+
role="button"
|
|
350
|
+
tabindex="0"
|
|
351
|
+
:aria-label="t('wm.containerShell.resizeShellWindow', {arrow1: 'left', arrow2: 'right'})"
|
|
352
|
+
aria-expanded="true"
|
|
320
353
|
@mousedown.prevent.stop="dragXStart($event)"
|
|
321
354
|
@touchstart.prevent.stop="dragXStart($event)"
|
|
355
|
+
@keyup.left.prevent.stop="resizeHorizontal(true)"
|
|
356
|
+
@keyup.right.prevent.stop="resizeHorizontal(false)"
|
|
322
357
|
>
|
|
323
358
|
<i
|
|
324
359
|
class="icon icon-code"
|
|
325
|
-
:alt="t('wm.containerShell.resizeShellWindow')"
|
|
360
|
+
:alt="t('wm.containerShell.resizeShellWindow', {arrow1: 'left', arrow2: 'right'})"
|
|
326
361
|
/>
|
|
327
362
|
</div>
|
|
328
363
|
<div
|
|
@@ -330,7 +365,13 @@ export default {
|
|
|
330
365
|
:key="i"
|
|
331
366
|
class="tab"
|
|
332
367
|
:class="{'active': tab.id === active}"
|
|
368
|
+
role="tab"
|
|
369
|
+
:aria-selected="tab.id === active"
|
|
370
|
+
:aria-label="tab.label"
|
|
371
|
+
:aria-controls="`panel-${tab.id}`"
|
|
372
|
+
tabindex="0"
|
|
333
373
|
@click="switchTo(tab.id)"
|
|
374
|
+
@keyup.enter.space="switchTo(tab.id)"
|
|
334
375
|
>
|
|
335
376
|
<i
|
|
336
377
|
v-if="tab.icon"
|
|
@@ -343,39 +384,56 @@ export default {
|
|
|
343
384
|
data-testid="wm-tab-close-button"
|
|
344
385
|
class="closer icon icon-fw icon-x wm-closer-button"
|
|
345
386
|
:alt="t('wm.containerShell.closeShellTab', { tab: tab.label })"
|
|
387
|
+
tabindex="0"
|
|
388
|
+
:aria-label="t('windowmanager.closeTab', { tabId: tab.id })"
|
|
346
389
|
@click.stop="close(tab.id)"
|
|
390
|
+
@keyup.enter.space.stop="close(tab.id)"
|
|
347
391
|
/>
|
|
348
392
|
</div>
|
|
349
393
|
<div
|
|
350
394
|
v-if="userPin == 'bottom'"
|
|
351
395
|
class="resizer resizer-y"
|
|
396
|
+
role="button"
|
|
397
|
+
tabindex="0"
|
|
398
|
+
:aria-label="t('wm.containerShell.resizeShellWindow', {arrow1: 'up', arrow2: 'down'})"
|
|
399
|
+
aria-expanded="true"
|
|
352
400
|
@mousedown.prevent.stop="dragYStart($event)"
|
|
353
401
|
@touchstart.prevent.stop="dragYStart($event)"
|
|
354
402
|
@click="toggle"
|
|
403
|
+
@keyup.up.prevent.stop="resizeVertical(true)"
|
|
404
|
+
@keyup.down.prevent.stop="resizeVertical(false)"
|
|
355
405
|
>
|
|
356
406
|
<i
|
|
357
407
|
class="icon icon-sort"
|
|
358
|
-
:alt="t('wm.containerShell.resizeShellWindow')"
|
|
408
|
+
:alt="t('wm.containerShell.resizeShellWindow', {arrow1: 'up', arrow2: 'down'})"
|
|
359
409
|
/>
|
|
360
410
|
</div>
|
|
361
411
|
<div
|
|
362
412
|
v-if="userPin == 'left'"
|
|
363
413
|
class="resizer resizer-x resizer-align-right"
|
|
414
|
+
role="button"
|
|
415
|
+
tabindex="0"
|
|
416
|
+
:aria-label="t('wm.containerShell.resizeShellWindow', {arrow1: 'left', arrow2: 'right'})"
|
|
417
|
+
aria-expanded="true"
|
|
364
418
|
@mousedown.prevent.stop="dragXStart($event)"
|
|
365
419
|
@touchstart.prevent.stop="dragXStart($event)"
|
|
420
|
+
@keyup.left.prevent.stop="resizeHorizontal(true)"
|
|
421
|
+
@keyup.right.prevent.stop="resizeHorizontal(false)"
|
|
366
422
|
>
|
|
367
423
|
<i
|
|
368
424
|
class="icon icon-code"
|
|
369
|
-
:alt="t('wm.containerShell.resizeShellWindow')"
|
|
425
|
+
:alt="t('wm.containerShell.resizeShellWindow', {arrow1: 'left', arrow2: 'right'})"
|
|
370
426
|
/>
|
|
371
427
|
</div>
|
|
372
428
|
</div>
|
|
373
429
|
<div
|
|
374
430
|
v-for="(tab, i) in tabs"
|
|
431
|
+
:id="`panel-${tab.id}`"
|
|
375
432
|
:key="i"
|
|
376
433
|
class="body"
|
|
377
434
|
:class="{'active': tab.id === active}"
|
|
378
435
|
draggable="false"
|
|
436
|
+
role="tabpanel"
|
|
379
437
|
@dragstart.prevent.stop
|
|
380
438
|
@dragend.prevent.stop
|
|
381
439
|
@mouseover="emitDraggable(false)"
|
|
@@ -442,6 +500,11 @@ export default {
|
|
|
442
500
|
z-index: 1;
|
|
443
501
|
}
|
|
444
502
|
|
|
503
|
+
&:focus-visible {
|
|
504
|
+
@include focus-outline;
|
|
505
|
+
outline-offset: -3px;
|
|
506
|
+
}
|
|
507
|
+
|
|
445
508
|
.closer {
|
|
446
509
|
margin-left: 5px;
|
|
447
510
|
border: 1px solid var(--body-text);
|
|
@@ -457,6 +520,11 @@ export default {
|
|
|
457
520
|
border-color: var(--link-border);
|
|
458
521
|
color: var(--link-border);
|
|
459
522
|
}
|
|
523
|
+
|
|
524
|
+
&:focus-visible {
|
|
525
|
+
@include focus-outline;
|
|
526
|
+
outline-offset: 1px;
|
|
527
|
+
}
|
|
460
528
|
}
|
|
461
529
|
}
|
|
462
530
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import TopLevelMenu from '@shell/components/nav/TopLevelMenu.vue';
|
|
2
|
-
import { SETTING } from '@shell/config/settings';
|
|
3
2
|
import { mount, Wrapper } from '@vue/test-utils';
|
|
4
3
|
import { CAPI, COUNT, MANAGEMENT } from '@shell/config/types';
|
|
5
4
|
import { PINNED_CLUSTERS } from '@shell/store/prefs';
|
|
@@ -429,45 +428,6 @@ describe('topLevelMenu', () => {
|
|
|
429
428
|
expect(description4.text()).toStrictEqual('some-description4');
|
|
430
429
|
});
|
|
431
430
|
|
|
432
|
-
it('should not "crash" the component if the structure of banner settings is in an old format', async() => {
|
|
433
|
-
const wrapper: Wrapper<InstanceType<typeof TopLevelMenu>> = mount(TopLevelMenu, {
|
|
434
|
-
global: {
|
|
435
|
-
mocks: {
|
|
436
|
-
$route: {},
|
|
437
|
-
$store: {
|
|
438
|
-
...generateStore(
|
|
439
|
-
[{ name: 'whatever' }],
|
|
440
|
-
[
|
|
441
|
-
// object based on https://github.com/rancher/dashboard/issues/10140#issuecomment-1883252402
|
|
442
|
-
{
|
|
443
|
-
id: SETTING.BANNERS,
|
|
444
|
-
value: JSON.stringify({
|
|
445
|
-
banner: {
|
|
446
|
-
color: '#78c9cf',
|
|
447
|
-
background: '#27292e',
|
|
448
|
-
text: 'Hello World!'
|
|
449
|
-
},
|
|
450
|
-
showHeader: 'true',
|
|
451
|
-
showFooter: 'true'
|
|
452
|
-
})
|
|
453
|
-
}
|
|
454
|
-
]
|
|
455
|
-
),
|
|
456
|
-
}
|
|
457
|
-
},
|
|
458
|
-
|
|
459
|
-
stubs: ['BrandImage', 'router-link'],
|
|
460
|
-
},
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
await waitForIt();
|
|
464
|
-
|
|
465
|
-
expect(wrapper.vm.sideMenuStyle).toStrictEqual({
|
|
466
|
-
marginBottom: '2em',
|
|
467
|
-
marginTop: '2em'
|
|
468
|
-
});
|
|
469
|
-
});
|
|
470
|
-
|
|
471
431
|
describe('searching a term', () => {
|
|
472
432
|
describe('should displays a no results message if have clusters but', () => {
|
|
473
433
|
it('given no matching clusters', async() => {
|