Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
7997bbbf
Commit
7997bbbf
authored
May 26, 2017
by
Clement Ho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Backport MR from EE
parent
7911f1c0
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
140 additions
and
8 deletions
+140
-8
app/assets/javascripts/gl_dropdown.js
app/assets/javascripts/gl_dropdown.js
+8
-2
app/assets/javascripts/users_select.js
app/assets/javascripts/users_select.js
+32
-2
app/controllers/autocomplete_controller.rb
app/controllers/autocomplete_controller.rb
+1
-1
app/views/projects/boards/components/sidebar/_assignee.html.haml
...ws/projects/boards/components/sidebar/_assignee.html.haml
+4
-1
app/views/shared/issuable/_sidebar_assignees.html.haml
app/views/shared/issuable/_sidebar_assignees.html.haml
+1
-1
app/views/shared/issuable/form/_metadata_issue_assignee.html.haml
...s/shared/issuable/form/_metadata_issue_assignee.html.haml
+1
-1
spec/controllers/autocomplete_controller_spec.rb
spec/controllers/autocomplete_controller_spec.rb
+14
-0
spec/features/issues/form_spec.rb
spec/features/issues/form_spec.rb
+62
-0
spec/features/issues/issue_sidebar_spec.rb
spec/features/issues/issue_sidebar_spec.rb
+17
-0
No files found.
app/assets/javascripts/gl_dropdown.js
View file @
7997bbbf
...
@@ -468,8 +468,8 @@ GitLabDropdown = (function() {
...
@@ -468,8 +468,8 @@ GitLabDropdown = (function() {
// Process the data to make sure rendered data
// Process the data to make sure rendered data
// matches the correct layout
// 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
));
this
.
options
.
processData
.
call
(
this
.
options
,
inputValue
,
this
.
filteredFullData
(),
this
.
parseData
.
bind
(
this
));
}
}
...
@@ -740,6 +740,12 @@ GitLabDropdown = (function() {
...
@@ -740,6 +740,12 @@ GitLabDropdown = (function() {
$input
.
attr
(
'
id
'
,
this
.
options
.
inputId
);
$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
)
{
if
(
this
.
options
.
inputMeta
)
{
$input
.
attr
(
'
data-meta
'
,
selectedObject
[
this
.
options
.
inputMeta
]);
$input
.
attr
(
'
data-meta
'
,
selectedObject
[
this
.
options
.
inputMeta
]);
}
}
...
...
app/assets/javascripts/users_select.js
View file @
7997bbbf
...
@@ -35,6 +35,7 @@ function UsersSelect(currentUser, els) {
...
@@ -35,6 +35,7 @@ function UsersSelect(currentUser, els) {
options
.
showCurrentUser
=
$dropdown
.
data
(
'
current-user
'
);
options
.
showCurrentUser
=
$dropdown
.
data
(
'
current-user
'
);
options
.
todoFilter
=
$dropdown
.
data
(
'
todo-filter
'
);
options
.
todoFilter
=
$dropdown
.
data
(
'
todo-filter
'
);
options
.
todoStateFilter
=
$dropdown
.
data
(
'
todo-state-filter
'
);
options
.
todoStateFilter
=
$dropdown
.
data
(
'
todo-state-filter
'
);
options
.
perPage
=
$dropdown
.
data
(
'
per-page
'
);
showNullUser
=
$dropdown
.
data
(
'
null-user
'
);
showNullUser
=
$dropdown
.
data
(
'
null-user
'
);
defaultNullUser
=
$dropdown
.
data
(
'
null-user-default
'
);
defaultNullUser
=
$dropdown
.
data
(
'
null-user-default
'
);
showMenuAbove
=
$dropdown
.
data
(
'
showMenuAbove
'
);
showMenuAbove
=
$dropdown
.
data
(
'
showMenuAbove
'
);
...
@@ -214,7 +215,36 @@ function UsersSelect(currentUser, els) {
...
@@ -214,7 +215,36 @@ function UsersSelect(currentUser, els) {
glDropdown
.
options
.
processData
(
term
,
users
,
callback
);
glDropdown
.
options
.
processData
(
term
,
users
,
callback
);
}.
bind
(
this
));
}.
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
anyUser
;
let
index
;
let
index
;
let
j
;
let
j
;
...
@@ -645,7 +675,7 @@ UsersSelect.prototype.users = function(query, options, callback) {
...
@@ -645,7 +675,7 @@ UsersSelect.prototype.users = function(query, options, callback) {
url
:
url
,
url
:
url
,
data
:
{
data
:
{
search
:
query
,
search
:
query
,
per_page
:
20
,
per_page
:
options
.
perPage
||
20
,
active
:
true
,
active
:
true
,
project_id
:
options
.
projectId
||
null
,
project_id
:
options
.
projectId
||
null
,
group_id
:
options
.
groupId
||
null
,
group_id
:
options
.
groupId
||
null
,
...
...
app/controllers/autocomplete_controller.rb
View file @
7997bbbf
...
@@ -9,7 +9,7 @@ class AutocompleteController < ApplicationController
...
@@ -9,7 +9,7 @@ class AutocompleteController < ApplicationController
@users
=
@users
.
where
.
not
(
id:
params
[
:skip_users
])
if
params
[
:skip_users
].
present?
@users
=
@users
.
where
.
not
(
id:
params
[
:skip_users
])
if
params
[
:skip_users
].
present?
@users
=
@users
.
active
@users
=
@users
.
active
@users
=
@users
.
reorder
(
:name
)
@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
if
params
[
:todo_filter
].
present?
&&
current_user
@users
=
@users
.
todo_authors
(
current_user
.
id
,
params
[
:todo_state_filter
])
@users
=
@users
.
todo_authors
(
current_user
.
id
,
params
[
:todo_state_filter
])
...
...
app/views/projects/boards/components/sidebar/_assignee.html.haml
View file @
7997bbbf
...
@@ -14,7 +14,10 @@
...
@@ -14,7 +14,10 @@
name:
"issue[assignee_ids][]"
,
name:
"issue[assignee_ids][]"
,
":value"
=>
"assignee.id"
,
":value"
=>
"assignee.id"
,
"v-if"
=>
"issue.assignees"
,
"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
.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'
}
},
%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"
,
":data-issuable-id"
=>
"issue.id"
,
...
...
app/views/shared/issuable/_sidebar_assignees.html.haml
View file @
7997bbbf
...
@@ -32,7 +32,7 @@
...
@@ -32,7 +32,7 @@
.selectbox.hide-collapsed
.selectbox.hide-collapsed
-
issuable
.
assignees
.
each
do
|
assignee
|
-
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
}
}
-
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
}
}
...
...
app/views/shared/issuable/form/_metadata_issue_assignee.html.haml
View file @
7997bbbf
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
.col-sm-10
{
class:
(
"col-lg-8"
if
has_due_date
)
}
.col-sm-10
{
class:
(
"col-lg-8"
if
has_due_date
)
}
.issuable-form-select-holder.selectbox
.issuable-form-select-holder.selectbox
-
issuable
.
assignees
.
each
do
|
assignee
|
-
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
-
if
issuable
.
assignees
.
length
===
0
=
hidden_field_tag
"
#{
issuable
.
to_ability_name
}
[assignee_ids][]"
,
0
,
id:
nil
,
data:
{
meta:
''
}
=
hidden_field_tag
"
#{
issuable
.
to_ability_name
}
[assignee_ids][]"
,
0
,
id:
nil
,
data:
{
meta:
''
}
...
...
spec/controllers/autocomplete_controller_spec.rb
View file @
7997bbbf
...
@@ -97,6 +97,20 @@ describe AutocompleteController do
...
@@ -97,6 +97,20 @@ describe AutocompleteController do
it
{
expect
(
body
.
size
).
to
eq
User
.
count
}
it
{
expect
(
body
.
size
).
to
eq
User
.
count
}
end
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
context
'unauthenticated user'
do
let
(
:public_project
)
{
create
(
:project
,
:public
)
}
let
(
:public_project
)
{
create
(
:project
,
:public
)
}
let
(
:body
)
{
JSON
.
parse
(
response
.
body
)
}
let
(
:body
)
{
JSON
.
parse
(
response
.
body
)
}
...
...
spec/features/issues/form_spec.rb
View file @
7997bbbf
...
@@ -3,6 +3,7 @@ require 'rails_helper'
...
@@ -3,6 +3,7 @@ require 'rails_helper'
describe
'New/edit issue'
,
:feature
,
:js
do
describe
'New/edit issue'
,
:feature
,
:js
do
include
GitlabRoutingHelper
include
GitlabRoutingHelper
include
ActionView
::
Helpers
::
JavaScriptHelper
include
ActionView
::
Helpers
::
JavaScriptHelper
include
FormHelper
let!
(
:project
)
{
create
(
:project
)
}
let!
(
:project
)
{
create
(
:project
)
}
let!
(
:user
)
{
create
(
:user
)}
let!
(
:user
)
{
create
(
:user
)}
...
@@ -23,6 +24,67 @@ describe 'New/edit issue', :feature, :js do
...
@@ -23,6 +24,67 @@ describe 'New/edit issue', :feature, :js do
visit
new_namespace_project_issue_path
(
project
.
namespace
,
project
)
visit
new_namespace_project_issue_path
(
project
.
namespace
,
project
)
end
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
describe
'single assignee'
do
before
do
before
do
click_button
'Unassigned'
click_button
'Unassigned'
...
...
spec/features/issues/issue_sidebar_spec.rb
View file @
7997bbbf
...
@@ -57,6 +57,23 @@ feature 'Issue Sidebar', feature: true do
...
@@ -57,6 +57,23 @@ feature 'Issue Sidebar', feature: true do
expect
(
page
.
find
(
'.dropdown-menu-user-link.is-active'
)).
to
have_content
(
user
.
name
)
expect
(
page
.
find
(
'.dropdown-menu-user-link.is-active'
)).
to
have_content
(
user
.
name
)
end
end
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
end
context
'as a allowed user'
do
context
'as a allowed user'
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment