Commit 53d4cad1 authored by Clement Ho's avatar Clement Ho

Merge branch '27174-filter-filters' into 'master'

prevent filtering Issues by multiple milestones, authors, or assignees

Closes #27174

See merge request !9406
parents ef447a62 6e7e9e80
...@@ -57,13 +57,15 @@ require('./filtered_search_dropdown'); ...@@ -57,13 +57,15 @@ require('./filtered_search_dropdown');
const dropdownData = []; const dropdownData = [];
[].forEach.call(this.input.closest('.filtered-search-input-container').querySelectorAll('.dropdown-menu'), (dropdownMenu) => { [].forEach.call(this.input.closest('.filtered-search-input-container').querySelectorAll('.dropdown-menu'), (dropdownMenu) => {
const { icon, hint, tag } = dropdownMenu.dataset; const { icon, hint, tag, type } = dropdownMenu.dataset;
if (icon && hint && tag) { if (icon && hint && tag) {
dropdownData.push({ dropdownData.push(
icon: `fa-${icon}`, Object.assign({
hint, icon: `fa-${icon}`,
tag: `<${tag}>`, hint,
}); tag: `<${tag}>`,
}, type && { type }),
);
} }
}); });
......
...@@ -51,14 +51,18 @@ ...@@ -51,14 +51,18 @@
static filterHint(input, item) { static filterHint(input, item) {
const updatedItem = item; const updatedItem = item;
const searchInput = gl.DropdownUtils.getSearchInput(input); const searchInput = gl.DropdownUtils.getSearchQuery(input);
let { lastToken } = gl.FilteredSearchTokenizer.processTokens(searchInput); const { lastToken, tokens } = gl.FilteredSearchTokenizer.processTokens(searchInput);
lastToken = lastToken.key || lastToken || ''; const lastKey = lastToken.key || lastToken || '';
const allowMultiple = item.type === 'array';
if (!lastToken || searchInput.split('').last() === ' ') { const itemInExistingTokens = tokens.some(t => t.key === item.hint);
if (!allowMultiple && itemInExistingTokens) {
updatedItem.droplab_hidden = true;
} else if (!lastKey || searchInput.split('').last() === ' ') {
updatedItem.droplab_hidden = false; updatedItem.droplab_hidden = false;
} else if (lastToken) { } else if (lastKey) {
const split = lastToken.split(':'); const split = lastKey.split(':');
const tokenName = split[0].split(' ').last(); const tokenName = split[0].split(' ').last();
const match = updatedItem.hint.indexOf(tokenName.toLowerCase()) === -1; const match = updatedItem.hint.indexOf(tokenName.toLowerCase()) === -1;
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
%li.filter-dropdown-item %li.filter-dropdown-item
%button.btn.btn-link.js-data-value %button.btn.btn-link.js-data-value
{{title}} {{title}}
#js-dropdown-label.dropdown-menu{ data: { icon: 'tag', hint: 'label', tag: '~label' } } #js-dropdown-label.dropdown-menu{ data: { icon: 'tag', hint: 'label', tag: '~label', type: 'array' } }
%ul{ data: { dropdown: true } } %ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'none' } } %li.filter-dropdown-item{ data: { value: 'none' } }
%button.btn.btn-link %button.btn.btn-link
......
---
title: Prevent filtering issues by multiple Milestones or Authors
merge_request:
author:
...@@ -126,7 +126,11 @@ require('~/filtered_search/filtered_search_dropdown_manager'); ...@@ -126,7 +126,11 @@ require('~/filtered_search/filtered_search_dropdown_manager');
beforeEach(() => { beforeEach(() => {
setFixtures(` setFixtures(`
<input type="text" id="test" /> <ul class="tokens-container">
<li class="input-token">
<input class="filtered-search" type="text" id="test" />
</li>
</ul>
`); `);
input = document.getElementById('test'); input = document.getElementById('test');
...@@ -142,7 +146,7 @@ require('~/filtered_search/filtered_search_dropdown_manager'); ...@@ -142,7 +146,7 @@ require('~/filtered_search/filtered_search_dropdown_manager');
input.value = 'o'; input.value = 'o';
updatedItem = gl.DropdownUtils.filterHint(input, { updatedItem = gl.DropdownUtils.filterHint(input, {
hint: 'label', hint: 'label',
}, 'o'); });
expect(updatedItem.droplab_hidden).toBe(true); expect(updatedItem.droplab_hidden).toBe(true);
}); });
...@@ -150,6 +154,29 @@ require('~/filtered_search/filtered_search_dropdown_manager'); ...@@ -150,6 +154,29 @@ require('~/filtered_search/filtered_search_dropdown_manager');
const updatedItem = gl.DropdownUtils.filterHint(input, {}, ''); const updatedItem = gl.DropdownUtils.filterHint(input, {}, '');
expect(updatedItem.droplab_hidden).toBe(false); expect(updatedItem.droplab_hidden).toBe(false);
}); });
it('should allow multiple if item.type is array', () => {
input.value = 'label:~first la';
const updatedItem = gl.DropdownUtils.filterHint(input, {
hint: 'label',
type: 'array',
});
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should prevent multiple if item.type is not array', () => {
input.value = 'milestone:~first mile';
let updatedItem = gl.DropdownUtils.filterHint(input, {
hint: 'milestone',
});
expect(updatedItem.droplab_hidden).toBe(true);
updatedItem = gl.DropdownUtils.filterHint(input, {
hint: 'milestone',
type: 'string',
});
expect(updatedItem.droplab_hidden).toBe(true);
});
}); });
describe('setDataValueIfSelected', () => { describe('setDataValueIfSelected', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment