@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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
3
|
+
import Banner from '@components/Banner/Banner.vue';
|
|
4
|
+
import { _CREATE, _EDIT } from '@shell/config/query-params';
|
|
5
|
+
export default {
|
|
6
|
+
name: 'SchedulingCustomization',
|
|
7
|
+
components: { Checkbox, Banner },
|
|
8
|
+
emits: ['scheduling-customization-changed'],
|
|
9
|
+
props: {
|
|
10
|
+
value: {
|
|
11
|
+
type: Object,
|
|
12
|
+
default: () => {},
|
|
13
|
+
},
|
|
14
|
+
mode: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: _CREATE
|
|
17
|
+
},
|
|
18
|
+
feature: {
|
|
19
|
+
type: Boolean,
|
|
20
|
+
required: true
|
|
21
|
+
},
|
|
22
|
+
defaultPC: {
|
|
23
|
+
type: Object,
|
|
24
|
+
default: () => {},
|
|
25
|
+
},
|
|
26
|
+
defaultPDB: {
|
|
27
|
+
type: Object,
|
|
28
|
+
default: () => {},
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
data() {
|
|
32
|
+
return { applyGlobal: false };
|
|
33
|
+
},
|
|
34
|
+
computed: {
|
|
35
|
+
isEdit() {
|
|
36
|
+
return this.mode === _EDIT;
|
|
37
|
+
},
|
|
38
|
+
enabled() {
|
|
39
|
+
return !!this.value;
|
|
40
|
+
},
|
|
41
|
+
settingMissmatch() {
|
|
42
|
+
const pdbMaxUnavailableMismatch = this.value?.podDisruptionBudget.maxUnavailable !== this.defaultPDB.maxUnavailable;
|
|
43
|
+
const pdbMinAvailableMismatch = this.value?.podDisruptionBudget.minAvailable !== this.defaultPDB.minAvailable;
|
|
44
|
+
const pcValueMismatch = this.value?.priorityClass.value !== this.defaultPC.value;
|
|
45
|
+
const pcPreemptionMismatch = this.value?.priorityClass.preemptionPolicy !== this.defaultPC.preemptionPolicy;
|
|
46
|
+
const pdbMismatch = !!this.value?.podDisruptionBudget && ( pdbMaxUnavailableMismatch || pdbMinAvailableMismatch);
|
|
47
|
+
const pcMismatch = !!this.value?.priorityClass && ( pcValueMismatch || pcPreemptionMismatch);
|
|
48
|
+
|
|
49
|
+
return pdbMismatch || pcMismatch;
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<div
|
|
57
|
+
class="mt-20"
|
|
58
|
+
>
|
|
59
|
+
<Checkbox
|
|
60
|
+
:value="enabled"
|
|
61
|
+
:mode="mode"
|
|
62
|
+
label-key="cluster.agentConfig.subGroups.schedulingCustomization.label"
|
|
63
|
+
descriptionKey="cluster.agentConfig.subGroups.schedulingCustomization.description"
|
|
64
|
+
data-testid="scheduling-customization-checkbox"
|
|
65
|
+
@update:value="$emit('scheduling-customization-changed', $event)"
|
|
66
|
+
>
|
|
67
|
+
<template
|
|
68
|
+
v-if="feature && isEdit && settingMissmatch"
|
|
69
|
+
#extra
|
|
70
|
+
>
|
|
71
|
+
<Banner
|
|
72
|
+
class="mt-10 mb-10"
|
|
73
|
+
color="info"
|
|
74
|
+
label-key="cluster.agentConfig.subGroups.schedulingCustomization.banner"
|
|
75
|
+
/>
|
|
76
|
+
<Checkbox
|
|
77
|
+
:value="applyGlobal"
|
|
78
|
+
:mode="mode"
|
|
79
|
+
label-key="cluster.agentConfig.subGroups.schedulingCustomization.innerCheckbox"
|
|
80
|
+
@update:value="$emit('scheduling-customization-changed', feature)"
|
|
81
|
+
/>
|
|
82
|
+
</template>
|
|
83
|
+
</Checkbox>
|
|
84
|
+
</div>
|
|
85
|
+
</template>
|
|
@@ -256,7 +256,8 @@ export default {
|
|
|
256
256
|
}"
|
|
257
257
|
:tabindex="disabled || isView ? -1 : 0"
|
|
258
258
|
@click="focusSearch"
|
|
259
|
-
@keydown.enter
|
|
259
|
+
@keydown.enter="focusSearch"
|
|
260
|
+
@keydown.down.prevent="focusSearch"
|
|
260
261
|
@keydown.space.prevent="focusSearch"
|
|
261
262
|
>
|
|
262
263
|
<v-select
|
|
@@ -281,7 +282,7 @@ export default {
|
|
|
281
282
|
:modelValue="value != null ? value : ''"
|
|
282
283
|
:dropdownShouldOpen="handleDropdownOpen"
|
|
283
284
|
:tabindex="-1"
|
|
284
|
-
|
|
285
|
+
role="listbox"
|
|
285
286
|
@update:modelValue="$emit('update:value', $event)"
|
|
286
287
|
@search:blur="onBlur"
|
|
287
288
|
@search:focus="onFocus"
|
|
@@ -147,7 +147,7 @@ export default {
|
|
|
147
147
|
|
|
148
148
|
showSshKnownHosts: {
|
|
149
149
|
type: Boolean,
|
|
150
|
-
default:
|
|
150
|
+
default: false,
|
|
151
151
|
},
|
|
152
152
|
},
|
|
153
153
|
|
|
@@ -632,6 +632,7 @@ export default {
|
|
|
632
632
|
>
|
|
633
633
|
<SSHKnownHosts
|
|
634
634
|
v-model:value="sshKnownHosts"
|
|
635
|
+
data-testid="auth-secret-known-ssh-hosts"
|
|
635
636
|
:mode="mode"
|
|
636
637
|
/>
|
|
637
638
|
</div>
|
|
@@ -206,7 +206,7 @@ export default {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
if (this.outputModifier) {
|
|
209
|
-
out = out === null ? null : `${ inputValue }${ this.unit }`;
|
|
209
|
+
out = out === null ? null : `${ parseInt(inputValue) }${ this.unit }`;
|
|
210
210
|
} else if ( this.outputAs === 'string' ) {
|
|
211
211
|
out = out === null ? '' : `${ inputValue }`;
|
|
212
212
|
} else if (out) {
|
|
@@ -235,7 +235,7 @@ export default {
|
|
|
235
235
|
:required="required"
|
|
236
236
|
:placeholder="placeholder"
|
|
237
237
|
:hide-arrows="hideArrows"
|
|
238
|
-
@
|
|
238
|
+
@update:value="update"
|
|
239
239
|
@blur="update($event.target.value)"
|
|
240
240
|
>
|
|
241
241
|
<template #suffix>
|
|
@@ -252,7 +252,6 @@ export default {
|
|
|
252
252
|
|
|
253
253
|
<style lang="scss" scoped>
|
|
254
254
|
.addon.with-tooltip {
|
|
255
|
-
|
|
256
|
-
right: 30px;
|
|
255
|
+
padding-right: 42px;
|
|
257
256
|
}
|
|
258
257
|
</style>
|
|
@@ -47,19 +47,22 @@ describe('the ArrayList', () => {
|
|
|
47
47
|
expect(arrayListBoxes).toHaveLength(2);
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
it('
|
|
50
|
+
it('should remove the correct item, emit the removed item and the updated values', async() => {
|
|
51
51
|
const wrapper = mount(ArrayList, {
|
|
52
52
|
props: {
|
|
53
|
-
value: ['string 1', 'string 2'],
|
|
53
|
+
value: ['string 0', 'string 1', 'string 2'],
|
|
54
54
|
mode: _EDIT,
|
|
55
55
|
},
|
|
56
56
|
});
|
|
57
|
-
const deleteButton = wrapper.get('[data-testid^="remove-item"]').element as HTMLElement;
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
jest.useFakeTimers();
|
|
59
|
+
await (wrapper.get('[data-testid="remove-item-1"]').element as HTMLElement).click();
|
|
60
|
+
jest.advanceTimersByTime(50);
|
|
61
|
+
jest.useRealTimers();
|
|
61
62
|
|
|
62
|
-
expect(
|
|
63
|
+
expect(wrapper.find('[data-testid="remove-item-2"]').exists()).toBe(false);
|
|
64
|
+
expect((wrapper.emitted('remove')![0][0] as any).row.value).toStrictEqual('string 1');
|
|
65
|
+
expect(wrapper.emitted('update:value')![0][0]).toStrictEqual(['string 0', 'string 2']);
|
|
63
66
|
});
|
|
64
67
|
|
|
65
68
|
it('add button is hidden in read-only mode', () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { _VIEW, _EDIT, _CREATE } from '@shell/config/query-params';
|
|
2
3
|
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
|
|
3
4
|
import { defineComponent } from 'vue';
|
|
4
5
|
|
|
@@ -137,6 +138,42 @@ describe('component: LabeledSelect', () => {
|
|
|
137
138
|
});
|
|
138
139
|
});
|
|
139
140
|
|
|
141
|
+
describe(`given {'disabled', 'mode', 'loading'} options`, () => {
|
|
142
|
+
it.each([
|
|
143
|
+
['open', false, _EDIT, false, true],
|
|
144
|
+
['open', false, _CREATE, false, true],
|
|
145
|
+
['not open', false, _VIEW, false, false],
|
|
146
|
+
['not open', false, _EDIT, true, false],
|
|
147
|
+
['not open', true, _EDIT, false, false],
|
|
148
|
+
])('should %p dropdown element if options are { disabled: %p, mode: %p, loading: %p }', async(
|
|
149
|
+
_,
|
|
150
|
+
disabled,
|
|
151
|
+
mode,
|
|
152
|
+
loading,
|
|
153
|
+
isOpen
|
|
154
|
+
) => {
|
|
155
|
+
const label = 'Foo';
|
|
156
|
+
const value = 'foo';
|
|
157
|
+
const wrapper = mount(LabeledSelect, {
|
|
158
|
+
props: {
|
|
159
|
+
value,
|
|
160
|
+
options: [
|
|
161
|
+
{ label, value },
|
|
162
|
+
],
|
|
163
|
+
disabled,
|
|
164
|
+
mode,
|
|
165
|
+
loading
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
await wrapper.trigger('click');
|
|
170
|
+
|
|
171
|
+
const dropdownOpen = wrapper.find('.vs--open');
|
|
172
|
+
|
|
173
|
+
expect(dropdownOpen.exists()).toBe(isOpen);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
140
177
|
describe('given attributes from parent element', () => {
|
|
141
178
|
it('should not pass classes to the select element', () => {
|
|
142
179
|
const customClass = 'bananas';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { _EDIT } from '@shell/config/query-params';
|
|
3
|
+
import { AUTH_TYPE } from '@shell/config/types';
|
|
4
|
+
import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthSecret.vue';
|
|
5
|
+
|
|
6
|
+
const requiredSetup = () => {
|
|
7
|
+
return { global: { mocks: { $fetchState: {} } } };
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
describe('component: SelectOrCreateAuthSecret', () => {
|
|
11
|
+
it.each([
|
|
12
|
+
['display', true],
|
|
13
|
+
['not display', false],
|
|
14
|
+
['not display', undefined], // prop's default value is used
|
|
15
|
+
])('mode edit: should %p sshKnownHosts field if enabled and auth type is SSH', (_, showSshKnownHosts) => {
|
|
16
|
+
const wrapper = mount(SelectOrCreateAuthSecret, {
|
|
17
|
+
...requiredSetup(),
|
|
18
|
+
props: {
|
|
19
|
+
mode: _EDIT,
|
|
20
|
+
namespace: 'default',
|
|
21
|
+
value: {},
|
|
22
|
+
showSshKnownHosts,
|
|
23
|
+
registerBeforeHook: () => {},
|
|
24
|
+
},
|
|
25
|
+
data() {
|
|
26
|
+
return { selected: AUTH_TYPE._SSH } as any;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const knownSshHosts = wrapper.find('[data-testid="auth-secret-known-ssh-hosts"]');
|
|
31
|
+
|
|
32
|
+
expect(knownSshHosts.exists()).toBe(showSshKnownHosts || false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -11,7 +11,7 @@ describe('component: UnitInput', () => {
|
|
|
11
11
|
expect(wrapper.isVisible()).toBe(true);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it.each(['blur', '
|
|
14
|
+
it.each(['blur', 'update:value'])('should emit input event when "%p" is fired', async(event) => {
|
|
15
15
|
const wrapper = mount(UnitInput, { props: { value: 1, delay: 0 } });
|
|
16
16
|
const input = wrapper.find('input');
|
|
17
17
|
|
|
@@ -20,7 +20,7 @@ describe('component: UnitInput', () => {
|
|
|
20
20
|
input.trigger(event);
|
|
21
21
|
|
|
22
22
|
expect(wrapper.emitted('update:value')).toBeTruthy();
|
|
23
|
-
expect(wrapper.emitted('update:value')[
|
|
23
|
+
expect(wrapper.emitted('update:value')[1]).toStrictEqual([4]);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it.each([
|
|
@@ -184,7 +184,7 @@ describe('component: UnitInput', () => {
|
|
|
184
184
|
input.trigger('blur');
|
|
185
185
|
|
|
186
186
|
expect(wrapper.emitted('update:value')).toBeTruthy();
|
|
187
|
-
expect(wrapper.emitted('update:value')[
|
|
187
|
+
expect(wrapper.emitted('update:value')[0][0]).toBe(value);
|
|
188
188
|
});
|
|
189
189
|
|
|
190
190
|
describe.each([
|
|
@@ -207,7 +207,7 @@ describe('component: UnitInput', () => {
|
|
|
207
207
|
expect(inputElement.value).toBe('123');
|
|
208
208
|
});
|
|
209
209
|
|
|
210
|
-
it.each(['
|
|
210
|
+
it.each(['update:value', 'blur'])('on %p 123 should display input value 123', async(trigger) => {
|
|
211
211
|
const wrapper = mount(UnitInput, {
|
|
212
212
|
props: {
|
|
213
213
|
value: '0',
|
|
@@ -248,7 +248,6 @@ describe('component: UnitInput', () => {
|
|
|
248
248
|
const input = wrapper.find('input');
|
|
249
249
|
|
|
250
250
|
await input.trigger('update:value');
|
|
251
|
-
await input.trigger('input');
|
|
252
251
|
|
|
253
252
|
expect(input.element.value).toBe('123');
|
|
254
253
|
});
|
|
@@ -151,7 +151,9 @@ export default {
|
|
|
151
151
|
</span>
|
|
152
152
|
<span
|
|
153
153
|
v-else-if="showTooltip"
|
|
154
|
-
v-clean-tooltip="{content: title, placement: tooltipPlacement}"
|
|
154
|
+
v-clean-tooltip="{content: title, placement: tooltipPlacement, triggers: ['hover', 'touch', 'focus'] }"
|
|
155
|
+
v-stripped-aria-label="title"
|
|
156
|
+
tabindex="0"
|
|
155
157
|
class="live-date"
|
|
156
158
|
>
|
|
157
159
|
{{ suffixedLabel }}
|
|
@@ -16,11 +16,19 @@ export default {
|
|
|
16
16
|
default: () => {}
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
|
-
data() {
|
|
20
|
-
const cloned = this.getLabel(this.value.toLowerCase());
|
|
21
|
-
const headless = this.value === 'ClusterIP' && this.row?.spec?.clusterIP === 'None' ? this.getLabel('headless') : undefined;
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
computed: {
|
|
21
|
+
translated() {
|
|
22
|
+
const value = this.value;
|
|
23
|
+
|
|
24
|
+
return this.getLabel(value.toLocaleLowerCase());
|
|
25
|
+
},
|
|
26
|
+
clusterIp() {
|
|
27
|
+
return this.row?.spec?.clusterIP;
|
|
28
|
+
},
|
|
29
|
+
headless() {
|
|
30
|
+
return this.value === 'ClusterIP' && this.clusterIp === 'None' ? this.getLabel('headless') : undefined;
|
|
31
|
+
}
|
|
24
32
|
},
|
|
25
33
|
|
|
26
34
|
methods: {
|
|
@@ -189,7 +189,8 @@ export default {
|
|
|
189
189
|
:aria-label="t('workload.healthScaleToggle')"
|
|
190
190
|
:aria-expanded="expanded"
|
|
191
191
|
@click="expanded = !expanded"
|
|
192
|
-
@keyup.enter
|
|
192
|
+
@keyup.enter="expanded = !expanded"
|
|
193
|
+
@keydown.space.prevent="expanded = !expanded"
|
|
193
194
|
>
|
|
194
195
|
<ProgressBarMulti
|
|
195
196
|
v-if="parts"
|
|
@@ -81,7 +81,7 @@ export default {
|
|
|
81
81
|
extensionHeaderActions: getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, this.$route),
|
|
82
82
|
ctx: this,
|
|
83
83
|
showImportModal: false,
|
|
84
|
-
showSearchModal: false
|
|
84
|
+
showSearchModal: false
|
|
85
85
|
};
|
|
86
86
|
},
|
|
87
87
|
|
|
@@ -403,6 +403,7 @@ export default {
|
|
|
403
403
|
<div>
|
|
404
404
|
<TopLevelMenu v-if="isRancherInHarvester || isMultiCluster || !isSingleProduct" />
|
|
405
405
|
</div>
|
|
406
|
+
|
|
406
407
|
<div
|
|
407
408
|
class="menu-spacer"
|
|
408
409
|
:class="{'isSingleProduct': isSingleProduct }"
|
|
@@ -410,20 +411,25 @@ export default {
|
|
|
410
411
|
<router-link
|
|
411
412
|
v-if="isSingleProduct && !isRancherInHarvester"
|
|
412
413
|
:to="singleProductLogoRoute"
|
|
414
|
+
role="link"
|
|
415
|
+
:alt="t('branding.logos.home')"
|
|
413
416
|
>
|
|
414
417
|
<BrandImage
|
|
415
418
|
v-if="isSingleProduct.supportCustomLogo && isHarvester"
|
|
416
419
|
class="side-menu-logo"
|
|
417
420
|
file-name="harvester.svg"
|
|
418
421
|
:support-custom-logo="true"
|
|
422
|
+
:alt="t('branding.logos.label')"
|
|
419
423
|
/>
|
|
420
424
|
<img
|
|
421
425
|
v-else
|
|
422
426
|
class="side-menu-logo"
|
|
423
427
|
:src="isSingleProduct.logo"
|
|
428
|
+
:alt="t('branding.logos.label')"
|
|
424
429
|
>
|
|
425
430
|
</router-link>
|
|
426
431
|
</div>
|
|
432
|
+
|
|
427
433
|
<div
|
|
428
434
|
v-if="!simple"
|
|
429
435
|
ref="product"
|
|
@@ -450,6 +456,7 @@ export default {
|
|
|
450
456
|
v-if="currentCluster"
|
|
451
457
|
:cluster="currentCluster"
|
|
452
458
|
class="mr-10"
|
|
459
|
+
:alt="t('branding.logos.label')"
|
|
453
460
|
/>
|
|
454
461
|
<div
|
|
455
462
|
v-if="currentCluster"
|
|
@@ -462,6 +469,7 @@ export default {
|
|
|
462
469
|
v-if="currentCluster"
|
|
463
470
|
:cluster="currentCluster"
|
|
464
471
|
class="ml-10"
|
|
472
|
+
:alt="t('branding.logos.label')"
|
|
465
473
|
/>
|
|
466
474
|
<div
|
|
467
475
|
v-if="!currentCluster"
|
|
@@ -470,6 +478,7 @@ export default {
|
|
|
470
478
|
<BrandImage
|
|
471
479
|
class="side-menu-logo-img"
|
|
472
480
|
file-name="rancher-logo.svg"
|
|
481
|
+
:alt="t('branding.logos.label')"
|
|
473
482
|
/>
|
|
474
483
|
</div>
|
|
475
484
|
</template>
|
|
@@ -484,12 +493,14 @@ export default {
|
|
|
484
493
|
:src="currentProduct.iconHeader"
|
|
485
494
|
class="cluster-os-logo mr-10"
|
|
486
495
|
style="width: 44px; height: 36px;"
|
|
496
|
+
:alt="t('branding.logos.label')"
|
|
487
497
|
>
|
|
488
498
|
<div class="product-name">
|
|
489
499
|
{{ prod }}
|
|
490
500
|
</div>
|
|
491
501
|
</div>
|
|
492
502
|
</div>
|
|
503
|
+
|
|
493
504
|
<div
|
|
494
505
|
v-else
|
|
495
506
|
class="simple-title"
|
|
@@ -507,8 +518,9 @@ export default {
|
|
|
507
518
|
>
|
|
508
519
|
<BrandImage
|
|
509
520
|
class="side-menu-logo-img"
|
|
510
|
-
data-testid="
|
|
521
|
+
data-testid="header__brand-img"
|
|
511
522
|
file-name="rancher-logo.svg"
|
|
523
|
+
:alt="t('branding.logos.label')"
|
|
512
524
|
/>
|
|
513
525
|
</div>
|
|
514
526
|
</div>
|
|
@@ -536,6 +548,9 @@ export default {
|
|
|
536
548
|
type="button"
|
|
537
549
|
class="btn header-btn role-tertiary"
|
|
538
550
|
data-testid="header-action-import-yaml"
|
|
551
|
+
role="button"
|
|
552
|
+
tabindex="0"
|
|
553
|
+
:aria-label="t('nav.import')"
|
|
539
554
|
@click="openImport()"
|
|
540
555
|
>
|
|
541
556
|
<i class="icon icon-upload icon-lg" />
|
|
@@ -563,6 +578,9 @@ export default {
|
|
|
563
578
|
:disabled="!shellEnabled"
|
|
564
579
|
type="button"
|
|
565
580
|
class="btn header-btn role-tertiary"
|
|
581
|
+
role="button"
|
|
582
|
+
tabindex="0"
|
|
583
|
+
:aria-label="t('nav.shellShortcut', {key:''})"
|
|
566
584
|
@shortkey="currentCluster.openShell()"
|
|
567
585
|
@click="currentCluster.openShell()"
|
|
568
586
|
>
|
|
@@ -576,6 +594,9 @@ export default {
|
|
|
576
594
|
type="button"
|
|
577
595
|
class="btn header-btn role-tertiary"
|
|
578
596
|
data-testid="btn-download-kubeconfig"
|
|
597
|
+
role="button"
|
|
598
|
+
tabindex="0"
|
|
599
|
+
:aria-label="t('nav.kubeconfig.download')"
|
|
579
600
|
@click="currentCluster.downloadKubeConfig()"
|
|
580
601
|
>
|
|
581
602
|
<i class="icon icon-file icon-lg" />
|
|
@@ -588,6 +609,9 @@ export default {
|
|
|
588
609
|
type="button"
|
|
589
610
|
class="btn header-btn role-tertiary"
|
|
590
611
|
data-testid="btn-copy-kubeconfig"
|
|
612
|
+
role="button"
|
|
613
|
+
tabindex="0"
|
|
614
|
+
:aria-label="t('nav.kubeconfig.copy')"
|
|
591
615
|
@click="copyKubeConfig($event)"
|
|
592
616
|
>
|
|
593
617
|
<i
|
|
@@ -603,11 +627,15 @@ export default {
|
|
|
603
627
|
|
|
604
628
|
<button
|
|
605
629
|
v-if="showSearch"
|
|
630
|
+
id="header-btn-search"
|
|
606
631
|
v-clean-tooltip="t('nav.resourceSearch.toolTip', {key: searchShortcut})"
|
|
607
632
|
v-shortkey="{windows: ['ctrl', 'k'], mac: ['meta', 'k']}"
|
|
608
633
|
type="button"
|
|
609
634
|
class="btn header-btn role-tertiary"
|
|
610
635
|
data-testid="header-resource-search"
|
|
636
|
+
role="button"
|
|
637
|
+
tabindex="0"
|
|
638
|
+
:aria-label="t('nav.resourceSearch.toolTip', {key: ''})"
|
|
611
639
|
@shortkey="openSearch()"
|
|
612
640
|
@click="openSearch()"
|
|
613
641
|
>
|
|
@@ -619,6 +647,8 @@ export default {
|
|
|
619
647
|
name="searchModal"
|
|
620
648
|
width="50%"
|
|
621
649
|
height="auto"
|
|
650
|
+
:trigger-focus-trap="true"
|
|
651
|
+
return-focus-selector="#header-btn-search"
|
|
622
652
|
@close="hideSearch()"
|
|
623
653
|
>
|
|
624
654
|
<Jump @closeSearch="hideSearch()" />
|
|
@@ -639,6 +669,9 @@ export default {
|
|
|
639
669
|
type="button"
|
|
640
670
|
class="btn header-btn role-tertiary"
|
|
641
671
|
:data-testid="`extension-header-action-${ action.labelKey || action.label }`"
|
|
672
|
+
role="button"
|
|
673
|
+
tabindex="0"
|
|
674
|
+
:aria-label="action.label"
|
|
642
675
|
@shortkey="handleExtensionAction(action, $event)"
|
|
643
676
|
@click="handleExtensionAction(action, $event)"
|
|
644
677
|
>
|
|
@@ -1,51 +1,22 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { computed } from 'vue';
|
|
3
3
|
import { useStore } from 'vuex';
|
|
4
|
-
import {
|
|
5
|
-
RcDropdown,
|
|
6
|
-
RcDropdownItem,
|
|
7
|
-
RcDropdownSeparator,
|
|
8
|
-
RcDropdownTrigger
|
|
9
|
-
} from '@components/RcDropdown';
|
|
10
|
-
|
|
11
|
-
const isPageActionMenuOpen = ref(false);
|
|
12
|
-
|
|
13
|
-
const showPageActionsMenu = (show: boolean) => {
|
|
14
|
-
isPageActionMenuOpen.value = show;
|
|
15
|
-
};
|
|
4
|
+
import { RcDropdownMenu } from '@components/RcDropdown';
|
|
16
5
|
|
|
17
6
|
const store = useStore();
|
|
18
7
|
const pageActions = computed(() => store.getters.pageActions);
|
|
19
|
-
const pageAction = (action: string) => {
|
|
8
|
+
const pageAction = (_event: Event, action: string) => {
|
|
20
9
|
store.dispatch('handlePageAction', action);
|
|
21
|
-
showPageActionsMenu(false);
|
|
22
10
|
};
|
|
23
11
|
</script>
|
|
24
12
|
|
|
25
13
|
<template>
|
|
26
|
-
<rc-dropdown
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<template #dropdownCollection>
|
|
35
|
-
<template
|
|
36
|
-
v-for="(a) in pageActions"
|
|
37
|
-
:key="a.label"
|
|
38
|
-
>
|
|
39
|
-
<rc-dropdown-item
|
|
40
|
-
v-if="!a.separator"
|
|
41
|
-
@click="pageAction(a)"
|
|
42
|
-
>
|
|
43
|
-
{{ a.labelKey ? t(a.labelKey) : a.label }}
|
|
44
|
-
</rc-dropdown-item>
|
|
45
|
-
<rc-dropdown-separator
|
|
46
|
-
v-else
|
|
47
|
-
/>
|
|
48
|
-
</template>
|
|
49
|
-
</template>
|
|
50
|
-
</rc-dropdown>
|
|
14
|
+
<rc-dropdown-menu
|
|
15
|
+
:options="pageActions"
|
|
16
|
+
:button-aria-label="t('nav.actionMenu.label')"
|
|
17
|
+
:dropdown-aria-label="t('nav.actionMenu.button.label')"
|
|
18
|
+
data-testid="page-actions-menu-action-button"
|
|
19
|
+
button-role="tertiary"
|
|
20
|
+
@select="pageAction"
|
|
21
|
+
/>
|
|
51
22
|
</template>
|
package/components/nav/Jump.vue
CHANGED
|
@@ -64,7 +64,7 @@ export default {
|
|
|
64
64
|
|
|
65
65
|
g.hidden = !!hidden;
|
|
66
66
|
});
|
|
67
|
-
}
|
|
67
|
+
}
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
</script>
|
|
@@ -76,6 +76,8 @@ export default {
|
|
|
76
76
|
v-model="value"
|
|
77
77
|
:placeholder="t('nav.resourceSearch.placeholder')"
|
|
78
78
|
class="search"
|
|
79
|
+
role="textbox"
|
|
80
|
+
:aria-label="t('nav.resourceSearch.label')"
|
|
79
81
|
@keyup.esc="$emit('closeSearch')"
|
|
80
82
|
>
|
|
81
83
|
<div class="results">
|
|
@@ -103,13 +105,17 @@ export default {
|
|
|
103
105
|
</template>
|
|
104
106
|
|
|
105
107
|
<style lang="scss" scoped>
|
|
106
|
-
.search, .search:hover
|
|
108
|
+
.search, .search:hover {
|
|
107
109
|
position: relative;
|
|
108
110
|
background-color: var(--dropdown-bg);
|
|
109
111
|
border-radius: 0;
|
|
110
112
|
box-shadow: none;
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
.search:focus-visible {
|
|
116
|
+
outline-offset: -2px;
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
.results {
|
|
114
120
|
margin-top: -1px;
|
|
115
121
|
overflow-y: auto;
|
|
@@ -894,12 +894,13 @@ export default {
|
|
|
894
894
|
display: inline-block;
|
|
895
895
|
|
|
896
896
|
.ns-glass {
|
|
897
|
-
|
|
897
|
+
top: 0;
|
|
898
|
+
bottom: 0;
|
|
898
899
|
left: 0;
|
|
900
|
+
right: 0;
|
|
899
901
|
opacity: 0;
|
|
900
|
-
position:
|
|
901
|
-
|
|
902
|
-
width: 100vw;
|
|
902
|
+
position: fixed;
|
|
903
|
+
|
|
903
904
|
z-index: z-index('overContent');
|
|
904
905
|
}
|
|
905
906
|
|
|
@@ -37,7 +37,7 @@ export default {
|
|
|
37
37
|
class="pin icon"
|
|
38
38
|
:class="{'icon-pin-outlined': !pinned, 'icon-pin': pinned}"
|
|
39
39
|
aria-role="button"
|
|
40
|
-
:aria-label="
|
|
40
|
+
:aria-label="t('nav.ariaLabel.pinCluster', { cluster: cluster.label })"
|
|
41
41
|
@click.stop.prevent="toggle"
|
|
42
42
|
@keydown.enter.prevent="toggle"
|
|
43
43
|
@keydown.space.prevent="toggle"
|
|
@@ -37,7 +37,7 @@ type ProvCluster = {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Order
|
|
40
|
+
* Order of v1 mgmt clusters
|
|
41
41
|
* 1. local cluster - https://github.com/rancher/dashboard/issues/10975
|
|
42
42
|
* 2. working clusters
|
|
43
43
|
* 3. name
|
|
@@ -47,10 +47,10 @@ const DEFAULT_SORT: Array<PaginationSort> = [
|
|
|
47
47
|
asc: false,
|
|
48
48
|
field: 'spec.internal',
|
|
49
49
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
{
|
|
51
|
+
asc: false,
|
|
52
|
+
field: 'status.connected'
|
|
53
|
+
},
|
|
54
54
|
{
|
|
55
55
|
asc: true,
|
|
56
56
|
field: 'spec.displayName',
|