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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
48eca938
Commit
48eca938
authored
May 01, 2017
by
Clement Ho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[skip ci] add multiple assignees to create issue page
parent
89ab47cd
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
115 additions
and
30 deletions
+115
-30
app/assets/javascripts/gl_dropdown.js
app/assets/javascripts/gl_dropdown.js
+4
-0
app/assets/javascripts/users_select.js
app/assets/javascripts/users_select.js
+86
-26
app/helpers/issuables_helper.rb
app/helpers/issuables_helper.rb
+10
-0
app/views/shared/issuable/form/_metadata.html.haml
app/views/shared/issuable/form/_metadata.html.haml
+15
-4
No files found.
app/assets/javascripts/gl_dropdown.js
View file @
48eca938
...
@@ -732,6 +732,10 @@ GitLabDropdown = (function() {
...
@@ -732,6 +732,10 @@ GitLabDropdown = (function() {
$input
.
attr
(
'
id
'
,
this
.
options
.
inputId
);
$input
.
attr
(
'
id
'
,
this
.
options
.
inputId
);
}
}
if
(
this
.
options
.
inputMeta
)
{
$input
.
attr
(
'
data-meta
'
,
selectedObject
[
this
.
options
.
inputMeta
]);
}
return
this
.
dropdown
.
before
(
$input
);
return
this
.
dropdown
.
before
(
$input
);
};
};
...
...
app/assets/javascripts/users_select.js
View file @
48eca938
...
@@ -52,9 +52,8 @@ import eventHub from './sidebar/event_hub';
...
@@ -52,9 +52,8 @@ import eventHub from './sidebar/event_hub';
$collapsedSidebar
=
$block
.
find
(
'
.sidebar-collapsed-user
'
);
$collapsedSidebar
=
$block
.
find
(
'
.sidebar-collapsed-user
'
);
$loading
=
$block
.
find
(
'
.block-loading
'
).
fadeOut
();
$loading
=
$block
.
find
(
'
.block-loading
'
).
fadeOut
();
if
(
$block
[
0
])
{
$block
[
0
].
addEventListener
(
'
assignYourself
'
,
()
=>
{
var
assignYourself
=
function
()
{
// Remove unassigned selected from the DOM
const
unassignedSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
const
unassignedSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
"
input[name='
"
+
(
$dropdown
.
data
(
'
field-name
'
))
+
"
'][value=0]
"
);
.
find
(
"
input[name='
"
+
(
$dropdown
.
data
(
'
field-name
'
))
+
"
'][value=0]
"
);
...
@@ -66,26 +65,73 @@ import eventHub from './sidebar/event_hub';
...
@@ -66,26 +65,73 @@ import eventHub from './sidebar/event_hub';
const
input
=
document
.
createElement
(
'
input
'
);
const
input
=
document
.
createElement
(
'
input
'
);
input
.
type
=
'
hidden
'
;
input
.
type
=
'
hidden
'
;
input
.
name
=
$dropdown
.
data
(
'
field-name
'
);
input
.
name
=
$dropdown
.
data
(
'
field-name
'
);
const
currentUserInfo
=
$dropdown
.
data
(
'
currentUserInfo
'
);
if
(
currentUserInfo
)
{
input
.
value
=
currentUserInfo
.
id
;
input
.
dataset
.
meta
=
currentUserInfo
.
name
;
}
else
if
(
_this
.
currentUser
)
{
input
.
value
=
_this
.
currentUser
.
id
;
input
.
value
=
_this
.
currentUser
.
id
;
}
$dropdown
.
before
(
input
);
$dropdown
.
before
(
input
);
});
}
}
var
getSelected
=
function
()
{
if
(
$block
[
0
])
{
$block
[
0
].
addEventListener
(
'
assignYourself
'
,
assignYourself
);
}
var
getSelectedUserInputs
=
function
()
{
return
$selectbox
return
$selectbox
.
find
(
`input[name="
${
$dropdown
.
data
(
'
field-name
'
)}
"]`
)
.
find
(
`input[name="
${
$dropdown
.
data
(
'
field-name
'
)}
"]`
);
}
var
getSelected
=
function
()
{
return
getSelectedUserInputs
()
.
map
((
index
,
input
)
=>
parseInt
(
input
.
value
,
10
))
.
map
((
index
,
input
)
=>
parseInt
(
input
.
value
,
10
))
.
get
();
.
get
();
};
};
var
getMultiSelectDropdownTitle
=
function
(
selectedUser
,
isSelected
)
{
const
selectedUsers
=
getSelected
()
.
filter
(
u
=>
u
!==
0
);
const
firstUser
=
getSelectedUserInputs
()
.
map
((
index
,
input
)
=>
({
name
:
input
.
dataset
.
meta
,
value
:
parseInt
(
input
.
value
,
10
),
}))
.
filter
(
u
=>
u
.
id
!==
0
)
.
get
(
0
);
if
(
selectedUsers
.
length
===
0
)
{
return
'
Unassigned
'
;
}
else
if
(
selectedUsers
.
length
===
1
)
{
return
firstUser
.
name
;
}
else
if
(
isSelected
)
{
let
otherSelected
=
selectedUsers
.
filter
(
s
=>
s
!==
selectedUser
.
id
);
return
`
${
selectedUser
.
name
}
+
${
otherSelected
.
length
}
more`
;
}
else
{
return
`
${
firstUser
.
name
}
+
${
selectedUsers
.
length
-
1
}
more`
;
}
}
$
(
'
.assign-to-me-link
'
).
on
(
'
click
'
,
(
e
)
=>
{
$
(
'
.assign-to-me-link
'
).
on
(
'
click
'
,
(
e
)
=>
{
e
.
preventDefault
();
e
.
preventDefault
();
$
(
e
.
currentTarget
).
hide
();
$
(
e
.
currentTarget
).
hide
();
if
(
$dropdown
.
data
(
'
multiSelect
'
))
{
assignYourself
();
const
currentUserInfo
=
$dropdown
.
data
(
'
currentUserInfo
'
);
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
text
(
getMultiSelectDropdownTitle
(
currentUserInfo
)).
removeClass
(
'
is-default
'
);
}
else
{
const
$input
=
$
(
`input[name="
${
$dropdown
.
data
(
'
field-name
'
)}
"]`
);
const
$input
=
$
(
`input[name="
${
$dropdown
.
data
(
'
field-name
'
)}
"]`
);
$input
.
val
(
gon
.
current_user_id
);
$input
.
val
(
gon
.
current_user_id
);
selectedId
=
$input
.
val
();
selectedId
=
$input
.
val
();
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
text
(
gon
.
current_user_fullname
).
removeClass
(
'
is-default
'
);
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
text
(
gon
.
current_user_fullname
).
removeClass
(
'
is-default
'
);
}
});
});
$block
.
on
(
'
click
'
,
'
.js-assign-yourself
'
,
(
e
)
=>
{
$block
.
on
(
'
click
'
,
'
.js-assign-yourself
'
,
(
e
)
=>
{
...
@@ -243,6 +289,10 @@ import eventHub from './sidebar/event_hub';
...
@@ -243,6 +289,10 @@ import eventHub from './sidebar/event_hub';
this
.
processData
(
inputValue
,
users
,
callback
);
this
.
processData
(
inputValue
,
users
,
callback
);
}
}
if
(
this
.
multiSelect
)
{
return
getMultiSelectDropdownTitle
(
selected
,
$
(
el
).
hasClass
(
'
is-active
'
));
}
if
(
selected
&&
'
id
'
in
selected
&&
$
(
el
).
hasClass
(
'
is-active
'
))
{
if
(
selected
&&
'
id
'
in
selected
&&
$
(
el
).
hasClass
(
'
is-active
'
))
{
if
(
selected
.
text
)
{
if
(
selected
.
text
)
{
return
selected
.
text
;
return
selected
.
text
;
...
@@ -259,15 +309,19 @@ import eventHub from './sidebar/event_hub';
...
@@ -259,15 +309,19 @@ import eventHub from './sidebar/event_hub';
eventHub
.
$emit
(
'
sidebar.saveAssignees
'
);
eventHub
.
$emit
(
'
sidebar.saveAssignees
'
);
}
}
if
(
!
$dropdown
.
data
(
'
always-show-selectbox
'
))
{
$selectbox
.
hide
();
$selectbox
.
hide
();
// Recalculate where .value is because vue might have changed it
// Recalculate where .value is because vue might have changed it
$block
=
$selectbox
.
closest
(
'
.block
'
);
$block
=
$selectbox
.
closest
(
'
.block
'
);
$value
=
$block
.
find
(
'
.value
'
);
$value
=
$block
.
find
(
'
.value
'
);
// display:block overrides the hide-collapse rule
// display:block overrides the hide-collapse rule
return
$value
.
css
(
'
display
'
,
''
);
$value
.
css
(
'
display
'
,
''
);
}
},
},
multiSelect
:
$dropdown
.
hasClass
(
'
js-multiselect
'
),
multiSelect
:
$dropdown
.
hasClass
(
'
js-multiselect
'
),
inputMeta
:
$dropdown
.
data
(
'
input-meta
'
),
clicked
:
function
(
options
)
{
clicked
:
function
(
options
)
{
const
{
$el
,
e
,
isMarking
}
=
options
;
const
{
$el
,
e
,
isMarking
}
=
options
;
const
user
=
options
.
selectedObj
;
const
user
=
options
.
selectedObj
;
...
@@ -322,6 +376,12 @@ import eventHub from './sidebar/event_hub';
...
@@ -322,6 +376,12 @@ import eventHub from './sidebar/event_hub';
// User unselected
// User unselected
eventHub
.
$emit
(
'
sidebar.removeAssignee
'
,
user
);
eventHub
.
$emit
(
'
sidebar.removeAssignee
'
,
user
);
}
}
if
(
getSelected
().
find
(
u
=>
u
===
gon
.
current_user_id
))
{
$
(
'
.assign-to-me-link
'
).
hide
();
}
else
{
$
(
'
.assign-to-me-link
'
).
show
();
}
}
}
var
isIssueIndex
,
isMRIndex
,
page
,
selected
;
var
isIssueIndex
,
isMRIndex
,
page
,
selected
;
...
...
app/helpers/issuables_helper.rb
View file @
48eca938
...
@@ -63,6 +63,16 @@ module IssuablesHelper
...
@@ -63,6 +63,16 @@ module IssuablesHelper
end
end
end
end
def
users_dropdown_label
(
selected_users
)
if
selected_users
.
length
==
0
"Unassigned"
elsif
selected_users
.
length
==
1
selected_users
[
0
].
name
else
"
#{
selected_users
[
0
].
name
}
+
#{
selected_users
.
length
-
1
}
more"
end
end
def
user_dropdown_label
(
user_id
,
default_label
)
def
user_dropdown_label
(
user_id
,
default_label
)
return
default_label
if
user_id
.
nil?
return
default_label
if
user_id
.
nil?
return
"Unassigned"
if
user_id
==
"0"
return
"Unassigned"
if
user_id
==
"0"
...
...
app/views/shared/issuable/form/_metadata.html.haml
View file @
48eca938
...
@@ -13,11 +13,22 @@
...
@@ -13,11 +13,22 @@
-
if
issuable
.
is_a?
(
Issue
)
-
if
issuable
.
is_a?
(
Issue
)
=
form
.
label
:assignee_ids
,
"Assignee"
,
class:
"control-label
#{
"col-lg-4"
if
has_due_date
}
"
=
form
.
label
:assignee_ids
,
"Assignee"
,
class:
"control-label
#{
"col-lg-4"
if
has_due_date
}
"
.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
.issuable-form-select-holder.selectbox
=
form
.
hidden_field
:assignee_ids
-
issuable
.
assignees
.
each
do
|
assignee
|
=
hidden_field_tag
"
#{
issuable
.
to_ability_name
}
[assignee_ids][]"
,
assignee
.
id
,
id:
nil
,
data:
{
meta:
assignee
.
name
}
-
options
=
{
toggle_class:
"js-user-search js-author-search"
,
title:
'Select assignee'
,
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
),
null_user:
true
,
current_user:
true
,
project_id:
issuable
.
project
.
try
(
:id
),
field_name:
"
#{
issuable
.
class
.
model_name
.
param_key
}
[assignee_ids][]"
,
default_label:
"Assignee"
}
}
-
options
[
:toggle_class
]
+=
' js-multiselect js-save-user-data'
-
options
[
:title
]
=
'Select assignee(s)'
-
options
[
:data
][
:multi_select
]
=
true
-
options
[
:data
][
'input-meta'
]
=
'name'
-
options
[
:data
][
'dropdown-header'
]
=
'Assignee(s)'
-
options
[
:data
][
'always-show-selectbox'
]
=
true
-
options
[
:data
][
:current_user_info
]
=
current_user
.
to_json
(
only:
[
:id
,
:name
])
=
dropdown_tag
(
user_dropdown_label
(
issuable
.
assignee_ids
,
"Assignee"
),
options:
{
toggle_class:
"js-dropdown-keep-input js-user-search js-issuable-form-dropdown js-assignee-search"
,
title:
"Select assignee"
,
filter:
true
,
dropdown_class:
"dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit"
,
=
dropdown_tag
(
users_dropdown_label
(
issuable
.
assignees
),
options:
options
)
placeholder:
"Search assignee"
,
data:
{
first_user:
current_user
.
try
(
:username
),
null_user:
true
,
current_user:
true
,
project_id:
issuable
.
project
.
try
(
:id
),
selected:
issuable
.
assignee_ids
,
field_name:
"
#{
issuable
.
class
.
model_name
.
param_key
}
[assignee_ids]"
,
default_label:
"Assignee"
}
})
=
link_to
'Assign to me'
,
'#'
,
class:
"assign-to-me-link
#{
'hide'
if
issuable
.
assignee_ids
.
split
(
', '
).
include?
(
current_user
.
id
)
}
"
=
link_to
'Assign to me'
,
'#'
,
class:
"assign-to-me-link
#{
'hide'
if
issuable
.
assignee_ids
.
split
(
', '
).
include?
(
current_user
.
id
)
}
"
-
else
-
else
=
form
.
label
:assignee_id
,
"Assignee"
,
class:
"control-label
#{
"col-lg-4"
if
has_due_date
}
"
=
form
.
label
:assignee_id
,
"Assignee"
,
class:
"control-label
#{
"col-lg-4"
if
has_due_date
}
"
...
...
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