Commit 887ef155 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'issue-boards-new-search-bar-ee' into 'master'

Port of issue-boards-new-search-bar to EE

See merge request !1397
parents 52d6736c 1e30dafb
......@@ -2,6 +2,9 @@
/* global Vue */
/* global BoardService */
import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub';
window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
require('./models/issue');
......@@ -61,10 +64,24 @@ $(() => {
},
created () {
if (this.milestoneTitle) {
this.state.filters.milestone_title = this.milestoneTitle;
const milestoneTitleParam = `milestone_title=${this.milestoneTitle}`;
Store.filter.path = [milestoneTitleParam].concat(
Store.filter.path.split('&').filter(param => param.match(/^milestone_title=(.*)$/g) === null)
).join('&');
Store.updateFiltersUrl(true);
}
gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId);
this.filterManager = new FilteredSearchBoards(Store.filter, true, [(this.milestoneTitle ? 'milestone' : null)]);
// Listen for updateTokens event
eventHub.$on('updateTokens', this.updateTokens);
},
beforeDestroy() {
eventHub.$off('updateTokens', this.updateTokens);
},
mounted () {
Store.disabled = this.disabled;
......@@ -83,11 +100,16 @@ $(() => {
Store.addBlankState();
this.loading = false;
});
}
},
methods: {
updateTokens() {
this.filterManager.updateTokens();
}
},
});
gl.IssueBoardsSearch = new Vue({
el: document.getElementById('js-boards-search'),
el: document.getElementById('js-add-list'),
data: {
filters: Store.state.filters,
milestoneTitle: $boardApp.dataset.boardMilestoneTitle,
......
......@@ -28,16 +28,16 @@ require('./board_list');
data () {
return {
detailIssue: Store.detail,
filters: Store.state.filters,
filter: Store.filter,
};
},
watch: {
filters: {
handler () {
filter: {
handler() {
this.list.page = 1;
this.list.getIssues(true);
},
deep: true
deep: true,
},
detailIssue: {
handler () {
......
......@@ -17,7 +17,8 @@ export default {
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath" />
:root-path="rootPath"
:update-filters="true" />
</li>
`,
components: {
......
......@@ -59,6 +59,9 @@ const extraMilestones = require('../mixins/extra_milestones');
},
},
methods: {
refreshPage() {
location.href = location.pathname;
},
loadMilestones(e) {
this.milestoneDropdownOpen = !this.milestoneDropdownOpen;
BoardService.loadMilestones.call(this);
......@@ -80,12 +83,9 @@ const extraMilestones = require('../mixins/extra_milestones');
if (this.currentBoard && this.currentPage !== 'new') {
this.currentBoard.name = this.board.name;
if (this.board.milestone) {
this.currentBoard.milestone_id = this.board.milestone_id;
this.currentBoard.milestone = this.board.milestone;
Store.state.filters.milestone_title = this.currentBoard.milestone_id ?
this.currentBoard.milestone.title : null;
if (this.currentPage === 'milestone') {
// We reload the page to make sure the store & state of the app are correct
this.refreshPage();
}
}
......
......@@ -42,12 +42,6 @@ require('./board_new_form');
this.loadBoards(false);
}
},
board: {
handler() {
this.updateMilestoneFilterDropdown();
},
deep: true,
},
},
computed: {
currentPage() {
......@@ -94,33 +88,9 @@ require('./board_new_form');
});
}
},
updateMilestoneFilterDropdown() {
const $milestoneDropdownToggle = $('.js-milestone-select');
const glDropdown = $milestoneDropdownToggle.data('glDropdown');
const $milestoneDropdown = $('.dropdown-menu-milestone');
const hideElements = this.board.milestone === undefined || this.board.milestone_id === null;
$('#milestone_title').val(this.board.milestone ? this.board.milestone.title : '');
if (glDropdown.fullData) {
glDropdown.parseData(glDropdown.fullData);
}
$milestoneDropdown.find('.dropdown-input, .dropdown-footer-list')
.toggle(hideElements);
$milestoneDropdown.find('.js-milestone-footer-content').toggle(!hideElements);
$milestoneDropdown.find('.dropdown-content li').show()
.filter((i, el) => $(el).find('.is-active').length === 0)
.toggle(hideElements);
$('.js-milestone-select .dropdown-toggle-text')
.text(hideElements ? 'Milestone' : this.board.milestone.title)
.toggleClass('is-default', hideElements);
},
},
created() {
this.state.currentBoard = this.currentBoard;
this.updateMilestoneFilterDropdown();
},
});
})();
/* global Vue */
import eventHub from '../eventhub';
(() => {
const Store = gl.issueBoards.BoardsStore;
......@@ -23,6 +25,11 @@
type: String,
required: true,
},
updateFilters: {
type: Boolean,
required: false,
default: false,
},
},
methods: {
showLabel(label) {
......@@ -31,29 +38,25 @@
return !this.list.label || label.id !== this.list.label.id;
},
filterByLabel(label, e) {
let labelToggleText = label.title;
const labelIndex = Store.state.filters.label_name.indexOf(label.title);
if (!this.updateFilters) return;
const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&');
const labelTitle = encodeURIComponent(label.title);
const param = `label_name[]=${labelTitle}`;
const labelIndex = filterPath.indexOf(param);
$(e.currentTarget).tooltip('hide');
if (labelIndex === -1) {
Store.state.filters.label_name.push(label.title);
$('.labels-filter').prepend(`<input type="hidden" name="label_name[]" value="${label.title}" />`);
filterPath.push(param);
} else {
Store.state.filters.label_name.splice(labelIndex, 1);
labelToggleText = Store.state.filters.label_name[0];
$(`.labels-filter input[name="label_name[]"][value="${label.title}"]`).remove();
filterPath.splice(labelIndex, 1);
}
const selectedLabels = Store.state.filters.label_name;
if (selectedLabels.length === 0) {
labelToggleText = 'Label';
} else if (selectedLabels.length > 1) {
labelToggleText = `${selectedLabels[0]} + ${selectedLabels.length - 1} more`;
}
$('.labels-filter .dropdown-toggle-text').text(labelToggleText);
gl.issueBoards.BoardsStore.filter.path = filterPath.join('&');
Store.updateFiltersUrl();
eventHub.$emit('updateTokens');
},
labelStyle(label) {
return {
......
import Vue from 'vue';
export default new Vue();
export default class FilteredSearchBoards extends gl.FilteredSearchManager {
constructor(store, updateUrl = false, cantEdit = []) {
super('boards');
this.store = store;
this.updateUrl = updateUrl;
// Issue boards is slightly different, we handle all the requests async
// instead or reloading the page, we just re-fire the list ajax requests
this.isHandledAsync = true;
this.cantEdit = cantEdit;
}
updateObject(path) {
this.store.path = path.substr(1);
if (this.updateUrl) {
gl.issueBoards.BoardsStore.updateFiltersUrl();
}
}
updateTokens() {
const tokens = document.querySelectorAll('.js-visual-token');
// Remove all the tokens as they will be replaced by the search manager
[].forEach.call(tokens, (el) => {
el.parentNode.removeChild(el);
});
this.loadSearchParamsFromURL();
// Get the placeholder back if search is empty
this.filteredSearchInput.dispatchEvent(new Event('input'));
}
canEdit(token) {
const tokenName = token.querySelector('.name').textContent.trim();
return this.cantEdit.indexOf(tokenName) === -1;
}
}
......@@ -10,7 +10,6 @@ class List {
this.title = obj.title;
this.type = obj.list_type;
this.preset = ['done', 'blank'].indexOf(this.type) > -1;
this.filters = gl.issueBoards.BoardsStore.state.filters;
this.page = 1;
this.loading = true;
this.loadingMore = false;
......@@ -65,12 +64,27 @@ class List {
}
getIssues (emptyIssues = true) {
const filters = this.filters;
const data = { page: this.page };
const data = gl.issueBoards.BoardsStore.filter.path.split('&').reduce((data, filterParam) => {
if (filterParam === '') return data;
const paramSplit = filterParam.split('=');
const paramKeyNormalized = paramSplit[0].replace('[]', '');
const isArray = paramSplit[0].indexOf('[]');
const value = decodeURIComponent(paramSplit[1]).replace(/\+/g, ' ');
if (isArray !== -1) {
if (!data[paramKeyNormalized]) {
data[paramKeyNormalized] = [];
}
data[paramKeyNormalized].push(value);
} else {
data[paramKeyNormalized] = value;
}
Object.keys(filters).forEach((key) => { data[key] = filters[key]; });
return data;
}, { page: this.page });
if (this.label) {
if (this.label && data.label_name) {
data.label_name = data.label_name.filter(label => label !== this.label.title);
}
......
......@@ -8,6 +8,9 @@
gl.issueBoards.BoardsStore = {
disabled: false,
filter: {
path: '',
},
state: {},
detail: {
issue: {}
......@@ -18,13 +21,7 @@
},
create () {
this.state.lists = [];
this.state.filters = {
author_id: gl.utils.getParameterValues('author_id')[0],
assignee_id: gl.utils.getParameterValues('assignee_id')[0],
milestone_title: gl.utils.getParameterValues('milestone_title')[0],
label_name: gl.utils.getParameterValues('label_name[]'),
search: ''
};
this.filter.path = gl.utils.getUrlParamsArray().join('&');
},
createNewListDropdownData() {
this.state.currentBoard = {};
......@@ -127,8 +124,12 @@
return list[key] === val && byType;
})[0];
},
updateFiltersUrl () {
history.pushState(null, null, `?${$.param(this.state.filters)}`);
updateFiltersUrl (replaceState = false) {
if (replaceState) {
history.replaceState(null, null, `?${this.filter.path}`);
} else {
history.pushState(null, null, `?${this.filter.path}`);
}
}
};
})();
......@@ -9,7 +9,7 @@
this.filteredSearchInput = document.querySelector('.filtered-search');
this.page = page;
if (this.page === 'issues') {
if (this.page === 'issues' || this.page === 'boards') {
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeysWithWeights;
}
......@@ -61,7 +61,7 @@
},
};
if (this.page === 'issues') {
if (this.page === 'issues' || this.page === 'boards') {
this.mapping.weight = {
reference: null,
gl: 'DropdownNonUser',
......
......@@ -6,7 +6,7 @@
this.tokensContainer = document.querySelector('.tokens-container');
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys;
if (page === 'issues') {
if (page === 'issues' || page === 'boards') {
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeysWithWeights;
}
......@@ -84,6 +84,8 @@
const { lastVisualToken } = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
if (this.filteredSearchInput.value === '' && lastVisualToken) {
if (this.canEdit && !this.canEdit(lastVisualToken)) return;
this.filteredSearchInput.value = gl.FilteredSearchVisualTokens.getLastTokenPartial();
gl.FilteredSearchVisualTokens.removeLastTokenPartial();
}
......@@ -109,8 +111,15 @@
e.preventDefault();
if (!activeElements.length) {
// Prevent droplab from opening dropdown
this.dropdownManager.destroyDroplab();
if (this.isHandledAsync) {
e.stopImmediatePropagation();
this.filteredSearchInput.blur();
this.dropdownManager.resetDropdowns();
} else {
// Prevent droplab from opening dropdown
this.dropdownManager.destroyDroplab();
}
this.search();
}
......@@ -142,6 +151,8 @@
editToken(e) {
const token = e.target.closest('.js-visual-token');
if (this.canEdit && !this.canEdit(token)) return;
if (token) {
gl.FilteredSearchVisualTokens.editToken(token);
this.tokenChange();
......@@ -191,6 +202,8 @@
[].forEach.call(this.tokensContainer.children, (t) => {
if (t.classList.contains('js-visual-token')) {
if (this.canEdit && !this.canEdit(t)) return;
removeElements.push(t);
}
});
......@@ -203,6 +216,10 @@
this.handleInputPlaceholder();
this.dropdownManager.resetDropdowns();
if (this.isHandledAsync) {
this.search();
}
}
handleInputVisualToken() {
......@@ -349,7 +366,11 @@
const parameterizedUrl = `?scope=all&utf8=✓&${paths.join('&')}`;
gl.utils.visitUrl(parameterizedUrl);
if (this.updateObject) {
this.updateObject(parameterizedUrl);
} else {
gl.utils.visitUrl(parameterizedUrl);
}
}
getUsernameParams() {
......
......@@ -353,31 +353,17 @@
return;
}
if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar') &&
!$dropdown.closest('.add-issues-modal').length) {
boardsModel = gl.issueBoards.BoardsStore.state.filters;
} else if ($dropdown.closest('.add-issues-modal').length) {
if ($dropdown.closest('.add-issues-modal').length) {
boardsModel = gl.issueBoards.ModalStore.store.filter;
}
if (boardsModel) {
if (label.isAny) {
boardsModel['label_name'] = [];
}
else if ($el.hasClass('is-active')) {
} else if ($el.hasClass('is-active')) {
boardsModel['label_name'].push(label.title);
}
else {
var filters = boardsModel['label_name'];
filters = filters.filter(function (filteredLabel) {
return filteredLabel !== label.title;
});
boardsModel['label_name'] = filters;
}
if (!$dropdown.closest('.add-issues-modal').length) {
gl.issueBoards.BoardsStore.updateFiltersUrl();
}
e.preventDefault();
return;
}
......
......@@ -146,18 +146,12 @@
return;
}
if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar') &&
!$dropdown.closest('.add-issues-modal').length) {
boardsStore = gl.issueBoards.BoardsStore.state.filters;
} else if ($dropdown.closest('.add-issues-modal').length) {
if ($dropdown.closest('.add-issues-modal').length) {
boardsStore = gl.issueBoards.ModalStore.store.filter;
}
if (boardsStore) {
boardsStore[$dropdown.data('field-name')] = selected.name;
if (!$dropdown.closest('.add-issues-modal').length) {
gl.issueBoards.BoardsStore.updateFiltersUrl();
}
e.preventDefault();
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
if (selected.name != null) {
......
......@@ -217,11 +217,6 @@
}
if ($el.closest('.add-issues-modal').length) {
gl.issueBoards.ModalStore.store.filter[$dropdown.data('field-name')] = user.id;
} else if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar')) {
selectedId = user.id;
gl.issueBoards.BoardsStore.state.filters[$dropdown.data('field-name')] = user.id;
gl.issueBoards.BoardsStore.updateFiltersUrl();
e.preventDefault();
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
selectedId = user.id;
return Issuable.filterResults($dropdown.closest('form'));
......
......@@ -156,7 +156,6 @@
width: 100%;
border: 1px solid $border-color;
background-color: $white-light;
max-width: 87%;
@media (max-width: $screen-xs-min) {
-webkit-flex: 1 1 100%;
......@@ -219,6 +218,11 @@
}
}
.filter-dropdown-container {
display: -webkit-flex;
display: flex;
}
.dropdown-menu .filter-dropdown-item {
padding: 0;
}
......
......@@ -551,8 +551,6 @@
.boards-switcher {
padding-right: 10px;
margin-right: 10px;
border-right: 1px solid $white-dark;
}
.board-milestone-list {
......
......@@ -5,6 +5,7 @@
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('filtered_search')
= page_specific_javascript_bundle_tag('boards')
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
......@@ -13,7 +14,8 @@
= render "projects/issues/head"
= render 'shared/issuable/filter', type: :boards, board: board
.hidden-xs.hidden-sm
= render 'shared/issuable/search_bar', type: :boards, board: board
#board-app.boards-app{ "v-cloak" => true, data: board_data }
.boards-list{ ":class" => "{ 'is-compact': detailIssueVisible }" }
......
- finder = controller.controller_name == 'issues' || controller.controller_name == 'boards' ? issues_finder : merge_requests_finder
- finder = controller.controller_name == 'issues' ? issues_finder : merge_requests_finder
- boards_page = controller.controller_name == 'boards'
- board = local_assigns[:board]
.issues-filters
.issues-details-filters.row-content-block.second-block
- if boards_page && board
#js-multiple-boards-switcher.filter-item.inline.boards-switcher{ "v-cloak" => true }
= render "projects/boards/switcher", board: board
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do
- if params[:search].present?
= hidden_field_tag :search, params[:search]
......@@ -38,21 +35,7 @@
%a{ href: page_filter_path(without: issuable_filter_params) } Reset filters
.pull-right
- if boards_page
#js-boards-search.issue-boards-search
%input.pull-left.form-control{ type: "search", placeholder: "Filter by name...", "v-model" => "filters.search", "debounce" => "250" }
- if can?(current_user, :admin_list, @project)
#js-add-issues-btn.pull-right.prepend-left-10
.dropdown.pull-right
%button.btn.btn-create.btn-inverted.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } }
Add list
.dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable
= render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Add list" }
- if can?(current_user, :admin_label, @project)
= render partial: "shared/issuable/label_page_create"
= dropdown_loading
- else
= render 'shared/sort_dropdown', type: local_assigns[:type]
= render 'shared/sort_dropdown'
- if @bulk_edit
.issues_bulk_update.hide
......
- type = local_assigns.fetch(:type)
- board = local_assigns.fetch(:board, nil)
.issues-filters
.issues-details-filters.row-content-block.second-block.filtered-search-block
- if type == :boards && board
#js-multiple-boards-switcher.inline.boards-switcher{ "v-cloak" => true }
= render "projects/boards/switcher", board: board
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do
- if params[:search].present?
= hidden_field_tag :search, params[:search]
......@@ -60,19 +64,20 @@
{{name}}
%span.dropdown-light-content
@{{username}}
#js-dropdown-milestone.dropdown-menu{ data: { icon: 'clock-o', hint: 'milestone', tag: '%milestone' } }
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'none' } }
%button.btn.btn-link
No Milestone
%li.filter-dropdown-item{ data: { value: 'upcoming' } }
%button.btn.btn-link
Upcoming
%li.divider
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
%button.btn.btn-link.js-data-value
{{title}}
- unless board && board.milestone_id
#js-dropdown-milestone.dropdown-menu{ data: { icon: 'clock-o', hint: 'milestone', tag: '%milestone' } }
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'none' } }
%button.btn.btn-link
No Milestone
%li.filter-dropdown-item{ data: { value: 'upcoming' } }
%button.btn.btn-link
Upcoming
%li.divider
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
%button.btn.btn-link.js-data-value
{{title}}
#js-dropdown-label.dropdown-menu{ data: { icon: 'tag', hint: 'label', tag: '~label' } }
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'none' } }
......@@ -85,7 +90,7 @@
%span.dropdown-label-box{ style: 'background: {{color}}' }
%span.label-title.js-data-value
{{title}}
- if type == :issues
- if type == :issues || type == :boards
#js-dropdown-weight.dropdown-menu{ data: { icon: 'balance-scale', hint: 'weight', tag: 'weight' } }
%ul{ 'data-dropdown' => true }
%li.filter-dropdown-item{ 'data-value' => 'none' }
......@@ -100,8 +105,20 @@
%li.filter-dropdown-item{ 'data-value' => "#{weight}" }
%button.btn.btn-link= weight
.pull-right.filter-dropdown-container
= render 'shared/sort_dropdown'
.filter-dropdown-container
- if type == :boards
- if can?(current_user, :admin_list, @project)
.dropdown.prepend-left-10#js-add-list
%button.btn.btn-create.btn-inverted.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } }
Add list
.dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable
= render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Add list" }
- if can?(current_user, :admin_label, @project)
= render partial: "shared/issuable/label_page_create"
= dropdown_loading
#js-add-issues-btn.prepend-left-10
- else
= render 'shared/sort_dropdown'
- if @bulk_edit
.issues_bulk_update.hide
......
---
title: Added new filtered search bar to issue boards
merge_request:
author:
......@@ -51,7 +51,7 @@ describe 'Issue Boards add issue modal', :feature, :js do
end
it 'does not show tooltip on add issues button' do
button = page.find('.issue-boards-search button', text: 'Add issues')
button = page.find('.filter-dropdown-container button', text: 'Add issues')
expect(button[:title]).not_to eq("Please add a list to your board first")
end
......
......@@ -26,7 +26,7 @@ describe 'Board with milestone', :feature, :js do
click_link 'test'
expect(find('.js-milestone-select')).to have_content(milestone.title)
expect(find('.tokens-container')).to have_content(milestone.title)
expect(all('.board')[1]).to have_selector('.card', count: 1)
end
end
......@@ -48,23 +48,41 @@ describe 'Board with milestone', :feature, :js do
click_link board.name
end
expect(find('.js-milestone-select')).to have_content(milestone.title)
expect(find('.tokens-container')).to have_content(milestone.title)
expect(all('.board')[1]).to have_selector('.card', count: 1)
end
it 'sets board to any milestone' do
update_board_milestone('Any Milestone')
expect(find('.js-milestone-select')).not_to have_content(milestone.title)
expect(page).not_to have_css('.js-visual-token')
expect(find('.tokens-container')).not_to have_content(milestone.title)
expect(page).to have_selector('.board', count: 2)
expect(all('.board')[1]).to have_selector('.card', count: 2)
end
it 'sets board to upcoming milestone' do
update_board_milestone('Upcoming')
expect(find('.js-milestone-select')).not_to have_content(milestone.title)
expect(find('.tokens-container')).not_to have_content(milestone.title)
expect(all('.board')[1]).to have_selector('.card', count: 0)
end
it 'does not allow milestone in filter to be editted' do
find('.filtered-search').native.send_keys(:backspace)
page.within('.tokens-container') do
expect(page).to have_selector('.value')
end
end
it 'does not render milestone in hint dropdown' do
find('.filtered-search').click
page.within('#js-dropdown-hint') do
expect(page).not_to have_button('Milestone')
end
end
end
def create_board_with_milestone
......
......@@ -29,7 +29,7 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'shows tooltip on add issues button' do
button = page.find('.issue-boards-search button', text: 'Add issues')
button = page.find('.filter-dropdown-container button', text: 'Add issues')
expect(button[:"data-original-title"]).to eq("Please add a list to your board first")
end
......@@ -115,9 +115,8 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'search done list' do
page.within('#js-boards-search') do
find('.form-control').set(issue8.title)
end
find('.filtered-search').set(issue8.title)
find('.filtered-search').native.send_keys(:enter)
wait_for_vue_resource
......@@ -127,9 +126,8 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'search list' do
page.within('#js-boards-search') do
find('.form-control').set(issue5.title)
end
find('.filtered-search').set(issue5.title)
find('.filtered-search').native.send_keys(:enter)
wait_for_vue_resource
......@@ -333,7 +331,7 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_vue_resource
expect(find('.issue-boards-search')).to have_selector('.open')
expect(page).to have_css('#js-add-list.open')
end
it 'creates new list from a new label' do
......@@ -359,17 +357,9 @@ describe 'Issue Boards', feature: true, js: true do
context 'filtering' do
it 'filters by author' do
page.within '.issues-filters' do
click_button('Author')
wait_for_ajax
page.within '.dropdown-menu-author' do
click_link(user2.name)
end
wait_for_vue_resource
expect(find('.js-author-search')).to have_content(user2.name)
end
set_filter("author", user2.username)
click_filter_link(user2.username)
submit_filter
wait_for_vue_resource
wait_for_board_cards(1, 1)
......@@ -377,17 +367,9 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'filters by assignee' do
page.within '.issues-filters' do
click_button('Assignee')
wait_for_ajax
page.within '.dropdown-menu-assignee' do
click_link(user.name)
end
wait_for_vue_resource
expect(find('.js-assignee-search')).to have_content(user.name)
end
set_filter("assignee", user.username)
click_filter_link(user.username)
submit_filter
wait_for_vue_resource
......@@ -396,17 +378,9 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'filters by milestone' do
page.within '.issues-filters' do
click_button('Milestone')
wait_for_ajax
page.within '.milestone-filter' do
click_link(milestone.title)
end
wait_for_vue_resource
expect(find('.js-milestone-select')).to have_content(milestone.title)
end
set_filter("milestone", "\"#{milestone.title}\"")
click_filter_link(milestone.title)
submit_filter
wait_for_vue_resource
wait_for_board_cards(1, 1)
......@@ -415,16 +389,9 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'filters by label' do
page.within '.issues-filters' do
click_button('Label')
wait_for_ajax
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
set_filter("label", testing.title)
click_filter_link(testing.title)
submit_filter
wait_for_vue_resource
wait_for_board_cards(1, 1)
......@@ -432,19 +399,14 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'filters by label with space after reload' do
page.within '.issues-filters' do
click_button('Label')
wait_for_ajax
page.within '.dropdown-menu-labels' do
click_link(accepting.title)
wait_for_vue_resource(spinner: false)
find('.dropdown-menu-close').click
end
end
set_filter("label", "\"#{accepting.title}\"")
click_filter_link(accepting.title)
submit_filter
# Test after reload
page.evaluate_script 'window.location.reload()'
wait_for_board_cards(1, 1)
wait_for_empty_boards((2..3))
wait_for_vue_resource
......@@ -460,26 +422,16 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'removes filtered labels' do
wait_for_vue_resource
set_filter("label", testing.title)
click_filter_link(testing.title)
submit_filter
page.within '.labels-filter' do
click_button('Label')
wait_for_ajax
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource(spinner: false)
end
expect(page).to have_css('input[name="label_name[]"]', visible: false)
wait_for_board_cards(1, 1)
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource(spinner: false)
end
find('.clear-search').click
submit_filter
expect(page).not_to have_css('input[name="label_name[]"]', visible: false)
end
wait_for_board_cards(1, 8)
end
it 'infinite scrolls list with label filter' do
......@@ -487,16 +439,9 @@ describe 'Issue Boards', feature: true, js: true do
create(:labeled_issue, project: project, labels: [planning, testing])
end
page.within '.issues-filters' do
click_button('Label')
wait_for_ajax
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
set_filter("label", testing.title)
click_filter_link(testing.title)
submit_filter
wait_for_vue_resource
......@@ -518,18 +463,13 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'filters by multiple labels' do
page.within '.issues-filters' do
click_button('Label')
wait_for_ajax
set_filter("label", testing.title)
click_filter_link(testing.title)
page.within(find('.dropdown-menu-labels')) do
click_link(testing.title)
wait_for_vue_resource
click_link(bug.title)
wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
set_filter("label", bug.title)
click_filter_link(bug.title)
submit_filter
wait_for_vue_resource
......@@ -545,14 +485,14 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_vue_resource
end
page.within('.tokens-container') do
expect(page).to have_content(bug.title)
end
wait_for_vue_resource
wait_for_board_cards(1, 1)
wait_for_empty_boards((2..3))
page.within('.labels-filter') do
expect(find('.dropdown-toggle-text')).to have_content(bug.title)
end
end
it 'removes label filter by clicking label button on issue' do
......@@ -560,16 +500,13 @@ describe 'Issue Boards', feature: true, js: true do
page.within(find('.card', match: :first)) do
click_button(bug.title)
end
wait_for_vue_resource
expect(page).to have_selector('.card', count: 1)
end
wait_for_vue_resource
page.within('.labels-filter') do
expect(find('.dropdown-toggle-text')).to have_content(bug.title)
end
end
end
end
......@@ -643,4 +580,20 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_board_cards(board, 0)
end
end
def set_filter(type, text)
find('.filtered-search').native.send_keys("#{type}:#{text}")
end
def submit_filter
find('.filtered-search').native.send_keys(:enter)
end
def click_filter_link(link_text)
page.within('.filtered-search-input-container') do
expect(page).to have_button(link_text)
click_button(link_text)
end
end
end
......@@ -176,7 +176,7 @@ describe 'Projects > Issuables > Default sort order', feature: true do
end
def selected_sort_order
find('.pull-right .dropdown button').text.downcase
find('.filter-dropdown-container .dropdown button').text.downcase
end
def visit_merge_requests_with_state(project, state)
......
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