@gitlab/ui 64.18.2 → 64.19.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [64.19.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v64.18.3...v64.19.0) (2023-07-11)
2
+
3
+
4
+ ### Features
5
+
6
+ * **GlFilteredSearchToken:** Expose applySuggestion via scoped slot ([91333fd](https://gitlab.com/gitlab-org/gitlab-ui/commit/91333fd72a99fa2ccbe9be79df008c4c90dc4f4b))
7
+
8
+ ## [64.18.3](https://gitlab.com/gitlab-org/gitlab-ui/compare/v64.18.2...v64.18.3) (2023-07-06)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **listbox:** Fix reset button on single select ([8684a7c](https://gitlab.com/gitlab-org/gitlab-ui/commit/8684a7c778ed4517f67ca6191b0a3634f45ca70f))
14
+
1
15
  ## [64.18.2](https://gitlab.com/gitlab-org/gitlab-ui/compare/v64.18.1...v64.18.2) (2023-07-05)
2
16
 
3
17
 
@@ -327,7 +327,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
327
327
  var inputValue = ref.inputValue;
328
328
  return [_c('gl-token',{staticClass:"gl-filtered-search-token-type",class:_vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_TITLE),attrs:{"view-only":""}},[_vm._v("\n "+_vm._s(inputValue)+"\n ")])]}}])}),_vm._v(" "),_c('gl-filtered-search-token-segment',{key:"operator-segment",attrs:{"active":_vm.isSegmentActive(_vm.$options.segments.SEGMENT_OPERATOR),"cursor-position":_vm.intendedCursorPosition,"options":_vm.operators,"option-text-field":"value","custom-input-keydown-handler":_vm.handleOperatorKeydown,"view-only":_vm.viewOnly},on:{"activate":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_OPERATOR)},"backspace":_vm.replaceWithTermIfEmpty,"complete":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_DATA)},"deactivate":function($event){return _vm.$emit('deactivate')},"previous":_vm.activatePreviousTitleSegment,"next":_vm.activateNextDataSegment},scopedSlots:_vm._u([{key:"view",fn:function(){return [_c('gl-token',{staticClass:"gl-filtered-search-token-operator",class:_vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_OPERATOR),attrs:{"variant":"search-value","view-only":""}},[_vm._v("\n "+_vm._s(_vm.operatorDescription)+"\n ")])]},proxy:true},{key:"option",fn:function(ref){
329
329
  var option = ref.option;
330
- return [_c('div',{staticClass:"gl-display-flex"},[_vm._v("\n "+_vm._s(_vm.showFriendlyText ? option.description : option.value)+"\n "),(option.description)?_c('span',{staticClass:"gl-filtered-search-token-operator-description"},[_vm._v("\n "+_vm._s(_vm.showFriendlyText ? option.value : option.description)+"\n ")]):_vm._e()])]}}]),model:{value:(_vm.tokenValue.operator),callback:function ($$v) {_vm.$set(_vm.tokenValue, "operator", $$v);},expression:"tokenValue.operator"}}),_vm._v(" "),(_vm.hasDataOrDataSegmentIsCurrentlyActive)?_c('gl-filtered-search-token-segment',{key:"data-segment",attrs:{"active":_vm.isSegmentActive(_vm.$options.segments.SEGMENT_DATA),"cursor-position":_vm.intendedCursorPosition,"multi-select":_vm.config.multiSelect,"options":_vm.config.options,"view-only":_vm.viewOnly,"search-input-attributes":_vm.dataSegmentInputAttributes},on:{"activate":_vm.activateDataSegment,"backspace":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_OPERATOR)},"complete":_vm.handleComplete,"select":function($event){return _vm.$emit('select', $event)},"submit":function($event){return _vm.$emit('submit')},"deactivate":function($event){return _vm.$emit('deactivate')},"split":function($event){return _vm.$emit('split', $event)},"previous":_vm.activatePreviousOperatorSegment,"next":function($event){return _vm.$emit('next')}},scopedSlots:_vm._u([{key:"suggestions",fn:function(){return [_vm._t("suggestions")]},proxy:true},{key:"view",fn:function(ref){
330
+ return [_c('div',{staticClass:"gl-display-flex"},[_vm._v("\n "+_vm._s(_vm.showFriendlyText ? option.description : option.value)+"\n "),(option.description)?_c('span',{staticClass:"gl-filtered-search-token-operator-description"},[_vm._v("\n "+_vm._s(_vm.showFriendlyText ? option.value : option.description)+"\n ")]):_vm._e()])]}}]),model:{value:(_vm.tokenValue.operator),callback:function ($$v) {_vm.$set(_vm.tokenValue, "operator", $$v);},expression:"tokenValue.operator"}}),_vm._v(" "),(_vm.hasDataOrDataSegmentIsCurrentlyActive)?_c('gl-filtered-search-token-segment',{key:"data-segment",attrs:{"active":_vm.isSegmentActive(_vm.$options.segments.SEGMENT_DATA),"cursor-position":_vm.intendedCursorPosition,"multi-select":_vm.config.multiSelect,"options":_vm.config.options,"view-only":_vm.viewOnly,"search-input-attributes":_vm.dataSegmentInputAttributes},on:{"activate":_vm.activateDataSegment,"backspace":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_OPERATOR)},"complete":_vm.handleComplete,"select":function($event){return _vm.$emit('select', $event)},"submit":function($event){return _vm.$emit('submit')},"deactivate":function($event){return _vm.$emit('deactivate')},"split":function($event){return _vm.$emit('split', $event)},"previous":_vm.activatePreviousOperatorSegment,"next":function($event){return _vm.$emit('next')}},scopedSlots:_vm._u([{key:"before-input",fn:function(scope){return [_vm._t("before-data-segment-input",null,null,scope)]}},{key:"suggestions",fn:function(){return [_vm._t("suggestions")]},proxy:true},{key:"view",fn:function(ref){
331
331
  var inputValue = ref.inputValue;
332
332
  return [_vm._t("view-token",function(){return [_c('gl-token',_vm._g({staticClass:"gl-filtered-search-token-data",class:_vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_DATA),attrs:{"variant":"search-value","view-only":_vm.viewOnly}},_vm.eventListeners),[_c('span',{staticClass:"gl-filtered-search-token-data-content"},[_vm._t("view",function(){return [_vm._v(_vm._s(inputValue))]},null,{ inputValue: inputValue })],2)])]},null,{
333
333
  inputValue: inputValue,
@@ -381,7 +381,7 @@ const __vue_script__ = script;
381
381
  var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',_vm._g(_vm._b({staticClass:"gl-filtered-search-token-segment",class:{
382
382
  'gl-filtered-search-token-segment-active': _vm.active,
383
383
  'gl-cursor-text!': _vm.viewOnly,
384
- },attrs:{"data-testid":"filtered-search-token-segment"}},'div',_vm.containerAttributes,false),_vm.viewOnly ? {} : { mousedown: _vm.emitIfInactive }),[(_vm.active)?[(((_vm.searchInputAttributes).type)==='checkbox')?_c('input',_vm._b({directives:[{name:"model",rawName:"v-model",value:(_vm.inputValue),expression:"inputValue"}],ref:"input",staticClass:"gl-filtered-search-token-segment-input",attrs:{"data-testid":"filtered-search-token-segment-input","aria-label":_vm.label,"readonly":_vm.viewOnly,"type":"checkbox"},domProps:{"checked":Array.isArray(_vm.inputValue)?_vm._i(_vm.inputValue,null)>-1:(_vm.inputValue)},on:{"keydown":_vm.handleInputKeydown,"blur":_vm.handleBlur,"change":function($event){var $$a=_vm.inputValue,$$el=$event.target,$$c=$$el.checked?(true):(false);if(Array.isArray($$a)){var $$v=null,$$i=_vm._i($$a,$$v);if($$el.checked){$$i<0&&(_vm.inputValue=$$a.concat([$$v]));}else {$$i>-1&&(_vm.inputValue=$$a.slice(0,$$i).concat($$a.slice($$i+1)));}}else {_vm.inputValue=$$c;}}}},'input',_vm.searchInputAttributes,false)):(((_vm.searchInputAttributes).type)==='radio')?_c('input',_vm._b({directives:[{name:"model",rawName:"v-model",value:(_vm.inputValue),expression:"inputValue"}],ref:"input",staticClass:"gl-filtered-search-token-segment-input",attrs:{"data-testid":"filtered-search-token-segment-input","aria-label":_vm.label,"readonly":_vm.viewOnly,"type":"radio"},domProps:{"checked":_vm._q(_vm.inputValue,null)},on:{"keydown":_vm.handleInputKeydown,"blur":_vm.handleBlur,"change":function($event){_vm.inputValue=null;}}},'input',_vm.searchInputAttributes,false)):_c('input',_vm._b({directives:[{name:"model",rawName:"v-model",value:(_vm.inputValue),expression:"inputValue"}],ref:"input",staticClass:"gl-filtered-search-token-segment-input",attrs:{"data-testid":"filtered-search-token-segment-input","aria-label":_vm.label,"readonly":_vm.viewOnly,"type":(_vm.searchInputAttributes).type},domProps:{"value":(_vm.inputValue)},on:{"keydown":_vm.handleInputKeydown,"blur":_vm.handleBlur,"input":function($event){if($event.target.composing){ return; }_vm.inputValue=$event.target.value;}}},'input',_vm.searchInputAttributes,false)),_vm._v(" "),_c('portal',{key:("operator-" + _vm._uid),attrs:{"to":_vm.portalName}},[(_vm.hasOptionsOrSuggestions)?_c('gl-filtered-search-suggestion-list',{key:("operator-" + _vm._uid),ref:"suggestions",attrs:{"initial-value":_vm.defaultSuggestedValue},on:{"suggestion":_vm.applySuggestion}},[(_vm.options)?_vm._l((_vm.options),function(option,idx){return _c('gl-filtered-search-suggestion',{key:((option.value) + "-" + idx),attrs:{"value":option.value,"icon-name":option.icon}},[_vm._t("option",function(){return [(option.component)?[_c(option.component,{tag:"component",attrs:{"option":option}})]:[_vm._v("\n "+_vm._s(option[_vm.optionTextField])+"\n ")]]},null,{ option: option })],2)}):_vm._t("suggestions")],2):_vm._e()],1)]:_vm._t("view",function(){return [_vm._v(_vm._s(_vm.inputValue))]},null,{ inputValue: _vm.inputValue })],2)};
384
+ },attrs:{"data-testid":"filtered-search-token-segment"}},'div',_vm.containerAttributes,false),_vm.viewOnly ? {} : { mousedown: _vm.emitIfInactive }),[(_vm.active)?[_vm._t("before-input",null,null,{ submitValue: _vm.applySuggestion }),_vm._v(" "),(((_vm.searchInputAttributes).type)==='checkbox')?_c('input',_vm._b({directives:[{name:"model",rawName:"v-model",value:(_vm.inputValue),expression:"inputValue"}],ref:"input",staticClass:"gl-filtered-search-token-segment-input",attrs:{"data-testid":"filtered-search-token-segment-input","aria-label":_vm.label,"readonly":_vm.viewOnly,"type":"checkbox"},domProps:{"checked":Array.isArray(_vm.inputValue)?_vm._i(_vm.inputValue,null)>-1:(_vm.inputValue)},on:{"keydown":_vm.handleInputKeydown,"blur":_vm.handleBlur,"change":function($event){var $$a=_vm.inputValue,$$el=$event.target,$$c=$$el.checked?(true):(false);if(Array.isArray($$a)){var $$v=null,$$i=_vm._i($$a,$$v);if($$el.checked){$$i<0&&(_vm.inputValue=$$a.concat([$$v]));}else {$$i>-1&&(_vm.inputValue=$$a.slice(0,$$i).concat($$a.slice($$i+1)));}}else {_vm.inputValue=$$c;}}}},'input',_vm.searchInputAttributes,false)):(((_vm.searchInputAttributes).type)==='radio')?_c('input',_vm._b({directives:[{name:"model",rawName:"v-model",value:(_vm.inputValue),expression:"inputValue"}],ref:"input",staticClass:"gl-filtered-search-token-segment-input",attrs:{"data-testid":"filtered-search-token-segment-input","aria-label":_vm.label,"readonly":_vm.viewOnly,"type":"radio"},domProps:{"checked":_vm._q(_vm.inputValue,null)},on:{"keydown":_vm.handleInputKeydown,"blur":_vm.handleBlur,"change":function($event){_vm.inputValue=null;}}},'input',_vm.searchInputAttributes,false)):_c('input',_vm._b({directives:[{name:"model",rawName:"v-model",value:(_vm.inputValue),expression:"inputValue"}],ref:"input",staticClass:"gl-filtered-search-token-segment-input",attrs:{"data-testid":"filtered-search-token-segment-input","aria-label":_vm.label,"readonly":_vm.viewOnly,"type":(_vm.searchInputAttributes).type},domProps:{"value":(_vm.inputValue)},on:{"keydown":_vm.handleInputKeydown,"blur":_vm.handleBlur,"input":function($event){if($event.target.composing){ return; }_vm.inputValue=$event.target.value;}}},'input',_vm.searchInputAttributes,false)),_vm._v(" "),_c('portal',{key:("operator-" + _vm._uid),attrs:{"to":_vm.portalName}},[(_vm.hasOptionsOrSuggestions)?_c('gl-filtered-search-suggestion-list',{key:("operator-" + _vm._uid),ref:"suggestions",attrs:{"initial-value":_vm.defaultSuggestedValue},on:{"suggestion":_vm.applySuggestion}},[(_vm.options)?_vm._l((_vm.options),function(option,idx){return _c('gl-filtered-search-suggestion',{key:((option.value) + "-" + idx),attrs:{"value":option.value,"icon-name":option.icon}},[_vm._t("option",function(){return [(option.component)?[_c(option.component,{tag:"component",attrs:{"option":option}})]:[_vm._v("\n "+_vm._s(option[_vm.optionTextField])+"\n ")]]},null,{ option: option })],2)}):_vm._t("suggestions")],2):_vm._e()],1)]:_vm._t("view",function(){return [_vm._v(_vm._s(_vm.inputValue))]},null,{ inputValue: _vm.inputValue })],2)};
385
385
  var __vue_staticRenderFns__ = [];
