@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.
Files changed (49) hide show
  1. package/assets/styles/base/_basic.scss +2 -1
  2. package/assets/styles/global/_form.scss +2 -1
  3. package/assets/styles/themes/_dark.scss +1 -1
  4. package/assets/translations/en-us.yaml +22 -4
  5. package/assets/translations/zh-hans.yaml +2 -3
  6. package/components/AppModal.vue +50 -0
  7. package/components/Carousel.vue +54 -47
  8. package/components/CopyToClipboardText.vue +3 -0
  9. package/components/Dialog.vue +20 -1
  10. package/components/PromptChangePassword.vue +3 -0
  11. package/components/ResourceDetail/Masthead.vue +1 -1
  12. package/components/Tabbed/index.vue +4 -7
  13. package/components/__tests__/Carousel.test.ts +56 -27
  14. package/components/form/LabeledSelect.vue +1 -1
  15. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
  16. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
  17. package/components/form/SSHKnownHosts/index.vue +101 -0
  18. package/components/form/Select.vue +1 -1
  19. package/components/form/SelectOrCreateAuthSecret.vue +43 -11
  20. package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
  21. package/composables/focusTrap.ts +68 -0
  22. package/detail/secret.vue +25 -0
  23. package/edit/fleet.cattle.io.gitrepo.vue +27 -22
  24. package/edit/provisioning.cattle.io.cluster/index.vue +26 -19
  25. package/edit/secret/index.vue +1 -1
  26. package/edit/secret/ssh.vue +21 -3
  27. package/list/provisioning.cattle.io.cluster.vue +1 -0
  28. package/models/fleet.cattle.io.gitrepo.js +2 -2
  29. package/models/provisioning.cattle.io.cluster.js +2 -12
  30. package/models/secret.js +5 -0
  31. package/package.json +1 -1
  32. package/pages/account/index.vue +4 -0
  33. package/pages/c/_cluster/explorer/ConfigBadge.vue +5 -4
  34. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
  35. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
  36. package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
  37. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
  38. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
  39. package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
  40. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
  41. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
  42. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
  43. package/pages/c/_cluster/uiplugins/index.vue +50 -12
  44. package/rancher-components/Card/Card.vue +7 -21
  45. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -0
  46. package/rancher-components/RcDropdown/RcDropdown.vue +11 -0
  47. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +2 -3
  48. package/rancher-components/RcDropdown/useDropdownCollection.ts +1 -0
  49. package/rancher-components/RcDropdown/useDropdownContext.ts +28 -1
@@ -408,7 +408,12 @@ export default {
408
408
  },
409
409
 
