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
Léo-Paul Géneau
gitlab-ce
Commits
dad534d9
Commit
dad534d9
authored
Dec 18, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
2a65a97e
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
588 additions
and
598 deletions
+588
-598
app/assets/javascripts/jobs/components/log/log.vue
app/assets/javascripts/jobs/components/log/log.vue
+1
-1
app/assets/javascripts/users_select.js
app/assets/javascripts/users_select.js
+563
-576
changelogs/unreleased/34625-Remove-IIFEs-from-users_select-js.yml
...gs/unreleased/34625-Remove-IIFEs-from-users_select-js.yml
+5
-0
doc/ci/multi_project_pipelines.md
doc/ci/multi_project_pipelines.md
+1
-0
qa/qa/page/project/job/show.rb
qa/qa/page/project/job/show.rb
+4
-4
qa/qa/resource/merge_request.rb
qa/qa/resource/merge_request.rb
+1
-1
qa/qa/resource/merge_request_from_fork.rb
qa/qa/resource/merge_request_from_fork.rb
+3
-1
qa/qa/resource/protected_branch.rb
qa/qa/resource/protected_branch.rb
+3
-1
qa/qa/resource/repository/project_push.rb
qa/qa/resource/repository/project_push.rb
+3
-1
qa/qa/resource/repository/push.rb
qa/qa/resource/repository/push.rb
+2
-1
qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
...reate/merge_request/view_merge_request_diff_patch_spec.rb
+2
-7
qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
...er_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
+0
-5
No files found.
app/assets/javascripts/jobs/components/log/log.vue
View file @
dad534d9
...
...
@@ -49,7 +49,7 @@ export default {
};
</
script
>
<
template
>
<code
class=
"job-log d-block"
>
<code
class=
"job-log d-block"
data-qa-selector=
"job_log_content"
>
<template
v-for=
"(section, index) in trace"
>
<collpasible-log-section
v-if=
"section.isHeader"
...
...
app/assets/javascripts/users_select.js
View file @
dad534d9
...
...
@@ -27,633 +27,620 @@ function UsersSelect(currentUser, els, options = {}) {
}
const
{
handleClick
}
=
options
;
const
userSelect
=
this
;
$els
.
each
((
i
,
dropdown
)
=>
{
const
userSelect
=
this
;
const
options
=
{};
const
$dropdown
=
$
(
dropdown
);
options
.
projectId
=
$dropdown
.
data
(
'
projectId
'
);
options
.
groupId
=
$dropdown
.
data
(
'
groupId
'
);
options
.
showCurrentUser
=
$dropdown
.
data
(
'
currentUser
'
);
options
.
todoFilter
=
$dropdown
.
data
(
'
todoFilter
'
);
options
.
todoStateFilter
=
$dropdown
.
data
(
'
todoStateFilter
'
);
options
.
iid
=
$dropdown
.
data
(
'
iid
'
);
options
.
issuableType
=
$dropdown
.
data
(
'
issuableType
'
);
const
showNullUser
=
$dropdown
.
data
(
'
nullUser
'
);
const
defaultNullUser
=
$dropdown
.
data
(
'
nullUserDefault
'
);
const
showMenuAbove
=
$dropdown
.
data
(
'
showMenuAbove
'
);
const
showAnyUser
=
$dropdown
.
data
(
'
anyUser
'
);
const
firstUser
=
$dropdown
.
data
(
'
firstUser
'
);
options
.
authorId
=
$dropdown
.
data
(
'
authorId
'
);
const
defaultLabel
=
$dropdown
.
data
(
'
defaultLabel
'
);
const
issueURL
=
$dropdown
.
data
(
'
issueUpdate
'
);
const
$selectbox
=
$dropdown
.
closest
(
'
.selectbox
'
);
let
$block
=
$selectbox
.
closest
(
'
.block
'
);
const
abilityName
=
$dropdown
.
data
(
'
abilityName
'
);
let
$value
=
$block
.
find
(
'
.value
'
);
const
$collapsedSidebar
=
$block
.
find
(
'
.sidebar-collapsed-user
'
);
const
$loading
=
$block
.
find
(
'
.block-loading
'
).
fadeOut
();
const
selectedIdDefault
=
defaultNullUser
&&
showNullUser
?
0
:
null
;
let
selectedId
=
$dropdown
.
data
(
'
selected
'
);
let
assignTo
;
let
assigneeTemplate
;
let
collapsedAssigneeTemplate
;
if
(
selectedId
===
undefined
)
{
selectedId
=
selectedIdDefault
;
}
$els
.
each
(
(
function
(
_this
)
{
return
function
(
i
,
dropdown
)
{
const
options
=
{};
const
$dropdown
=
$
(
dropdown
);
options
.
projectId
=
$dropdown
.
data
(
'
projectId
'
);
options
.
groupId
=
$dropdown
.
data
(
'
groupId
'
);
options
.
showCurrentUser
=
$dropdown
.
data
(
'
currentUser
'
);
options
.
todoFilter
=
$dropdown
.
data
(
'
todoFilter
'
);
options
.
todoStateFilter
=
$dropdown
.
data
(
'
todoStateFilter
'
);
options
.
iid
=
$dropdown
.
data
(
'
iid
'
);
options
.
issuableType
=
$dropdown
.
data
(
'
issuableType
'
);
const
showNullUser
=
$dropdown
.
data
(
'
nullUser
'
);
const
defaultNullUser
=
$dropdown
.
data
(
'
nullUserDefault
'
);
const
showMenuAbove
=
$dropdown
.
data
(
'
showMenuAbove
'
);
const
showAnyUser
=
$dropdown
.
data
(
'
anyUser
'
);
const
firstUser
=
$dropdown
.
data
(
'
firstUser
'
);
options
.
authorId
=
$dropdown
.
data
(
'
authorId
'
);
const
defaultLabel
=
$dropdown
.
data
(
'
defaultLabel
'
);
const
issueURL
=
$dropdown
.
data
(
'
issueUpdate
'
);
const
$selectbox
=
$dropdown
.
closest
(
'
.selectbox
'
);
let
$block
=
$selectbox
.
closest
(
'
.block
'
);
const
abilityName
=
$dropdown
.
data
(
'
abilityName
'
);
let
$value
=
$block
.
find
(
'
.value
'
);
const
$collapsedSidebar
=
$block
.
find
(
'
.sidebar-collapsed-user
'
);
const
$loading
=
$block
.
find
(
'
.block-loading
'
).
fadeOut
();
const
selectedIdDefault
=
defaultNullUser
&&
showNullUser
?
0
:
null
;
let
selectedId
=
$dropdown
.
data
(
'
selected
'
);
let
assignTo
;
let
assigneeTemplate
;
let
collapsedAssigneeTemplate
;
if
(
selectedId
===
undefined
)
{
selectedId
=
selectedIdDefault
;
}
const
assignYourself
=
function
()
{
const
unassignedSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value=0]`
);
const
assignYourself
=
function
()
{
const
unassignedSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value=0]`
);
if
(
unassignedSelected
)
{
unassignedSelected
.
remove
();
}
// Save current selected user to the DOM
const
currentUserInfo
=
$dropdown
.
data
(
'
currentUserInfo
'
)
||
{};
const
currentUser
=
userSelect
.
currentUser
||
{};
const
fieldName
=
$dropdown
.
data
(
'
fieldName
'
);
const
userName
=
currentUserInfo
.
name
;
const
userId
=
currentUserInfo
.
id
||
currentUser
.
id
;
const
inputHtmlString
=
_
.
template
(
`
<input type="hidden" name="<%- fieldName %>"
data-meta="<%- userName %>"
value="<%- userId %>" />
`
)({
fieldName
,
userName
,
userId
});
if
(
$selectbox
)
{
$dropdown
.
parent
().
before
(
inputHtmlString
);
}
else
{
$dropdown
.
after
(
inputHtmlString
);
}
};
if
(
unassignedSelected
)
{
unassignedSelected
.
remove
(
);
}
if
(
$block
[
0
]
)
{
$block
[
0
].
addEventListener
(
'
assignYourself
'
,
assignYourself
);
}
// Save current selected user to the DOM
const
currentUserInfo
=
$dropdown
.
data
(
'
currentUserInfo
'
)
||
{};
const
currentUser
=
_this
.
currentUser
||
{};
const
fieldName
=
$dropdown
.
data
(
'
fieldName
'
);
const
userName
=
currentUserInfo
.
name
;
const
userId
=
currentUserInfo
.
id
||
currentUser
.
id
;
const
inputHtmlString
=
_
.
template
(
`
<input type="hidden" name="<%- fieldName %>"
data-meta="<%- userName %>"
value="<%- userId %>" />
`
)({
fieldName
,
userName
,
userId
});
if
(
$selectbox
)
{
$dropdown
.
parent
().
before
(
inputHtmlString
);
}
else
{
$dropdown
.
after
(
inputHtmlString
);
}
};
const
getSelectedUserInputs
=
function
()
{
return
$selectbox
.
find
(
`input[name="
${
$dropdown
.
data
(
'
fieldName
'
)}
"]`
);
};
if
(
$block
[
0
])
{
$block
[
0
].
addEventListener
(
'
assignYourself
'
,
assignYourself
);
}
const
getSelected
=
function
()
{
return
getSelectedUserInputs
()
.
map
((
index
,
input
)
=>
parseInt
(
input
.
value
,
10
))
.
get
();
};
const
getSelectedUserInputs
=
function
()
{
return
$selectbox
.
find
(
`input[name="
${
$dropdown
.
data
(
'
fieldName
'
)}
"]`
);
};
const
getSelected
=
function
()
{
return
getSelectedUserInputs
()
.
map
((
index
,
input
)
=>
parseInt
(
input
.
value
,
10
))
.
get
();
};
const
checkMaxSelect
=
function
()
{
const
maxSelect
=
$dropdown
.
data
(
'
maxSelect
'
);
if
(
maxSelect
)
{
const
selected
=
getSelected
();
if
(
selected
.
length
>
maxSelect
)
{
const
firstSelectedId
=
selected
[
0
];
const
firstSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value=
${
firstSelectedId
}
]`
);
firstSelected
.
remove
();
emitSidebarEvent
(
'
sidebar.removeAssignee
'
,
{
id
:
firstSelectedId
,
});
}
}
};
const
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
s__
(
'
UsersSelect|Unassigned
'
);
}
else
if
(
selectedUsers
.
length
===
1
)
{
return
firstUser
.
name
;
}
else
if
(
isSelected
)
{
const
otherSelected
=
selectedUsers
.
filter
(
s
=>
s
!==
selectedUser
.
id
);
return
sprintf
(
s__
(
'
UsersSelect|%{name} + %{length} more
'
),
{
name
:
selectedUser
.
name
,
length
:
otherSelected
.
length
,
});
}
else
{
return
sprintf
(
s__
(
'
UsersSelect|%{name} + %{length} more
'
),
{
name
:
firstUser
.
name
,
length
:
selectedUsers
.
length
-
1
,
});
}
};
const
checkMaxSelect
=
function
()
{
const
maxSelect
=
$dropdown
.
data
(
'
maxSelect
'
);
if
(
maxSelect
)
{
const
selected
=
getSelected
();
$
(
'
.assign-to-me-link
'
).
on
(
'
click
'
,
e
=>
{
e
.
preventDefault
();
$
(
e
.
currentTarget
).
hide
();
if
(
selected
.
length
>
maxSelect
)
{
const
firstSelectedId
=
selected
[
0
];
const
firstSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value=
${
firstSelectedId
}
]`
);
if
(
$dropdown
.
data
(
'
multiSelect
'
))
{
assignYourself
();
checkMaxSelect
();
firstSelected
.
remove
();
emitSidebarEvent
(
'
sidebar.removeAssignee
'
,
{
id
:
firstSelectedId
,
});
}
}
};
const
currentUserInfo
=
$dropdown
.
data
(
'
currentUserInfo
'
);
$dropdown
.
find
(
'
.dropdown-toggle-text
'
)
.
text
(
getMultiSelectDropdownTitle
(
currentUserInfo
))
.
removeClass
(
'
is-default
'
);
}
else
{
const
$input
=
$
(
`input[name="
${
$dropdown
.
data
(
'
fieldName
'
)}
"]`
);
$input
.
val
(
gon
.
current_user_id
);
selectedId
=
$input
.
val
();
$dropdown
.
find
(
'
.dropdown-toggle-text
'
)
.
text
(
gon
.
current_user_fullname
)
.
removeClass
(
'
is-default
'
);
}
const
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
s__
(
'
UsersSelect|Unassigned
'
);
}
else
if
(
selectedUsers
.
length
===
1
)
{
return
firstUser
.
name
;
}
else
if
(
isSelected
)
{
const
otherSelected
=
selectedUsers
.
filter
(
s
=>
s
!==
selectedUser
.
id
);
return
sprintf
(
s__
(
'
UsersSelect|%{name} + %{length} more
'
),
{
name
:
selectedUser
.
name
,
length
:
otherSelected
.
length
,
});
$block
.
on
(
'
click
'
,
'
.js-assign-yourself
'
,
e
=>
{
e
.
preventDefault
();
return
assignTo
(
_this
.
currentUser
.
id
);
}
else
{
return
sprintf
(
s__
(
'
UsersSelect|%{name} + %{length} more
'
),
{
name
:
firstUser
.
name
,
length
:
selectedUsers
.
length
-
1
,
});
}
};
assignTo
=
function
(
selected
)
{
const
data
=
{};
data
[
abilityName
]
=
{};
data
[
abilityName
].
assignee_id
=
selected
!=
null
?
selected
:
null
;
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
return
axios
.
put
(
issueURL
,
data
).
then
(({
data
})
=>
{
let
user
=
{};
let
tooltipTitle
=
user
.
name
;
$dropdown
.
trigger
(
'
loaded.gl.dropdown
'
);
$loading
.
fadeOut
();
if
(
data
.
assignee
)
{
user
=
{
name
:
data
.
assignee
.
name
,
username
:
data
.
assignee
.
username
,
avatar
:
data
.
assignee
.
avatar_url
,
};
tooltipTitle
=
_
.
escape
(
user
.
name
);
}
else
{
user
=
{
name
:
s__
(
'
UsersSelect|Unassigned
'
),
username
:
''
,
avatar
:
''
,
$
(
'
.assign-to-me-link
'
).
on
(
'
click
'
,
e
=>
{
e
.
preventDefault
();
$
(
e
.
currentTarget
).
hide
();
if
(
$dropdown
.
data
(
'
multiSelect
'
))
{
assignYourself
();
checkMaxSelect
();
const
currentUserInfo
=
$dropdown
.
data
(
'
currentUserInfo
'
);
$dropdown
.
find
(
'
.dropdown-toggle-text
'
)
.
text
(
getMultiSelectDropdownTitle
(
currentUserInfo
))
.
removeClass
(
'
is-default
'
);
}
else
{
const
$input
=
$
(
`input[name="
${
$dropdown
.
data
(
'
fieldName
'
)}
"]`
);
$input
.
val
(
gon
.
current_user_id
);
selectedId
=
$input
.
val
();
$dropdown
.
find
(
'
.dropdown-toggle-text
'
)
.
text
(
gon
.
current_user_fullname
)
.
removeClass
(
'
is-default
'
);
}
});
$block
.
on
(
'
click
'
,
'
.js-assign-yourself
'
,
e
=>
{
e
.
preventDefault
();
return
assignTo
(
userSelect
.
currentUser
.
id
);
});
assignTo
=
function
(
selected
)
{
const
data
=
{};
data
[
abilityName
]
=
{};
data
[
abilityName
].
assignee_id
=
selected
!=
null
?
selected
:
null
;
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
return
axios
.
put
(
issueURL
,
data
).
then
(({
data
})
=>
{
let
user
=
{};
let
tooltipTitle
=
user
.
name
;
$dropdown
.
trigger
(
'
loaded.gl.dropdown
'
);
$loading
.
fadeOut
();
if
(
data
.
assignee
)
{
user
=
{
name
:
data
.
assignee
.
name
,
username
:
data
.
assignee
.
username
,
avatar
:
data
.
assignee
.
avatar_url
,
};
tooltipTitle
=
_
.
escape
(
user
.
name
);
}
else
{
user
=
{
name
:
s__
(
'
UsersSelect|Unassigned
'
),
username
:
''
,
avatar
:
''
,
};
tooltipTitle
=
s__
(
'
UsersSelect|Assignee
'
);
}
$value
.
html
(
assigneeTemplate
(
user
));
$collapsedSidebar
.
attr
(
'
title
'
,
tooltipTitle
).
tooltip
(
'
_fixTitle
'
);
return
$collapsedSidebar
.
html
(
collapsedAssigneeTemplate
(
user
));
});
};
collapsedAssigneeTemplate
=
_
.
template
(
'
<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>
'
,
);
assigneeTemplate
=
_
.
template
(
`<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
${
sprintf
(
s__
(
'
UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}
'
),
{
openingTag
:
'
<a href="#" class="js-assign-yourself">
'
,
closingTag
:
'
</a>
'
,
})}
</span> <% } %>`
,
);
return
$dropdown
.
glDropdown
({
showMenuAbove
,
data
(
term
,
callback
)
{
return
userSelect
.
users
(
term
,
options
,
users
=>
{
// GitLabDropdownFilter returns this.instance
// GitLabDropdownRemote returns this.options.instance
const
glDropdown
=
this
.
instance
||
this
.
options
.
instance
;
glDropdown
.
options
.
processData
(
term
,
users
,
callback
);
});
},
processData
(
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
,
canMerge
}
=
input
.
dataset
;
return
{
avatar_url
:
avatarUrl
||
avatar_url
,
id
:
userId
,
name
,
username
,
can_merge
:
parseBoolean
(
canMerge
),
};
tooltipTitle
=
s__
(
'
UsersSelect|Assignee
'
);
}
$value
.
html
(
assigneeTemplate
(
user
));
$collapsedSidebar
.
attr
(
'
title
'
,
tooltipTitle
).
tooltip
(
'
_fixTitle
'
);
return
$collapsedSidebar
.
html
(
collapsedAssigneeTemplate
(
user
));
});
};
collapsedAssigneeTemplate
=
_
.
template
(
'
<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>
'
,
);
assigneeTemplate
=
_
.
template
(
`<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
${
sprintf
(
s__
(
'
UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}
'
),
{
openingTag
:
'
<a href="#" class="js-assign-yourself">
'
,
closingTag
:
'
</a>
'
,
})}
</span> <% } %>`
,
);
return
$dropdown
.
glDropdown
({
showMenuAbove
,
data
(
term
,
callback
)
{
return
_this
.
users
(
term
,
options
,
users
=>
{
// GitLabDropdownFilter returns this.instance
// GitLabDropdownRemote returns this.options.instance
const
glDropdown
=
this
.
instance
||
this
.
options
.
instance
;
glDropdown
.
options
.
processData
(
term
,
users
,
callback
);
});
},
processData
(
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
,
canMerge
}
=
input
.
dataset
;
return
{
avatar_url
:
avatarUrl
||
avatar_url
,
id
:
userId
,
name
,
username
,
can_merge
:
parseBoolean
(
canMerge
),
};
});
users
=
data
.
concat
(
selectedUsers
);
}
users
=
data
.
concat
(
selectedUsers
);
}
let
anyUser
;
let
index
;
let
len
;
let
name
;
let
obj
;
let
showDivider
;
if
(
term
.
length
===
0
)
{
showDivider
=
0
;
if
(
firstUser
)
{
// Move current user to the front of the list
for
(
index
=
0
,
len
=
users
.
length
;
index
<
len
;
index
+=
1
)
{
obj
=
users
[
index
];
if
(
obj
.
username
===
firstUser
)
{
users
.
splice
(
index
,
1
);
users
.
unshift
(
obj
);
break
;
}
}
let
anyUser
;
let
index
;
let
len
;
let
name
;
let
obj
;
let
showDivider
;
if
(
term
.
length
===
0
)
{
showDivider
=
0
;
if
(
firstUser
)
{
// Move current user to the front of the list
for
(
index
=
0
,
len
=
users
.
length
;
index
<
len
;
index
+=
1
)
{
obj
=
users
[
index
];
if
(
obj
.
username
===
firstUser
)
{
users
.
splice
(
index
,
1
);
users
.
unshift
(
obj
);
break
;
}
if
(
showNullUser
)
{
}
}
if
(
showNullUser
)
{
showDivider
+=
1
;
users
.
unshift
({
beforeDivider
:
true
,
name
:
s__
(
'
UsersSelect|Unassigned
'
),
id
:
0
,
});
}
if
(
showAnyUser
)
{
showDivider
+=
1
;
name
=
showAnyUser
;
if
(
name
===
true
)
{
name
=
s__
(
'
UsersSelect|Any User
'
);
}
anyUser
=
{
beforeDivider
:
true
,
name
,
id
:
null
,
};
users
.
unshift
(
anyUser
);
}
if
(
showDivider
)
{
users
.
splice
(
showDivider
,
0
,
{
type
:
'
divider
'
});
}
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
const
selected
=
getSelected
().
filter
(
i
=>
i
!==
0
);
if
(
selected
.
length
>
0
)
{
if
(
$dropdown
.
data
(
'
dropdownHeader
'
))
{
showDivider
+=
1
;
users
.
unshift
({
beforeDivider
:
true
,
name
:
s__
(
'
UsersSelect|Unassigned
'
),
id
:
0
,
users
.
splice
(
showDivider
,
0
,
{
type
:
'
header
'
,
content
:
$dropdown
.
data
(
'
dropdownHeader
'
),
});
}
if
(
showAnyUser
)
{
showDivider
+=
1
;
name
=
showAnyUser
;
if
(
name
===
true
)
{
name
=
s__
(
'
UsersSelect|Any User
'
);
}
anyUser
=
{
beforeDivider
:
true
,
name
,
id
:
null
,
};
users
.
unshift
(
anyUser
);
}
if
(
showDivider
)
{
users
.
splice
(
showDivider
,
0
,
{
type
:
'
divider
'
});
}
const
selectedUsers
=
users
.
filter
(
u
=>
selected
.
indexOf
(
u
.
id
)
!==
-
1
)
.
sort
((
a
,
b
)
=>
a
.
name
>
b
.
name
);
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
const
selected
=
getSelected
().
filter
(
i
=>
i
!==
0
);
users
=
users
.
filter
(
u
=>
selected
.
indexOf
(
u
.
id
)
===
-
1
);
if
(
selected
.
length
>
0
)
{
if
(
$dropdown
.
data
(
'
dropdownHeader
'
))
{
showDivider
+=
1
;
users
.
splice
(
showDivider
,
0
,
{
type
:
'
header
'
,
content
:
$dropdown
.
data
(
'
dropdownHeader
'
),
});
}
selectedUsers
.
forEach
(
selectedUser
=>
{
showDivider
+=
1
;
users
.
splice
(
showDivider
,
0
,
selectedUser
);
});
const
selectedUsers
=
users
.
filter
(
u
=>
selected
.
indexOf
(
u
.
id
)
!==
-
1
)
.
sort
((
a
,
b
)
=>
a
.
name
>
b
.
name
);
users
.
splice
(
showDivider
+
1
,
0
,
{
type
:
'
divider
'
});
}
}
}
users
=
users
.
filter
(
u
=>
selected
.
indexOf
(
u
.
id
)
===
-
1
);
callback
(
users
);
if
(
showMenuAbove
)
{
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
}
},
filterable
:
true
,
filterRemote
:
true
,
search
:
{
fields
:
[
'
name
'
,
'
username
'
],
},
selectable
:
true
,
fieldName
:
$dropdown
.
data
(
'
fieldName
'
),
toggleLabel
(
selected
,
el
,
glDropdown
)
{
const
inputValue
=
glDropdown
.
filterInput
.
val
();
if
(
this
.
multiSelect
&&
inputValue
===
''
)
{
// Remove non-users from the fullData array
const
users
=
glDropdown
.
filteredFullData
();
const
callback
=
glDropdown
.
parseData
.
bind
(
glDropdown
);
// Update the data model
this
.
processData
(
inputValue
,
users
,
callback
);
}
selectedUsers
.
forEach
(
selectedUser
=>
{
showDivider
+=
1
;
users
.
splice
(
showDivider
,
0
,
selectedUser
);
});
if
(
this
.
multiSelect
)
{
return
getMultiSelectDropdownTitle
(
selected
,
$
(
el
).
hasClass
(
'
is-active
'
));
}
users
.
splice
(
showDivider
+
1
,
0
,
{
type
:
'
divider
'
});
}
}
}
if
(
selected
&&
'
id
'
in
selected
&&
$
(
el
).
hasClass
(
'
is-active
'
))
{
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
removeClass
(
'
is-default
'
);
if
(
selected
.
text
)
{
return
selected
.
text
;
}
else
{
return
selected
.
name
;
}
}
else
{
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
addClass
(
'
is-default
'
);
return
defaultLabel
;
}
},
defaultLabel
,
hidden
()
{
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
emitSidebarEvent
(
'
sidebar.saveAssignees
'
);
}
callback
(
users
);
if
(
showMenuAbove
)
{
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
}
},
filterable
:
true
,
filterRemote
:
true
,
search
:
{
fields
:
[
'
name
'
,
'
username
'
],
},
selectable
:
true
,
fieldName
:
$dropdown
.
data
(
'
fieldName
'
),
toggleLabel
(
selected
,
el
,
glDropdown
)
{
const
inputValue
=
glDropdown
.
filterInput
.
val
();
if
(
this
.
multiSelect
&&
inputValue
===
''
)
{
// Remove non-users from the fullData array
const
users
=
glDropdown
.
filteredFullData
();
const
callback
=
glDropdown
.
parseData
.
bind
(
glDropdown
);
// Update the data model
this
.
processData
(
inputValue
,
users
,
callback
);
}
if
(
!
$dropdown
.
data
(
'
alwaysShowSelectbox
'
))
{
$selectbox
.
hide
();
if
(
this
.
multiSelect
)
{
return
getMultiSelectDropdownTitle
(
selected
,
$
(
el
).
hasClass
(
'
is-active
'
));
}
// Recalculate where .value is because vue might have changed it
$block
=
$selectbox
.
closest
(
'
.block
'
);
$value
=
$block
.
find
(
'
.value
'
);
// display:block overrides the hide-collapse rule
$value
.
css
(
'
display
'
,
''
);
}
},
multiSelect
:
$dropdown
.
hasClass
(
'
js-multiselect
'
),
inputMeta
:
$dropdown
.
data
(
'
inputMeta
'
),
clicked
(
options
)
{
const
{
$el
,
e
,
isMarking
}
=
options
;
const
user
=
options
.
selectedObj
;
$el
.
tooltip
(
'
dispose
'
);
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
const
isActive
=
$el
.
hasClass
(
'
is-active
'
);
const
previouslySelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value!=0]`
);
if
(
selected
&&
'
id
'
in
selected
&&
$
(
el
).
hasClass
(
'
is-active
'
))
{
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
removeClass
(
'
is-default
'
);
if
(
selected
.
text
)
{
return
selected
.
text
;
}
else
{
return
selected
.
name
;
}
}
else
{
$dropdown
.
find
(
'
.dropdown-toggle-text
'
).
addClass
(
'
is-default
'
);
return
defaultLabel
;
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect
();
if
(
user
.
beforeDivider
&&
user
.
name
.
toLowerCase
()
===
'
unassigned
'
)
{
// Unassigned selected
previouslySelected
.
each
((
index
,
element
)
=>
{
element
.
remove
();
});
emitSidebarEvent
(
'
sidebar.removeAllAssignees
'
);
}
else
if
(
isActive
)
{
// user selected
emitSidebarEvent
(
'
sidebar.addAssignee
'
,
user
);
// Remove unassigned selection (if it was previously selected)
const
unassignedSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value=0]`
);
if
(
unassignedSelected
)
{
unassignedSelected
.
remove
();
}
},
defaultLabel
,
hidden
()
{
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
emitSidebarEvent
(
'
sidebar.saveAssignees
'
);
}
else
{
if
(
previouslySelected
.
length
===
0
)
{
// Select unassigned because there is no more selected users
this
.
addInput
(
$dropdown
.
data
(
'
fieldName
'
),
0
,
{});
}
if
(
!
$dropdown
.
data
(
'
alwaysShowSelectbox
'
))
{
$selectbox
.
hide
();
// User unselected
emitSidebarEvent
(
'
sidebar.removeAssignee
'
,
user
);
}
// Recalculate where .value is because vue might have changed it
$block
=
$selectbox
.
closest
(
'
.block
'
);
$value
=
$block
.
find
(
'
.value
'
);
// display:block overrides the hide-collapse rule
$value
.
css
(
'
display
'
,
''
);
}
},
multiSelect
:
$dropdown
.
hasClass
(
'
js-multiselect
'
),
inputMeta
:
$dropdown
.
data
(
'
inputMeta
'
),
clicked
(
options
)
{
const
{
$el
,
e
,
isMarking
}
=
options
;
const
user
=
options
.
selectedObj
;
$el
.
tooltip
(
'
dispose
'
);
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
const
isActive
=
$el
.
hasClass
(
'
is-active
'
);
const
previouslySelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value!=0]`
);
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect
();
if
(
user
.
beforeDivider
&&
user
.
name
.
toLowerCase
()
===
'
unassigned
'
)
{
// Unassigned selected
previouslySelected
.
each
((
index
,
element
)
=>
{
element
.
remove
();
});
emitSidebarEvent
(
'
sidebar.removeAllAssignees
'
);
}
else
if
(
isActive
)
{
// user selected
emitSidebarEvent
(
'
sidebar.addAssignee
'
,
user
);
// Remove unassigned selection (if it was previously selected)
const
unassignedSelected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
'][value=0]`
);
if
(
unassignedSelected
)
{
unassignedSelected
.
remove
();
}
}
else
{
if
(
previouslySelected
.
length
===
0
)
{
// Select unassigned because there is no more selected users
this
.
addInput
(
$dropdown
.
data
(
'
fieldName
'
),
0
,
{});
}
if
(
getSelected
().
find
(
u
=>
u
===
gon
.
current_user_id
))
{
$
(
'
.assign-to-me-link
'
).
hide
();
}
else
{
$
(
'
.assign-to-me-link
'
).
show
();
}
}
// User unselected
emitSidebarEvent
(
'
sidebar.removeAssignee
'
,
user
);
}
const
page
=
$
(
'
body
'
).
attr
(
'
data-page
'
);
const
isIssueIndex
=
page
===
'
projects:issues:index
'
;
const
isMRIndex
=
page
===
page
&&
page
===
'
projects:merge_requests:index
'
;
if
(
$dropdown
.
hasClass
(
'
js-filter-bulk-update
'
)
||
$dropdown
.
hasClass
(
'
js-issuable-form-dropdown
'
)
)
{
e
.
preventDefault
();
if
(
getSelected
().
find
(
u
=>
u
===
gon
.
current_user_id
))
{
$
(
'
.assign-to-me-link
'
).
hide
();
}
else
{
$
(
'
.assign-to-me-link
'
).
show
();
}
}
const
isSelecting
=
user
.
id
!==
selectedId
;
selectedId
=
isSelecting
?
user
.
id
:
selectedIdDefault
;
const
page
=
$
(
'
body
'
).
attr
(
'
data-page
'
);
const
isIssueIndex
=
page
===
'
projects:issues:index
'
;
const
isMRIndex
=
page
===
page
&&
page
===
'
projects:merge_requests:index
'
;
if
(
$dropdown
.
hasClass
(
'
js-filter-bulk-update
'
)
||
$dropdown
.
hasClass
(
'
js-issuable-form-dropdown
'
)
)
{
e
.
preventDefault
();
const
isSelecting
=
user
.
id
!==
selectedId
;
selectedId
=
isSelecting
?
user
.
id
:
selectedIdDefault
;
if
(
selectedId
===
gon
.
current_user_id
)
{
$
(
'
.assign-to-me-link
'
).
hide
();
}
else
{
$
(
'
.assign-to-me-link
'
).
show
();
}
return
;
}
if
(
$el
.
closest
(
'
.add-issues-modal
'
).
length
)
{
ModalStore
.
store
.
filter
[
$dropdown
.
data
(
'
fieldName
'
)]
=
user
.
id
;
}
else
if
(
handleClick
)
{
e
.
preventDefault
();
handleClick
(
user
,
isMarking
);
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
(
isIssueIndex
||
isMRIndex
))
{
return
Issuable
.
filterResults
(
$dropdown
.
closest
(
'
form
'
));
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
))
{
return
$dropdown
.
closest
(
'
form
'
).
submit
();
}
else
if
(
!
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
const
selected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
']`
)
.
val
();
return
assignTo
(
selected
);
}
if
(
selectedId
===
gon
.
current_user_id
)
{
$
(
'
.assign-to-me-link
'
).
hide
();
}
else
{
$
(
'
.assign-to-me-link
'
).
show
();
}
return
;
}
if
(
$el
.
closest
(
'
.add-issues-modal
'
).
length
)
{
ModalStore
.
store
.
filter
[
$dropdown
.
data
(
'
fieldName
'
)]
=
user
.
id
;
}
else
if
(
handleClick
)
{
e
.
preventDefault
();
handleClick
(
user
,
isMarking
);
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
(
isIssueIndex
||
isMRIndex
))
{
return
Issuable
.
filterResults
(
$dropdown
.
closest
(
'
form
'
));
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
))
{
return
$dropdown
.
closest
(
'
form
'
).
submit
();
}
else
if
(
!
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
const
selected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
$dropdown
.
data
(
'
fieldName
'
)}
']`
)
.
val
();
return
assignTo
(
selected
);
}
// Automatically close dropdown after assignee is selected
// since CE has no multiple assignees
// EE does not have a max-select
if
(
$dropdown
.
data
(
'
maxSelect
'
)
&&
getSelected
().
length
===
$dropdown
.
data
(
'
maxSelect
'
)
)
{
// Close the dropdown
$dropdown
.
dropdown
(
'
toggle
'
);
}
},
id
(
user
)
{
return
user
.
id
;
},
opened
(
e
)
{
const
$el
=
$
(
e
.
currentTarget
);
const
selected
=
getSelected
();
if
(
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
)
&&
selected
.
length
===
0
)
{
this
.
addInput
(
$dropdown
.
data
(
'
fieldName
'
),
0
,
{});
}
$el
.
find
(
'
.is-active
'
).
removeClass
(
'
is-active
'
);
// Automatically close dropdown after assignee is selected
// since CE has no multiple assignees
// EE does not have a max-select
if
(
$dropdown
.
data
(
'
maxSelect
'
)
&&
getSelected
().
length
===
$dropdown
.
data
(
'
maxSelect
'
))
{
// Close the dropdown
$dropdown
.
dropdown
(
'
toggle
'
);
}
},
id
(
user
)
{
return
user
.
id
;
},
opened
(
e
)
{
const
$el
=
$
(
e
.
currentTarget
);
const
selected
=
getSelected
();
if
(
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
)
&&
selected
.
length
===
0
)
{
this
.
addInput
(
$dropdown
.
data
(
'
fieldName
'
),
0
,
{});
}
$el
.
find
(
'
.is-active
'
).
removeClass
(
'
is-active
'
);
function
highlightSelected
(
id
)
{
$el
.
find
(
`li[data-user-id="
${
id
}
"] .dropdown-menu-user-link`
).
addClass
(
'
is-active
'
);
}
function
highlightSelected
(
id
)
{
$el
.
find
(
`li[data-user-id="
${
id
}
"] .dropdown-menu-user-link`
).
addClass
(
'
is-active
'
);
}
if
(
selected
.
length
>
0
)
{
getSelected
().
forEach
(
selectedId
=>
highlightSelected
(
selectedId
));
}
else
if
(
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
))
{
highlightSelected
(
0
);
}
else
{
highlightSelected
(
selectedId
);
}
},
updateLabel
:
$dropdown
.
data
(
'
dropdownTitle
'
),
renderRow
(
user
)
{
const
username
=
user
.
username
?
`@
${
user
.
username
}
`
:
''
;
const
avatar
=
user
.
avatar_url
?
user
.
avatar_url
:
gon
.
default_avatar_url
;
if
(
selected
.
length
>
0
)
{
getSelected
().
forEach
(
selectedId
=>
highlightSelected
(
selectedId
));
}
else
if
(
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
))
{
highlightSelected
(
0
);
}
else
{
highlightSelected
(
selectedId
);
}
},
updateLabel
:
$dropdown
.
data
(
'
dropdownTitle
'
),
renderRow
(
user
)
{
const
username
=
user
.
username
?
`@
${
user
.
username
}
`
:
''
;
const
avatar
=
user
.
avatar_url
?
user
.
avatar_url
:
gon
.
default_avatar_url
;
let
selected
=
false
;
let
selected
=
false
;
if
(
this
.
multiSelect
)
{
selected
=
getSelected
().
find
(
u
=>
user
.
id
===
u
);
if
(
this
.
multiSelect
)
{
selected
=
getSelected
().
find
(
u
=>
user
.
id
===
u
);
const
{
fieldName
}
=
this
;
const
field
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
fieldName
}
'][value='
${
user
.
id
}
']`
);
const
{
fieldName
}
=
this
;
const
field
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
`input[name='
${
fieldName
}
'][value='
${
user
.
id
}
']`
);
if
(
field
.
length
)
{
selected
=
true
;
}
}
else
{
selected
=
user
.
id
===
selectedId
;
}
if
(
field
.
length
)
{
selected
=
true
;
}
}
else
{
selected
=
user
.
id
===
selectedId
;
}
let
img
=
''
;
if
(
user
.
beforeDivider
!=
null
)
{
`<li><a href='#' class='
${
selected
===
true
?
'
is-active
'
:
''
}
'>
${
_
.
escape
(
user
.
name
,
)}
</a></li>`
;
}
else
{
// 0 margin, because it's now handled by a wrapper
img
=
`<img src='
${
avatar
}
' class='avatar avatar-inline m-0' width='32' />`
;
}
let
img
=
''
;
if
(
user
.
beforeDivider
!=
null
)
{
`<li><a href='#' class='
${
selected
===
true
?
'
is-active
'
:
''
}
'>
${
_
.
escape
(
user
.
name
,
)}
</a></li>`
;
}
else
{
// 0 margin, because it's now handled by a wrapper
img
=
`<img src='
${
avatar
}
' class='avatar avatar-inline m-0' width='32' />`
;
}
return
_this
.
renderRow
(
options
.
issuableType
,
user
,
selected
,
username
,
img
);
},
});
};
})(
this
),
);
return
userSelect
.
renderRow
(
options
.
issuableType
,
user
,
selected
,
username
,
img
);
},
});
});
import
(
/* webpackChunkName: 'select2' */
'
select2/select2
'
)
.
then
(()
=>
{
$
(
'
.ajax-users-select
'
).
each
(
(
function
(
_this
)
{
return
function
(
i
,
select
)
{
const
options
=
{};
options
.
skipLdap
=
$
(
select
).
hasClass
(
'
skip_ldap
'
);
options
.
projectId
=
$
(
select
).
data
(
'
projectId
'
);
options
.
groupId
=
$
(
select
).
data
(
'
groupId
'
);
options
.
showCurrentUser
=
$
(
select
).
data
(
'
currentUser
'
);
options
.
authorId
=
$
(
select
).
data
(
'
authorId
'
);
options
.
skipUsers
=
$
(
select
).
data
(
'
skipUsers
'
);
const
showNullUser
=
$
(
select
).
data
(
'
nullUser
'
);
const
showAnyUser
=
$
(
select
).
data
(
'
anyUser
'
);
const
showEmailUser
=
$
(
select
).
data
(
'
emailUser
'
);
const
firstUser
=
$
(
select
).
data
(
'
firstUser
'
);
return
$
(
select
).
select2
({
placeholder
:
__
(
'
Search for a user
'
),
multiple
:
$
(
select
).
hasClass
(
'
multiselect
'
),
minimumInputLength
:
0
,
query
(
query
)
{
return
_this
.
users
(
query
.
term
,
options
,
users
=>
{
let
name
;
const
data
=
{
results
:
users
,
};
if
(
query
.
term
.
length
===
0
)
{
if
(
firstUser
)
{
// Move current user to the front of the list
const
ref
=
data
.
results
;
for
(
let
index
=
0
,
len
=
ref
.
length
;
index
<
len
;
index
+=
1
)
{
const
obj
=
ref
[
index
];
if
(
obj
.
username
===
firstUser
)
{
data
.
results
.
splice
(
index
,
1
);
data
.
results
.
unshift
(
obj
);
break
;
}
}
}
if
(
showNullUser
)
{
const
nullUser
=
{
name
:
s__
(
'
UsersSelect|Unassigned
'
),
id
:
0
,
};
data
.
results
.
unshift
(
nullUser
);
}
if
(
showAnyUser
)
{
name
=
showAnyUser
;
if
(
name
===
true
)
{
name
=
s__
(
'
UsersSelect|Any User
'
);
}
const
anyUser
=
{
name
,
id
:
null
,
};
data
.
results
.
unshift
(
anyUser
);
$
(
'
.ajax-users-select
'
).
each
((
i
,
select
)
=>
{
const
options
=
{};
options
.
skipLdap
=
$
(
select
).
hasClass
(
'
skip_ldap
'
);
options
.
projectId
=
$
(
select
).
data
(
'
projectId
'
);
options
.
groupId
=
$
(
select
).
data
(
'
groupId
'
);
options
.
showCurrentUser
=
$
(
select
).
data
(
'
currentUser
'
);
options
.
authorId
=
$
(
select
).
data
(
'
authorId
'
);
options
.
skipUsers
=
$
(
select
).
data
(
'
skipUsers
'
);
const
showNullUser
=
$
(
select
).
data
(
'
nullUser
'
);
const
showAnyUser
=
$
(
select
).
data
(
'
anyUser
'
);
const
showEmailUser
=
$
(
select
).
data
(
'
emailUser
'
);
const
firstUser
=
$
(
select
).
data
(
'
firstUser
'
);
return
$
(
select
).
select2
({
placeholder
:
__
(
'
Search for a user
'
),
multiple
:
$
(
select
).
hasClass
(
'
multiselect
'
),
minimumInputLength
:
0
,
query
(
query
)
{
return
userSelect
.
users
(
query
.
term
,
options
,
users
=>
{
let
name
;
const
data
=
{
results
:
users
,
};
if
(
query
.
term
.
length
===
0
)
{
if
(
firstUser
)
{
// Move current user to the front of the list
const
ref
=
data
.
results
;
for
(
let
index
=
0
,
len
=
ref
.
length
;
index
<
len
;
index
+=
1
)
{
const
obj
=
ref
[
index
];
if
(
obj
.
username
===
firstUser
)
{
data
.
results
.
splice
(
index
,
1
);
data
.
results
.
unshift
(
obj
);
break
;
}
}
if
(
showEmailUser
&&
data
.
results
.
length
===
0
&&
query
.
term
.
match
(
/^
[^
@
]
+@
[^
@
]
+$/
)
)
{
const
trimmed
=
query
.
term
.
trim
();
const
emailUser
=
{
name
:
sprintf
(
__
(
'
Invite "%{trimmed}" by email
'
),
{
trimmed
}),
username
:
trimmed
,
id
:
trimmed
,
invite
:
true
,
};
data
.
results
.
unshift
(
emailUser
);
}
if
(
showNullUser
)
{
const
nullUser
=
{
name
:
s__
(
'
UsersSelect|Unassigned
'
),
id
:
0
,
};
data
.
results
.
unshift
(
nullUser
);
}
if
(
showAnyUser
)
{
name
=
showAnyUser
;
if
(
name
===
true
)
{
name
=
s__
(
'
UsersSelect|Any User
'
);
}
return
query
.
callback
(
data
);
});
},
initSelection
()
{
const
args
=
1
<=
arguments
.
length
?
[].
slice
.
call
(
arguments
,
0
)
:
[];
return
_this
.
initSelection
.
apply
(
_this
,
args
);
},
formatResult
()
{
const
args
=
1
<=
arguments
.
length
?
[].
slice
.
call
(
arguments
,
0
)
:
[];
return
_this
.
formatResult
.
apply
(
_this
,
args
);
},
formatSelection
()
{
const
args
=
1
<=
arguments
.
length
?
[].
slice
.
call
(
arguments
,
0
)
:
[];
return
_this
.
formatSelection
.
apply
(
_this
,
args
);
},
dropdownCssClass
:
'
ajax-users-dropdown
'
,
// we do not want to escape markup since we are displaying html in results
escapeMarkup
(
m
)
{
return
m
;
},
const
anyUser
=
{
name
,
id
:
null
,
};
data
.
results
.
unshift
(
anyUser
);
}
}
if
(
showEmailUser
&&
data
.
results
.
length
===
0
&&
query
.
term
.
match
(
/^
[^
@
]
+@
[^
@
]
+$/
))
{
const
trimmed
=
query
.
term
.
trim
();
const
emailUser
=
{
name
:
sprintf
(
__
(
'
Invite "%{trimmed}" by email
'
),
{
trimmed
}),
username
:
trimmed
,
id
:
trimmed
,
invite
:
true
,
};
data
.
results
.
unshift
(
emailUser
);
}
return
query
.
callback
(
data
);
});
};
})(
this
),
);
},
initSelection
()
{
const
args
=
1
<=
arguments
.
length
?
[].
slice
.
call
(
arguments
,
0
)
:
[];
return
userSelect
.
initSelection
.
apply
(
userSelect
,
args
);
},
formatResult
()
{
const
args
=
1
<=
arguments
.
length
?
[].
slice
.
call
(
arguments
,
0
)
:
[];
return
userSelect
.
formatResult
.
apply
(
userSelect
,
args
);
},
formatSelection
()
{
const
args
=
1
<=
arguments
.
length
?
[].
slice
.
call
(
arguments
,
0
)
:
[];
return
userSelect
.
formatSelection
.
apply
(
userSelect
,
args
);
},
dropdownCssClass
:
'
ajax-users-dropdown
'
,
// we do not want to escape markup since we are displaying html in results
escapeMarkup
(
m
)
{
return
m
;
},
});
});
})
.
catch
(()
=>
{});
}
...
...
changelogs/unreleased/34625-Remove-IIFEs-from-users_select-js.yml
0 → 100644
View file @
dad534d9
---
title
:
Remove IIFEs from users_select.js
merge_request
:
19290
author
:
minghuan lei
type
:
other
doc/ci/multi_project_pipelines.md
View file @
dad534d9
...
...
@@ -221,6 +221,7 @@ Some features are not implemented yet. For example, support for environments.
-
`trigger`
(to define a downstream pipeline trigger)
-
`stage`
-
`allow_failure`
-
[
`rules`
](
yaml/README.md#rules
)
-
`only`
and
`except`
-
`when`
(only with
`on_success`
,
`on_failure`
, and
`always`
values)
-
`extends`
qa/qa/page/project/job/show.rb
View file @
dad534d9
...
...
@@ -5,8 +5,8 @@ module QA::Page
class
Show
<
QA
::
Page
::
Base
include
Component
::
CiBadgeLink
view
'app/assets/javascripts/jobs/components/
job_
log.vue'
do
element
:
build_trace
view
'app/assets/javascripts/jobs/components/
log/
log.vue'
do
element
:
job_log_content
end
view
'app/assets/javascripts/jobs/components/stages_dropdown.vue'
do
...
...
@@ -25,7 +25,7 @@ module QA::Page
result
=
''
wait
(
reload:
false
,
max:
wait
,
interval:
1
)
do
result
=
find_element
(
:
build_trace
).
text
result
=
find_element
(
:
job_log_content
).
text
result
.
include?
(
'Job'
)
end
...
...
@@ -37,7 +37,7 @@ module QA::Page
def
loaded?
(
wait:
60
)
wait
(
reload:
true
,
max:
wait
,
interval:
1
)
do
has_element?
(
:
build_trace
,
wait:
1
)
has_element?
(
:
job_log_content
,
wait:
1
)
end
end
end
...
...
qa/qa/resource/merge_request.rb
View file @
dad534d9
...
...
@@ -54,7 +54,7 @@ module QA
@assignee
=
nil
@milestone
=
nil
@labels
=
[]
@file_name
=
"added_file.txt"
@file_name
=
"added_file
-
#{
SecureRandom
.
hex
(
8
)
}
.txt"
@file_content
=
"File Added"
@target_new_branch
=
true
@no_preparation
=
false
...
...
qa/qa/resource/merge_request_from_fork.rb
View file @
dad534d9
# frozen_string_literal: true
require
'securerandom'
module
QA
module
Resource
class
MergeRequestFromFork
<
MergeRequest
...
...
@@ -13,7 +15,7 @@ module QA
Repository
::
ProjectPush
.
fabricate!
do
|
resource
|
resource
.
project
=
fork
.
project
resource
.
branch_name
=
fork_branch
resource
.
file_name
=
'file2.txt'
resource
.
file_name
=
"file2-
#{
SecureRandom
.
hex
(
8
)
}
.txt"
resource
.
user
=
fork
.
user
end
end
...
...
qa/qa/resource/protected_branch.rb
View file @
dad534d9
# frozen_string_literal: true
require
'securerandom'
module
QA
module
Resource
class
ProtectedBranch
<
Base
...
...
@@ -15,7 +17,7 @@ module QA
attribute
:branch
do
Repository
::
ProjectPush
.
fabricate!
do
|
project_push
|
project_push
.
project
=
project
project_push
.
file_name
=
'new_file.md'
project_push
.
file_name
=
"new_file-
#{
SecureRandom
.
hex
(
8
)
}
.md"
project_push
.
commit_message
=
'Add new file'
project_push
.
branch_name
=
branch_name
project_push
.
new_branch
=
true
...
...
qa/qa/resource/repository/project_push.rb
View file @
dad534d9
# frozen_string_literal: true
require
'securerandom'
module
QA
module
Resource
module
Repository
...
...
@@ -15,7 +17,7 @@ module QA
end
def
initialize
@file_name
=
'file.txt'
@file_name
=
"file-
#{
SecureRandom
.
hex
(
8
)
}
.txt"
@file_content
=
'# This is test project'
@commit_message
=
"This is a test commit"
@branch_name
=
'master'
...
...
qa/qa/resource/repository/push.rb
View file @
dad534d9
# frozen_string_literal: true
require
'pathname'
require
'securerandom'
module
QA
module
Resource
...
...
@@ -13,7 +14,7 @@ module QA
attr_writer
:remote_branch
,
:gpg_key_id
def
initialize
@file_name
=
'file.txt'
@file_name
=
"file-
#{
SecureRandom
.
hex
(
8
)
}
.txt"
@file_content
=
'# This is test file'
@commit_message
=
"This is a test commit"
@branch_name
=
'master'
...
...
qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
View file @
dad534d9
...
...
@@ -4,12 +4,7 @@ module QA
context
'Create'
do
describe
'Download merge request patch and diff'
do
before
(
:context
)
do
project
=
Resource
::
Project
.
fabricate_via_api!
do
|
project
|
project
.
name
=
'project'
end
@merge_request
=
Resource
::
MergeRequest
.
fabricate_via_api!
do
|
merge_request
|
merge_request
.
project
=
project
merge_request
.
title
=
'This is a merge request'
merge_request
.
description
=
'... for downloading patches and diffs'
end
...
...
@@ -23,7 +18,7 @@ module QA
expect
(
page
.
text
).
to
start_with
(
'From'
)
expect
(
page
).
to
have_content
(
'Subject: [PATCH] This is a test commit'
)
expect
(
page
).
to
have_content
(
'diff --git a/added_file.txt b/added_file.txt'
)
expect
(
page
).
to
have_content
(
"diff --git a/
#{
@merge_request
.
file_name
}
b/
#{
@merge_request
.
file_name
}
"
)
end
it
'views the merge request plain diff'
do
...
...
@@ -32,7 +27,7 @@ module QA
@merge_request
.
visit!
Page
::
MergeRequest
::
Show
.
perform
(
&
:view_plain_diff
)
expect
(
page
.
text
).
to
start_with
(
'diff --git a/added_file.txt b/added_file.txt'
)
expect
(
page
.
text
).
to
start_with
(
"diff --git a/
#{
@merge_request
.
file_name
}
b/
#{
@merge_request
.
file_name
}
"
)
expect
(
page
).
to
have_content
(
'+File Added'
)
end
end
...
...
qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
View file @
dad534d9
...
...
@@ -6,10 +6,6 @@ module QA
context
'Release'
,
:docker
do
describe
'Git clone using a deploy key'
do
before
do
# Handle WIP Job Logs flag - https://gitlab.com/gitlab-org/gitlab/issues/31162
@job_log_json_flag_enabled
=
Runtime
::
Feature
.
enabled?
(
'job_log_json'
)
Runtime
::
Feature
.
disable
(
'job_log_json'
)
if
@job_log_json_flag_enabled
Flow
::
Login
.
sign_in
@runner_name
=
"qa-runner-
#{
Time
.
now
.
to_i
}
"
...
...
@@ -29,7 +25,6 @@ module QA
end
after
do
Runtime
::
Feature
.
enable
(
'job_log_json'
)
if
@job_log_json_flag_enabled
Service
::
DockerRun
::
GitlabRunner
.
new
(
@runner_name
).
remove!
end
...
...
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