@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
package/components/Carousel.vue
CHANGED
|
@@ -43,24 +43,29 @@ export default {
|
|
|
43
43
|
activeItemId: 0,
|
|
44
44
|
autoScroll: true,
|
|
45
45
|
autoScrollSlideInterval: null,
|
|
46
|
+
isTransitionning: false, // prevents showing empty spaces caused by aggressive clicking
|
|
47
|
+
shouldDisableTransition: false // smoothes the move from the first/last slides to the previous/next slide
|
|
46
48
|
};
|
|
47
49
|
},
|
|
48
50
|
|
|
49
51
|
computed: {
|
|
50
52
|
...mapGetters(['clusterId']),
|
|
51
53
|
trackStyle() {
|
|
52
|
-
let sliderItem = ( this.activeItemId + 1) * 100 / (this.slider.length + 2);
|
|
53
|
-
const width = 60 * (this.slider.length + 2);
|
|
54
|
-
|
|
55
54
|
if (this.slider.length === 1) {
|
|
56
|
-
|
|
55
|
+
return `
|
|
56
|
+
width: 100%;
|
|
57
|
+
left: 0%;
|
|
58
|
+
`;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
const width = 60 * (this.slider.length + 2);
|
|
62
|
+
const left = -(40 + this.activeItemId * 60);
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
return `
|
|
65
|
+
width: ${ width }%;
|
|
66
|
+
left: ${ left }%;
|
|
67
|
+
transition: ${ this.shouldDisableTransition ? 'none' : '700ms ease-in-out' };
|
|
68
|
+
`;
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
|
|
@@ -77,10 +82,14 @@ export default {
|
|
|
77
82
|
},
|
|
78
83
|
|
|
79
84
|
nextPrev(direction) {
|
|
80
|
-
this.
|
|
81
|
-
|
|
85
|
+
if (this.isTransitionning) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
this.isTransitionning = true;
|
|
90
|
+
this.autoScroll = false;
|
|
91
|
+
this.shouldDisableTransition = false;
|
|
92
|
+
const slideTrack = this.$refs.slider;
|
|
84
93
|
|
|
85
94
|
direction !== 'prev' ? (this.activeItemId++) : (this.activeItemId--);
|
|
86
95
|
|
|
@@ -88,21 +97,27 @@ export default {
|
|
|
88
97
|
},
|
|
89
98
|
|
|
90
99
|
slideTransition() {
|
|
91
|
-
const slideTrack = document.getElementById('slide-track');
|
|
92
100
|
const slidesArray = this.slider.length + 2;
|
|
93
101
|
|
|
94
102
|
if (this.activeItemId === -1) {
|
|
95
|
-
|
|
103
|
+
this.shouldDisableTransition = true;
|
|
96
104
|
this.activeItemId = this.slider.length - 1;
|
|
97
105
|
}
|
|
106
|
+
|
|
98
107
|
if (this.activeItemId === slidesArray - 2) {
|
|
99
|
-
|
|
108
|
+
this.shouldDisableTransition = true;
|
|
100
109
|
this.activeItemId = 0;
|
|
101
110
|
}
|
|
111
|
+
|
|
112
|
+
this.isTransitionning = false;
|
|
102
113
|
},
|
|
103
114
|
|
|
104
115
|
autoScrollSlide() {
|
|
105
|
-
if (this.
|
|
116
|
+
if (!this.autoScroll) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.activeItemId < (this.slider.length + 1)) {
|
|
106
121
|
this.activeItemId++;
|
|
107
122
|
}
|
|
108
123
|
|
|
@@ -120,23 +135,21 @@ export default {
|
|
|
120
135
|
},
|
|
121
136
|
|
|
122
137
|
mounted() {
|
|
123
|
-
const slideTrack =
|
|
138
|
+
const slideTrack = this.$refs.slider;
|
|
124
139
|
|
|
125
|
-
if (this.slider.length
|
|
126
|
-
|
|
127
|
-
} else {
|
|
128
|
-
const node = document.getElementById('slide0');
|
|
140
|
+
if (this.slider.length > 1) {
|
|
141
|
+
const firstSlide = this.$refs['slide0']?.[0];
|
|
129
142
|
|
|
130
|
-
if (
|
|
131
|
-
const clone =
|
|
143
|
+
if (firstSlide) {
|
|
144
|
+
const clone = firstSlide.cloneNode(true);
|
|
132
145
|
|
|
133
146
|
slideTrack.appendChild(clone);
|
|
134
147
|
}
|
|
135
148
|
|
|
136
|
-
const
|
|
149
|
+
const lastSlide = this.$refs[`slide${ this.slider.length - 1 }`]?.[0];
|
|
137
150
|
|
|
138
|
-
if (
|
|
139
|
-
const cloneLast =
|
|
151
|
+
if (lastSlide) {
|
|
152
|
+
const cloneLast = lastSlide.cloneNode(true);
|
|
140
153
|
|
|
141
154
|
slideTrack.insertBefore(cloneLast, slideTrack.children[0]);
|
|
142
155
|
}
|
|
@@ -159,7 +172,7 @@ export default {
|
|
|
159
172
|
<template>
|
|
160
173
|
<div
|
|
161
174
|
class="slider"
|
|
162
|
-
:class="{'
|
|
175
|
+
:class="{'disabled': sliders.length === 1}"
|
|
163
176
|
>
|
|
164
177
|
<div
|
|
165
178
|
id="slide-track"
|
|
@@ -170,8 +183,8 @@ export default {
|
|
|
170
183
|
<component
|
|
171
184
|
:is="asLink ? 'a' : 'div'"
|
|
172
185
|
v-for="(slide, i) in sliders"
|
|
173
|
-
:id="`slide`
|
|
174
|
-
ref="slide"
|
|
186
|
+
:id="`slide${i}`"
|
|
187
|
+
:ref="`slide${i}`"
|
|
175
188
|
:key="get(slide, keyField)"
|
|
176
189
|
class="slide"
|
|
177
190
|
:class="{'singleSlide': sliders.length === 1}"
|
|
@@ -187,7 +200,7 @@ export default {
|
|
|
187
200
|
<div class="slide-content-right">
|
|
188
201
|
<BadgeState
|
|
189
202
|
:label="slide.repoName"
|
|
190
|
-
color="
|
|
203
|
+
color="slide-badge mb-20"
|
|
191
204
|
/>
|
|
192
205
|
<h1>{{ slide.chartNameDisplay }}</h1>
|
|
193
206
|
<p>{{ slide.chartDescription }}</p>
|
|
@@ -196,33 +209,49 @@ export default {
|
|
|
196
209
|
</component>
|
|
197
210
|
</div>
|
|
198
211
|
<div
|
|
212
|
+
role="button"
|
|
213
|
+
class="prev"
|
|
214
|
+
:aria-label="t('carousel.previous')"
|
|
215
|
+
:aria-disabled="sliders.length === 1"
|
|
216
|
+
:class="{'disabled': sliders.length === 1}"
|
|
217
|
+
tabindex="0"
|
|
218
|
+
@click="nextPrev('prev')"
|
|
219
|
+
@keyup.enter.space="nextPrev('prev')"
|
|
220
|
+
>
|
|
221
|
+
<i
|
|
222
|
+
class="icon icon-chevron-left icon-4x"
|
|
223
|
+
/>
|
|
224
|
+
</div>
|
|
225
|
+
<div
|
|
226
|
+
role="button"
|
|
227
|
+
class="next"
|
|
228
|
+
:aria-label="t('carousel.next')"
|
|
229
|
+
:aria-disabled="sliders.length === 1"
|
|
230
|
+
:class="{'disabled': sliders.length === 1}"
|
|
231
|
+
tabindex="0"
|
|
232
|
+
@click="nextPrev('next')"
|
|
233
|
+
@keyup.enter.space="nextPrev('next')"
|
|
234
|
+
>
|
|
235
|
+
<i
|
|
236
|
+
class="icon icon-chevron-right icon-4x"
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
239
|
+
<div
|
|
240
|
+
v-if="sliders.length > 1"
|
|
199
241
|
class="controls"
|
|
200
|
-
:class="{'disable': sliders.length === 1}"
|
|
201
242
|
>
|
|
202
243
|
<div
|
|
203
244
|
v-for="(slide, i) in slider"
|
|
204
245
|
:key="i"
|
|
205
246
|
class="control-item"
|
|
206
247
|
:class="{'active': activeItemId === i}"
|
|
248
|
+
role="button"
|
|
249
|
+
tabindex="0"
|
|
250
|
+
:aria-label="t('carousel.controlItem', { number: i+1 })"
|
|
207
251
|
@click="scrollSlide(i, slider.length)"
|
|
252
|
+
@keyup.enter.space="scrollSlide(i, slider.length)"
|
|
208
253
|
/>
|
|
209
254
|
</div>
|
|
210
|
-
<div
|
|
211
|
-
ref="prev"
|
|
212
|
-
class="prev"
|
|
213
|
-
:class="{'disable': sliders.length === 1}"
|
|
214
|
-
@click="nextPrev('prev')"
|
|
215
|
-
>
|
|
216
|
-
<i class="icon icon-chevron-left icon-4x" />
|
|
217
|
-
</div>
|
|
218
|
-
<div
|
|
219
|
-
ref="next"
|
|
220
|
-
class="next"
|
|
221
|
-
:class="{'disable': sliders.length === 1}"
|
|
222
|
-
@click="nextPrev('next')"
|
|
223
|
-
>
|
|
224
|
-
<i class="icon icon-chevron-right icon-4x" />
|
|
225
|
-
</div>
|
|
226
255
|
</div>
|
|
227
256
|
</template>
|
|
228
257
|
|
|
@@ -234,37 +263,21 @@ export default {
|
|
|
234
263
|
place-items: center;
|
|
235
264
|
overflow: hidden;
|
|
236
265
|
margin-bottom: 30px;
|
|
237
|
-
|
|
266
|
+
height: 245px;
|
|
238
267
|
|
|
239
|
-
&.
|
|
240
|
-
&.
|
|
268
|
+
&.disabled::before,
|
|
269
|
+
&.disabled::after {
|
|
241
270
|
display: none;
|
|
242
271
|
}
|
|
243
|
-
|
|
244
|
-
&.disable:hover {
|
|
245
|
-
.prev,
|
|
246
|
-
.next {
|
|
247
|
-
display: none;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
&:hover {
|
|
252
|
-
.prev,
|
|
253
|
-
.next {
|
|
254
|
-
display: block;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
272
|
}
|
|
258
273
|
|
|
259
274
|
.slide-track {
|
|
260
275
|
display: flex;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
transition: 1s ease-in-out;
|
|
264
|
-
left: 21%;
|
|
276
|
+
position: absolute;
|
|
277
|
+
top: 0;
|
|
265
278
|
}
|
|
266
279
|
|
|
267
|
-
.
|
|
280
|
+
.slide-badge {
|
|
268
281
|
background: var(--app-partner-accent);
|
|
269
282
|
color: var(--body-bg);
|
|
270
283
|
}
|
|
@@ -329,7 +342,7 @@ export default {
|
|
|
329
342
|
.slider::before {
|
|
330
343
|
left: 0;
|
|
331
344
|
top: 0;
|
|
332
|
-
&.
|
|
345
|
+
&.disabled {
|
|
333
346
|
display: none;
|
|
334
347
|
}
|
|
335
348
|
}
|
|
@@ -340,15 +353,13 @@ export default {
|
|
|
340
353
|
}
|
|
341
354
|
|
|
342
355
|
.controls {
|
|
356
|
+
position: absolute;
|
|
357
|
+
bottom: 0;
|
|
343
358
|
width: 100%;
|
|
344
359
|
display: flex;
|
|
345
360
|
justify-content: center;
|
|
346
361
|
margin-top: 10px;
|
|
347
362
|
|
|
348
|
-
&.disable {
|
|
349
|
-
display: none;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
363
|
.control-item {
|
|
353
364
|
width: 10px;
|
|
354
365
|
height: 10px;
|
|
@@ -367,13 +378,16 @@ export default {
|
|
|
367
378
|
position: absolute;
|
|
368
379
|
z-index: 20;
|
|
369
380
|
top: 90px;
|
|
370
|
-
display: none;
|
|
371
381
|
cursor: pointer;
|
|
372
382
|
|
|
373
383
|
&.disabled .icon {
|
|
374
384
|
color: var(--disabled-bg);
|
|
375
385
|
cursor: not-allowed;
|
|
376
386
|
}
|
|
387
|
+
|
|
388
|
+
.icon:focus-visible {
|
|
389
|
+
@include focus-outline;
|
|
390
|
+
}
|
|
377
391
|
}
|
|
378
392
|
|
|
379
393
|
.next {
|
|
@@ -7,6 +7,7 @@ import { SETTING } from '@shell/config/settings';
|
|
|
7
7
|
import { mapGetters } from 'vuex';
|
|
8
8
|
import { isRancherPrime } from '@shell/config/version';
|
|
9
9
|
import { fetchLinks } from '@shell/config/home-links';
|
|
10
|
+
import { processLink } from '@shell/plugins/clean-html';
|
|
10
11
|
|
|
11
12
|
// i18n-ignore footer.wechat.title, footer.wechat.modalText, footer.wechat.modalText2
|
|
12
13
|
export default {
|
|
@@ -77,7 +78,11 @@ export default {
|
|
|
77
78
|
all.push(...this.links.defaults.filter((link) => link.enabled));
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
// Process the links
|
|
82
|
+
return all.map((item) => ({
|
|
83
|
+
...item,
|
|
84
|
+
value: processLink(item.value)
|
|
85
|
+
}));
|
|
81
86
|
}
|
|
82
87
|
},
|
|
83
88
|
methods: {
|
|
@@ -48,9 +48,12 @@ export default {
|
|
|
48
48
|
<a
|
|
49
49
|
v-if="text"
|
|
50
50
|
class="copy-to-clipboard-text"
|
|
51
|
+
role="button"
|
|
52
|
+
:aria-label="t('generic.copyToClipboard')"
|
|
51
53
|
:class="{ 'copied': copied, 'plain': plain}"
|
|
52
54
|
href="#"
|
|
53
55
|
@click="clicked"
|
|
56
|
+
@keyup.space="clicked"
|
|
54
57
|
>
|
|
55
58
|
{{ text }} <i
|
|
56
59
|
class="icon"
|
package/components/Dialog.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import AsyncButton from '@shell/components/AsyncButton';
|
|
3
|
-
import AppModal from '@shell/components/AppModal.vue';
|
|
3
|
+
import AppModal, { DEFAULT_ITERABLE_NODE_SELECTOR } from '@shell/components/AppModal.vue';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
emits: ['okay', 'closed'],
|
|
@@ -21,6 +21,22 @@ export default {
|
|
|
21
21
|
mode: {
|
|
22
22
|
type: String,
|
|
23
23
|
default: '',
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* forcefully set return focus element based on this selector
|
|
28
|
+
*/
|
|
29
|
+
returnFocusSelector: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: '',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* will return focus to the first iterable node of this container select
|
|
36
|
+
*/
|
|
37
|
+
returnFocusFirstIterableNodeSelector: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: DEFAULT_ITERABLE_NODE_SELECTOR,
|
|
24
40
|
}
|
|
25
41
|
},
|
|
26
42
|
|
|
@@ -60,6 +76,9 @@ export default {
|
|
|
60
76
|
:name="name"
|
|
61
77
|
height="auto"
|
|
62
78
|
:scrollable="true"
|
|
79
|
+
:trigger-focus-trap="true"
|
|
80
|
+
:return-focus-selector="returnFocusSelector"
|
|
81
|
+
:return-focus-first-iterable-node-selector="returnFocusFirstIterableNodeSelector"
|
|
63
82
|
@close="closeDialog(false)"
|
|
64
83
|
@before-open="beforeOpen"
|
|
65
84
|
>
|
|
@@ -87,7 +87,10 @@ export default {
|
|
|
87
87
|
<div class="growl-list">
|
|
88
88
|
<div
|
|
89
89
|
v-for="(growl, idx) in stack"
|
|
90
|
-
:key="
|
|
90
|
+
:key="growl.id"
|
|
91
|
+
role="alert"
|
|
92
|
+
:aria-labelledby="`growl-title-${ growl.id }`"
|
|
93
|
+
:aria-describedby="`growl-message-${ growl.id }`"
|
|
91
94
|
:data-testid="`growl-list-item-${idx}`"
|
|
92
95
|
:class="{'growl': true, ['bg-'+growl.color]: true}"
|
|
93
96
|
>
|
|
@@ -103,11 +106,15 @@ export default {
|
|
|
103
106
|
class="close hand icon icon-close"
|
|
104
107
|
@click="close(growl)"
|
|
105
108
|
/>
|
|
106
|
-
<div
|
|
109
|
+
<div
|
|
110
|
+
:id="`growl-title-${ growl.id }`"
|
|
111
|
+
class="growl-text-title"
|
|
112
|
+
>
|
|
107
113
|
{{ growl.title }}
|
|
108
114
|
</div>
|
|
109
115
|
<p
|
|
110
116
|
v-if="growl.message"
|
|
117
|
+
:id="`growl-message-${ growl.id }`"
|
|
111
118
|
:class="{ 'has-title': !!growl.title }"
|
|
112
119
|
>
|
|
113
120
|
{{ growl.message }}
|
|
@@ -11,6 +11,10 @@ export default {
|
|
|
11
11
|
mode: {
|
|
12
12
|
type: String,
|
|
13
13
|
default: ''
|
|
14
|
+
},
|
|
15
|
+
showIcon: {
|
|
16
|
+
type: Boolean,
|
|
17
|
+
default: true
|
|
14
18
|
}
|
|
15
19
|
},
|
|
16
20
|
|
|
@@ -89,7 +93,10 @@ export default {
|
|
|
89
93
|
class="locale-chooser"
|
|
90
94
|
>
|
|
91
95
|
{{ selectedLocaleLabel }}
|
|
92
|
-
<i
|
|
96
|
+
<i
|
|
97
|
+
v-if="showIcon"
|
|
98
|
+
class="icon icon-fw icon-sort-down"
|
|
99
|
+
/>
|
|
93
100
|
</a>
|
|
94
101
|
<template #popper>
|
|
95
102
|
<ul
|
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
import { defineComponent } from 'vue';
|
|
3
3
|
import ResourceFetch from '@shell/mixins/resource-fetch';
|
|
4
4
|
import ResourceTable from '@shell/components/ResourceTable.vue';
|
|
5
|
-
import { StorePaginationResult } from '@shell/types/store/pagination.types';
|
|
6
|
-
|
|
7
|
-
export type FetchSecondaryResourcesOpts = { canPaginate: boolean }
|
|
8
|
-
export type FetchSecondaryResources = (opts: FetchSecondaryResourcesOpts) => Promise<any>
|
|
9
|
-
|
|
10
|
-
export type FetchPageSecondaryResourcesOpts = { canPaginate: boolean, force: boolean, page: any[], pagResult: StorePaginationResult }
|
|
11
|
-
export type FetchPageSecondaryResources = (opts: FetchPageSecondaryResourcesOpts) => Promise<any>
|
|
12
5
|
|
|
13
6
|
/**
|
|
14
7
|
* This is meant to enable ResourceList like capabilities outside of List pages / components
|
|
@@ -57,6 +50,8 @@ export default defineComponent({
|
|
|
57
50
|
* Information may be required from resources other than the primary one shown per row
|
|
58
51
|
*
|
|
59
52
|
* This will fetch them ALL and will be run in a non-server-side pagination world
|
|
53
|
+
*
|
|
54
|
+
* of type PagTableFetchSecondaryResources
|
|
60
55
|
*/
|
|
61
56
|
fetchSecondaryResources: {
|
|
62
57
|
type: Function,
|
|
@@ -69,6 +64,8 @@ export default defineComponent({
|
|
|
69
64
|
* This will fetch only those relevant to the current page using server-side pagination based filters
|
|
70
65
|
*
|
|
71
66
|
* called from shell/mixins/resource-fetch-api-pagination.js
|
|
67
|
+
*
|
|
68
|
+
* of type PagTableFetchPageSecondaryResources
|
|
72
69
|
*/
|
|
73
70
|
fetchPageSecondaryResources: {
|
|
74
71
|
type: Function,
|
|
@@ -90,6 +90,19 @@ export default {
|
|
|
90
90
|
|
|
91
91
|
return out.filter((obj) => obj.percent);
|
|
92
92
|
},
|
|
93
|
+
ariaLabelText() {
|
|
94
|
+
if (Array.isArray(this.values) && this.values.length) {
|
|
95
|
+
let ariaLabel = '';
|
|
96
|
+
|
|
97
|
+
this.values.forEach((val) => {
|
|
98
|
+
ariaLabel += `${ val.value } ${ val.value === 1 ? 'item' : 'items' } ${ val.label }`;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return ariaLabel;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
93
106
|
}
|
|
94
107
|
};
|
|
95
108
|
|
|
@@ -108,6 +121,7 @@ function toPercent(value, min, max) {
|
|
|
108
121
|
<div
|
|
109
122
|
v-trim-whitespace
|
|
110
123
|
:class="{progress: true, multi: pieces.length > 1}"
|
|
124
|
+
:aria-label="ariaLabelText"
|
|
111
125
|
>
|
|
112
126
|
<div
|
|
113
127
|
v-for="(piece, idx) of pieces"
|
|
@@ -43,6 +43,7 @@ export default {
|
|
|
43
43
|
name="password-modal"
|
|
44
44
|
:width="500"
|
|
45
45
|
:height="465"
|
|
46
|
+
:trigger-focus-trap="true"
|
|
46
47
|
@close="show(false)"
|
|
47
48
|
>
|
|
48
49
|
<Card
|
|
@@ -68,6 +69,8 @@ export default {
|
|
|
68
69
|
<!-- type reset is required by lastpass -->
|
|
69
70
|
<button
|
|
70
71
|
class="btn role-secondary"
|
|
72
|
+
role="button"
|
|
73
|
+
:aria-label="t('changePassword.cancel')"
|
|
71
74
|
type="reset"
|
|
72
75
|
@click="show(false)"
|
|
73
76
|
>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import ResourceLabeledSelect from '@shell/components/form/ResourceLabeledSelect.vue';
|
|
4
|
+
import { PaginationParamFilter } from '@shell/types/store/pagination.types';
|
|
5
|
+
|
|
5
6
|
import { PVC, STORAGE_CLASS } from '@shell/config/types';
|
|
6
7
|
import Question from './Question';
|
|
7
8
|
|
|
@@ -14,7 +15,7 @@ const LEGACY_MAP = {
|
|
|
14
15
|
export default {
|
|
15
16
|
emits: ['update:value'],
|
|
16
17
|
|
|
17
|
-
components: { LabeledInput,
|
|
18
|
+
components: { LabeledInput, ResourceLabeledSelect },
|
|
18
19
|
mixins: [Question],
|
|
19
20
|
|
|
20
21
|
props: {
|
|
@@ -29,12 +30,6 @@ export default {
|
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
|
|
32
|
-
async fetch() {
|
|
33
|
-
if ( this.typeSchema ) {
|
|
34
|
-
this.all = await this.$store.dispatch(`${ this.inStore }/findAll`, { type: this.typeName });
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
|
|
38
33
|
data() {
|
|
39
34
|
const t = this.question.type;
|
|
40
35
|
|
|
@@ -57,29 +52,61 @@ export default {
|
|
|
57
52
|
return {
|
|
58
53
|
typeName,
|
|
59
54
|
typeSchema,
|
|
60
|
-
all:
|
|
55
|
+
all: [],
|
|
56
|
+
allResourceSettings: {
|
|
57
|
+
updateResources: (all) => {
|
|
58
|
+
// Filter to only include required namespaced resources
|
|
59
|
+
const resources = this.isNamespaced ? all.filter((r) => r.metadata.namespace === this.targetNamespace) : all;
|
|
60
|
+
|
|
61
|
+
return this.mapResourcesToOptions(resources);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
paginateResourceSetting: {
|
|
65
|
+
updateResources: (resources) => {
|
|
66
|
+
return this.mapResourcesToOptions(resources);
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* of type PaginateTypeOverridesFn
|
|
70
|
+
* @param [LabelSelectPaginationFunctionOptions] opts
|
|
71
|
+
* @returns LabelSelectPaginationFunctionOptions
|
|
72
|
+
*/
|
|
73
|
+
requestSettings: (opts) => {
|
|
74
|
+
// Filter to only include required namespaced resources
|
|
75
|
+
const filters = this.isNamespaced ? [
|
|
76
|
+
PaginationParamFilter.createSingleField({ field: 'metadata.namespace', value: this.targetNamespace }),
|
|
77
|
+
] : [];
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
...opts,
|
|
81
|
+
filters,
|
|
82
|
+
groupByNamespace: false,
|
|
83
|
+
classify: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
},
|
|
61
87
|
};
|
|
62
88
|
},
|
|
63
89
|
|
|
90
|
+
methods: {
|
|
91
|
+
mapResourcesToOptions(resources) {
|
|
92
|
+
return resources.map((r) => {
|
|
93
|
+
if (r.id) {
|
|
94
|
+
return {
|
|
95
|
+
label: r.nameDisplay || r.metadata.name,
|
|
96
|
+
value: r.metadata.name
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
return r;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
},
|
|
105
|
+
|
|
64
106
|
computed: {
|
|
65
107
|
isNamespaced() {
|
|
66
108
|
return !!this.typeSchema?.attributes?.namespaced;
|
|
67
109
|
},
|
|
68
|
-
|
|
69
|
-
options() {
|
|
70
|
-
let out = this.all;
|
|
71
|
-
|
|
72
|
-
if ( this.isNamespaced ) {
|
|
73
|
-
out = filterBy(this.all, 'metadata.namespace', this.targetNamespace);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return out.map((x) => {
|
|
77
|
-
return {
|
|
78
|
-
label: x.nameDisplay || x.metadata.name,
|
|
79
|
-
value: x.metadata.name
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
110
|
},
|
|
84
111
|
};
|
|
85
112
|
</script>
|
|
@@ -90,15 +117,17 @@ export default {
|
|
|
90
117
|
class="row"
|
|
91
118
|
>
|
|
92
119
|
<div class="col span-6">
|
|
93
|
-
<
|
|
94
|
-
:
|
|
95
|
-
:
|
|
120
|
+
<ResourceLabeledSelect
|
|
121
|
+
:resource-type="typeName"
|
|
122
|
+
:in-store="inStore"
|
|
96
123
|
:disabled="$fetchState.pending || disabled"
|
|
97
124
|
:label="displayLabel"
|
|
98
125
|
:placeholder="question.description"
|
|
99
126
|
:required="question.required"
|
|
100
127
|
:value="value"
|
|
101
128
|
:tooltip="displayTooltip"
|
|
129
|
+
:paginated-resource-settings="paginateResourceSetting"
|
|
130
|
+
:all-resources-settings="allResourceSettings"
|
|
102
131
|
@update:value="!$fetchState.pending && $emit('update:value', $event)"
|
|
103
132
|
/>
|
|
104
133
|
</div>
|
|
@@ -104,6 +104,10 @@ export default {
|
|
|
104
104
|
:is="asLink ? 'a' : 'div'"
|
|
105
105
|
v-for="(r, idx) in rows"
|
|
106
106
|
:key="get(r, keyField)"
|
|
107
|
+
:role="asLink ? 'link' : null"
|
|
108
|
+
:aria-disabled="asLink && get(r, disabledField) === true ? true : null"
|
|
109
|
+
:aria-label="get(r, nameField)"
|
|
110
|
+
:tabindex="get(r, disabledField) === true ? -1 : 0"
|
|
107
111
|
:href="asLink ? get(r, linkField) : null"
|
|
108
112
|
:target="get(r, targetField)"
|
|
109
113
|
:rel="rel"
|
|
@@ -111,9 +115,12 @@ export default {
|
|
|
111
115
|
:data-testid="componentTestid + '-' + get(r, nameField)"
|
|
112
116
|
:class="{
|
|
113
117
|
'has-description': !!get(r, descriptionField),
|
|
114
|
-
'has-side-label': !!get(r, sideLabelField),
|
|
118
|
+
'has-side-label': !!get(r, sideLabelField),
|
|
119
|
+
[colorFor(r, idx)]: true,
|
|
120
|
+
disabled: get(r, disabledField) === true
|
|
115
121
|
}"
|
|
116
122
|
@click="select(r, idx)"
|
|
123
|
+
@keyup.enter.space="select(r, idx)"
|
|
117
124
|
>
|
|
118
125
|
<div
|
|
119
126
|
class="side-label"
|
|
@@ -212,6 +219,10 @@ export default {
|
|
|
212
219
|
text-decoration: none !important;
|
|
213
220
|
color: $color;
|
|
214
221
|
|
|
222
|
+
&:focus-visible {
|
|
223
|
+
@include focus-outline;
|
|
224
|
+
}
|
|
225
|
+
|
|
215
226
|
&:hover:not(.disabled) {
|
|
216
227
|
box-shadow: 0 0 30px var(--shadow);
|
|
217
228
|
transition: box-shadow 0.1s ease-in-out;
|