@rancher/shell 3.0.2-rc.3 → 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 +2 -1
- package/assets/styles/global/_form.scss +2 -1
- package/assets/styles/themes/_dark.scss +1 -1
- package/assets/translations/en-us.yaml +22 -4
- package/assets/translations/zh-hans.yaml +2 -3
- package/components/AppModal.vue +50 -0
- package/components/Carousel.vue +54 -47
- package/components/CopyToClipboardText.vue +3 -0
- package/components/Dialog.vue +20 -1
- package/components/PromptChangePassword.vue +3 -0
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/Tabbed/index.vue +4 -7
- package/components/__tests__/Carousel.test.ts +56 -27
- package/components/form/LabeledSelect.vue +1 -1
- 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/Select.vue +1 -1
- package/components/form/SelectOrCreateAuthSecret.vue +43 -11
- package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
- package/composables/focusTrap.ts +68 -0
- package/detail/secret.vue +25 -0
- package/edit/fleet.cattle.io.gitrepo.vue +27 -22
- package/edit/provisioning.cattle.io.cluster/index.vue +26 -19
- package/edit/secret/index.vue +1 -1
- package/edit/secret/ssh.vue +21 -3
- package/list/provisioning.cattle.io.cluster.vue +1 -0
- package/models/fleet.cattle.io.gitrepo.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +2 -12
- package/models/secret.js +5 -0
- package/package.json +1 -1
- package/pages/account/index.vue +4 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +5 -4
- 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/rancher-components/Card/Card.vue +7 -21
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +11 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +2 -3
- package/rancher-components/RcDropdown/useDropdownCollection.ts +1 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +28 -1
|
@@ -5,6 +5,7 @@ import { Banner } from '@components/Banner';
|
|
|
5
5
|
import LazyImage from '@shell/components/LazyImage';
|
|
6
6
|
import { MANAGEMENT } from '@shell/config/types';
|
|
7
7
|
import { SETTING } from '@shell/config/settings';
|
|
8
|
+
import { useWatcherBasedSetupFocusTrapWithDestroyIncluded } from '@shell/composables/focusTrap';
|
|
8
9
|
|
|
9
10
|
export default {
|
|
10
11
|
async fetch() {
|
|
@@ -22,7 +23,6 @@ export default {
|
|
|
22
23
|
ChartReadme,
|
|
23
24
|
LazyImage
|
|
24
25
|
},
|
|
25
|
-
|
|
26
26
|
data() {
|
|
27
27
|
return {
|
|
28
28
|
showSlideIn: false,
|
|
@@ -32,9 +32,12 @@ export default {
|
|
|
32
32
|
versionError: undefined,
|
|
33
33
|
defaultIcon: require('~shell/assets/images/generic-plugin.svg'),
|
|
34
34
|
headerBannerSize: 0,
|
|
35
|
+
isActive: false
|
|
35
36
|
};
|
|
36
37
|
},
|
|
37
|
-
|
|
38
|
+
created() {
|
|
39
|
+
useWatcherBasedSetupFocusTrapWithDestroyIncluded(() => this.showSlideIn, '#slide-in-content-element');
|
|
40
|
+
},
|
|
38
41
|
computed: {
|
|
39
42
|
...mapGetters({ theme: 'prefs/theme' }),
|
|
40
43
|
|
|
@@ -46,7 +49,20 @@ export default {
|
|
|
46
49
|
return {};
|
|
47
50
|
},
|
|
48
51
|
},
|
|
49
|
-
|
|
52
|
+
watch: {
|
|
53
|
+
showSlideIn: {
|
|
54
|
+
handler(neu) {
|
|
55
|
+
// we register the global event on slidein visibility
|
|
56
|
+
// so that it doesn't collide with other global events
|
|
57
|
+
if (neu) {
|
|
58
|
+
document.addEventListener('keyup', this.handleEscapeKey);
|
|
59
|
+
} else {
|
|
60
|
+
document.removeEventListener('keyup', this.handleEscapeKey);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
immediate: true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
50
66
|
methods: {
|
|
51
67
|
show(info) {
|
|
52
68
|
this.info = info;
|
|
@@ -115,6 +131,22 @@ export default {
|
|
|
115
131
|
|
|
116
132
|
handleVersionBtnClass(version) {
|
|
117
133
|
return { 'version-active': version.version === this.infoVersion, disabled: !version.isVersionCompatible };
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
onEnter() {
|
|
137
|
+
this.isActive = true; // Set active state after the transition
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
onLeave() {
|
|
141
|
+
this.isActive = false; // Remove active state when fully closed
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
handleEscapeKey(event) {
|
|
145
|
+
event.stopPropagation();
|
|
146
|
+
|
|
147
|
+
if (event.key === 'Escape') {
|
|
148
|
+
this.hide();
|
|
149
|
+
}
|
|
118
150
|
}
|
|
119
151
|
}
|
|
120
152
|
};
|
|
@@ -130,123 +162,139 @@ export default {
|
|
|
130
162
|
data-testid="extension-details-bg"
|
|
131
163
|
@click="hide()"
|
|
132
164
|
/>
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
165
|
+
<transition
|
|
166
|
+
name="slide"
|
|
167
|
+
@after-enter="onEnter"
|
|
168
|
+
@after-leave="onLeave"
|
|
137
169
|
>
|
|
138
170
|
<div
|
|
139
|
-
v-if="
|
|
140
|
-
|
|
171
|
+
v-if="showSlideIn"
|
|
172
|
+
id="slide-in-content-element"
|
|
173
|
+
class="slideIn"
|
|
174
|
+
data-testid="extension-details"
|
|
175
|
+
:class="{'active': isActive}"
|
|
141
176
|
>
|
|
142
|
-
<div
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
>
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
:
|
|
150
|
-
:error-src="defaultIcon"
|
|
151
|
-
:src="info.icon"
|
|
152
|
-
class="icon plugin-icon-img"
|
|
153
|
-
/>
|
|
154
|
-
<img
|
|
155
|
-
v-else
|
|
156
|
-
:src="defaultIcon"
|
|
157
|
-
class="icon plugin-icon-img"
|
|
158
|
-
>
|
|
159
|
-
</div>
|
|
160
|
-
<div class="plugin-title">
|
|
161
|
-
<h2
|
|
162
|
-
class="slideIn__header"
|
|
163
|
-
data-testid="extension-details-title"
|
|
177
|
+
<div
|
|
178
|
+
v-if="info"
|
|
179
|
+
class="plugin-info-content"
|
|
180
|
+
>
|
|
181
|
+
<div class="plugin-header">
|
|
182
|
+
<div
|
|
183
|
+
class="plugin-icon"
|
|
184
|
+
:class="applyDarkModeBg"
|
|
164
185
|
>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
@click="showSlideIn = false"
|
|
186
|
+
<LazyImage
|
|
187
|
+
v-if="info.icon"
|
|
188
|
+
:initial-src="defaultIcon"
|
|
189
|
+
:error-src="defaultIcon"
|
|
190
|
+
:src="info.icon"
|
|
191
|
+
class="icon plugin-icon-img"
|
|
192
|
+
/>
|
|
193
|
+
<img
|
|
194
|
+
v-else
|
|
195
|
+
:src="defaultIcon"
|
|
196
|
+
class="icon plugin-icon-img"
|
|
177
197
|
>
|
|
178
|
-
|
|
198
|
+
</div>
|
|
199
|
+
<div class="plugin-title">
|
|
200
|
+
<h2
|
|
201
|
+
class="slideIn__header"
|
|
202
|
+
data-testid="extension-details-title"
|
|
203
|
+
>
|
|
204
|
+
{{ info.label }}
|
|
205
|
+
</h2>
|
|
206
|
+
<p class="plugin-description">
|
|
207
|
+
{{ info.description }}
|
|
208
|
+
</p>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="plugin-close">
|
|
211
|
+
<div class="slideIn__header__buttons">
|
|
212
|
+
<div
|
|
213
|
+
class="slideIn__header__button"
|
|
214
|
+
data-testid="extension-details-close"
|
|
215
|
+
role="button"
|
|
216
|
+
:aria-label="t('plugins.closePluginPanel')"
|
|
217
|
+
tabindex="0"
|
|
218
|
+
@click="hide()"
|
|
219
|
+
@keyup.enter.space="hide()"
|
|
220
|
+
>
|
|
221
|
+
<i class="icon icon-close" />
|
|
222
|
+
</div>
|
|
179
223
|
</div>
|
|
180
224
|
</div>
|
|
181
225
|
</div>
|
|
182
|
-
|
|
183
|
-
<div>
|
|
184
|
-
<Banner
|
|
185
|
-
v-if="info.builtin"
|
|
186
|
-
color="warning"
|
|
187
|
-
:label="t('plugins.descriptions.built-in')"
|
|
188
|
-
class="mt-10"
|
|
189
|
-
/>
|
|
190
|
-
<template v-else>
|
|
226
|
+
<div>
|
|
191
227
|
<Banner
|
|
192
|
-
v-if="
|
|
228
|
+
v-if="info.builtin"
|
|
193
229
|
color="warning"
|
|
194
|
-
:label="t('plugins.descriptions.
|
|
230
|
+
:label="t('plugins.descriptions.built-in')"
|
|
195
231
|
class="mt-10"
|
|
196
232
|
/>
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
233
|
+
<template v-else>
|
|
234
|
+
<Banner
|
|
235
|
+
v-if="!info.certified"
|
|
236
|
+
color="warning"
|
|
237
|
+
:label="t('plugins.descriptions.third-party')"
|
|
238
|
+
class="mt-10"
|
|
239
|
+
/>
|
|
240
|
+
<Banner
|
|
241
|
+
v-if="info.experimental"
|
|
242
|
+
color="warning"
|
|
243
|
+
:label="t('plugins.descriptions.experimental')"
|
|
244
|
+
class="mt-10"
|
|
245
|
+
/>
|
|
246
|
+
</template>
|
|
247
|
+
</div>
|
|
205
248
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
>
|
|
214
|
-
<a
|
|
215
|
-
v-clean-tooltip="handleVersionBtnTooltip(v)"
|
|
216
|
-
class="version-link"
|
|
217
|
-
:class="handleVersionBtnClass(v)"
|
|
218
|
-
@click="loadPluginVersionInfo(v.version)"
|
|
249
|
+
<h3 v-if="info.versions.length">
|
|
250
|
+
{{ t('plugins.info.versions') }}
|
|
251
|
+
</h3>
|
|
252
|
+
<div class="plugin-versions mb-10">
|
|
253
|
+
<div
|
|
254
|
+
v-for="v in info.versions"
|
|
255
|
+
:key="`${v.name}-${v.version}`"
|
|
219
256
|
>
|
|
220
|
-
|
|
221
|
-
|
|
257
|
+
<a
|
|
258
|
+
v-clean-tooltip="handleVersionBtnTooltip(v)"
|
|
259
|
+
class="version-link"
|
|
260
|
+
:class="handleVersionBtnClass(v)"
|
|
261
|
+
:tabindex="!v.isVersionCompatible ? -1 : 0"
|
|
262
|
+
role="button"
|
|
263
|
+
:aria-label="t('plugins.viewVersionDetails', {name: v.name, version: v.version})"
|
|
264
|
+
@click="loadPluginVersionInfo(v.version)"
|
|
265
|
+
@keyup.enter.space="loadPluginVersionInfo(v.version)"
|
|
266
|
+
>
|
|
267
|
+
{{ v.version }}
|
|
268
|
+
</a>
|
|
269
|
+
</div>
|
|
222
270
|
</div>
|
|
223
|
-
</div>
|
|
224
271
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
</h3>
|
|
231
|
-
<div
|
|
232
|
-
v-if="versionInfo"
|
|
233
|
-
class="plugin-info-detail"
|
|
234
|
-
>
|
|
235
|
-
<ChartReadme
|
|
236
|
-
v-if="versionInfo"
|
|
237
|
-
:version-info="versionInfo"
|
|
238
|
-
/>
|
|
239
|
-
</div>
|
|
240
|
-
<div v-if="!info.versions.length">
|
|
241
|
-
<h3>
|
|
242
|
-
{{ t('plugins.info.versions') }}
|
|
272
|
+
<div v-if="versionError">
|
|
273
|
+
{{ t('plugins.info.versionError') }}
|
|
274
|
+
</div>
|
|
275
|
+
<h3 v-if="versionInfo">
|
|
276
|
+
{{ t('plugins.info.detail') }}
|
|
243
277
|
</h3>
|
|
244
|
-
<div
|
|
245
|
-
|
|
278
|
+
<div
|
|
279
|
+
v-if="versionInfo"
|
|
280
|
+
class="plugin-info-detail"
|
|
281
|
+
>
|
|
282
|
+
<ChartReadme
|
|
283
|
+
v-if="versionInfo"
|
|
284
|
+
:version-info="versionInfo"
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
<div v-if="!info.versions.length">
|
|
288
|
+
<h3>
|
|
289
|
+
{{ t('plugins.info.versions') }}
|
|
290
|
+
</h3>
|
|
291
|
+
<div class="version-link version-active version-builtin">
|
|
292
|
+
{{ info.displayVersion }}
|
|
293
|
+
</div>
|
|
246
294
|
</div>
|
|
247
295
|
</div>
|
|
248
296
|
</div>
|
|
249
|
-
</
|
|
297
|
+
</transition>
|
|
250
298
|
</div>
|
|
251
299
|
</template>
|
|
252
300
|
<style lang="scss" scoped>
|
|
@@ -284,10 +332,30 @@ export default {
|
|
|
284
332
|
z-index: 10;
|
|
285
333
|
display: flex;
|
|
286
334
|
flex-direction: column;
|
|
287
|
-
|
|
288
335
|
padding: 10px;
|
|
289
336
|
|
|
290
|
-
|
|
337
|
+
&.active {
|
|
338
|
+
right: 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* Enter animation */
|
|
342
|
+
&.slide-enter-active {
|
|
343
|
+
transition: right 0.5s ease; /* Animates both enter and leave */
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
&.slide-leave-active {
|
|
347
|
+
transition: right 0.5s ease; /* Animates both enter and leave */
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
&.slide-enter-from,
|
|
351
|
+
&.slide-leave-to {
|
|
352
|
+
right: -$slideout-width; /* Off-screen position */
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
&.slide-enter-to,
|
|
356
|
+
&.slide-leave-from {
|
|
357
|
+
right: 0; /* Fully visible position */
|
|
358
|
+
}
|
|
291
359
|
|
|
292
360
|
&__header {
|
|
293
361
|
text-transform: capitalize;
|
|
@@ -378,6 +446,10 @@ export default {
|
|
|
378
446
|
&.version-builtin {
|
|
379
447
|
display: inline-block;
|
|
380
448
|
}
|
|
449
|
+
|
|
450
|
+
&:focus-visible {
|
|
451
|
+
@include focus-outline;
|
|
452
|
+
}
|
|
381
453
|
}
|
|
382
454
|
|
|
383
455
|
&__header {
|
|
@@ -395,13 +467,20 @@ export default {
|
|
|
395
467
|
align-items: center;
|
|
396
468
|
justify-content: center;
|
|
397
469
|
padding: 2px;
|
|
470
|
+
|
|
398
471
|
> i {
|
|
399
472
|
font-size: 20px;
|
|
400
473
|
opacity: 0.5;
|
|
401
474
|
}
|
|
475
|
+
|
|
402
476
|
&:hover {
|
|
403
477
|
background-color: var(--wm-closer-hover-bg);
|
|
404
478
|
}
|
|
479
|
+
|
|
480
|
+
&:focus-visible {
|
|
481
|
+
@include focus-outline;
|
|
482
|
+
outline-offset: -2px;
|
|
483
|
+
}
|
|
405
484
|
}
|
|
406
485
|
}
|
|
407
486
|
|
|
@@ -419,10 +498,6 @@ export default {
|
|
|
419
498
|
overflow: auto;
|
|
420
499
|
}
|
|
421
500
|
}
|
|
422
|
-
|
|
423
|
-
&__show {
|
|
424
|
-
right: 0;
|
|
425
|
-
}
|
|
426
501
|
}
|
|
427
502
|
}
|
|
428
503
|
</style>
|
|
@@ -62,6 +62,8 @@ export default {
|
|
|
62
62
|
v-if="showFeaturesButton"
|
|
63
63
|
class="btn role-primary enable-plugin-support"
|
|
64
64
|
data-testid="extension-feature-button"
|
|
65
|
+
role="button"
|
|
66
|
+
:aria-label="t('plugins.setup.install.featuresButton')"
|
|
65
67
|
@click="redirectToFeatureFlags"
|
|
66
68
|
>
|
|
67
69
|
{{ t('plugins.setup.install.featuresButton') }}
|
|
@@ -20,7 +20,12 @@ export default {
|
|
|
20
20
|
};
|
|
21
21
|
},
|
|
22
22
|
|
|
23
|
-
computed: {
|
|
23
|
+
computed: {
|
|
24
|
+
...mapGetters({ allCharts: 'catalog/charts' }),
|
|
25
|
+
returnFocusSelector() {
|
|
26
|
+
return `[data-testid="extension-card-uninstall-btn-${ this.plugin?.name }"]`;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
24
29
|
|
|
25
30
|
methods: {
|
|
26
31
|
showDialog(plugin) {
|
|
@@ -78,6 +83,9 @@ export default {
|
|
|
78
83
|
name="uninstallPluginDialog"
|
|
79
84
|
height="auto"
|
|
80
85
|
:scrollable="true"
|
|
86
|
+
:trigger-focus-trap="true"
|
|
87
|
+
:return-focus-selector="returnFocusSelector"
|
|
88
|
+
:return-focus-first-iterable-node-selector="'#extensions-main-page'"
|
|
81
89
|
@close="closeDialog(false)"
|
|
82
90
|
>
|
|
83
91
|
<div
|
|
@@ -627,8 +627,12 @@ export default {
|
|
|
627
627
|
</script>
|
|
628
628
|
|
|
629
629
|
<template>
|
|
630
|
-
<div
|
|
630
|
+
<div
|
|
631
|
+
id="extensions-main-page"
|
|
632
|
+
class="plugins"
|
|
633
|
+
>
|
|
631
634
|
<div class="plugin-header">
|
|
635
|
+
<!-- catalog view header -->
|
|
632
636
|
<template v-if="showCatalogList">
|
|
633
637
|
<div class="catalog-title">
|
|
634
638
|
<h2
|
|
@@ -637,6 +641,9 @@ export default {
|
|
|
637
641
|
>
|
|
638
642
|
<a
|
|
639
643
|
class="link"
|
|
644
|
+
role="link"
|
|
645
|
+
tabindex="0"
|
|
646
|
+
:aria-label="t('plugins.manageCatalog.title')"
|
|
640
647
|
@click="manageExtensionView()"
|
|
641
648
|
>
|
|
642
649
|
{{ t('plugins.manageCatalog.title') }}:
|
|
@@ -650,6 +657,7 @@ export default {
|
|
|
650
657
|
/>
|
|
651
658
|
</div>
|
|
652
659
|
</template>
|
|
660
|
+
<!-- normal extensions view header -->
|
|
653
661
|
<template v-else>
|
|
654
662
|
<h2 data-testid="extensions-page-title">
|
|
655
663
|
<TabTitle breadcrumb="vendor-only">
|
|
@@ -658,6 +666,7 @@ export default {
|
|
|
658
666
|
</h2>
|
|
659
667
|
</template>
|
|
660
668
|
<div class="actions-container">
|
|
669
|
+
<!-- extensions reload toast/notification -->
|
|
661
670
|
<div
|
|
662
671
|
v-if="reloadRequired"
|
|
663
672
|
class="plugin-reload-banner mr-20"
|
|
@@ -670,11 +679,14 @@ export default {
|
|
|
670
679
|
<button
|
|
671
680
|
class="ml-10 btn btn-sm role-primary"
|
|
672
681
|
data-testid="extension-reload-banner-reload-btn"
|
|
682
|
+
role="button"
|
|
683
|
+
:aria-label="t('plugins.labels.reloadRancher')"
|
|
673
684
|
@click="reload()"
|
|
674
685
|
>
|
|
675
686
|
{{ t('generic.reload') }}
|
|
676
687
|
</button>
|
|
677
688
|
</div>
|
|
689
|
+
<!-- extensions menu -->
|
|
678
690
|
<div v-if="hasFeatureFlag && hasMenuActions">
|
|
679
691
|
<button
|
|
680
692
|
ref="actions"
|
|
@@ -682,6 +694,8 @@ export default {
|
|
|
682
694
|
type="button"
|
|
683
695
|
class="btn role-multi-action actions"
|
|
684
696
|
data-testid="extensions-page-menu"
|
|
697
|
+
role="button"
|
|
698
|
+
:aria-label="t('plugins.labels.menu')"
|
|
685
699
|
@click="setMenu"
|
|
686
700
|
>
|
|
687
701
|
<i class="icon icon-actions" />
|
|
@@ -702,8 +716,10 @@ export default {
|
|
|
702
716
|
</div>
|
|
703
717
|
</div>
|
|
704
718
|
|
|
719
|
+
<!-- extensions slide-in panel -->
|
|
705
720
|
<PluginInfoPanel ref="infoPanel" />
|
|
706
721
|
|
|
722
|
+
<!-- extensions not enabled by feature flag -->
|
|
707
723
|
<div v-if="!hasFeatureFlag">
|
|
708
724
|
<div
|
|
709
725
|
v-if="loading"
|
|
@@ -724,6 +740,7 @@ export default {
|
|
|
724
740
|
/>
|
|
725
741
|
</div>
|
|
726
742
|
<div v-else>
|
|
743
|
+
<!-- Extension Catalog list view -->
|
|
727
744
|
<template v-if="showCatalogList">
|
|
728
745
|
<CatalogList
|
|
729
746
|
@showCatalogLoadDialog="showCatalogLoadDialog"
|
|
@@ -741,6 +758,8 @@ export default {
|
|
|
741
758
|
<button
|
|
742
759
|
class="ml-10 btn btn-sm role-primary"
|
|
743
760
|
data-testid="extensions-new-repos-banner-action-btn"
|
|
761
|
+
role="button"
|
|
762
|
+
:aria-label="t('plugins.addRepos.bannerBtn')"
|
|
744
763
|
@click="showAddExtensionReposDialog()"
|
|
745
764
|
>
|
|
746
765
|
{{ t('plugins.addRepos.bannerBtn') }}
|
|
@@ -800,14 +819,20 @@ export default {
|
|
|
800
819
|
:message="emptyMessage"
|
|
801
820
|
/>
|
|
802
821
|
<template v-else>
|
|
822
|
+
<!-- extension card! -->
|
|
803
823
|
<div
|
|
804
824
|
v-for="(plugin, i) in list"
|
|
825
|
+
:id="`list-item-${i}`"
|
|
805
826
|
:key="i"
|
|
806
827
|
class="plugin"
|
|
807
828
|
:data-testid="`extension-card-${plugin.name}`"
|
|
829
|
+
role="button"
|
|
830
|
+
tabindex="0"
|
|
831
|
+
:aria-label="plugin.name || ''"
|
|
808
832
|
@click="showPluginDetail(plugin)"
|
|
833
|
+
@keyup.enter.space="showPluginDetail(plugin)"
|
|
809
834
|
>
|
|
810
|
-
<!--
|
|
835
|
+
<!-- extension icon -->
|
|
811
836
|
<div
|
|
812
837
|
class="plugin-icon"
|
|
813
838
|
:class="applyDarkModeBg"
|
|
@@ -825,13 +850,14 @@ export default {
|
|
|
825
850
|
class="icon plugin-icon-img"
|
|
826
851
|
>
|
|
827
852
|
</div>
|
|
828
|
-
<!--
|
|
853
|
+
<!-- extension card -->
|
|
829
854
|
<div class="plugin-metadata">
|
|
830
|
-
<!--
|
|
855
|
+
<!-- extension basic info -->
|
|
831
856
|
<div class="plugin-name">
|
|
832
857
|
{{ plugin.label }}
|
|
833
858
|
</div>
|
|
834
859
|
<div>{{ plugin.description }}</div>
|
|
860
|
+
<!-- extension version info and error display -->
|
|
835
861
|
<div class="plugin-version">
|
|
836
862
|
<span
|
|
837
863
|
v-if="plugin.installing"
|
|
@@ -858,7 +884,7 @@ export default {
|
|
|
858
884
|
>{{ plugin.incompatibilityMessage }}</p>
|
|
859
885
|
</span>
|
|
860
886
|
</div>
|
|
861
|
-
<!--
|
|
887
|
+
<!-- extension badges -->
|
|
862
888
|
<div
|
|
863
889
|
v-if="plugin.builtin"
|
|
864
890
|
class="plugin-badges"
|
|
@@ -885,9 +911,9 @@ export default {
|
|
|
885
911
|
</div>
|
|
886
912
|
</div>
|
|
887
913
|
<div class="plugin-spacer" />
|
|
888
|
-
<!--
|
|
914
|
+
<!-- extension actions -->
|
|
889
915
|
<div class="plugin-actions">
|
|
890
|
-
<!--
|
|
916
|
+
<!-- extension status -->
|
|
891
917
|
<div
|
|
892
918
|
v-if="plugin.helmError"
|
|
893
919
|
v-clean-tooltip="t('plugins.helmError')"
|
|
@@ -910,7 +936,7 @@ export default {
|
|
|
910
936
|
{{ t('plugins.labels.uninstalling') }}
|
|
911
937
|
</div>
|
|
912
938
|
</div>
|
|
913
|
-
<!--
|
|
939
|
+
<!-- extension buttons -->
|
|
914
940
|
<div
|
|
915
941
|
v-else-if="plugin.installed"
|
|
916
942
|
class="plugin-buttons"
|
|
@@ -919,7 +945,10 @@ export default {
|
|
|
919
945
|
v-if="!plugin.builtin"
|
|
920
946
|
class="btn role-secondary"
|
|
921
947
|
:data-testid="`extension-card-uninstall-btn-${plugin.name}`"
|
|
922
|
-
|
|
948
|
+
role="button"
|
|
949
|
+
:aria-label="t('plugins.uninstall.label')"
|
|
950
|
+
@click.stop="showUninstallDialog(plugin, $event)"
|
|
951
|
+
@keyup.space.stop="showUninstallDialog(plugin, $event)"
|
|
923
952
|
>
|
|
924
953
|
{{ t('plugins.uninstall.label') }}
|
|
925
954
|
</button>
|
|
@@ -927,7 +956,10 @@ export default {
|
|
|
927
956
|
v-if="plugin.upgrade"
|
|
928
957
|
class="btn role-secondary"
|
|
929
958
|
:data-testid="`extension-card-update-btn-${plugin.name}`"
|
|
930
|
-
|
|
959
|
+
role="button"
|
|
960
|
+
:aria-label="t('plugins.update.label')"
|
|
961
|
+
@click.stop="showInstallDialog(plugin, 'update', $event)"
|
|
962
|
+
@keyup.space.stop="showInstallDialog(plugin, 'update', $event)"
|
|
931
963
|
>
|
|
932
964
|
{{ t('plugins.update.label') }}
|
|
933
965
|
</button>
|
|
@@ -935,7 +967,10 @@ export default {
|
|
|
935
967
|
v-if="!plugin.upgrade && plugin.installableVersions && plugin.installableVersions.length > 1"
|
|
936
968
|
class="btn role-secondary"
|
|
937
969
|
:data-testid="`extension-card-rollback-btn-${plugin.name}`"
|
|
938
|
-
|
|
970
|
+
role="button"
|
|
971
|
+
:aria-label="t('plugins.rollback.label')"
|
|
972
|
+
@click.stop="showInstallDialog(plugin, 'rollback', $event)"
|
|
973
|
+
@keyup.space.stop="showInstallDialog(plugin, 'rollback', $event)"
|
|
939
974
|
>
|
|
940
975
|
{{ t('plugins.rollback.label') }}
|
|
941
976
|
</button>
|
|
@@ -947,7 +982,10 @@ export default {
|
|
|
947
982
|
<button
|
|
948
983
|
class="btn role-secondary"
|
|
949
984
|
:data-testid="`extension-card-install-btn-${plugin.name}`"
|
|
950
|
-
|
|
985
|
+
role="button"
|
|
986
|
+
:aria-label="t('plugins.install.label')"
|
|
987
|
+
@click.stop="showInstallDialog(plugin, 'install', $event)"
|
|
988
|
+
@keyup.space.stop="showInstallDialog(plugin, 'install', $event)"
|
|
951
989
|
>
|
|
952
990
|
{{ t('plugins.install.label') }}
|
|
953
991
|
</button>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { defineComponent, PropType } from 'vue';
|
|
3
|
-
import {
|
|
3
|
+
import { useBasicSetupFocusTrap } from '@shell/composables/focusTrap';
|
|
4
4
|
|
|
5
5
|
export default defineComponent({
|
|
6
|
+
|
|
6
7
|
name: 'Card',
|
|
7
8
|
props: {
|
|
8
9
|
/**
|
|
@@ -56,32 +57,17 @@ export default defineComponent({
|
|
|
56
57
|
default: false,
|
|
57
58
|
},
|
|
58
59
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
mounted() {
|
|
63
|
-
if (this.triggerFocusTrap) {
|
|
64
|
-
this.focusTrapInstance = createFocusTrap(this.$refs.cardContainer as HTMLElement, {
|
|
65
|
-
escapeDeactivates: true,
|
|
66
|
-
allowOutsideClick: true,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
this.$nextTick(() => {
|
|
70
|
-
this.focusTrapInstance.activate();
|
|
71
|
-
});
|
|
60
|
+
setup(props) {
|
|
61
|
+
if (props.triggerFocusTrap) {
|
|
62
|
+
useBasicSetupFocusTrap('#focus-trap-card-container-element');
|
|
72
63
|
}
|
|
73
|
-
}
|
|
74
|
-
beforeUnmount() {
|
|
75
|
-
if (this.focusTrapInstance && this.triggerFocusTrap) {
|
|
76
|
-
this.focusTrapInstance.deactivate();
|
|
77
|
-
}
|
|
78
|
-
},
|
|
64
|
+
}
|
|
79
65
|
});
|
|
80
66
|
</script>
|
|
81
67
|
|
|
82
68
|
<template>
|
|
83
69
|
<div
|
|
84
|
-
|
|
70
|
+
id="focus-trap-card-container-element"
|
|
85
71
|
class="card-container"
|
|
86
72
|
:class="{'highlight-border': showHighlightBorder, 'card-sticky': sticky}"
|
|
87
73
|
data-testid="card"
|