summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClement Ho <ClemMakesApps@gmail.com>2017-05-26 16:27:30 -0500
committerClement Ho <ClemMakesApps@gmail.com>2017-05-26 16:27:30 -0500
commit7997bbbfef61b65be5548582dc6b50db52ddce55 (patch)
tree0082d719999e432d777fb9a98f385dded966ead2
parent7911f1c0877247f943d2c5dc1cb26de19fe69c8c (diff)
downloadgitlab-ce-7997bbbfef61b65be5548582dc6b50db52ddce55.tar.gz
Backport MR from EE
-rw-r--r--app/assets/javascripts/gl_dropdown.js10
-rw-r--r--app/assets/javascripts/users_select.js34
-rw-r--r--app/controllers/autocomplete_controller.rb2
-rw-r--r--app/views/projects/boards/components/sidebar/_assignee.html.haml5
-rw-r--r--app/views/shared/issuable/_sidebar_assignees.html.haml2
-rw-r--r--app/views/shared/issuable/form/_metadata_issue_assignee.html.haml2
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb14
-rw-r--r--spec/features/issues/form_spec.rb62
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb17
9 files changed, 140 insertions, 8 deletions
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index 24c423dd01e..d34561e5512 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -468,8 +468,8 @@ GitLabDropdown = (function() {
// Process the data to make sure rendered data
// matches the correct layout
- if (this.fullData && hasMultiSelect && this.options.processData) {
- const inputValue = this.filterInput.val();
+ const inputValue = this.filterInput.val();
+ if (this.fullData && hasMultiSelect && this.options.processData && inputValue.length === 0) {
this.options.processData.call(this.options, inputValue, this.filteredFullData(), this.parseData.bind(this));
}
@@ -740,6 +740,12 @@ GitLabDropdown = (function() {
$input.attr('id', this.options.inputId);
}
+ if (this.options.multiSelect) {
+ Object.keys(selectedObject).forEach((attribute) => {
+ $input.attr(`data-${attribute}`, selectedObject[attribute]);
+ });
+ }
+
if (this.options.inputMeta) {
$input.attr('data-meta', selectedObject[this.options.inputMeta]);
}
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index aea3592c6ba..ec45253e50b 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -35,6 +35,7 @@ function UsersSelect(currentUser, els) {
options.showCurrentUser = $dropdown.data('current-user');
options.todoFilter = $dropdown.data('todo-filter');
options.todoStateFilter = $dropdown.data('todo-state-filter');
+ options.perPage = $dropdown.data('per-page');
showNullUser = $dropdown.data('null-user');
defaultNullUser = $dropdown.data('null-user-default');
showMenuAbove = $dropdown.data('showMenuAbove');
@@ -214,7 +215,36 @@ function UsersSelect(currentUser, els) {
glDropdown.options.processData(term, users, callback);
}.bind(this));
},
- processData: function(term, users, callback) {
+ processData: function(term, data, callback) {
+ let users = data;
+
+ // Only show assigned user list when there is no search term
+ if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
+ const selectedInputs = getSelectedUserInputs();
+
+ // Potential duplicate entries when dealing with issue board
+ // because issue board is also managed by vue
+ const selectedUsers = _.uniq(selectedInputs, false, a => a.value)
+ .filter((input) => {
+ const userId = parseInt(input.value, 10);
+ const inUsersArray = users.find(u => u.id === userId);
+
+ return !inUsersArray && userId !== 0;
+ })
+ .map((input) => {
+ const userId = parseInt(input.value, 10);
+ const { avatarUrl, avatar_url, name, username } = input.dataset;
+ return {
+ avatar_url: avatarUrl || avatar_url,
+ id: userId,
+ name,
+ username,
+ };
+ });
+
+ users = data.concat(selectedUsers);
+ }
+
let anyUser;
let index;
let j;
@@ -645,7 +675,7 @@ UsersSelect.prototype.users = function(query, options, callback) {
url: url,
data: {
search: query,
- per_page: 20,
+ per_page: options.perPage || 20,
active: true,
project_id: options.projectId || null,
group_id: options.groupId || null,
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index e2f5aa8508e..907717dcb96 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -9,7 +9,7 @@ class AutocompleteController < ApplicationController
@users = @users.where.not(id: params[:skip_users]) if params[:skip_users].present?
@users = @users.active
@users = @users.reorder(:name)
- @users = @users.page(params[:page])
+ @users = @users.page(params[:page]).per(params[:per_page])
if params[:todo_filter].present? && current_user
@users = @users.todo_authors(current_user.id, params[:todo_state_filter])
diff --git a/app/views/projects/boards/components/sidebar/_assignee.html.haml b/app/views/projects/boards/components/sidebar/_assignee.html.haml
index 48f8c656080..e8db868f49b 100644
--- a/app/views/projects/boards/components/sidebar/_assignee.html.haml
+++ b/app/views/projects/boards/components/sidebar/_assignee.html.haml
@@ -14,7 +14,10 @@
name: "issue[assignee_ids][]",
":value" => "assignee.id",
"v-if" => "issue.assignees",
- "v-for" => "assignee in issue.assignees" }
+ "v-for" => "assignee in issue.assignees",
+ ":data-avatar_url" => "assignee.avatar",
+ ":data-name" => "assignee.name",
+ ":data-username" => "assignee.username" }
.dropdown
%button.dropdown-menu-toggle.js-user-search.js-author-search.js-multiselect.js-save-user-data.js-issue-board-sidebar{ type: "button", ref: "assigneeDropdown", data: { toggle: "dropdown", field_name: "issue[assignee_ids][]", first_user: (current_user.username if current_user), current_user: "true", project_id: @project.id, null_user: "true", multi_select: "true", 'max-select' => 1, dropdown: { header: 'Assignee' } },
":data-issuable-id" => "issue.id",
diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml
index 26567c08eb6..bcfa1dc826e 100644
--- a/app/views/shared/issuable/_sidebar_assignees.html.haml
+++ b/app/views/shared/issuable/_sidebar_assignees.html.haml
@@ -32,7 +32,7 @@
.selectbox.hide-collapsed
- issuable.assignees.each do |assignee|
- = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil
+ = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
- options = { toggle_class: 'js-user-search js-author-search', title: 'Assign to', filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: 'Search users', data: { first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true } }
diff --git a/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml b/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml
index 8119f19291b..77175c839a6 100644
--- a/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml
+++ b/app/views/shared/issuable/form/_metadata_issue_assignee.html.haml
@@ -2,7 +2,7 @@
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder.selectbox
- issuable.assignees.each do |assignee|
- = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { meta: assignee.name }
+ = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { meta: assignee.name, avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
- if issuable.assignees.length === 0
= hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil, data: { meta: '' }
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index 7d2f6dd9d0a..412d3643e94 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -97,6 +97,20 @@ describe AutocompleteController do
it { expect(body.size).to eq User.count }
end
+ context 'limited users per page' do
+ let(:per_page) { 2 }
+
+ before do
+ sign_in(user)
+ get(:users, per_page: per_page)
+ end
+
+ let(:body) { JSON.parse(response.body) }
+
+ it { expect(body).to be_kind_of(Array) }
+ it { expect(body.size).to eq per_page }
+ end
+
context 'unauthenticated user' do
let(:public_project) { create(:project, :public) }
let(:body) { JSON.parse(response.body) }
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 009b3bc8bf6..32478155720 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -3,6 +3,7 @@ require 'rails_helper'
describe 'New/edit issue', :feature, :js do
include GitlabRoutingHelper
include ActionView::Helpers::JavaScriptHelper
+ include FormHelper
let!(:project) { create(:project) }
let!(:user) { create(:user)}
@@ -23,6 +24,67 @@ describe 'New/edit issue', :feature, :js do
visit new_namespace_project_issue_path(project.namespace, project)
end
+ describe 'shorten users API pagination limit' do
+ before do
+ allow_any_instance_of(FormHelper).to receive(:issue_dropdown_options).and_wrap_original do |original, *args|
+ issuable = *args[0]
+ has_multiple_assignees = *args[1]
+
+ options = {
+ toggle_class: 'js-user-search js-assignee-search js-multiselect js-save-user-data',
+ title: 'Select assignee',
+ filter: true,
+ dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee',
+ placeholder: 'Search users',
+ data: {
+ per_page: 1,
+ null_user: true,
+ current_user: true,
+ project_id: project.try(:id),
+ field_name: "issue[assignee_ids][]",
+ default_label: 'Assignee',
+ 'max-select': 1,
+ 'dropdown-header': 'Assignee',
+ multi_select: true,
+ 'input-meta': 'name',
+ 'always-show-selectbox': true,
+ }
+ }
+
+
+ if has_multiple_assignees
+ options[:title] = 'Select assignee(s)'
+ options[:data][:'dropdown-header'] = 'Assignee(s)'
+ options[:data].delete(:'max-select')
+ end
+
+ options
+ end
+
+ visit new_namespace_project_issue_path(project.namespace, project)
+
+ click_button 'Unassigned'
+
+ wait_for_requests
+ end
+
+ it 'should display selected users even if they are not part of the original API call' do
+ find('.dropdown-input-field').native.send_keys user2.name
+
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_content user2.name
+ click_link user2.name
+ end
+
+ find('.js-dropdown-input-clear').click
+
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_content user.name
+ expect(find('.dropdown-menu-user a.is-active').first(:xpath, '..')['data-user-id']).to eq(user2.id.to_s)
+ end
+ end
+ end
+
describe 'single assignee' do
before do
click_button 'Unassigned'
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index 99ad8013023..96c24750250 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -57,6 +57,23 @@ feature 'Issue Sidebar', feature: true do
expect(page.find('.dropdown-menu-user-link.is-active')).to have_content(user.name)
end
end
+
+ it 'keeps your filtered term after filtering and dismissing the dropdown' do
+ find('.dropdown-input-field').native.send_keys user2.name
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ expect(page).not_to have_content 'Unassigned'
+ click_link user2.name
+ end
+
+ find('.js-right-sidebar').click
+ find('.block.assignee .edit-link').click
+
+ expect(page.all('.dropdown-menu-user li').length).to eq(1)
+ expect(find('.dropdown-input-field').value).to eq(user2.name)
+ end
end
context 'as a allowed user' do