386
386
 
387
387
  /* style */
@@ -396,10 +396,8 @@ var script = {
396
396
  return false;
397
397
  }
398
398
 
399
- /**
400
- * hide if no selection
401
- */
402
- if (this.selected.length === 0) {
399
+ // hide if no selection
400
+ if (!this.selected || this.selected.length === 0) {
403
401
  return false;
404
402
  }
405
403
  if (this.multiple) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Wed, 05 Jul 2023 16:22:25 GMT
3
+ * Generated on Tue, 11 Jul 2023 14:54:39 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Wed, 05 Jul 2023 16:22:25 GMT
3
+ * Generated on Tue, 11 Jul 2023 14:54:39 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Wed, 05 Jul 2023 16:22:25 GMT
3
+ * Generated on Tue, 11 Jul 2023 14:54:39 GMT
4
4
  */
5
5
 
6
6
  export const BLACK = "#fff";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Wed, 05 Jul 2023 16:22:25 GMT
3
+ * Generated on Tue, 11 Jul 2023 14:54:39 GMT
4
4
  */
5
5
 
6
6
  export const BLACK = "#000";
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Wed, 05 Jul 2023 16:22:25 GMT
3
+ // Generated on Tue, 11 Jul 2023 14:54:39 GMT
4
4
 
5
5
  $red-950: #fff4f3;
6
6
  $red-900: #fcf1ef;
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Wed, 05 Jul 2023 16:22:25 GMT
3
+ // Generated on Tue, 11 Jul 2023 14:54:39 GMT
4
4
 
5
5
  $brand-gray-05: #2b2838 !default;
6
6
  $brand-gray-04: #45424d !default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "64.18.2",
3
+ "version": "64.19.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -85,28 +85,28 @@
85
85
  },