410
410
  async doCreate(name, credentials) {
411
- const { selected, publicKey, privateKey } = credentials;
411
+ const {
412
+ selected,
413
+ publicKey,
414
+ privateKey,
415
+ sshKnownHosts
416
+ } = credentials;
412
417
 
413
418
  if ( ![AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3].includes(selected) ) {
414
419
  return;
@@ -456,6 +461,11 @@ export default {
456
461
  [publicField]: base64Encode(publicKey),
457
462
  [privateField]: base64Encode(privateKey),
458
463
  };
464
+
465
+ // Add ssh known hosts
466
+ if (selected === AUTH_TYPE._SSH && sshKnownHosts) {
467
+ secret.data.known_hosts = base64Encode(sshKnownHosts);
468
+ }
459
469
  }
460
470
 
461
471
  await secret.save();
@@ -546,17 +556,7 @@ export default {
546
556
  @update:value="$emit('input', $event)"
547
557
  />
548
558
 
549
- <div class="row">
550
- <div class="col span-6">
551
- <Banner
552
- color="info col span-6"
553
- >
554
- <div>
555
- {{ t('fleet.gitRepo.repo.protocolBanner') }}
556
- </div>
557
- </Banner>
558
- </div>
559
- </div>
559
+ <h2 v-t="'fleet.gitRepo.repo.title'" />
560
560
  <div
561
561
  class="row"
562
562
  :class="{'mt-20': isView}"
@@ -586,6 +586,10 @@ export default {
586
586
  />
587
587
  </div>
588
588
  </div>
589
+
590
+ <div class="spacer" />
591
+ <h2 v-t="'fleet.gitRepo.auth.title'" />
592
+
589
593
  <SelectOrCreateAuthSecret
590
594
  :value="value.spec.clientSecretName"
591
595
  :register-before-hook="registerBeforeHook"
@@ -633,8 +637,7 @@ export default {
633
637
  </div>
634
638
 
635
639
  <template v-if="isTls">
636
- <div class="spacer" />
637
- <div class="row">
640
+ <div class="row mt-20">
638
641
  <div class="col span-6">
639
642
  <LabeledSelect
640
643
  :label="t('fleet.gitRepo.tls.label')"
@@ -663,7 +666,7 @@ export default {
663
666
  <div class="resource-handling">
664
667
  <Checkbox
665
668
  v-model:value="correctDriftEnabled"
666
- :tooltip="t('fleet.gitRepo.resources.correctDriftBanner')"
669
+ :tooltip="t('fleet.gitRepo.resources.correctDriftTooltip')"
667
670
  data-testid="GitRepo-correctDrift-checkbox"
668
671
  class="check"
669
672
  type="checkbox"
@@ -672,7 +675,7 @@ export default {
672
675
  />
673
676
  <Checkbox
674
677
  v-model:value="value.spec.keepResources"
675
- :tooltip="t('fleet.gitRepo.resources.keepResourcesBanner')"
678
+ :tooltip="t('fleet.gitRepo.resources.keepResourcesTooltip')"
676
679
  data-testid="GitRepo-keepResources-checkbox"
677
680
  class="check"
678
681
  type="checkbox"
@@ -681,19 +684,16 @@ export default {
681
684
  />
682
685
  </div>
683
686
  <div class="spacer" />
684
- <h2 v-t="'fleet.gitRepo.paths.label'" />
685
687
  <ArrayList
686
688
  v-model:value="value.spec.paths"
687
689
  data-testid="gitRepo-paths"
690
+ :title="t('fleet.gitRepo.paths.label')"
688
691
  :mode="mode"
689
692
  :initial-empty-row="false"
690
693
  :value-placeholder="t('fleet.gitRepo.paths.placeholder')"
691
694
  :add-label="t('fleet.gitRepo.paths.addLabel')"
692
- >
693
- <template #empty>
694
- <Banner label-key="fleet.gitRepo.paths.empty" />
695
- </template>
696
- </ArrayList>
695
+ :protip="t('fleet.gitRepo.paths.empty')"
696
+ />
697
697
  </template>
698
698
  <template #stepTargetInfo>
699
699
  <h2 v-t="isLocal ? 'fleet.gitRepo.target.labelLocal' : 'fleet.gitRepo.target.label'" />
@@ -771,6 +771,11 @@ export default {
771
771
  </template>
772
772
 
773
773
  <style lang="scss" scoped>
774
+ :deep() .select-or-create-auth-secret {
775
+ .row {
776
+ margin-top: 10px !important;
777
+ }
778
+ }
774
779
  .resource-handling {
775
780
  display: flex;
776
781
  flex-direction: column;
@@ -12,7 +12,7 @@ import { mapGetters } from 'vuex';
12
12
  import { sortBy } from '@shell/utils/sort';
13
13
  import { PROVISIONER, _RKE1, _RKE2 } from '@shell/store/prefs';
14
14
  import { filterAndArrangeCharts } from '@shell/store/catalog';
15
- import { CATALOG } from '@shell/config/labels-annotations';
15
+ import { CATALOG, CAPI as CAPI_ANNOTATIONS } from '@shell/config/labels-annotations';
16
16
  import { CAPI, MANAGEMENT, DEFAULT_WORKSPACE } from '@shell/config/types';
17
17
  import { mapFeature, RKE2 as RKE2_FEATURE, RKE1_UI } from '@shell/store/features';
18
18
  import { allHash } from '@shell/utils/promise';
@@ -173,17 +173,7 @@ export default {
173
173
  },
174
174
 
175
175
  data() {
176
- let subType = null;
177
-
178
- subType = this.$route.query[SUB_TYPE] || null;
179
-
180
- if ( this.$route.query[SUB_TYPE]) {
181
- subType = this.$route.query[SUB_TYPE];
182
- } else if (this.value.isImported) {
183
- subType = IMPORTED;
184
- } else if (this.value.isLocal) {
185
- subType = LOCAL;
186
- }
176
+ const subType = this.$route.query[SUB_TYPE] || null;
187
177
  const rkeType = this.$route.query[RKE_TYPE] || null;
188
178
  const chart = this.$route.query[CHART] || null;
189
179
  const isImport = this.realMode === _IMPORT;
@@ -223,6 +213,14 @@ export default {
223
213
 
224
214
  emberLink() {
225
215
  if (this.value) {
216
+ // for imported and local clusters, set subtype using properties from prov cluster model
217
+ //
218
+ if (this.value.isImported) {
219
+ this.selectType(IMPORTED, false);
220
+ } else if (this.value.isLocal) {
221
+ this.selectType(LOCAL, false);
222
+ }
223
+
226
224
  // set subtype if editing EKS/GKE/AKS cluster -- this ensures that the component provided by extension is loaded instead of iframing old ember ui
227
225
  if (this.value.provisioner) {
228
226
  const matchingSubtype = this.subTypes.find((st) => DRIVER_TO_IMPORT[st.id.toLowerCase()] === this.value.provisioner.toLowerCase());
@@ -231,6 +229,16 @@ export default {
231
229
  this.selectType(matchingSubtype.id, false);
232
230
  }
233
231
  }
232
+
233
+ // subType set by the ui during cluster creation
234
+ // this is likely from a ui extension trying to load custom ui to edit the cluster
235
+ const fromAnnotation = this.value.annotations?.[CAPI_ANNOTATIONS.UI_CUSTOM_PROVIDER];
236
+
237
+ if (fromAnnotation) {
238
+ this.selectType(fromAnnotation, false);
239
+
240
+ return '';
241
+ }
234
242
  // For custom RKE2 clusters, don't load an Ember page.
235
243
  // It should be the dashboard.
236
244
  if ( this.value.isRke2 && ((this.value.isCustom && this.mode === _EDIT) || (this.value.isCustom && this.as === _CONFIG && this.mode === _VIEW) || (this.subType || '').toLowerCase() === 'custom')) {
@@ -240,17 +248,18 @@ export default {
240
248
 
241
249
  return '';
242
250
  }
243
- // For RKE2/K3s clusters provisioned in Rancher with node pools,
251
+ // For existing RKE2/K3s clusters provisioned in Rancher,
252
+ // set the subtype using the machine pool provisioner
244
253
  // do not use an iFramed Ember page.
245
254
  if ( this.value.isRke2 && this.value.machineProvider ) {
246
- // Edit existing RKE2
247
255
  this.selectType(this.value.machineProvider, false);
248
256
 
249
257
  return '';
250
258
  }
259
+
251
260
  if ( this.subType ) {
252
261
  // if driver type has a custom form component, don't load an ember page
253
- if (this.selectedSubType.component) {
262
+ if (this.selectedSubType?.component) {
254
263
  return '';
255
264
  }
256
265
  // For RKE1 and hosted Kubernetes Clusters, set the ember link
@@ -259,8 +268,6 @@ export default {
259
268
  return this.selectedSubType.emberLink;
260
269
  }
261
270
 
262
- this.selectType(this.subType, false);
263
-
264
271
  return '';
265
272
  }
266
273
 
@@ -379,8 +386,8 @@ export default {
379
386
 
380
387
  // Add from extensions
381
388
  this.extensions.forEach((ext) => {
382
- // if the rke toggle is set to rke1, don't add extensions that specify rke2 group
383
- // default group is rke2
389
+ // if the rke toggle is set to rke1, don't add extensions that specify rke2 group
390
+ // default group is rke2
384
391
  if (!this.isRke2 && (ext.group === _RKE2 || !ext.group)) {
385
392
  return;
386
393
  }
@@ -206,7 +206,7 @@ export default {
206
206
  case TYPES.TLS:
207
207
  return this.t('secret.certificate.certificate');
208
208
  case TYPES.SSH:
209
- return this.t('secret.ssh.keys');
209
+ return this.value.supportsSshKnownHosts ? this.t('secret.ssh.keysAndHosts') : this.t('secret.ssh.keys');
210
210
  case TYPES.BASIC:
211
211
  return this.t('secret.authentication');
212
212
  default:
@@ -20,16 +20,21 @@ export default {
20
20
  data() {
21
21
  const username = this.value.decodedData['ssh-publickey'] || '';
22
22
  const password = this.value.decodedData['ssh-privatekey'] || '';
23
+ const knownHosts = this.value.decodedData['known_hosts'] || '';
24
+ const showKnownHosts = this.value.supportsSshKnownHosts;
23
25
 
24
26
  return {
25
27
  username,
26
28
  password,
29
+ knownHosts,
30
+ showKnownHosts,
27
31
  };
28
32
  },
29
33
 
30
34
  watch: {
31
- username: 'update',
32
- password: 'update',
35
+ username: 'update',
36
+ password: 'update',
37
+ knownHosts: 'update'
33
38
  },
34
39
 
35
40
  methods: {
@@ -39,8 +44,9 @@ export default {
39
44
  update() {
40
45
  this.value.setData('ssh-publickey', this.username);
41
46
  this.value.setData('ssh-privatekey', this.password);
47
+ this.value.setData('known_hosts', this.knownHosts);
42
48
  }
43
- },
49
+ }
44
50
  };
45
51
  </script>
46
52
 
@@ -78,5 +84,17 @@ export default {
78
84
  />
79
85
  </div>
80
86
  </div>
87
+ <div class="row mt-40">
88
+ <div class="col span-12">
89
+ <LabeledInput
90
+ v-if="showKnownHosts"
91
+ v-model:value="knownHosts"
92
+ type="multiline"
93
+ :label="t('secret.ssh.knownHosts')"
94
+ :mode="mode"
95
+ :placeholder="t('secret.ssh.knownHostsPlaceholder')"
96
+ />
97
+ </div>
98
+ </div>
81
99
  </div>
82
100
  </template>
@@ -174,6 +174,7 @@ export default {
174
174
  // results are filtered so we wouldn't get the correct count on indicator...
175
175
  return { loadIndeterminate: true };
176
176
  }
177
+
177
178
  };
178
179
  </script>
179
180
 
@@ -178,7 +178,7 @@ export default class GitRepo extends SteveModel {
178
178
  }
179
179
 
180
180
  get github() {
181
- const match = this.spec.repo.match(/^https?:\/\/github\.com\/(.*?)(\.git)?\/*$/);
181
+ const match = (this.spec.repo || '').match(/^https?:\/\/github\.com\/(.*?)(\.git)?\/*$/);
182
182
 
183
183
  if (match) {
184
184
  return match[1];
@@ -196,7 +196,7 @@ export default class GitRepo extends SteveModel {
196
196
  }
197
197
 
198
198
  get repoDisplay() {
199
- let repo = this.spec.repo;
199
+ let repo = this.spec.repo || '';
200
200
 
201
201
  if (!repo) {
202
202
  return null;
@@ -5,7 +5,7 @@ import SteveModel from '@shell/plugins/steve/steve-class';
5
5
  import { findBy } from '@shell/utils/array';
6
6
  import { get, set } from '@shell/utils/object';
7
7
  import { sortBy } from '@shell/utils/sort';
8
- import { escapeHtml, ucFirst } from '@shell/utils/string';
8
+ import { ucFirst } from '@shell/utils/string';
9
9
  import { compare } from '@shell/utils/version';
10
10
  import { AS, MODE, _VIEW, _YAML } from '@shell/config/query-params';
11
11
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
@@ -988,17 +988,7 @@ export default class ProvCluster extends SteveModel {
988
988
 
989
989
  get groupByParent() {
990
990
  // Customer helper can report if the cluster has a parent cluster
991
- return this.customProvisionerHelper?.parentCluster?.(this);
992
- }
993
-
994
- get groupByLabel() {
995
- const name = this.groupByParent;
996
-
997
- if (name) {
998
- return this.$rootGetters['i18n/t']('resourceTable.groupLabel.cluster', { name: escapeHtml(name) });
999
- } else {
1000
- return this.$rootGetters['i18n/t']('resourceTable.groupLabel.notInACluster');
1001
- }
991
+ return this.customProvisionerHelper?.parentCluster?.(this) || this.t('resourceTable.groupLabel.notInACluster');
1002
992
  }
1003
993
 
1004
994
  get hasError() {
package/models/secret.js CHANGED
@@ -49,6 +49,11 @@ export default class Secret extends SteveModel {
49
49
  return this._type === TYPES.CLOUD_CREDENTIAL || (this.metadata.namespace === 'cattle-global-data' && this.metadata.generateName === 'cc-');
50
50
  }
51
51
 
52
+ // For Fleet SSH secrets - does the secret have the 'known_hosts' data key?
53
+ get supportsSshKnownHosts() {
54
+ return this._type === TYPES.SSH && 'known_hosts' in this.data;
55
+ }
56
+
52
57
  get issuer() {
53
58
  const { metadata:{ annotations = {} } } = this;
54
59
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.2-rc.3",
3
+ "version": "3.0.2-rc.4",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -160,6 +160,8 @@ export default {
160
160
  <div>
161
161
  <button
162
162
  v-if="canChangePassword"
163
+ role="button"
164
+ :aria-label="t('accountAndKeys.account.change')"
163
165
  type="button"
164
166
  class="btn role-primary"
165
167
  data-testid="account_change_password"
@@ -182,6 +184,8 @@ export default {
182
184
  </div>
183
185
  <button
184
186
  v-if="apiKeySchema"
187
+ role="button"
188
+ :aria-label="t('accountAndKeys.apiKeys.add.label')"
185
189
  class="btn role-primary add mb-20"
186
190
  data-testid="account_create_api_keys"
187
191
  @click="addKey"
@@ -24,9 +24,7 @@ export default {
24
24
  </script>
25
25
 
26
26
  <template>
27
- <div
28
- class="config-badge"
29
- >
27
+ <div class="config-badge">
30
28
  <div>
31
29
  <button
32
30
  class="badge-install btn btn-sm role-secondary"
@@ -34,7 +32,6 @@ export default {
34
32
  role="button"
35
33
  tabindex="0"
36
34
  @click="customBadgeDialog"
37
- @keyup.space="customBadgeDialog"
38
35
  >
39
36
  <i
40
37
  v-clean-tooltip="tooltip"
@@ -60,6 +57,10 @@ export default {
60
57
  > I {
61
58
  line-height: inherit;
62
59
  }
60
+
61
+ &:focus {
62
+ outline: 0;
63
+ }
63
64
  }
64
65
 
65
66
  </style>
@@ -42,7 +42,8 @@ export default {
42
42
  branch: UI_PLUGINS_REPOS.PARTNERS.BRANCH,
43
43
  }
44
44
  },
45
- isDialogActive: false,
45
+ isDialogActive: false,
46
+ returnFocusSelector: '[data-testid="extensions-page-menu"]'
46
47
  };
47
48
  },
48
49
 
@@ -109,6 +110,7 @@ export default {
109
110
  :title="t('plugins.addRepos.title')"
110
111
  mode="add"
111
112
  data-testid="add-extensions-repos-modal"
113
+ :return-focus-selector="returnFocusSelector"
112
114
  @okay="doAddRepos"
113
115
  @closed="isDialogActive = false"
114
116
  >
@@ -128,6 +128,7 @@ export default {
128
128
  ...initialState(),
129
129
  secondaryResourceData: null,
130
130
  showModal: false,
131
+ returnFocusSelector: '[data-testid="extensions-catalog-load-dialog"]'
131
132
  };
132
133
  },
133
134
 
@@ -434,6 +435,8 @@ export default {
434
435
  name="catalogLoadDialog"
435
436
  height="auto"
436
437
  :scrollable="true"
438
+ :trigger-focus-trap="true"
439
+ :return-focus-selector="returnFocusSelector"
437
440
  @close="closeDialog()"
438
441
  >
439
442
  <Loading
@@ -23,7 +23,11 @@ export default {
23
23
 
24
24
  data() {
25
25
  return {
26
- catalog: undefined, busy: false, plugins: null, showModal: false,
26
+ catalog: undefined,
27
+ busy: false,
28
+ plugins: null,
29
+ showModal: false,
30
+ returnFocusSelector: '[data-testid="extensions-catalog-load-dialog"]'
27
31
  };
28
32
  },
29
33
 
@@ -121,6 +125,8 @@ export default {
121
125
  name="uninstallCatalogDialog"
122
126
  height="auto"
123
127
  :scrollable="true"
128
+ :trigger-focus-trap="true"
129
+ :return-focus-selector="returnFocusSelector"
124
130
  @close="closeDialog(false)"
125
131
  >
126
132
  <div
@@ -95,10 +95,12 @@ export default {
95
95
  <template #header-left>
96
96
  <div>
97
97
  <button
98
- class="btn bg-primary mr-10"
98
+ class="btn role-primary mr-10"
99
99
  type="button"
100
100
  aria-haspopup="dialog"
101
101
  data-testid="extensions-catalog-load-dialog"
102
+ role="button"
103
+ :aria-label="t('plugins.manageCatalog.imageLoad.load')"
102
104
  @click="$emit('showCatalogLoadDialog')"
103
105
  >
104
106
  {{ t('plugins.manageCatalog.imageLoad.load') }}
@@ -18,17 +18,18 @@ export default {
18
18
 
19
19
  data() {
20
20
  return {
21
- name: '',
22
- location: '',
23
- persist: false,
24
- canModifyName: true,
25
- canModifyLocation: true,
26
- showModal: false,
21
+ name: '',
22
+ location: '',
23
+ persist: false,
24
+ canModifyName: true,
25
+ canModifyLocation: true,
26
+ showModal: false,
27
+ returnFocusSelector: '[data-testid="extensions-page-menu"]'
27
28
  };
28
29
  },
29
30
 
30
31
  watch: {
31
- name(neu, old) {
32
+ name(neu) {
32
33
  if (this.canModifyLocation) {
33
34
  this.location = `/pkg/${ neu }/${ neu }.umd.min.js`;
34
35
  }
@@ -154,6 +155,8 @@ export default {
154
155
  name="developerInstallPluginDialog"
155
156
  height="auto"
156
157
  :scrollable="true"
158
+ :trigger-focus-trap="true"
159
+ :return-focus-selector="returnFocusSelector"
157
160
  @close="closeDialog()"
158
161
  >
159
162
  <div class="plugin-install-dialog">
@@ -74,6 +74,10 @@ export default {
74
74
 
75
75
  chartVersionLoadsWithoutAuth() {
76
76
  return this.chartVersionInfo?.values?.plugin?.noAuth;
77
+ },
78
+
79
+ returnFocusSelector() {
80
+ return `[data-testid="extension-card-${ this.mode }-btn-${ this.plugin?.name }"]`;
77
81
  }
78
82
  },
79
83
 
@@ -251,6 +255,9 @@ export default {
251
255
  name="installPluginDialog"
252
256
  height="auto"
253
257
  :scrollable="true"
258
+ :trigger-focus-trap="true"
259
+ :return-focus-selector="returnFocusSelector"
260
+ :return-focus-first-iterable-node-selector="'#extensions-main-page'"
254
261
  @close="closeDialog(false)"
255
262
  >
256
263
  <div