Merge branch 'issue-boards-search' into 'master'
Added search for all lists on issue boards ## What does this MR do? Adds a search box to allow the user to search all lists in issue boards rather than just the backlog. ## Screenshots (if relevant) ![Screen_Shot_2016-08-30_at_10.33.15](/uploads/67e96055d60a9b3209ce3831a1980c09/Screen_Shot_2016-08-30_at_10.33.15.png) ![Screen_Shot_2016-08-30_at_10.33.19](/uploads/8d5253b8f2ecf1cf9a69d70be8ccf1f9/Screen_Shot_2016-08-30_at_10.33.19.png) ## What are the relevant issue numbers? Closes #21139 See merge request !6101
This commit is contained in:
commit
d2e0f9db75
10 changed files with 71 additions and 104 deletions
|
@ -21,6 +21,7 @@ v 8.12.0 (unreleased)
|
|||
- Add Sentry logging to API calls
|
||||
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
|
||||
- Remove unused mixins (ClemMakesApps)
|
||||
- Add search to all issue board lists
|
||||
- Fix groups sort dropdown alignment (ClemMakesApps)
|
||||
- Add horizontal scrolling to all sub-navs on mobile viewports (ClemMakesApps)
|
||||
- Fix markdown help references (ClemMakesApps)
|
||||
|
|
|
@ -54,4 +54,11 @@ $(() => {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
gl.IssueBoardsSearch = new Vue({
|
||||
el: '#js-boards-seach',
|
||||
data: {
|
||||
filters: Store.state.filters
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,15 +21,10 @@
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
query: '',
|
||||
filters: Store.state.filters
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
query () {
|
||||
this.list.filters = this.getFilterData();
|
||||
this.list.getIssues(true);
|
||||
},
|
||||
filters: {
|
||||
handler () {
|
||||
this.list.page = 1;
|
||||
|
@ -38,16 +33,6 @@
|
|||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getFilterData () {
|
||||
const filters = this.filters;
|
||||
let queryData = { search: this.query };
|
||||
|
||||
Object.keys(filters).forEach((key) => { queryData[key] = filters[key]; });
|
||||
|
||||
return queryData;
|
||||
}
|
||||
},
|
||||
ready () {
|
||||
const options = gl.issueBoards.getBoardSortableDefaultOptions({
|
||||
disabled: this.disabled,
|
||||
|
|
|
@ -58,10 +58,6 @@ class List {
|
|||
}
|
||||
}
|
||||
|
||||
canSearch () {
|
||||
return this.type === 'backlog';
|
||||
}
|
||||
|
||||
getIssues (emptyIssues = true) {
|
||||
const filters = this.filters;
|
||||
let data = { page: this.page };
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
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[]')
|
||||
label_name: gl.utils.getParameterValues('label_name[]'),
|
||||
search: ''
|
||||
};
|
||||
},
|
||||
addList (listObj) {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
.is-dragging {
|
||||
// Important because plugin sets inline CSS
|
||||
opacity: 1!important;
|
||||
|
||||
|
||||
* {
|
||||
// !important to make sure no style can override this when dragging
|
||||
cursor: -webkit-grabbing!important;
|
||||
|
@ -160,40 +160,6 @@
|
|||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.board-search-container {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
|
||||
.form-control {
|
||||
padding-right: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.board-search-icon,
|
||||
.board-search-clear-btn {
|
||||
position: absolute;
|
||||
right: $gl-padding + 10px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.board-search-icon {
|
||||
color: $gl-placeholder-color;
|
||||
}
|
||||
|
||||
.board-search-clear-btn {
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
||||
&:hover {
|
||||
color: $gl-link-color;
|
||||
}
|
||||
}
|
||||
|
||||
.board-delete {
|
||||
margin-right: 10px;
|
||||
padding: 0;
|
||||
|
@ -304,3 +270,12 @@
|
|||
margin-right: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.issue-boards-search {
|
||||
width: 335px;
|
||||
|
||||
.form-control {
|
||||
display: inline-block;
|
||||
width: 210px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@
|
|||
%button.board-delete.has-tooltip.pull-right{ type: "button", title: "Delete list", "aria-label" => "Delete list", data: { placement: "bottom" }, "@click.stop" => "deleteBoard" }
|
||||
= icon("trash")
|
||||
= icon("spinner spin", class: "board-header-loading-spinner pull-right", "v-show" => "list.loadingMore")
|
||||
.board-inner-container.board-search-container{ "v-if" => "list.canSearch()" }
|
||||
%input.form-control{ type: "text", placeholder: "Search issues", "v-model" => "query", "debounce" => "250" }
|
||||
= icon("search", class: "board-search-icon", "v-show" => "!query")
|
||||
%button.board-search-clear-btn{ type: "button", role: "button", "aria-label" => "Clear search", "@click" => "query = ''", "v-show" => "query" }
|
||||
= icon("times", class: "board-search-clear")
|
||||
%board-list{ "inline-template" => true,
|
||||
"v-if" => "list.type !== 'blank'",
|
||||
":list" => "list",
|
||||
|
|
|
@ -27,15 +27,18 @@
|
|||
= render "shared/issuable/label_dropdown"
|
||||
|
||||
.pull-right
|
||||
- if controller.controller_name == 'boards' && can?(current_user, :admin_list, @project)
|
||||
.dropdown
|
||||
%button.btn.btn-create.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, project_id: @project.try(:id) } }
|
||||
Create new 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: "Create a new list" }
|
||||
- if can?(current_user, :admin_label, @project)
|
||||
= render partial: "shared/issuable/label_page_create"
|
||||
= dropdown_loading
|
||||
- if controller.controller_name == 'boards'
|
||||
#js-boards-seach.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)
|
||||
.dropdown.pull-right
|
||||
%button.btn.btn-create.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, project_id: @project.try(:id) } }
|
||||
Create new 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: "Create a new list" }
|
||||
- if can?(current_user, :admin_label, @project)
|
||||
= render partial: "shared/issuable/label_page_create"
|
||||
= dropdown_loading
|
||||
- else
|
||||
= render 'shared/sort_dropdown'
|
||||
|
||||
|
|
|
@ -110,6 +110,45 @@ describe 'Issue Boards', feature: true, js: true do
|
|||
end
|
||||
end
|
||||
|
||||
it 'search backlog list' do
|
||||
page.within('#js-boards-seach') do
|
||||
find('.form-control').set(issue1.title)
|
||||
end
|
||||
|
||||
wait_for_vue_resource
|
||||
|
||||
expect(find('.board:nth-child(1)')).to have_selector('.card', count: 1)
|
||||
expect(find('.board:nth-child(2)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(4)')).to have_selector('.card', count: 0)
|
||||
end
|
||||
|
||||
it 'search done list' do
|
||||
page.within('#js-boards-seach') do
|
||||
find('.form-control').set(issue8.title)
|
||||
end
|
||||
|
||||
wait_for_vue_resource
|
||||
|
||||
expect(find('.board:nth-child(1)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(2)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(4)')).to have_selector('.card', count: 1)
|
||||
end
|
||||
|
||||
it 'search list' do
|
||||
page.within('#js-boards-seach') do
|
||||
find('.form-control').set(issue5.title)
|
||||
end
|
||||
|
||||
wait_for_vue_resource
|
||||
|
||||
expect(find('.board:nth-child(1)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(2)')).to have_selector('.card', count: 1)
|
||||
expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0)
|
||||
expect(find('.board:nth-child(4)')).to have_selector('.card', count: 0)
|
||||
end
|
||||
|
||||
it 'allows user to delete board' do
|
||||
page.within(find('.board:nth-child(2)')) do
|
||||
find('.board-delete').click
|
||||
|
@ -162,32 +201,6 @@ describe 'Issue Boards', feature: true, js: true do
|
|||
end
|
||||
end
|
||||
|
||||
it 'is searchable' do
|
||||
page.within(find('.board', match: :first)) do
|
||||
find('.form-control').set issue1.title
|
||||
|
||||
wait_for_vue_resource(spinner: false)
|
||||
|
||||
expect(page).to have_selector('.card', count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
it 'clears search' do
|
||||
page.within(find('.board', match: :first)) do
|
||||
find('.form-control').set issue1.title
|
||||
|
||||
expect(page).to have_selector('.card', count: 1)
|
||||
|
||||
find('.board-search-clear-btn').click
|
||||
end
|
||||
|
||||
wait_for_vue_resource
|
||||
|
||||
page.within(find('.board', match: :first)) do
|
||||
expect(page).to have_selector('.card', count: 6)
|
||||
end
|
||||
end
|
||||
|
||||
it 'moves issue from backlog into list' do
|
||||
drag_to(list_to_index: 1)
|
||||
|
||||
|
|
|
@ -60,15 +60,6 @@ describe('List model', () => {
|
|||
}, 0);
|
||||
});
|
||||
|
||||
it('can\'t search when not backlog', () => {
|
||||
expect(list.canSearch()).toBe(false);
|
||||
});
|
||||
|
||||
it('can search when backlog', () => {
|
||||
list.type = 'backlog';
|
||||
expect(list.canSearch()).toBe(true);
|
||||
});
|
||||
|
||||
it('gets issue from list', (done) => {
|
||||
setTimeout(() => {
|
||||
const issue = list.findIssue(1);
|
||||
|
|
Loading…
Reference in a new issue