86
86
  "devDependencies": {
87
87
  "@arkweid/lefthook": "0.7.7",
88
- "@babel/core": "^7.22.5",
89
- "@babel/preset-env": "^7.22.5",
88
+ "@babel/core": "^7.22.8",
89
+ "@babel/preset-env": "^7.22.7",
90
90
  "@babel/preset-react": "^7.22.5",
91
91
  "@gitlab/eslint-plugin": "19.0.0",
92
92
  "@gitlab/fonts": "^1.2.0",
93
93
  "@gitlab/stylelint-config": "4.1.0",
94
- "@gitlab/svgs": "3.53.0",
94
+ "@gitlab/svgs": "3.54.0",
95
95
  "@rollup/plugin-commonjs": "^11.1.0",
96
96
  "@rollup/plugin-node-resolve": "^7.1.3",
97
97
  "@rollup/plugin-replace": "^2.3.2",
98
- "@storybook/addon-a11y": "7.0.24",
99
- "@storybook/addon-docs": "7.0.24",
100
- "@storybook/addon-essentials": "7.0.24",
101
- "@storybook/addon-storyshots": "7.0.24",
102
- "@storybook/addon-storyshots-puppeteer": "7.0.24",
103
- "@storybook/addon-viewport": "7.0.24",
104
- "@storybook/builder-webpack5": "7.0.24",
105
- "@storybook/theming": "7.0.24",
106
- "@storybook/vue": "7.0.24",
107
- "@storybook/vue-webpack5": "7.0.24",
108
- "@storybook/vue3": "7.0.24",
109
- "@storybook/vue3-webpack5": "7.0.24",
98
+ "@storybook/addon-a11y": "7.0.26",
99
+ "@storybook/addon-docs": "7.0.26",
100
+ "@storybook/addon-essentials": "7.0.26",
101
+ "@storybook/addon-storyshots": "7.0.26",
102
+ "@storybook/addon-storyshots-puppeteer": "7.0.26",
103
+ "@storybook/addon-viewport": "7.0.26",
104
+ "@storybook/builder-webpack5": "7.0.26",
105
+ "@storybook/theming": "7.0.26",
106
+ "@storybook/vue": "7.0.26",
107
+ "@storybook/vue-webpack5": "7.0.26",
108
+ "@storybook/vue3": "7.0.26",
109
+ "@storybook/vue3-webpack5": "7.0.26",
110
110
  "@vue/compat": "^3.2.40",
111
111
  "@vue/compiler-sfc": "^3.2.40",
112
112
  "@vue/test-utils": "1.3.0",
@@ -118,7 +118,7 @@
118
118
  "babel-loader": "^8.0.5",
119
119
  "babel-plugin-require-context-hook": "^1.0.0",
120
120
  "bootstrap": "4.6.2",
121
- "cypress": "12.16.0",
121
+ "cypress": "12.17.0",
122
122
  "emoji-regex": "^10.0.0",
123
123
  "eslint": "8.44.0",
124
124
  "eslint-import-resolver-jest": "3.0.2",
@@ -127,9 +127,9 @@
127
127
  "glob": "^7.2.0",
128
128
  "identity-obj-proxy": "^3.0.0",
129
129
  "inquirer-select-directory": "^1.2.0",
130
- "jest": "^29.5.0",
131
- "jest-circus": "29.5.0",
132
- "jest-environment-jsdom": "29.5.0",
130
+ "jest": "^29.6.1",
131
+ "jest-circus": "29.6.1",
132
+ "jest-environment-jsdom": "29.6.1",
133
133
  "markdownlint-cli": "^0.29.0",
134
134
  "mockdate": "^2.0.5",
135
135
  "module-alias": "^2.2.2",
@@ -154,7 +154,7 @@
154
154
  "sass-loader": "^10.2.0",
155
155
  "sass-true": "^6.1.0",
156
156
  "start-server-and-test": "^1.10.6",
157
- "storybook": "7.0.24",
157
+ "storybook": "7.0.26",
158
158
  "storybook-dark-mode": "3.0.0",
159
159
  "style-dictionary": "^3.8.0",
160
160
  "stylelint": "14.9.1",
@@ -2,6 +2,7 @@ import GlLoadingIcon from '../loading_icon/loading_icon.vue';
2
2
  import GlIcon from '../icon/icon.vue';
3
3
  import GlToken from '../token/token.vue';
4
4
  import GlAvatar from '../avatar/avatar.vue';
5
+ import GlDatepicker from '../datepicker/datepicker.vue';
5
6
  import GlDropdownDivider from '../dropdown/dropdown_divider.vue';
6
7
  import { setStoryTimeout } from '../../../utils/test_utils';
7
8
  import { makeContainer } from '../../../utils/story_decorators/container';
@@ -284,6 +285,58 @@ const LabelToken = {
284
285
  `,
285
286
  };
286
287
 
288
+ const DateToken = {
289
+ name: 'DateToken',
290
+ __v_skip: true /* temporary workaround for @vue/compat */,
291
+ components: {
292
+ GlIcon,
293
+ GlDatepicker,
294
+ GlFilteredSearchToken,
295
+ },
296
+ props: ['value', 'active', 'viewOnly'],
297
+ inheritAttrs: false,
298
+ data() {
299
+ return {
300
+ dataSegmentInputAttributes: {
301
+ id: 'this-id',
302
+ placeholder: 'YYYY-MM-DD',
303
+ style: 'padding-left: 23px;',
304
+ },
305
+ };
306
+ },
307
+ methods: {
308
+ selectValue(value, submitValue) {
309
+ const date = new Date(value);
310
+ const offset = date.getTimezoneOffset();
311
+ const offsetDdate = new Date(date.getTime() - offset * 60 * 1000);
312
+ const dateString = offsetDdate.toISOString().split('T')[0];
313
+ submitValue(dateString);
314
+ },
315
+ },
316
+ template: `
317
+ <div>
318
+ <gl-filtered-search-token
319
+ :data-segment-input-attributes="dataSegmentInputAttributes"
320
+ v-bind="{ ...this.$props, ...this.$attrs }"
321
+ v-on="$listeners"
322
+ >
323
+ <template #before-data-segment-input="{ submitValue }">
324
+ <gl-icon
325
+ class="gl-text-gray-500"
326
+ name="calendar"
327
+ style="margin-right: -20px; z-index: 1; pointer-events: none;"
328
+ />
329
+ <gl-datepicker
330
+ class="gl-display-none!"
331
+ target='#this-id'
332
+ :container="null"
333
+ @input="selectValue($event, submitValue)" />
334
+ </template>
335
+ </gl-filtered-search-token>
336
+ </div>
337
+ `,
338
+ };
339
+
287
340
  const tokens = [
288
341
  {
289
342
  type: 'author',
@@ -308,6 +361,16 @@ const tokens = [
308
361
  { icon: 'eye', value: 'false', title: 'No' },
309
362
  ],
310
363
  },
364
+ {
365
+ type: 'date',
366
+ icon: 'history',
367
+ title: 'Created',
368
+ token: DateToken,
369
+ operators: [
370
+ { value: '<', description: 'before' },
371
+ { value: '>', description: 'after' },
372
+ ],
373
+ },
311
374
  ];
312
375
 
313
376
  const components = {
@@ -1,8 +1,12 @@
1
+ import * as Vue from 'vue';
1
2
  import { shallowMount, mount } from '@vue/test-utils';
2
- import { observable, nextTick } from 'vue';
3
+ import { observable, nextTick, h } from 'vue';
3
4
  import GlFilteredSearchToken from './filtered_search_token.vue';
4
5
  import GlFilteredSearchTokenSegment from './filtered_search_token_segment.vue';
5
6
 
7
+ const TEST_ID_BEFORE_DATA_SEGMENT_INPUT_BUTTON = 'before-data-input-button';
8
+ const TEST_APPLY_VALUE = 'Lorem-ipsum-apply';
9
+
6
10
  describe('Filtered search token', () => {
7
11
  let wrapper;
8
12
 
@@ -39,6 +43,23 @@ describe('Filtered search token', () => {
39
43
  });
40
44
  };
41
45
 
46
+ const createSlot = (testId, onClick) => {
47
+ // why: Vue3 has a different format for creating VNodes
48
+ return Vue.version.startsWith('3')
49
+ ? h('button', {
50
+ 'data-testid': testId,
51
+ onClick,
52
+ })
53
+ : h('button', {
54
+ attrs: {
55
+ 'data-testid': testId,
56
+ },
57
+ on: {
58
+ click: onClick,
59
+ },
60
+ });
61
+ };
62
+
42
63
  const mountComponent = (props) => {
43
64
  wrapper = mount(GlFilteredSearchToken, {
44
65
  provide: {
@@ -58,6 +79,10 @@ describe('Filtered search token', () => {
58
79
  },
59
80
  },
60
81
  propsData: { ...defaultProps, ...props },
82
+ scopedSlots: {
83
+ 'before-data-segment-input': ({ submitValue }) =>
84
+ createSlot(TEST_ID_BEFORE_DATA_SEGMENT_INPUT_BUTTON, () => submitValue(TEST_APPLY_VALUE)),
85
+ },
61
86
  });
62
87
  };
63
88
 
@@ -282,6 +307,25 @@ describe('Filtered search token', () => {
282
307
 
283
308
  expect(value).toEqual(originalValue());
284
309
  });
310
+
311
+ it('renders before-data-segment-input scoped slot which can submitValue', async () => {
312
+ mountComponent({ active: true, value: observable({ operator: '=', data: '' }) });
313
+
314
+ // what: Activate data segment
315
+ await wrapper.find('input').trigger('keydown', { key: ' ' });
316
+
317
+ expect(wrapper.emitted()).toEqual({});
318
+
319
+ const beforeDataInputButton = wrapper.find(
320
+ `[data-testid="${TEST_ID_BEFORE_DATA_SEGMENT_INPUT_BUTTON}"]`
321
+ );
322
+ beforeDataInputButton.trigger('click');
323
+
324
+ expect(wrapper.emitted()).toEqual({
325
+ complete: [[]],
326
+ select: [[TEST_APPLY_VALUE]],
327
+ });
328
+ });
285
329
  });
286
330
 
287
331
  describe('when multi select', () => {
@@ -421,6 +421,9 @@ export default {
421
421
  @previous="activatePreviousOperatorSegment"
422
422
  @next="$emit('next')"
423
423
  >
424
+ <template #before-input="scope">
425
+ <slot name="before-data-segment-input" v-bind="scope"></slot>
426
+ </template>
424
427
  <template #suggestions>
425
428
  <!-- @slot The suggestions (implemented with GlFilteredSearchSuggestion). -->
426
429
 
@@ -416,6 +416,7 @@ export default {
416
416
  v-on="viewOnly ? {} : { mousedown: emitIfInactive }"
417
417
  >
418
418
  <template v-if="active">
419
+ <slot name="before-input" v-bind="{ submitValue: applySuggestion }"></slot>
419
420
  <input
420
421
  ref="input"
421
422
  v-bind="searchInputAttributes"
@@ -427,7 +428,6 @@ export default {
427
428
  @keydown="handleInputKeydown"
428
429
  @blur="handleBlur"
429
430
  />
430
-
431
431
  <portal :key="`operator-${_uid}`" :to="portalName">
432
432
  <gl-filtered-search-suggestion-list
433
433
  v-if="hasOptionsOrSuggestions"
@@ -506,6 +506,7 @@ describe('GlCollapsibleListbox', () => {
506
506
  description | props
507
507
  ${'multi-select'} | ${{ multiple: true, selected: [] }}
508
508
  ${'single-select'} | ${{ multiple: false, selected: [] }}
509
+ ${'single-select'} | ${{ multiple: false, selected: undefined }}
509
510
  `('hides the button if the selection is empty in $description mode', ({ props }) => {
510
511
  buildWrapper({
511
512
  headerText: 'Select assignee',
@@ -406,10 +406,8 @@ export default {
406
406
  return false;
407
407
  }
408
408
 
409
- /**
410
- * hide if no selection
411
- */
412
- if (this.selected.length === 0) {
409
+ // hide if no selection
410
+ if (!this.selected || this.selected.length === 0) {
413
411
  return false;
414
412
  }
415
413