@gitlab/ui 72.7.0 → 72.8.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 +7 -0
- package/dist/components/base/dropdown/dropdown.js +2 -6
- package/dist/components/base/filtered_search/filtered_search_term.js +2 -0
- package/dist/components/base/filtered_search/filtered_search_token.js +3 -1
- package/dist/components/base/filtered_search/filtered_search_token_segment.js +4 -1
- package/dist/components/base/new_dropdowns/disclosure/utils.js +5 -1
- package/dist/components/base/new_dropdowns/listbox/utils.js +6 -0
- package/dist/components/base/sorting/sorting.js +1 -0
- package/dist/components/charts/column/column.js +1 -1
- package/dist/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.js +2 -0
- package/dist/components/experimental/duo/chat/duo_chat.js +2 -0
- package/dist/components/utilities/sprintf/sprintf.js +3 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/dist/utils/is_slot_empty.js +4 -0
- package/dist/utils/number_utils.js +1 -1
- package/dist/utils/utils.js +1 -1
- package/package.json +3 -3
- package/src/components/base/broadcast_message/broadcast_message.stories.js +1 -0
- package/src/components/base/drawer/drawer.spec.js +1 -0
- package/src/components/base/dropdown/dropdown.vue +2 -6
- package/src/components/base/filtered_search/filtered_search.spec.js +11 -0
- package/src/components/base/filtered_search/filtered_search_term.vue +1 -0
- package/src/components/base/filtered_search/filtered_search_token.vue +1 -0
- package/src/components/base/filtered_search/filtered_search_token_segment.vue +3 -1
- package/src/components/base/form/form_fields/form_fields.spec.js +1 -0
- package/src/components/base/new_dropdowns/disclosure/utils.js +2 -0
- package/src/components/base/new_dropdowns/listbox/listbox.spec.js +2 -0
- package/src/components/base/new_dropdowns/listbox/listbox.stories.js +4 -0
- package/src/components/base/new_dropdowns/listbox/utils.js +3 -0
- package/src/components/base/sorting/sorting.vue +1 -0
- package/src/components/charts/column/__snapshots__/column_chart.spec.js.snap +1 -1
- package/src/components/charts/column/column.stories.js +18 -3
- package/src/components/charts/column/column.vue +16 -1
- package/src/components/charts/column/column_chart.spec.js +106 -20
- package/src/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.vue +1 -0
- package/src/components/experimental/duo/chat/duo_chat.vue +1 -0
- package/src/components/utilities/intersection_observer/intersection_observer.spec.js +1 -0
- package/src/components/utilities/intersperse/intersperse.spec.js +1 -0
- package/src/components/utilities/sprintf/sprintf.vue +1 -0
- package/src/utils/is_slot_empty.js +3 -0
- package/src/utils/number_utils.js +1 -1
- package/src/utils/utils.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [72.8.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v72.7.0...v72.8.0) (2024-01-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **GlColumnChart:** allow customising chart tooltip ([ed6ee9e](https://gitlab.com/gitlab-org/gitlab-ui/commit/ed6ee9e3139cba2793d90d955c39c41f6ab2b5af))
|
|
7
|
+
|
|
1
8
|
# [72.7.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v72.6.0...v72.7.0) (2024-01-14)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Vue from 'vue';
|
|
2
2
|
import { BDropdown } from 'bootstrap-vue/esm/index.js';
|
|
3
|
-
import { selectAll
|
|
3
|
+
import { selectAll } from 'bootstrap-vue/esm/utils/dom';
|
|
4
4
|
import merge from 'lodash/merge';
|
|
5
5
|
import { buttonCategoryOptions, dropdownVariantOptions, buttonSizeOptions } from '../../../utils/constants';
|
|
6
|
+
import { filterVisible } from '../../../utils/utils';
|
|
6
7
|
import { ButtonMixin } from '../../mixins/button_mixin';
|
|
7
8
|
import GlButton from '../button/button';
|
|
8
9
|
import GlIcon from '../icon/icon';
|
|
@@ -11,11 +12,6 @@ import GlDropdownDivider from './dropdown_divider';
|
|
|
11
12
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
12
13
|
|
|
13
14
|
//
|
|
14
|
-
|
|
15
|
-
// Return an Array of visible items
|
|
16
|
-
function filterVisible(els) {
|
|
17
|
-
return (els || []).filter(isVisible);
|
|
18
|
-
}
|
|
19
15
|
const Selector = {
|
|
20
16
|
ITEM_SELECTOR: '.dropdown-item:not(.disabled):not([disabled]),.form-control:not(.disabled):not([disabled])'
|
|
21
17
|
};
|
|
@@ -109,7 +109,9 @@ var script = {
|
|
|
109
109
|
return hasData || this.isSegmentActive(SEGMENT_DATA);
|
|
110
110
|
},
|
|
111
111
|
availableTokensWithSelf() {
|
|
112
|
-
return [this.config, ...this.availableTokens.filter(token => token !== this.config)].map(
|
|
112
|
+
return [this.config, ...this.availableTokens.filter(token => token !== this.config)].map(
|
|
113
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
114
|
+
tokenToOption);
|
|
113
115
|
},
|
|
114
116
|
operatorDescription() {
|
|
115
117
|
const operator = this.operators.find(op => op.value === this.tokenValue.operator);
|
|
@@ -28,7 +28,9 @@ const isVue3Fragment = vnode => {
|
|
|
28
28
|
const isVNodeEmpty = vnode => {
|
|
29
29
|
if (isVue3Fragment(vnode)) {
|
|
30
30
|
// vnode.children might be an array or single node in edge cases
|
|
31
|
-
return Array.isArray(vnode.children) ?
|
|
31
|
+
return Array.isArray(vnode.children) ?
|
|
32
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
33
|
+
vnode.children.every(isVNodeEmpty) : isVNodeEmpty(vnode.children);
|
|
32
34
|
}
|
|
33
35
|
if (isVue3Comment(vnode)) {
|
|
34
36
|
return true;
|
|
@@ -40,6 +42,7 @@ const isSlotNotEmpty = slot => {
|
|
|
40
42
|
return false;
|
|
41
43
|
}
|
|
42
44
|
const vnodes = typeof slot === 'function' ? slot() : slot;
|
|
45
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
43
46
|
return !(Array.isArray(vnodes) ? vnodes.every(isVNodeEmpty) : isVNodeEmpty(vnodes));
|
|
44
47
|
};
|
|
45
48
|
var script = {
|
|
@@ -6,7 +6,11 @@ const itemValidator = item => {
|
|
|
6
6
|
return (item === null || item === void 0 ? void 0 : (_item$text = item.text) === null || _item$text === void 0 ? void 0 : _item$text.length) > 0 && !Array.isArray(item === null || item === void 0 ? void 0 : item.items);
|
|
7
7
|
};
|
|
8
8
|
const isItem = item => Boolean(item) && itemValidator(item);
|
|
9
|
-
const isGroup = group => Boolean(group) && Array.isArray(group.items) && Boolean(group.items.length) &&
|
|
9
|
+
const isGroup = group => Boolean(group) && Array.isArray(group.items) && Boolean(group.items.length) &&
|
|
10
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
11
|
+
group.items.every(isItem);
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
10
14
|
const itemsValidator = items => items.every(isItem) || items.every(isGroup);
|
|
11
15
|
const isListItem = tag => ['gl-disclosure-dropdown-group', 'gl-disclosure-dropdown-item', 'li'].includes(tag);
|
|
12
16
|
const isValidSlotTagVue2 = vNode => {
|
|
@@ -2,6 +2,8 @@ import isNumber from 'lodash/isNumber';
|
|
|
2
2
|
import isString from 'lodash/isString';
|
|
3
3
|
|
|
4
4
|
const isOption = item => Boolean(item) && (isString(item.value) || isNumber(item.value));
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
5
7
|
const isGroup = function () {
|
|
6
8
|
let {
|
|
7
9
|
options
|
|
@@ -10,6 +12,8 @@ const isGroup = function () {
|
|
|
10
12
|
};
|
|
11
13
|
const hasNoDuplicates = array => array.length === new Set(array).size;
|
|
12
14
|
const flattenedOptions = items => items.flatMap(item => isOption(item) ? item : item.options);
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
13
17
|
const isAllOptionsOrAllGroups = items => items.every(isOption) || items.every(isGroup);
|
|
14
18
|
const hasUniqueValues = items => hasNoDuplicates(flattenedOptions(items).map(_ref => {
|
|
15
19
|
let {
|
|
@@ -17,6 +21,8 @@ const hasUniqueValues = items => hasNoDuplicates(flattenedOptions(items).map(_re
|
|
|
17
21
|
} = _ref;
|
|
18
22
|
return value;
|
|
19
23
|
}));
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
20
26
|
const hasUniqueGroups = items => hasNoDuplicates(items.filter(isGroup).map(_ref2 => {
|
|
21
27
|
let {
|
|
22
28
|
text
|
|
@@ -191,7 +191,7 @@ const __vue_script__ = script;
|
|
|
191
191
|
/* template */
|
|
192
192
|
var __vue_render__ = function () {
|
|
193
193
|
var _obj;
|
|
194
|
-
var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"position-relative",class:( _obj = {}, _obj[_vm.$options.HEIGHT_AUTO_CLASSES] = _vm.autoHeight, _obj )},[_c('chart',_vm._g(_vm._b({class:{ 'gl-flex-grow-1': _vm.autoHeight },attrs:{"height":_vm.height,"options":_vm.options},on:{"created":_vm.onCreated}},'chart',_vm.$attrs,false),_vm.$listeners)),_vm._v(" "),(_vm.chart)?_c('chart-tooltip',{attrs:{"chart":_vm.chart,"use-default-tooltip-formatter":true}}):_vm._e()],1)};
|
|
194
|
+
var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"position-relative",class:( _obj = {}, _obj[_vm.$options.HEIGHT_AUTO_CLASSES] = _vm.autoHeight, _obj )},[_c('chart',_vm._g(_vm._b({class:{ 'gl-flex-grow-1': _vm.autoHeight },attrs:{"height":_vm.height,"options":_vm.options},on:{"created":_vm.onCreated}},'chart',_vm.$attrs,false),_vm.$listeners)),_vm._v(" "),(_vm.chart)?_c('chart-tooltip',{ref:"dataTooltip",attrs:{"chart":_vm.chart,"use-default-tooltip-formatter":true},scopedSlots:_vm._u([(_vm.$scopedSlots['tooltip-title'])?{key:"title",fn:function(scope){return [_vm._t("tooltip-title",null,null,scope)]}}:null,(_vm.$scopedSlots['tooltip-content'])?{key:"default",fn:function(scope){return [_vm._t("tooltip-content",null,null,scope)]}}:null,(_vm.$scopedSlots['tooltip-value'])?{key:"tooltip-value",fn:function(scope){return [_vm._t("tooltip-value",null,null,scope)]}}:null],null,true)}):_vm._e()],1)};
|
|
195
195
|
var __vue_staticRenderFns__ = [];
|
|
196
196
|
|
|
197
197
|
/* style */
|
|
@@ -5,6 +5,8 @@ const i18n = {
|
|
|
5
5
|
CONVERSATION_NEW_CHAT: 'New chat'
|
|
6
6
|
};
|
|
7
7
|
const isMessage = item => Boolean(item) && (item === null || item === void 0 ? void 0 : item.role);
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
8
10
|
const itemsValidator = items => items.every(isMessage);
|
|
9
11
|
var script = {
|
|
10
12
|
name: 'GlDuoChatConversation',
|
|
@@ -48,6 +48,8 @@ const slashCommands = [{
|
|
|
48
48
|
description: 'Explain the selected snippet.'
|
|
49
49
|
}];
|
|
50
50
|
const isMessage = item => Boolean(item) && (item === null || item === void 0 ? void 0 : item.role);
|
|
51
|
+
|
|
52
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
51
53
|
const itemsValidator = items => items.every(isMessage);
|
|
52
54
|
var script = {
|
|
53
55
|
name: 'GlDuoChat',
|
|
@@ -63,7 +63,9 @@ var script = {
|
|
|
63
63
|
type: Object,
|
|
64
64
|
required: false,
|
|
65
65
|
default: undefined,
|
|
66
|
-
validator: value => Object.values(value).every(
|
|
66
|
+
validator: value => Object.values(value).every(
|
|
67
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
68
|
+
tagPair => Array.isArray(tagPair) && tagPair.length === 2 && tagPair.every(isString))
|
|
67
69
|
}
|
|
68
70
|
},
|
|
69
71
|
/**
|
package/dist/tokens/js/tokens.js
CHANGED
|
@@ -13,10 +13,12 @@ function isEmpty(vnode) {
|
|
|
13
13
|
return true;
|
|
14
14
|
}
|
|
15
15
|
if (Array.isArray(vnode)) {
|
|
16
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
16
17
|
return vnode.every(isEmpty);
|
|
17
18
|
}
|
|
18
19
|
if (Fragment && vnode.type === Fragment) {
|
|
19
20
|
// Vue.js 3 fragment, check children
|
|
21
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
20
22
|
return vnode.children.every(isEmpty);
|
|
21
23
|
}
|
|
22
24
|
return false;
|
|
@@ -28,6 +30,8 @@ function isSlotEmpty(vueInstance, slot, slotArgs) {
|
|
|
28
30
|
// we need to check both $slots and $scopedSlots due to https://github.com/vuejs/core/issues/8869
|
|
29
31
|
// additionally, in @vue/compat $slot might be a function instead of array of vnodes (sigh)
|
|
30
32
|
callIfNeeded(vueInstance.$slots[slot] || vueInstance.$scopedSlots[slot], slotArgs) : (_vueInstance$$scopedS = (_vueInstance$$scopedS2 = vueInstance.$scopedSlots)[slot]) === null || _vueInstance$$scopedS === void 0 ? void 0 : _vueInstance$$scopedS.call(_vueInstance$$scopedS2, slotArgs);
|
|
33
|
+
|
|
34
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
31
35
|
return isEmpty(slotContent);
|
|
32
36
|
}
|
|
33
37
|
|
package/dist/utils/utils.js
CHANGED
|
@@ -171,7 +171,7 @@ function stopEvent(event) {
|
|
|
171
171
|
* Return an Array of visible items
|
|
172
172
|
*/
|
|
173
173
|
function filterVisible(els) {
|
|
174
|
-
return (els || []).filter(isVisible);
|
|
174
|
+
return (els || []).filter(el => isVisible(el));
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
export { colorFromBackground, debounceByAnimationFrame, filterVisible, focusFirstFocusableElement, hexToRgba, isDev, isElementFocusable, isElementTabbable, logWarning, relativeLuminance, rgbFromHex, rgbFromString, stopEvent, throttle, toSrgb, uid };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "72.
|
|
3
|
+
"version": "72.8.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -93,10 +93,10 @@
|
|
|
93
93
|
"@babel/preset-env": "^7.23.8",
|
|
94
94
|
"@babel/preset-react": "^7.23.3",
|
|
95
95
|
"@cypress/grep": "^4.0.1",
|
|
96
|
-
"@gitlab/eslint-plugin": "19.
|
|
96
|
+
"@gitlab/eslint-plugin": "19.4.0",
|
|
97
97
|
"@gitlab/fonts": "^1.3.0",
|
|
98
98
|
"@gitlab/stylelint-config": "5.0.1",
|
|
99
|
-
"@gitlab/svgs": "3.
|
|
99
|
+
"@gitlab/svgs": "3.75.0",
|
|
100
100
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
101
101
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
102
102
|
"@rollup/plugin-replace": "^2.3.2",
|
|
@@ -69,6 +69,7 @@ const StackedStory = (args, { argTypes }) => ({
|
|
|
69
69
|
GlBroadcastMessage,
|
|
70
70
|
},
|
|
71
71
|
props: Object.keys(argTypes),
|
|
72
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
72
73
|
template: `<div>${Object.keys(colorThemes).map(templateWithTheme).join('')}</div>`,
|
|
73
74
|
});
|
|
74
75
|
export const Stacked = StackedStory.bind({});
|
|
@@ -2,24 +2,20 @@
|
|
|
2
2
|
<script>
|
|
3
3
|
import Vue from 'vue';
|
|
4
4
|
import { BDropdown } from 'bootstrap-vue';
|
|
5
|
-
import {
|
|
5
|
+
import { selectAll } from 'bootstrap-vue/src/utils/dom';
|
|
6
6
|
import merge from 'lodash/merge';
|
|
7
7
|
import {
|
|
8
8
|
buttonCategoryOptions,
|
|
9
9
|
buttonSizeOptions,
|
|
10
10
|
dropdownVariantOptions,
|
|
11
11
|
} from '../../../utils/constants';
|
|
12
|
+
import { filterVisible } from '../../../utils/utils';
|
|
12
13
|
import { ButtonMixin } from '../../mixins/button_mixin';
|
|
13
14
|
import GlButton from '../button/button.vue';
|
|
14
15
|
import GlIcon from '../icon/icon.vue';
|
|
15
16
|
import GlLoadingIcon from '../loading_icon/loading_icon.vue';
|
|
16
17
|
import GlDropdownDivider from './dropdown_divider.vue';
|
|
17
18
|
|
|
18
|
-
// Return an Array of visible items
|
|
19
|
-
function filterVisible(els) {
|
|
20
|
-
return (els || []).filter(isVisible);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
19
|
const Selector = {
|
|
24
20
|
ITEM_SELECTOR:
|
|
25
21
|
'.dropdown-item:not(.disabled):not([disabled]),.form-control:not(.disabled):not([disabled])',
|
|
@@ -59,6 +59,7 @@ describe('Filtered search', () => {
|
|
|
59
59
|
describe('value manipulation', () => {
|
|
60
60
|
it('creates term when empty', () => {
|
|
61
61
|
createComponent();
|
|
62
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
62
63
|
expect(wrapper.emitted().input[0][0].map(stripId)).toStrictEqual([
|
|
63
64
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
64
65
|
]);
|
|
@@ -202,6 +203,7 @@ describe('Filtered search', () => {
|
|
|
202
203
|
|
|
203
204
|
await nextTick();
|
|
204
205
|
|
|
206
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
205
207
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
206
208
|
{ type: 'faketoken', value: { data: '' } },
|
|
207
209
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
@@ -220,6 +222,7 @@ describe('Filtered search', () => {
|
|
|
220
222
|
|
|
221
223
|
await nextTick();
|
|
222
224
|
|
|
225
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
223
226
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
224
227
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
225
228
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
@@ -335,6 +338,7 @@ describe('Filtered search', () => {
|
|
|
335
338
|
|
|
336
339
|
await nextTick();
|
|
337
340
|
|
|
341
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
338
342
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
339
343
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
340
344
|
]);
|
|
@@ -348,6 +352,7 @@ describe('Filtered search', () => {
|
|
|
348
352
|
|
|
349
353
|
await nextTick();
|
|
350
354
|
|
|
355
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
351
356
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
352
357
|
{ type: 'faketoken', value: { data: 'test' } },
|
|
353
358
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
@@ -369,6 +374,7 @@ describe('Filtered search', () => {
|
|
|
369
374
|
|
|
370
375
|
await nextTick();
|
|
371
376
|
|
|
377
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
372
378
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
373
379
|
{ type: 'faketoken', value: { data: 'test' } },
|
|
374
380
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
@@ -382,6 +388,7 @@ describe('Filtered search', () => {
|
|
|
382
388
|
|
|
383
389
|
await nextTick();
|
|
384
390
|
|
|
391
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
385
392
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
386
393
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
387
394
|
{ type: TERM_TOKEN_TYPE, value: { data: '' } },
|
|
@@ -398,6 +405,7 @@ describe('Filtered search', () => {
|
|
|
398
405
|
await nextTick();
|
|
399
406
|
|
|
400
407
|
expect(wrapper.findAllComponents(GlFilteredSearchTerm).at(2).props('active')).toBe(true);
|
|
408
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
401
409
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
402
410
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
403
411
|
{ type: TERM_TOKEN_TYPE, value: { data: 'two' } },
|
|
@@ -415,6 +423,7 @@ describe('Filtered search', () => {
|
|
|
415
423
|
|
|
416
424
|
await nextTick();
|
|
417
425
|
|
|
426
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
418
427
|
expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
|
|
419
428
|
{ type: TERM_TOKEN_TYPE, value: { data: 'one' } },
|
|
420
429
|
{ type: TERM_TOKEN_TYPE, value: { data: 'foo' } },
|
|
@@ -445,6 +454,7 @@ describe('Filtered search', () => {
|
|
|
445
454
|
});
|
|
446
455
|
wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('submit');
|
|
447
456
|
expect(wrapper.emitted('submit')).toBeDefined();
|
|
457
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
448
458
|
expect(wrapper.emitted().submit[0][0].map(stripId)).toStrictEqual([
|
|
449
459
|
'one two',
|
|
450
460
|
{ type: 'faketoken', value: { data: 'smth' } },
|
|
@@ -505,6 +515,7 @@ describe('Filtered search', () => {
|
|
|
505
515
|
});
|
|
506
516
|
await nextTick();
|
|
507
517
|
|
|
518
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
508
519
|
expect(wrapper.findComponent(GlFilteredSearchTerm).props('currentValue').map(stripId)).toEqual([
|
|
509
520
|
{ type: 'filtered-search-term', value: { data: 'one' } },
|
|
510
521
|
{ type: 'filtered-search-term', value: { data: '' } },
|
|
@@ -24,7 +24,8 @@ const isVNodeEmpty = (vnode) => {
|
|
|
24
24
|
if (isVue3Fragment(vnode)) {
|
|
25
25
|
// vnode.children might be an array or single node in edge cases
|
|
26
26
|
return Array.isArray(vnode.children)
|
|
27
|
-
?
|
|
27
|
+
? // eslint-disable-next-line unicorn/no-array-callback-reference
|
|
28
|
+
vnode.children.every(isVNodeEmpty)
|
|
28
29
|
: isVNodeEmpty(vnode.children);
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -41,6 +42,7 @@ const isSlotNotEmpty = (slot) => {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
const vnodes = typeof slot === 'function' ? slot() : slot;
|
|
45
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
44
46
|
return !(Array.isArray(vnodes) ? vnodes.every(isVNodeEmpty) : isVNodeEmpty(vnodes));
|
|
45
47
|
};
|
|
46
48
|
|
|
@@ -78,6 +78,7 @@ describe('GlFormFields', () => {
|
|
|
78
78
|
};
|
|
79
79
|
};
|
|
80
80
|
const findFormGroups = () => wrapper.findAllComponents(GlFormGroup).wrappers;
|
|
81
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
81
82
|
const findFormGroupsAsData = () => findFormGroups().map(mapFormGroupToData);
|
|
82
83
|
const findFormGroupFromLabel = (label) =>
|
|
83
84
|
wrapper.findAllComponents(GlFormGroup).wrappers.find((x) => x.attributes('label') === label);
|
|
@@ -9,8 +9,10 @@ const isGroup = (group) =>
|
|
|
9
9
|
Boolean(group) &&
|
|
10
10
|
Array.isArray(group.items) &&
|
|
11
11
|
Boolean(group.items.length) &&
|
|
12
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
12
13
|
group.items.every(isItem);
|
|
13
14
|
|
|
15
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
14
16
|
const itemsValidator = (items) => items.every(isItem) || items.every(isGroup);
|
|
15
17
|
|
|
16
18
|
const isListItem = (tag) =>
|
|
@@ -48,6 +48,7 @@ describe('GlCollapsibleListbox', () => {
|
|
|
48
48
|
const findListContainer = () => wrapper.find('[role="listbox"]');
|
|
49
49
|
const findListboxItems = (root = wrapper) => root.findAllComponents(GlListboxItem);
|
|
50
50
|
const findListboxGroups = () => wrapper.findAllComponents(GlListboxGroup);
|
|
51
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
51
52
|
const findListItem = (index) => findListboxItems().at(index).find(ITEM_SELECTOR);
|
|
52
53
|
const findHeaderText = () => wrapper.find("[data-testid='listbox-header-text']");
|
|
53
54
|
const findSearchBox = () => wrapper.find("[data-testid='listbox-search-input']");
|
|
@@ -241,6 +242,7 @@ describe('GlCollapsibleListbox', () => {
|
|
|
241
242
|
|
|
242
243
|
it('should focus the first selected item', async () => {
|
|
243
244
|
await showDropdown();
|
|
245
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
244
246
|
expect(findListboxItems().at(1).find(ITEM_SELECTOR).element).toHaveFocus();
|
|
245
247
|
});
|
|
246
248
|
|
|
@@ -388,9 +388,13 @@ export const Groups = makeGroupedExample({
|
|
|
388
388
|
const isSelected = (option) => this.selected.includes(option.value);
|
|
389
389
|
const notSelected = (option) => !isSelected(option);
|
|
390
390
|
|
|
391
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
391
392
|
const selectedBranches = mockGroups[0].options.filter(isSelected);
|
|
393
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
392
394
|
const availableBranches = mockGroups[0].options.filter(notSelected);
|
|
395
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
393
396
|
const selectedTags = mockGroups[1].options.filter(isSelected);
|
|
397
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
394
398
|
const availableTags = mockGroups[1].options.filter(notSelected);
|
|
395
399
|
|
|
396
400
|
return [
|
|
@@ -3,17 +3,20 @@ import isString from 'lodash/isString';
|
|
|
3
3
|
|
|
4
4
|
const isOption = (item) => Boolean(item) && (isString(item.value) || isNumber(item.value));
|
|
5
5
|
|
|
6
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
6
7
|
const isGroup = ({ options } = {}) => Array.isArray(options) && options.every(isOption);
|
|
7
8
|
|
|
8
9
|
const hasNoDuplicates = (array) => array.length === new Set(array).size;
|
|
9
10
|
|
|
10
11
|
const flattenedOptions = (items) => items.flatMap((item) => (isOption(item) ? item : item.options));
|
|
11
12
|
|
|
13
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
12
14
|
const isAllOptionsOrAllGroups = (items) => items.every(isOption) || items.every(isGroup);
|
|
13
15
|
|
|
14
16
|
const hasUniqueValues = (items) =>
|
|
15
17
|
hasNoDuplicates(flattenedOptions(items).map(({ value }) => value));
|
|
16
18
|
|
|
19
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
17
20
|
const hasUniqueGroups = (items) => hasNoDuplicates(items.filter(isGroup).map(({ text }) => text));
|
|
18
21
|
|
|
19
22
|
const itemsValidator = (items) =>
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from '../../../utils/charts/mock_data';
|
|
8
8
|
import { toolbox } from '../../../utils/charts/story_config';
|
|
9
9
|
|
|
10
|
-
const template = `
|
|
10
|
+
const template = (content = '') => `
|
|
11
11
|
<gl-column-chart
|
|
12
12
|
:bars="bars"
|
|
13
13
|
:lines="lines"
|
|
@@ -18,7 +18,9 @@ const template = `
|
|
|
18
18
|
:x-axis-title="xAxisTitle"
|
|
19
19
|
:x-axis-type="xAxisType"
|
|
20
20
|
:height="height"
|
|
21
|
-
|
|
21
|
+
>
|
|
22
|
+
${content}
|
|
23
|
+
</gl-column-chart>
|
|
22
24
|
`;
|
|
23
25
|
|
|
24
26
|
const generateProps = ({
|
|
@@ -46,7 +48,7 @@ const generateProps = ({
|
|
|
46
48
|
const Template = (args, { argTypes }) => ({
|
|
47
49
|
components: { GlColumnChart },
|
|
48
50
|
props: Object.keys(argTypes),
|
|
49
|
-
template,
|
|
51
|
+
template: template(),
|
|
50
52
|
});
|
|
51
53
|
|
|
52
54
|
export const Default = Template.bind({});
|
|
@@ -90,6 +92,19 @@ SecondaryYAxisLine.args = generateProps({
|
|
|
90
92
|
secondaryDataTitle: 'New line data',
|
|
91
93
|
});
|
|
92
94
|
|
|
95
|
+
export const WithCustomTooltip = (args, { argTypes }) => ({
|
|
96
|
+
components: { GlColumnChart },
|
|
97
|
+
props: Object.keys(argTypes),
|
|
98
|
+
template: template(`
|
|
99
|
+
<template #tooltip-title="{ params }">Custom tooltip title: {{params && params.value}}</template>
|
|
100
|
+
<template #tooltip-content="{ params }">
|
|
101
|
+
<div v-for="p in params && params.seriesData">Wow so custom: {{p.seriesName}}: {{p.value[1]}}</div>
|
|
102
|
+
</template>
|
|
103
|
+
`),
|
|
104
|
+
});
|
|
105
|
+
WithCustomTooltip.args = generateProps();
|
|
106
|
+
WithCustomTooltip.tags = ['skip-visual-test'];
|
|
107
|
+
|
|
93
108
|
export default {
|
|
94
109
|
title: 'charts/column-chart',
|
|
95
110
|
component: GlColumnChart,
|
|
@@ -184,6 +184,21 @@ export default {
|
|
|
184
184
|
v-on="$listeners"
|
|
185
185
|
@created="onCreated"
|
|
186
186
|
/>
|
|
187
|
-
<chart-tooltip
|
|
187
|
+
<chart-tooltip
|
|
188
|
+
v-if="chart"
|
|
189
|
+
ref="dataTooltip"
|
|
190
|
+
:chart="chart"
|
|
191
|
+
:use-default-tooltip-formatter="true"
|
|
192
|
+
>
|
|
193
|
+
<template v-if="$scopedSlots['tooltip-title']" #title="scope">
|
|
194
|
+
<slot name="tooltip-title" v-bind="scope"></slot>
|
|
195
|
+
</template>
|
|
196
|
+
<template v-if="$scopedSlots['tooltip-content']" #default="scope">
|
|
197
|
+
<slot name="tooltip-content" v-bind="scope"></slot>
|
|
198
|
+
</template>
|
|
199
|
+
<template v-if="$scopedSlots['tooltip-value']" #tooltip-value="scope">
|
|
200
|
+
<slot name="tooltip-value" v-bind="scope"></slot>
|
|
201
|
+
</template>
|
|
202
|
+
</chart-tooltip>
|
|
188
203
|
</div>
|
|
189
204
|
</template>
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { nextTick } from 'vue';
|
|
1
2
|
import { shallowMount } from '@vue/test-utils';
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createMockChartInstance,
|
|
5
|
+
ChartTooltipStub,
|
|
6
|
+
chartTooltipStubData,
|
|
7
|
+
} from '~helpers/chart_stubs';
|
|
3
8
|
import { expectHeightAutoClasses } from '~helpers/chart_height';
|
|
4
9
|
import {
|
|
5
10
|
mockDefaultLineData,
|
|
@@ -8,7 +13,6 @@ import {
|
|
|
8
13
|
mockDefaultStackedBarData,
|
|
9
14
|
} from '../../../utils/charts/mock_data';
|
|
10
15
|
import Chart from '../chart/chart.vue';
|
|
11
|
-
import ChartTooltip from '../tooltip/tooltip.vue';
|
|
12
16
|
import ColumnChart from './column.vue';
|
|
13
17
|
|
|
14
18
|
let mockChartInstance;
|
|
@@ -28,42 +32,45 @@ describe('column chart component', () => {
|
|
|
28
32
|
|
|
29
33
|
const chartItemClickedSpy = jest.fn();
|
|
30
34
|
const findChart = () => wrapper.findComponent(Chart);
|
|
31
|
-
const findChartTooltip = () => wrapper.findComponent(
|
|
35
|
+
const findChartTooltip = () => wrapper.findComponent({ ref: 'dataTooltip' });
|
|
32
36
|
|
|
33
37
|
const emitChartCreated = () => findChart().vm.$emit('created', mockChartInstance);
|
|
34
38
|
|
|
35
|
-
const factory = (props = defaultChartProps,
|
|
39
|
+
const factory = (props = defaultChartProps, options = {}) => {
|
|
36
40
|
wrapper = shallowMount(ColumnChart, {
|
|
37
41
|
propsData: { ...props },
|
|
38
42
|
listeners: {
|
|
39
43
|
chartItemClicked: chartItemClickedSpy,
|
|
40
44
|
},
|
|
41
|
-
|
|
45
|
+
...options,
|
|
42
46
|
});
|
|
43
47
|
};
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
describe('mounted', () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
factory();
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
mockChartInstance = createMockChartInstance();
|
|
54
|
+
emitChartCreated();
|
|
55
|
+
});
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
it('emits "created" when onCreated is called', () => {
|
|
58
|
+
expect(wrapper.emitted('created')).toHaveLength(1);
|
|
59
|
+
});
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
it('calls event listener when "chartItemClicked" is emitted on the Chart component', () => {
|
|
62
|
+
findChart().vm.$emit('chartItemClicked');
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
expect(chartItemClickedSpy).toHaveBeenCalled();
|
|
65
|
+
});
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
it('should correctly render the chart', () => {
|
|
68
|
+
const chart = findChart();
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
expect(chart.props('options')).toMatchSnapshot();
|
|
71
|
+
});
|
|
66
72
|
});
|
|
73
|
+
|
|
67
74
|
describe('with line data provided', () => {
|
|
68
75
|
beforeEach(() => {
|
|
69
76
|
factory({
|
|
@@ -120,11 +127,90 @@ describe('column chart component', () => {
|
|
|
120
127
|
|
|
121
128
|
describe('tooltip', () => {
|
|
122
129
|
it('configures chart tooltip', async () => {
|
|
130
|
+
factory(defaultChartProps, {
|
|
131
|
+
stubs: {
|
|
132
|
+
'chart-tooltip': ChartTooltipStub,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
mockChartInstance = createMockChartInstance();
|
|
136
|
+
emitChartCreated();
|
|
137
|
+
await nextTick();
|
|
138
|
+
|
|
123
139
|
expect(findChartTooltip().props()).toMatchObject({
|
|
124
140
|
chart: mockChartInstance,
|
|
125
141
|
useDefaultTooltipFormatter: true,
|
|
126
142
|
});
|
|
127
143
|
});
|
|
144
|
+
|
|
145
|
+
describe('custom tooltip slots', () => {
|
|
146
|
+
const { params, title, content } = chartTooltipStubData;
|
|
147
|
+
|
|
148
|
+
it('customizes value', async () => {
|
|
149
|
+
const tooltipValueSlot = jest.fn().mockReturnValue('Custom tooltip value');
|
|
150
|
+
|
|
151
|
+
factory(defaultChartProps, {
|
|
152
|
+
stubs: {
|
|
153
|
+
'chart-tooltip': ChartTooltipStub,
|
|
154
|
+
},
|
|
155
|
+
scopedSlots: {
|
|
156
|
+
'tooltip-value': tooltipValueSlot,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
mockChartInstance = createMockChartInstance();
|
|
161
|
+
emitChartCreated();
|
|
162
|
+
await nextTick();
|
|
163
|
+
|
|
164
|
+
expect(tooltipValueSlot).toHaveBeenCalledWith({ value: 9 });
|
|
165
|
+
expect(findChartTooltip().text()).toBe('Custom tooltip value');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('customizes title', async () => {
|
|
169
|
+
const tooltipTitleSlot = jest.fn().mockReturnValue('Custom tooltip title');
|
|
170
|
+
|
|
171
|
+
factory(defaultChartProps, {
|
|
172
|
+
stubs: {
|
|
173
|
+
'chart-tooltip': ChartTooltipStub,
|
|
174
|
+
},
|
|
175
|
+
scopedSlots: {
|
|
176
|
+
'tooltip-title': tooltipTitleSlot,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
mockChartInstance = createMockChartInstance();
|
|
181
|
+
emitChartCreated();
|
|
182
|
+
await nextTick();
|
|
183
|
+
|
|
184
|
+
expect(tooltipTitleSlot).toHaveBeenCalledWith({
|
|
185
|
+
params,
|
|
186
|
+
title,
|
|
187
|
+
});
|
|
188
|
+
expect(findChartTooltip().text()).toBe('Custom tooltip title');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('customizes content', async () => {
|
|
192
|
+
const tooltipContentSlot = jest.fn().mockReturnValue('Custom tooltip content');
|
|
193
|
+
|
|
194
|
+
factory(defaultChartProps, {
|
|
195
|
+
stubs: {
|
|
196
|
+
'chart-tooltip': ChartTooltipStub,
|
|
197
|
+
},
|
|
198
|
+
scopedSlots: {
|
|
199
|
+
'tooltip-content': tooltipContentSlot,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
mockChartInstance = createMockChartInstance();
|
|
204
|
+
emitChartCreated();
|
|
205
|
+
await nextTick();
|
|
206
|
+
|
|
207
|
+
expect(tooltipContentSlot).toHaveBeenCalledWith({
|
|
208
|
+
params,
|
|
209
|
+
content,
|
|
210
|
+
});
|
|
211
|
+
expect(findChartTooltip().text()).toBe('Custom tooltip content');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
128
214
|
});
|
|
129
215
|
|
|
130
216
|
describe('height', () => {
|
|
@@ -98,6 +98,7 @@ describe('IntersectionObserver', () => {
|
|
|
98
98
|
triggerIntersectionObserver(entry);
|
|
99
99
|
|
|
100
100
|
expect(allWrappers).toHaveLength(2);
|
|
101
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
101
102
|
expect(allWrappers.map((x) => x.emitted())).toEqual(allWrappers.map(createExpectation));
|
|
102
103
|
});
|
|
103
104
|
});
|
|
@@ -23,6 +23,7 @@ describe('Intersperse Component', () => {
|
|
|
23
23
|
createComponent(defaultSlotContent);
|
|
24
24
|
|
|
25
25
|
selectorsToCheck.forEach((selector) => {
|
|
26
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
26
27
|
expect(wrapper.find(selector).exists()).toBe(true);
|
|
27
28
|
});
|
|
28
29
|
}
|
|
@@ -68,6 +68,7 @@ export default {
|
|
|
68
68
|
default: undefined,
|
|
69
69
|
validator: (value) =>
|
|
70
70
|
Object.values(value).every(
|
|
71
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
71
72
|
(tagPair) => Array.isArray(tagPair) && tagPair.length === 2 && tagPair.every(isString)
|
|
72
73
|
),
|
|
73
74
|
},
|
|
@@ -13,11 +13,13 @@ function isEmpty(vnode) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
if (Array.isArray(vnode)) {
|
|
16
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
16
17
|
return vnode.every(isEmpty);
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
if (Fragment && vnode.type === Fragment) {
|
|
20
21
|
// Vue.js 3 fragment, check children
|
|
22
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
21
23
|
return vnode.children.every(isEmpty);
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -33,5 +35,6 @@ export function isSlotEmpty(vueInstance, slot, slotArgs) {
|
|
|
33
35
|
callIfNeeded(vueInstance.$slots[slot] || vueInstance.$scopedSlots[slot], slotArgs)
|
|
34
36
|
: vueInstance.$scopedSlots[slot]?.(slotArgs);
|
|
35
37
|
|
|
38
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
36
39
|
return isEmpty(slotContent);
|
|
37
40
|
}
|
|
@@ -9,7 +9,7 @@ export const addition = (a, b) => a + b;
|
|
|
9
9
|
* Returns the sum of all arguments
|
|
10
10
|
* @param {...Number} numbers
|
|
11
11
|
*/
|
|
12
|
-
export const sum = (...numbers) => numbers.reduce(addition);
|
|
12
|
+
export const sum = (...numbers) => numbers.reduce(addition); // eslint-disable-line unicorn/no-array-callback-reference
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Returns the average of all arguments
|
package/src/utils/utils.js
CHANGED