@rancher/shell 3.0.3 → 3.0.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/translations/en-us.yaml +1 -0
- package/components/PromptRemove.vue +1 -1
- package/components/SortableTable/index.vue +33 -7
- package/components/StatusBadge.vue +10 -4
- package/components/auth/Principal.vue +9 -3
- package/components/form/ArrayList.vue +9 -0
- package/components/form/KeyValue.vue +1 -1
- package/dialog/DeactivateDriverDialog.vue +4 -4
- package/dialog/GitRepoForceUpdateDialog.vue +1 -1
- package/edit/fleet.cattle.io.gitrepo.vue +1 -0
- package/machine-config/__tests__/vmwarevsphere.test.ts +48 -3
- package/machine-config/vmwarevsphere.vue +16 -0
- package/package.json +2 -2
- package/pages/about.vue +16 -8
- package/promptRemove/management.cattle.io.fleetworkspace.vue +1 -1
- package/promptRemove/management.cattle.io.globalrole.vue +1 -1
- package/promptRemove/management.cattle.io.project.vue +2 -2
- package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
- package/promptRemove/pod.vue +1 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +3 -3
- package/rancher-components/RcDropdown/RcDropdown.vue +3 -3
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +4 -2
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +2 -2
- package/types/shell/index.d.ts +1 -1
- package/utils/__tests__/string.test.ts +2 -2
- package/utils/string.js +1 -3
|
@@ -2521,6 +2521,7 @@ fleet:
|
|
|
2521
2521
|
placeholder: "Paste in one or more certificates, starting with -----BEGIN CERTIFICATE----"
|
|
2522
2522
|
paths:
|
|
2523
2523
|
label: Paths
|
|
2524
|
+
ariaLabel: Enter path for Git Repo
|
|
2524
2525
|
placeholder: e.g. /directory/in/your/repo
|
|
2525
2526
|
addLabel: Add Path
|
|
2526
2527
|
empty: The root of the repo is used by default. Multiple different directories can be provided.
|
|
@@ -354,7 +354,7 @@ export default {
|
|
|
354
354
|
<div class="mb-10">
|
|
355
355
|
<template v-if="!hasCustomRemove">
|
|
356
356
|
{{ t('promptRemove.attemptingToRemove', { type }) }} <span
|
|
357
|
-
v-clean-html="resourceNames(names, t)"
|
|
357
|
+
v-clean-html="resourceNames(names, null, t)"
|
|
358
358
|
/>
|
|
359
359
|
</template>
|
|
360
360
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { mapGetters } from 'vuex';
|
|
3
|
-
import { defineAsyncComponent,
|
|
3
|
+
import { defineAsyncComponent, ref, onMounted, onBeforeUnmount } from 'vue';
|
|
4
4
|
import day from 'dayjs';
|
|
5
|
+
import semver from 'semver';
|
|
5
6
|
import isEmpty from 'lodash/isEmpty';
|
|
6
7
|
import { dasherize, ucFirst } from '@shell/utils/string';
|
|
7
8
|
import { get, clone } from '@shell/utils/object';
|
|
@@ -24,6 +25,7 @@ import { getParent } from '@shell/utils/dom';
|
|
|
24
25
|
import { FORMATTERS } from '@shell/components/SortableTable/sortable-config';
|
|
25
26
|
import ButtonMultiAction from '@shell/components/ButtonMultiAction.vue';
|
|
26
27
|
import ActionMenu from '@shell/components/ActionMenuShell.vue';
|
|
28
|
+
import { getVersionInfo } from '@shell/utils/version';
|
|
27
29
|
|
|
28
30
|
// Uncomment for table performance debugging
|
|
29
31
|
// import tableDebug from './debug';
|
|
@@ -528,7 +530,7 @@ export default {
|
|
|
528
530
|
},
|
|
529
531
|
},
|
|
530
532
|
setup(_props, { emit }) {
|
|
531
|
-
const table =
|
|
533
|
+
const table = ref(null);
|
|
532
534
|
|
|
533
535
|
const handleEnterKey = (event) => {
|
|
534
536
|
if (event.key === 'Enter' && !event.target?.classList?.contains('checkbox-custom')) {
|
|
@@ -543,6 +545,8 @@ export default {
|
|
|
543
545
|
onBeforeUnmount(() => {
|
|
544
546
|
table.value.removeEventListener('keyup', handleEnterKey);
|
|
545
547
|
});
|
|
548
|
+
|
|
549
|
+
return { table };
|
|
546
550
|
},
|
|
547
551
|
|
|
548
552
|
created() {
|
|
@@ -763,6 +767,12 @@ export default {
|
|
|
763
767
|
});
|
|
764
768
|
|
|
765
769
|
return rows;
|
|
770
|
+
},
|
|
771
|
+
|
|
772
|
+
featureDropdownMenu() {
|
|
773
|
+
const { fullVersion } = getVersionInfo(this.$store);
|
|
774
|
+
|
|
775
|
+
return semver.gte(semver.coerce(fullVersion).version, '2.11.0');
|
|
766
776
|
}
|
|
767
777
|
},
|
|
768
778
|
|
|
@@ -1487,11 +1497,27 @@ export default {
|
|
|
1487
1497
|
:row="row.row"
|
|
1488
1498
|
:index="i"
|
|
1489
1499
|
>
|
|
1490
|
-
<
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1500
|
+
<template v-if="featureDropdownMenu">
|
|
1501
|
+
<ActionMenu
|
|
1502
|
+
:resource="row.row"
|
|
1503
|
+
:data-testid="componentTestid + '-' + i + '-action-button'"
|
|
1504
|
+
:button-aria-label="t('sortableTable.tableActionsLabel', { resource: row?.row?.id || '' })"
|
|
1505
|
+
/>
|
|
1506
|
+
</template>
|
|
1507
|
+
<template v-else>
|
|
1508
|
+
<ButtonMultiAction
|
|
1509
|
+
:id="`actionButton+${i}+${(row.row && row.row.name) ? row.row.name : ''}`"
|
|
1510
|
+
:ref="`actionButton${i}`"
|
|
1511
|
+
aria-haspopup="true"
|
|
1512
|
+
aria-expanded="false"
|
|
1513
|
+
:aria-label="t('sortableTable.tableActionsLabel', { resource: row?.row?.id || '' })"
|
|
1514
|
+
:data-testid="componentTestid + '-' + i + '-action-button'"
|
|
1515
|
+
:borderless="true"
|
|
1516
|
+
@click="handleActionButtonClick(i, $event)"
|
|
1517
|
+
@keyup.enter="handleActionButtonClick(i, $event)"
|
|
1518
|
+
@keyup.space="handleActionButtonClick(i, $event)"
|
|
1519
|
+
/>
|
|
1520
|
+
</template>
|
|
1495
1521
|
</slot>
|
|
1496
1522
|
</td>
|
|
1497
1523
|
</tr>
|
|
@@ -19,10 +19,16 @@ const STATUS = {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
status?: 'success' | 'warning' | 'info' | 'error',
|
|
25
|
+
label?: string
|
|
26
|
+
}>(),
|
|
27
|
+
{
|
|
28
|
+
status: 'success',
|
|
29
|
+
label: '',
|
|
30
|
+
}
|
|
31
|
+
);
|
|
26
32
|
|
|
27
33
|
</script>
|
|
28
34
|
<template>
|
|
@@ -98,9 +98,9 @@ export default {
|
|
|
98
98
|
>
|
|
99
99
|
<table>
|
|
100
100
|
<tbody>
|
|
101
|
-
<tr><
|
|
102
|
-
<tr><
|
|
103
|
-
<tr><
|
|
101
|
+
<tr><th>{{ t('principal.name') }}: </th><td>{{ principal.name || principal.loginName }}</td></tr>
|
|
102
|
+
<tr><th>{{ t('principal.loginName') }}: </th><td>{{ principal.loginName }}</td></tr>
|
|
103
|
+
<tr><th>{{ t('principal.type') }}: </th><td>{{ principal.displayType }}</td></tr>
|
|
104
104
|
</tbody>
|
|
105
105
|
</table>
|
|
106
106
|
</div>
|
|
@@ -164,6 +164,12 @@ export default {
|
|
|
164
164
|
grid-template-rows: auto math.div($size, 2);
|
|
165
165
|
column-gap: 10px;
|
|
166
166
|
|
|
167
|
+
th {
|
|
168
|
+
text-align: left;
|
|
169
|
+
font-weight: normal;
|
|
170
|
+
padding-right: 10px;
|
|
171
|
+
}
|
|
172
|
+
|
|
167
173
|
&.showLabels {
|
|
168
174
|
grid-template-areas:
|
|
169
175
|
"avatar name";
|
|
@@ -94,6 +94,10 @@ export default {
|
|
|
94
94
|
// we only want functions in the rules array
|
|
95
95
|
validator: (rules) => rules.every((rule) => ['function'].includes(typeof rule))
|
|
96
96
|
},
|
|
97
|
+
a11yLabel: {
|
|
98
|
+
type: String,
|
|
99
|
+
default: '',
|
|
100
|
+
},
|
|
97
101
|
},
|
|
98
102
|
data() {
|
|
99
103
|
const input = (Array.isArray(this.value) ? this.value : []).slice();
|
|
@@ -316,6 +320,7 @@ export default {
|
|
|
316
320
|
:data-testid="`input-${idx}`"
|
|
317
321
|
:placeholder="valuePlaceholder"
|
|
318
322
|
:disabled="isView || disabled"
|
|
323
|
+
:aria-label="a11yLabel ? a11yLabel : undefined"
|
|
319
324
|
@paste="onPaste(idx, $event)"
|
|
320
325
|
>
|
|
321
326
|
</slot>
|
|
@@ -336,6 +341,8 @@ export default {
|
|
|
336
341
|
:disabled="isView"
|
|
337
342
|
class="btn role-link"
|
|
338
343
|
:data-testid="`remove-item-${idx}`"
|
|
344
|
+
:aria-label="`${_removeLabel} ${idx + 1}`"
|
|
345
|
+
role="button"
|
|
339
346
|
@click="remove(row, idx)"
|
|
340
347
|
>
|
|
341
348
|
{{ _removeLabel }}
|
|
@@ -368,6 +375,8 @@ export default {
|
|
|
368
375
|
class="btn role-tertiary add"
|
|
369
376
|
:disabled="loading || disableAdd"
|
|
370
377
|
data-testid="array-list-button"
|
|
378
|
+
:aria-label="_addLabel"
|
|
379
|
+
role="button"
|
|
371
380
|
@click="add()"
|
|
372
381
|
>
|
|
373
382
|
<i
|
|
@@ -823,7 +823,7 @@ export default {
|
|
|
823
823
|
type="button"
|
|
824
824
|
role="button"
|
|
825
825
|
:disabled="isView || isProtected(row.key) || disabled"
|
|
826
|
-
:aria-label="removeLabel || t('generic.remove')"
|
|
826
|
+
:aria-label="`${removeLabel || t('generic.remove')} ${ i+1 }`"
|
|
827
827
|
class="btn role-link"
|
|
828
828
|
@click="remove(i)"
|
|
829
829
|
>
|
|
@@ -31,12 +31,12 @@ export default {
|
|
|
31
31
|
},
|
|
32
32
|
computed: {
|
|
33
33
|
formattedText() {
|
|
34
|
-
const
|
|
35
|
-
const count =
|
|
36
|
-
const remaining =
|
|
34
|
+
const driverNames = this.drivers.map((obj) => obj.nameDisplay);
|
|
35
|
+
const count = driverNames.length;
|
|
36
|
+
const remaining = driverNames.length > 5 ? driverNames.length - 5 : 0;
|
|
37
37
|
|
|
38
38
|
const plusMore = this.t('drivers.deactivate.andOthers', { count: remaining });
|
|
39
|
-
const names = resourceNames(
|
|
39
|
+
const names = resourceNames(driverNames, plusMore, this.t, false);
|
|
40
40
|
const warningDrivers = this.t('drivers.deactivate.warningDrivers', { names, count });
|
|
41
41
|
|
|
42
42
|
return this.t('drivers.deactivate.warning', { warningDrivers, count });
|
|
@@ -659,6 +659,7 @@ export default {
|
|
|
659
659
|
:initial-empty-row="false"
|
|
660
660
|
:value-placeholder="t('fleet.gitRepo.paths.placeholder')"
|
|
661
661
|
:add-label="t('fleet.gitRepo.paths.addLabel')"
|
|
662
|
+
:a11y-label="t('fleet.gitRepo.paths.ariaLabel')"
|
|
662
663
|
:add-icon="'icon-plus'"
|
|
663
664
|
:protip="t('fleet.gitRepo.paths.empty')"
|
|
664
665
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mount } from '@vue/test-utils';
|
|
1
|
+
import { mount, shallowMount } from '@vue/test-utils';
|
|
2
2
|
import vmwarevsphere from '@shell/machine-config/vmwarevsphere.vue';
|
|
3
3
|
import { DEFAULT_VALUES, SENTINEL } from '@shell/machine-config/vmwarevsphere-config';
|
|
4
4
|
|
|
@@ -172,12 +172,12 @@ describe('component: vmwarevsphere', () => {
|
|
|
172
172
|
name: 'tag_name',
|
|
173
173
|
category: 'tag_category',
|
|
174
174
|
};
|
|
175
|
-
const
|
|
175
|
+
const expectedResult = [{
|
|
176
176
|
...tag, label: `${ tag.category } / ${ tag.name }`, value: tag.id
|
|
177
177
|
}];
|
|
178
178
|
const wrapper = mount(vmwarevsphere, defaultCreateSetup);
|
|
179
179
|
|
|
180
|
-
expect(wrapper.vm.mapTagsToContent([tag])).toStrictEqual(
|
|
180
|
+
expect(wrapper.vm.mapTagsToContent([tag])).toStrictEqual(expectedResult);
|
|
181
181
|
});
|
|
182
182
|
});
|
|
183
183
|
|
|
@@ -254,4 +254,49 @@ describe('component: vmwarevsphere', () => {
|
|
|
254
254
|
});
|
|
255
255
|
});
|
|
256
256
|
});
|
|
257
|
+
|
|
258
|
+
describe('syncNetworkValueForLegacyLabels', () => {
|
|
259
|
+
it('should update the current network value properly', () => {
|
|
260
|
+
const legacyName = 'legacy_name';
|
|
261
|
+
const legacyValue = 'legacy_value';
|
|
262
|
+
const networkLabel = 'network_label';
|
|
263
|
+
|
|
264
|
+
const wrapper = shallowMount(vmwarevsphere, {
|
|
265
|
+
...defaultEditSetup,
|
|
266
|
+
propsData: {
|
|
267
|
+
...defaultEditSetup.propsData,
|
|
268
|
+
value: {
|
|
269
|
+
...defaultEditSetup.propsData.value,
|
|
270
|
+
network: [legacyName]
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
computed: {
|
|
274
|
+
networks: () => [
|
|
275
|
+
{
|
|
276
|
+
name: legacyName, label: networkLabel, value: legacyValue
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'name1', label: 'label1', value: 'value1'
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: 'name2', label: 'label2', value: 'value2'
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: 'name3', label: 'label3', value: 'value3'
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'name4', label: 'label4', value: 'value4'
|
|
289
|
+
},
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// check the current network before updating
|
|
295
|
+
expect(wrapper.vm.value.network).toStrictEqual([legacyName]);
|
|
296
|
+
|
|
297
|
+
wrapper.vm.syncNetworkValueForLegacyLabels();
|
|
298
|
+
|
|
299
|
+
expect(wrapper.vm.value.network).toStrictEqual([legacyValue]);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
257
302
|
});
|
|
@@ -558,6 +558,7 @@ export default {
|
|
|
558
558
|
this.resetValueIfNecessary('network', content, options, true);
|
|
559
559
|
|
|
560
560
|
set(this, 'networksResults', content);
|
|
561
|
+
this.syncNetworkValueForLegacyLabels();
|
|
561
562
|
this.vappMode = this.getInitialVappMode(this.value);
|
|
562
563
|
},
|
|
563
564
|
|
|
@@ -669,6 +670,21 @@ export default {
|
|
|
669
670
|
}
|
|
670
671
|
},
|
|
671
672
|
|
|
673
|
+
// Network labels have been updated to include the MOID.
|
|
674
|
+
// To ensure previously selected networks remain consistent with this change,
|
|
675
|
+
// we update the current network value to allow correct selection from the network list.
|
|
676
|
+
syncNetworkValueForLegacyLabels() {
|
|
677
|
+
const currentNetwork = this.value.network[0];
|
|
678
|
+
|
|
679
|
+
if (this.mode !== _CREATE && currentNetwork) {
|
|
680
|
+
const networkMatch = this.networks.find((network) => currentNetwork === network.name && currentNetwork !== network.label);
|
|
681
|
+
|
|
682
|
+
if (networkMatch) {
|
|
683
|
+
this.value.network = [networkMatch.value];
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
|
|
672
688
|
mapPathOptionsToContent(pathOptions) {
|
|
673
689
|
return (pathOptions || []).map((pathOption) => {
|
|
674
690
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rancher/shell",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4",
|
|
4
4
|
"description": "Rancher Dashboard Shell",
|
|
5
5
|
"repository": "https://github.com/rancherlabs/dashboard",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"add": "2.0.6",
|
|
52
52
|
"ansi_up": "5.0.0",
|
|
53
53
|
"axios-retry": "3.1.9",
|
|
54
|
-
"axios": "
|
|
54
|
+
"axios": "1.8.4",
|
|
55
55
|
"babel-eslint": "10.1.0",
|
|
56
56
|
"babel-plugin-module-resolver": "4.0.0",
|
|
57
57
|
"babel-preset-vue": "2.0.2",
|
package/pages/about.vue
CHANGED
|
@@ -119,8 +119,12 @@ export default {
|
|
|
119
119
|
<table>
|
|
120
120
|
<thead>
|
|
121
121
|
<tr>
|
|
122
|
-
<th
|
|
123
|
-
|
|
122
|
+
<th class="custom-th">
|
|
123
|
+
{{ t('about.versions.component') }}
|
|
124
|
+
</th>
|
|
125
|
+
<th class="custom-th">
|
|
126
|
+
{{ t('about.versions.version') }}
|
|
127
|
+
</th>
|
|
124
128
|
</tr>
|
|
125
129
|
</thead>
|
|
126
130
|
<tr v-if="rancherVersion">
|
|
@@ -210,11 +214,11 @@ export default {
|
|
|
210
214
|
v-for="(d, i) in downloadImageList"
|
|
211
215
|
:key="i"
|
|
212
216
|
>
|
|
213
|
-
<
|
|
217
|
+
<th>
|
|
214
218
|
<div class="os">
|
|
215
219
|
<i :class="`icon ${d.icon} mr-5`" /> {{ t(d.label) }}
|
|
216
220
|
</div>
|
|
217
|
-
</
|
|
221
|
+
</th>
|
|
218
222
|
<td>
|
|
219
223
|
<a
|
|
220
224
|
v-if="d.imageList"
|
|
@@ -241,11 +245,11 @@ export default {
|
|
|
241
245
|
:key="i"
|
|
242
246
|
class="link"
|
|
243
247
|
>
|
|
244
|
-
<
|
|
248
|
+
<th>
|
|
245
249
|
<div class="os">
|
|
246
250
|
<i :class="`icon ${d.icon} mr-5`" /> {{ t(d.label) }}
|
|
247
251
|
</div>
|
|
248
|
-
</
|
|
252
|
+
</th>
|
|
249
253
|
<td>
|
|
250
254
|
<a
|
|
251
255
|
v-if="d.cliLink"
|
|
@@ -273,7 +277,7 @@ export default {
|
|
|
273
277
|
overflow: hidden;
|
|
274
278
|
border-radius: var(--border-radius);
|
|
275
279
|
|
|
276
|
-
tr >
|
|
280
|
+
tr > th:first-of-type {
|
|
277
281
|
width: 20%;
|
|
278
282
|
}
|
|
279
283
|
|
|
@@ -284,11 +288,15 @@ export default {
|
|
|
284
288
|
text-align: left;
|
|
285
289
|
}
|
|
286
290
|
|
|
287
|
-
th {
|
|
291
|
+
th.custom-th {
|
|
288
292
|
background-color: var(--sortable-table-top-divider);
|
|
289
293
|
border-bottom: 1px solid var(--sortable-table-top-divider);
|
|
290
294
|
}
|
|
291
295
|
|
|
296
|
+
th:not(.custom-th) {
|
|
297
|
+
font-weight: normal;
|
|
298
|
+
}
|
|
299
|
+
|
|
292
300
|
a {
|
|
293
301
|
cursor: pointer;
|
|
294
302
|
}
|
|
@@ -21,7 +21,7 @@ export default {
|
|
|
21
21
|
|
|
22
22
|
<template>
|
|
23
23
|
<div>
|
|
24
|
-
{{ t('promptRemove.attemptingToRemove', { type }) }} <span v-clean-html="resourceNames(names, t)" />
|
|
24
|
+
{{ t('promptRemove.attemptingToRemove', { type }) }} <span v-clean-html="resourceNames(names, null, t)" />
|
|
25
25
|
<div
|
|
26
26
|
v-if="info"
|
|
27
27
|
class="text info mb-10 mt-20"
|
|
@@ -94,7 +94,7 @@ export default {
|
|
|
94
94
|
<template v-if="!canSeeProjectlessNamespaces">
|
|
95
95
|
<span class="delete-warning"> {{ t('promptRemove.willDeleteAssociatedNamespaces') }}</span> <br>
|
|
96
96
|
<div
|
|
97
|
-
v-clean-html="resourceNames(names, t)"
|
|
97
|
+
v-clean-html="resourceNames(names, null, t)"
|
|
98
98
|
class="mt-10"
|
|
99
99
|
/>
|
|
100
100
|
</template>
|
|
@@ -108,7 +108,7 @@ export default {
|
|
|
108
108
|
:label="t('promptRemove.deleteAssociatedNamespaces')"
|
|
109
109
|
/>
|
|
110
110
|
<div class="mt-10 ml-20">
|
|
111
|
-
<span v-clean-html="resourceNames(names, t)" />
|
|
111
|
+
<span v-clean-html="resourceNames(names, null, t)" />
|
|
112
112
|
</div>
|
|
113
113
|
</div>
|
|
114
114
|
</div>
|
package/promptRemove/pod.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { defineComponent, onMounted, onBeforeUnmount,
|
|
2
|
+
import { defineComponent, onMounted, onBeforeUnmount, ref } from 'vue';
|
|
3
3
|
|
|
4
4
|
type StateType = boolean | 'true' | 'false' | undefined;
|
|
5
5
|
|
|
@@ -34,7 +34,7 @@ export default defineComponent({
|
|
|
34
34
|
emits: ['update:value'],
|
|
35
35
|
|
|
36
36
|
setup() {
|
|
37
|
-
const switchChrome =
|
|
37
|
+
const switchChrome = ref<HTMLElement | null>(null);
|
|
38
38
|
const focus = () => {
|
|
39
39
|
switchChrome.value?.classList.add('focus');
|
|
40
40
|
};
|
|
@@ -43,7 +43,7 @@ export default defineComponent({
|
|
|
43
43
|
switchChrome.value?.classList.remove('focus');
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
const switchInput =
|
|
46
|
+
const switchInput = ref<HTMLInputElement | null>(null);
|
|
47
47
|
|
|
48
48
|
onMounted(() => {
|
|
49
49
|
switchInput.value?.addEventListener('focus', focus);
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* </template>
|
|
21
21
|
* </rc-dropdown>
|
|
22
22
|
*/
|
|
23
|
-
import {
|
|
23
|
+
import { ref } from 'vue';
|
|
24
24
|
import { useClickOutside } from '@shell/composables/useClickOutside';
|
|
25
25
|
import { useDropdownContext } from '@components/RcDropdown/useDropdownContext';
|
|
26
26
|
|
|
@@ -42,8 +42,8 @@ const {
|
|
|
42
42
|
|
|
43
43
|
provideDropdownContext();
|
|
44
44
|
|
|
45
|
-
const popperContainer =
|
|
46
|
-
const dropdownTarget =
|
|
45
|
+
const popperContainer = ref(null);
|
|
46
|
+
const dropdownTarget = ref(null);
|
|
47
47
|
|
|
48
48
|
useClickOutside(dropdownTarget, () => showMenu(false));
|
|
49
49
|
|
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
import { RcDropdownMenuComponentProps, DropdownOption } from './types';
|
|
9
9
|
import IconOrSvg from '@shell/components/IconOrSvg';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
withDefaults(defineProps<RcDropdownMenuComponentProps>(), {
|
|
12
|
+
buttonRole: 'primary',
|
|
13
|
+
buttonSize: undefined,
|
|
14
|
+
});
|
|
13
15
|
|
|
14
16
|
const emit = defineEmits(['update:open', 'select']);
|
|
15
17
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* A button that opens a menu. Used in conjunction with `RcDropdown.vue`.
|
|
4
4
|
*/
|
|
5
|
-
import { inject, onMounted,
|
|
5
|
+
import { inject, onMounted, ref } from 'vue';
|
|
6
6
|
import { RcButton, RcButtonType } from '@components/RcButton';
|
|
7
7
|
import { DropdownContext, defaultContext } from './types';
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ const {
|
|
|
13
13
|
handleKeydown,
|
|
14
14
|
} = inject<DropdownContext>('dropdownContext') || defaultContext;
|
|
15
15
|
|
|
16
|
-
const dropdownTrigger =
|
|
16
|
+
const dropdownTrigger = ref<RcButtonType | null>(null);
|
|
17
17
|
|
|
18
18
|
onMounted(() => {
|
|
19
19
|
registerTrigger(dropdownTrigger.value);
|
package/types/shell/index.d.ts
CHANGED
|
@@ -4361,7 +4361,7 @@ export function random32(count: any): number | number[];
|
|
|
4361
4361
|
export function randomStr(length?: number, chars?: string): any;
|
|
4362
4362
|
export function formatPercent(value: any, maxPrecision?: number): string;
|
|
4363
4363
|
export function pluralize(str: any): any;
|
|
4364
|
-
export function resourceNames(names: any, t: any,
|
|
4364
|
+
export function resourceNames(names: any, plusMore: any, t: any, endString: any): any;
|
|
4365
4365
|
export function indent(lines: any, count?: number, token?: string, afterRegex?: any): any;
|
|
4366
4366
|
export function decamelize(str: any): any;
|
|
4367
4367
|
export function dasherize(str: any): any;
|
|
@@ -81,9 +81,9 @@ describe('fx: resourceNames', () => {
|
|
|
81
81
|
it.each(args)(`having: %p`, (
|
|
82
82
|
names,
|
|
83
83
|
expectation,
|
|
84
|
-
options,
|
|
84
|
+
options: any,
|
|
85
85
|
) => {
|
|
86
|
-
const result = resourceNames(names, t, options);
|
|
86
|
+
const result = resourceNames(names, options.plusMore, t, options.endString);
|
|
87
87
|
|
|
88
88
|
expect(result).toStrictEqual(expectation);
|
|
89
89
|
});
|
package/utils/string.js
CHANGED
|
@@ -151,11 +151,9 @@ export function pluralize(str) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export function resourceNames(names, t,
|
|
154
|
+
export function resourceNames(names, plusMore, t, endString) {
|
|
155
155
|
const MAX_NAMES_COUNT = 5;
|
|
156
156
|
|
|
157
|
-
let { plusMore, endString } = options;
|
|
158
|
-
|
|
159
157
|
// plusMore default value
|
|
160
158
|
if (!plusMore) {
|
|
161
159
|
plusMore = t('promptRemove.andOthers', { count: names.length > MAX_NAMES_COUNT ? names.length - MAX_NAMES_COUNT : 0 });
|