@gitlab/ui 38.1.0 → 38.3.0
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/CHANGELOG.md +27 -0
- package/dist/components/base/dropdown/dropdown.documentation.js +1 -5
- package/dist/components/base/dropdown/dropdown_item.documentation.js +2 -3
- package/dist/components/base/filtered_search/filtered_search.js +13 -20
- package/dist/components/base/filtered_search/filtered_search_suggestion.js +1 -1
- package/dist/components/base/filtered_search/filtered_search_token.js +31 -23
- package/dist/components/base/filtered_search/filtered_search_utils.js +42 -9
- package/dist/components/base/form/form_checkbox_tree/form_checkbox_tree.documentation.js +2 -27
- package/dist/components/base/form/form_checkbox_tree/form_checkbox_tree.js +16 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/dist/utils/use_mock_intersection_observer.js +2 -2
- package/documentation/components_documentation.js +0 -4
- package/documentation/documented_stories.js +4 -1
- package/package.json +12 -12
- package/src/components/base/avatar_link/avatar_link.stories.js +2 -2
- package/src/components/base/dropdown/dropdown.documentation.js +0 -3
- package/src/components/base/dropdown/dropdown.md +7 -2
- package/src/components/base/dropdown/dropdown.stories.js +487 -439
- package/src/components/base/dropdown/dropdown_item.documentation.js +0 -1
- package/src/components/base/dropdown/dropdown_item.md +0 -6
- package/src/components/base/dropdown/dropdown_item.stories.js +107 -35
- package/src/components/base/filtered_search/filtered_search.spec.js +37 -12
- package/src/components/base/filtered_search/filtered_search.stories.js +15 -7
- package/src/components/base/filtered_search/filtered_search.vue +12 -14
- package/src/components/base/filtered_search/filtered_search_suggestion.vue +1 -0
- package/src/components/base/filtered_search/filtered_search_token.spec.js +31 -1
- package/src/components/base/filtered_search/filtered_search_token.stories.js +1 -0
- package/src/components/base/filtered_search/filtered_search_token.vue +30 -21
- package/src/components/base/filtered_search/filtered_search_utils.js +38 -5
- package/src/components/base/form/form.stories.js +2 -0
- package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.documentation.js +0 -26
- package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.md +0 -4
- package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.stories.js +123 -92
- package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.vue +13 -1
- package/src/components/base/form/form_radio_group/form_radio_group.stories.js +2 -1
- package/src/components/base/markdown/markdown.scss +21 -0
- package/src/components/base/markdown/markdown_typescale_demo.html +17 -6
- package/src/components/base/navbar/navbar.stories.js +2 -1
- package/src/components/base/skeleton_loader/skeleton_loader.stories.js +67 -21
- package/src/components/base/tabs/tabs/tabs.stories.js +2 -2
- package/src/scss/typescale/typescale.md +0 -2
- package/src/scss/typescale/typescale.stories.js +17 -4
- package/src/scss/utilities.scss +24 -0
- package/src/scss/utility-mixins/display.scss +12 -0
- package/src/utils/use_mock_intersection_observer.js +3 -3
- package/dist/components/base/dropdown/dropdown_divider.documentation.js +0 -8
- package/dist/components/base/dropdown/dropdown_form.documentation.js +0 -17
- package/dist/components/base/dropdown/dropdown_section_header.documentation.js +0 -8
- package/dist/components/base/dropdown/dropdown_text.documentation.js +0 -8
- package/dist/components/base/dropdown/examples/dropdown.default.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.links.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_avatar_and_secondary_text.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_checked_items.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_clear_all.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_divider.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_form.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_header.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_highlighted_items.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_icons.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_right_align.example.js +0 -38
- package/dist/components/base/dropdown/examples/dropdown.with_search.example.js +0 -67
- package/dist/components/base/dropdown/examples/dropdown.with_section_headers.example.js +0 -38
- package/dist/components/base/dropdown/examples/index.js +0 -85
- package/dist/components/base/form/form_checkbox_tree/examples/form_checkbox_tree.basic.example.js +0 -103
- package/dist/components/base/form/form_checkbox_tree/examples/index.js +0 -13
- package/src/components/base/dropdown/dropdown_divider.documentation.js +0 -6
- package/src/components/base/dropdown/dropdown_divider.md +0 -7
- package/src/components/base/dropdown/dropdown_divider.stories.js +0 -16
- package/src/components/base/dropdown/dropdown_form.documentation.js +0 -9
- package/src/components/base/dropdown/dropdown_form.md +0 -4
- package/src/components/base/dropdown/dropdown_form.stories.js +0 -17
- package/src/components/base/dropdown/dropdown_section_header.documentation.js +0 -6
- package/src/components/base/dropdown/dropdown_section_header.stories.js +0 -17
- package/src/components/base/dropdown/dropdown_text.documentation.js +0 -6
- package/src/components/base/dropdown/dropdown_text.stories.js +0 -16
- package/src/components/base/dropdown/examples/dropdown.default.example.vue +0 -7
- package/src/components/base/dropdown/examples/dropdown.links.example.vue +0 -7
- package/src/components/base/dropdown/examples/dropdown.with_avatar_and_secondary_text.example.vue +0 -7
- package/src/components/base/dropdown/examples/dropdown.with_checked_items.example.vue +0 -6
- package/src/components/base/dropdown/examples/dropdown.with_clear_all.example.vue +0 -7
- package/src/components/base/dropdown/examples/dropdown.with_divider.example.vue +0 -9
- package/src/components/base/dropdown/examples/dropdown.with_form.example.vue +0 -10
- package/src/components/base/dropdown/examples/dropdown.with_header.example.vue +0 -7
- package/src/components/base/dropdown/examples/dropdown.with_highlighted_items.example.vue +0 -9
- package/src/components/base/dropdown/examples/dropdown.with_icons.example.vue +0 -43
- package/src/components/base/dropdown/examples/dropdown.with_right_align.example.vue +0 -7
- package/src/components/base/dropdown/examples/dropdown.with_search.example.vue +0 -38
- package/src/components/base/dropdown/examples/dropdown.with_section_headers.example.vue +0 -10
- package/src/components/base/dropdown/examples/index.js +0 -99
- package/src/components/base/form/form_checkbox_tree/examples/form_checkbox_tree.basic.example.vue +0 -77
- package/src/components/base/form/form_checkbox_tree/examples/index.js +0 -15
|
@@ -1,42 +1,114 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { documentedStoriesOf } from '../../../../documentation/documented_stories';
|
|
1
|
+
import iconSpriteInfo from '@gitlab/svgs/dist/icons.json';
|
|
3
2
|
import { GlDropdownItem } from '../../../index';
|
|
3
|
+
import { variantCssColorMap } from '../../../utils/constants';
|
|
4
4
|
import readme from './dropdown_item.md';
|
|
5
5
|
|
|
6
6
|
const components = {
|
|
7
7
|
GlDropdownItem,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
10
|
+
const wrap = (template) => `
|
|
11
|
+
<ul class="gl-list-style-none gl-pl-0">
|
|
12
|
+
<gl-dropdown-item
|
|
13
|
+
:avatar-url="avatarUrl"
|
|
14
|
+
:icon-color="iconColor"
|
|
15
|
+
:icon-name="iconName"
|
|
16
|
+
:icon-right-aria-label="iconRightAriaLabel"
|
|
17
|
+
:icon-right-name="iconRightName"
|
|
18
|
+
:is-checked="isChecked"
|
|
19
|
+
:is-check-item="isCheckItem"
|
|
20
|
+
:is-check-centered="isCheckCentered"
|
|
21
|
+
:secondary-text="secondaryText">
|
|
22
|
+
${template}
|
|
23
|
+
</gl-dropdown-item>
|
|
24
|
+
</ul>
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const defaultValue = (prop) => GlDropdownItem.props[prop].default;
|
|
28
|
+
|
|
29
|
+
const generateProps = ({
|
|
30
|
+
avatarUrl = defaultValue('avatarUrl'),
|
|
31
|
+
iconColor = defaultValue('iconColor'),
|
|
32
|
+
iconName = defaultValue('iconName'),
|
|
33
|
+
iconRightAriaLabel = defaultValue('iconRightAriaLabel'),
|
|
34
|
+
iconRightName = defaultValue('iconRightName'),
|
|
35
|
+
isChecked = defaultValue('isChecked'),
|
|
36
|
+
isCheckItem = defaultValue('isCheckItem'),
|
|
37
|
+
isCheckCentered = defaultValue('isCheckCentered'),
|
|
38
|
+
secondaryText = defaultValue('secondaryText'),
|
|
39
|
+
} = {}) => ({
|
|
40
|
+
avatarUrl,
|
|
41
|
+
iconColor,
|
|
42
|
+
iconName,
|
|
43
|
+
iconRightAriaLabel,
|
|
44
|
+
iconRightName,
|
|
45
|
+
isChecked,
|
|
46
|
+
isCheckItem,
|
|
47
|
+
isCheckCentered,
|
|
48
|
+
secondaryText,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const Default = (args, { argTypes }) => ({
|
|
52
|
+
props: Object.keys(argTypes),
|
|
53
|
+
components,
|
|
54
|
+
template: wrap('Some item'),
|
|
55
|
+
});
|
|
56
|
+
Default.args = generateProps();
|
|
57
|
+
|
|
58
|
+
export const Checked = (args, { argTypes }) => ({
|
|
59
|
+
props: Object.keys(argTypes),
|
|
60
|
+
components,
|
|
61
|
+
template: wrap('Some item'),
|
|
62
|
+
});
|
|
63
|
+
Checked.args = generateProps({ isChecked: true, isCheckItem: true });
|
|
64
|
+
|
|
65
|
+
export const CheckedWithAvatar = (args, { argTypes }) => ({
|
|
66
|
+
props: Object.keys(argTypes),
|
|
67
|
+
components,
|
|
68
|
+
template: wrap('Sid Sijbrandij'),
|
|
69
|
+
});
|
|
70
|
+
CheckedWithAvatar.args = generateProps({
|
|
71
|
+
isChecked: true,
|
|
72
|
+
isCheckItem: true,
|
|
73
|
+
isCheckCentered: true,
|
|
74
|
+
avatarUrl: './img/avatar.png',
|
|
75
|
+
secondaryText: '@sytses',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const CheckedWithSecondaryText = (args, { argTypes }) => ({
|
|
79
|
+
props: Object.keys(argTypes),
|
|
80
|
+
components,
|
|
81
|
+
template: wrap('Some item'),
|
|
82
|
+
});
|
|
83
|
+
CheckedWithSecondaryText.args = generateProps({
|
|
84
|
+
isChecked: true,
|
|
85
|
+
isCheckItem: true,
|
|
86
|
+
secondaryText: 'Lorem ipsum dolar sit amit...',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
export default {
|
|
90
|
+
title: 'base/dropdown/dropdown-item',
|
|
91
|
+
component: GlDropdownItem,
|
|
92
|
+
parameters: {
|
|
93
|
+
bootstrapComponent: 'b-dropdown-item',
|
|
94
|
+
docs: {
|
|
95
|
+
description: {
|
|
96
|
+
component: readme,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
argTypes: {
|
|
101
|
+
iconColor: {
|
|
102
|
+
options: Object.keys(variantCssColorMap),
|
|
103
|
+
control: {
|
|
104
|
+
type: 'select',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
iconName: {
|
|
108
|
+
options: iconSpriteInfo.icons,
|
|
109
|
+
control: {
|
|
110
|
+
type: 'select',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Vue, { nextTick } from 'vue';
|
|
2
|
+
import { omit } from 'lodash';
|
|
2
3
|
import { shallowMount, mount } from '@vue/test-utils';
|
|
3
4
|
import GlFilteredSearch from './filtered_search.vue';
|
|
4
5
|
import GlFilteredSearchSuggestion from './filtered_search_suggestion.vue';
|
|
@@ -17,6 +18,8 @@ const FakeToken = {
|
|
|
17
18
|
|
|
18
19
|
Vue.directive('GlTooltip', () => {});
|
|
19
20
|
|
|
21
|
+
const stripId = (token) => (typeof token === 'object' ? omit(token, 'id') : token);
|
|
22
|
+
|
|
20
23
|
let wrapper;
|
|
21
24
|
describe('Filtered search', () => {
|
|
22
25
|
const defaultProps = {
|
|
@@ -41,7 +44,7 @@ describe('Filtered search', () => {
|
|
|
41
44
|
describe('value manipulation', () => {
|
|
42
45
|
it('creates term when empty', () => {
|
|
43
46
|
createComponent();
|
|
44
|
-
expect(wrapper.emitted().input[0][0]).toStrictEqual([
|
|
47
|
+
expect(wrapper.emitted().input[0][0].map(stripId)).toStrictEqual([
|
|
45
48
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
46
49
|
]);
|
|
47
50
|
});
|
|
@@ -56,7 +59,7 @@ describe('Filtered search', () => {
|
|
|
56
59
|
value: [{ type: 'faketoken', value: { data: '' } }],
|
|
57
60
|
});
|
|
58
61
|
|
|
59
|
-
expect(wrapper.emitted().input[0][0].pop()).toStrictEqual({
|
|
62
|
+
expect(stripId(wrapper.emitted().input[0][0].pop())).toStrictEqual({
|
|
60
63
|
type: TERM_TOKEN_TYPE,
|
|
61
64
|
value: { data: '' },
|
|
62
65
|
});
|
|
@@ -172,7 +175,7 @@ describe('Filtered search', () => {
|
|
|
172
175
|
|
|
173
176
|
await nextTick();
|
|
174
177
|
|
|
175
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
178
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
176
179
|
{ type: 'faketoken', value: { data: '' } },
|
|
177
180
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
178
181
|
{ type: TERM_TOKEN_TYPE, value: { data: 'three' } },
|
|
@@ -190,7 +193,7 @@ describe('Filtered search', () => {
|
|
|
190
193
|
|
|
191
194
|
await nextTick();
|
|
192
195
|
|
|
193
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
196
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
194
197
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
195
198
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
196
199
|
]);
|
|
@@ -305,7 +308,7 @@ describe('Filtered search', () => {
|
|
|
305
308
|
|
|
306
309
|
await nextTick();
|
|
307
310
|
|
|
308
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
311
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
309
312
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
310
313
|
]);
|
|
311
314
|
});
|
|
@@ -318,7 +321,7 @@ describe('Filtered search', () => {
|
|
|
318
321
|
|
|
319
322
|
await nextTick();
|
|
320
323
|
|
|
321
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
324
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
322
325
|
{ type: 'faketoken', value: { data: 'test' } },
|
|
323
326
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
324
327
|
]);
|
|
@@ -339,7 +342,7 @@ describe('Filtered search', () => {
|
|
|
339
342
|
|
|
340
343
|
await nextTick();
|
|
341
344
|
|
|
342
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
345
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
343
346
|
{ type: 'faketoken', value: { data: 'test' } },
|
|
344
347
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
345
348
|
]);
|
|
@@ -352,7 +355,7 @@ describe('Filtered search', () => {
|
|
|
352
355
|
|
|
353
356
|
await nextTick();
|
|
354
357
|
|
|
355
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
358
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
356
359
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
357
360
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
358
361
|
]);
|
|
@@ -368,7 +371,7 @@ describe('Filtered search', () => {
|
|
|
368
371
|
await nextTick();
|
|
369
372
|
|
|
370
373
|
expect(wrapper.findAllComponents(GlFilteredSearchTerm).at(2).props('active')).toBe(true);
|
|
371
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
374
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
372
375
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
373
376
|
{ type: TERM_TOKEN_TYPE, value: { data: 'two' } },
|
|
374
377
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
@@ -385,7 +388,7 @@ describe('Filtered search', () => {
|
|
|
385
388
|
|
|
386
389
|
await nextTick();
|
|
387
390
|
|
|
388
|
-
expect(wrapper.emitted().input.pop()[0]).toStrictEqual([
|
|
391
|
+
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
389
392
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
390
393
|
{ type: TERM_TOKEN_TYPE, value: { data: 'foo' } },
|
|
391
394
|
{ type: TERM_TOKEN_TYPE, value: { data: 'bar' } },
|
|
@@ -415,7 +418,7 @@ describe('Filtered search', () => {
|
|
|
415
418
|
});
|
|
416
419
|
wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('submit');
|
|
417
420
|
expect(wrapper.emitted().submit).toBeDefined();
|
|
418
|
-
expect(wrapper.emitted().submit[0][0]).toStrictEqual([
|
|
421
|
+
expect(wrapper.emitted().submit[0][0].map(stripId)).toStrictEqual([
|
|
419
422
|
'one two',
|
|
420
423
|
{ type: 'faketoken', value: { data: 'smth' } },
|
|
421
424
|
'four five',
|
|
@@ -475,7 +478,7 @@ describe('Filtered search', () => {
|
|
|
475
478
|
});
|
|
476
479
|
await nextTick();
|
|
477
480
|
|
|
478
|
-
expect(wrapper.findComponent(GlFilteredSearchTerm).props('currentValue')).toEqual([
|
|
481
|
+
expect(wrapper.findComponent(GlFilteredSearchTerm).props('currentValue').map(stripId)).toEqual([
|
|
479
482
|
{ type: 'filtered-search-term', value: { data: 'one' } },
|
|
480
483
|
{ type: 'filtered-search-term', value: { data: '' } },
|
|
481
484
|
]);
|
|
@@ -705,4 +708,26 @@ describe('Filtered search integration tests', () => {
|
|
|
705
708
|
|
|
706
709
|
expect(wrapper.findAllComponents(GlFilteredSearchTerm)).toHaveLength(1);
|
|
707
710
|
});
|
|
711
|
+
|
|
712
|
+
// Regression test for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1761
|
|
713
|
+
it('does not incorrectly activate next token of the same type after token destruction', async () => {
|
|
714
|
+
mountComponent({
|
|
715
|
+
value: [
|
|
716
|
+
{ type: 'static', value: { data: 'first', operator: '=' } },
|
|
717
|
+
{ type: 'static', value: { data: 'second', operator: '=' } },
|
|
718
|
+
{ type: 'unique', value: { data: 'something' } },
|
|
719
|
+
],
|
|
720
|
+
});
|
|
721
|
+
await nextTick();
|
|
722
|
+
|
|
723
|
+
expect(
|
|
724
|
+
wrapper.findAllComponents(GlFilteredSearchToken).wrappers.map((cmp) => cmp.props('active'))
|
|
725
|
+
).toEqual([false, false, false]);
|
|
726
|
+
|
|
727
|
+
await wrapper.find('.gl-token-close').trigger('mousedown');
|
|
728
|
+
|
|
729
|
+
expect(
|
|
730
|
+
wrapper.findAllComponents(GlFilteredSearchToken).wrappers.map((cmp) => cmp.props('active'))
|
|
731
|
+
).toEqual([false, false]);
|
|
732
|
+
});
|
|
708
733
|
});
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
GlFilteredSearchTerm,
|
|
7
7
|
GlFilteredSearchTokenSegment,
|
|
8
8
|
GlLoadingIcon,
|
|
9
|
+
GlIcon,
|
|
9
10
|
GlToken,
|
|
10
11
|
GlAvatar,
|
|
11
12
|
} from '../../../index';
|
|
@@ -56,14 +57,14 @@ const UserToken = {
|
|
|
56
57
|
setStoryTimeout(() => {
|
|
57
58
|
this.loadingView = false;
|
|
58
59
|
this.activeUser = fakeUsers.find((u) => u.username === this.value.data);
|
|
59
|
-
},
|
|
60
|
+
}, 500);
|
|
60
61
|
},
|
|
61
62
|
loadSuggestions() {
|
|
62
63
|
this.loadingSuggestions = true;
|
|
63
64
|
setStoryTimeout(() => {
|
|
64
65
|
this.loadingSuggestions = false;
|
|
65
66
|
this.users = fakeUsers;
|
|
66
|
-
},
|
|
67
|
+
}, 500);
|
|
67
68
|
},
|
|
68
69
|
},
|
|
69
70
|
watch: {
|
|
@@ -132,7 +133,7 @@ const MilestoneToken = {
|
|
|
132
133
|
setStoryTimeout(() => {
|
|
133
134
|
this.loadingSuggestions = false;
|
|
134
135
|
this.milestones = fakeMilestones;
|
|
135
|
-
},
|
|
136
|
+
}, 500);
|
|
136
137
|
},
|
|
137
138
|
},
|
|
138
139
|
watch: {
|
|
@@ -214,7 +215,7 @@ const LabelToken = {
|
|
|
214
215
|
setStoryTimeout(() => {
|
|
215
216
|
this.loadingSuggestions = false;
|
|
216
217
|
this.labels = fakeLabels;
|
|
217
|
-
},
|
|
218
|
+
}, 500);
|
|
218
219
|
},
|
|
219
220
|
},
|
|
220
221
|
watch: {
|
|
@@ -322,7 +323,7 @@ export const WithHistoryItems = () => ({
|
|
|
322
323
|
type: 'demotoken',
|
|
323
324
|
title: 'Unique',
|
|
324
325
|
icon: 'document',
|
|
325
|
-
token:
|
|
326
|
+
token: GlFilteredSearchToken,
|
|
326
327
|
operators: [{ value: '=', description: 'is', default: 'true' }],
|
|
327
328
|
options: [
|
|
328
329
|
{ icon: 'heart', title: 'heart', value: 1 },
|
|
@@ -374,14 +375,14 @@ export const WithFriendlyText = () => ({
|
|
|
374
375
|
icon: 'weight',
|
|
375
376
|
title: 'Weight',
|
|
376
377
|
unique: true,
|
|
377
|
-
token:
|
|
378
|
+
token: GlFilteredSearchToken,
|
|
378
379
|
},
|
|
379
380
|
{
|
|
380
381
|
type: 'confidential',
|
|
381
382
|
icon: 'eye-slash',
|
|
382
383
|
title: 'Confidential',
|
|
383
384
|
unique: true,
|
|
384
|
-
token:
|
|
385
|
+
token: GlFilteredSearchToken,
|
|
385
386
|
options: [
|
|
386
387
|
{ icon: 'eye-slash', value: 'Yes', title: 'Yes' },
|
|
387
388
|
{ icon: 'eye', value: 'No', title: 'No' },
|
|
@@ -406,6 +407,13 @@ export const WithFriendlyText = () => ({
|
|
|
406
407
|
export const WithMultiSelect = () => {
|
|
407
408
|
const MultiUserToken = {
|
|
408
409
|
props: ['value', 'active', 'config'],
|
|
410
|
+
components: {
|
|
411
|
+
GlFilteredSearchToken,
|
|
412
|
+
GlFilteredSearchSuggestion,
|
|
413
|
+
GlLoadingIcon,
|
|
414
|
+
GlIcon,
|
|
415
|
+
GlAvatar,
|
|
416
|
+
},
|
|
409
417
|
inheritAttrs: false,
|
|
410
418
|
data() {
|
|
411
419
|
return {
|
|
@@ -8,8 +8,9 @@ import GlSearchBoxByClick from '../search_box_by_click/search_box_by_click.vue';
|
|
|
8
8
|
import GlFilteredSearchTerm from './filtered_search_term.vue';
|
|
9
9
|
import {
|
|
10
10
|
isEmptyTerm,
|
|
11
|
-
TERM_TOKEN_TYPE,
|
|
12
11
|
INTENT_ACTIVATE_PREVIOUS,
|
|
12
|
+
createTerm,
|
|
13
|
+
ensureTokenId,
|
|
13
14
|
normalizeTokens,
|
|
14
15
|
denormalizeTokens,
|
|
15
16
|
needDenormalization,
|
|
@@ -19,13 +20,6 @@ Vue.use(PortalVue);
|
|
|
19
20
|
|
|
20
21
|
let portalUuid = 0;
|
|
21
22
|
|
|
22
|
-
function createTerm(data = '') {
|
|
23
|
-
return {
|
|
24
|
-
type: TERM_TOKEN_TYPE,
|
|
25
|
-
value: { data },
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
23
|
function initialState() {
|
|
30
24
|
return [createTerm()];
|
|
31
25
|
}
|
|
@@ -160,6 +154,13 @@ export default {
|
|
|
160
154
|
watch: {
|
|
161
155
|
tokens: {
|
|
162
156
|
handler() {
|
|
157
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
158
|
+
const invalidToken = this.tokens.find((token) => !token.id);
|
|
159
|
+
if (invalidToken) {
|
|
160
|
+
throw new Error(`Token does not have an id:\n${JSON.stringify(invalidToken)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
163
164
|
if (this.tokens.length === 0 || !this.isLastTokenEmpty()) {
|
|
164
165
|
this.tokens.push(createTerm());
|
|
165
166
|
}
|
|
@@ -255,7 +256,7 @@ export default {
|
|
|
255
256
|
},
|
|
256
257
|
|
|
257
258
|
replaceToken(idx, token) {
|
|
258
|
-
this.$set(this.tokens, idx, { ...token, value: { data: '', ...token.value } });
|
|
259
|
+
this.$set(this.tokens, idx, ensureTokenId({ ...token, value: { data: '', ...token.value } }));
|
|
259
260
|
this.activeTokenIdx = idx;
|
|
260
261
|
},
|
|
261
262
|
|
|
@@ -269,10 +270,7 @@ export default {
|
|
|
269
270
|
return;
|
|
270
271
|
}
|
|
271
272
|
|
|
272
|
-
const newTokens = newStrings.map((data) => (
|
|
273
|
-
type: TERM_TOKEN_TYPE,
|
|
274
|
-
value: { data },
|
|
275
|
-
}));
|
|
273
|
+
const newTokens = newStrings.map((data) => createTerm(data));
|
|
276
274
|
|
|
277
275
|
this.tokens.splice(idx + 1, 0, ...newTokens);
|
|
278
276
|
|
|
@@ -340,7 +338,7 @@ export default {
|
|
|
340
338
|
<component
|
|
341
339
|
:is="getTokenComponent(token.type)"
|
|
342
340
|
ref="tokens"
|
|
343
|
-
:key="
|
|
341
|
+
:key="token.id"
|
|
344
342
|
v-model="token.value"
|
|
345
343
|
:config="getTokenEntry(token.type)"
|
|
346
344
|
:active="activeTokenIdx === idx"
|
|
@@ -225,8 +225,16 @@ describe('Filtered search token', () => {
|
|
|
225
225
|
mountComponent({ value: { operator: '=', data: 'something' } });
|
|
226
226
|
const closeWrapper = wrapper.find('.gl-token-close');
|
|
227
227
|
closeWrapper.element.closest = () => closeWrapper.element;
|
|
228
|
-
closeWrapper.trigger('mousedown');
|
|
229
228
|
|
|
229
|
+
const preventDefaultSpy = jest.fn();
|
|
230
|
+
const stopPropagationSpy = jest.fn();
|
|
231
|
+
closeWrapper.trigger('mousedown', {
|
|
232
|
+
preventDefault: preventDefaultSpy,
|
|
233
|
+
stopPropagation: stopPropagationSpy,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(preventDefaultSpy).toHaveBeenCalled();
|
|
237
|
+
expect(stopPropagationSpy).toHaveBeenCalled();
|
|
230
238
|
expect(wrapper.emitted().destroy).toHaveLength(1);
|
|
231
239
|
});
|
|
232
240
|
|
|
@@ -247,6 +255,16 @@ describe('Filtered search token', () => {
|
|
|
247
255
|
expect(wrapper.emitted().input[0][0].operator).toBe('=');
|
|
248
256
|
expect(findDataSegment().props().active).toBe(true);
|
|
249
257
|
});
|
|
258
|
+
|
|
259
|
+
it('does not mutate its value prop', async () => {
|
|
260
|
+
const originalValue = () => ({ operator: '', data: '' });
|
|
261
|
+
const value = observable(originalValue());
|
|
262
|
+
mountComponent({ active: true, value });
|
|
263
|
+
|
|
264
|
+
await wrapper.find('input').trigger('keydown', { key: 'q' });
|
|
265
|
+
|
|
266
|
+
expect(value).toEqual(originalValue());
|
|
267
|
+
});
|
|
250
268
|
});
|
|
251
269
|
|
|
252
270
|
describe('when multi select', () => {
|
|
@@ -270,5 +288,17 @@ describe('Filtered search token', () => {
|
|
|
270
288
|
|
|
271
289
|
expect(wrapper.emitted('input')).toEqual([[{ data: '', operator: '=' }]]);
|
|
272
290
|
});
|
|
291
|
+
|
|
292
|
+
it('passes down the value prop to the data segment if it changes', async () => {
|
|
293
|
+
createComponent({
|
|
294
|
+
value: { operator: '=', data: 'alpha' },
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
await wrapper.setProps({
|
|
298
|
+
value: { operator: '=', data: 'gamma' },
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(findDataSegment().props('value')).toEqual('gamma');
|
|
302
|
+
});
|
|
273
303
|
});
|
|
274
304
|
});
|