Commit 4d9b4d35 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce

parents 3d4c2d0b 9007af2c
...@@ -43,6 +43,10 @@ v 7.10.0 (unreleased) ...@@ -43,6 +43,10 @@ v 7.10.0 (unreleased)
- Link note avatar to user. - Link note avatar to user.
- Make Git-over-SSH errors more descriptive. - Make Git-over-SSH errors more descriptive.
- Fix EmailsOnPush. - Fix EmailsOnPush.
- Refactor issue filtering
- AJAX selectbox for issue assignee and author filters
- Fix issue with missing options in issue filtering dropdown if selected one
- Prevent holding Control-Enter or Command-Enter from posting comment multiple times.
v 7.9.0 v 7.9.0
- Send EmailsOnPush email when branch or tag is created or deleted. - Send EmailsOnPush email when branch or tag is created or deleted.
......
@Api = @Api =
groups_path: "/api/:version/groups.json" groups_path: "/api/:version/groups.json"
group_path: "/api/:version/groups/:id.json" group_path: "/api/:version/groups/:id.json"
users_path: "/api/:version/users.json"
user_path: "/api/:version/users/:id.json"
notes_path: "/api/:version/projects/:id/notes.json"
namespaces_path: "/api/:version/namespaces.json" namespaces_path: "/api/:version/namespaces.json"
project_users_path: "/api/:version/projects/:id/users.json"
# Get 20 (depends on api) recent notes
# and sort the ascending from oldest to newest
notes: (project_id, callback) ->
url = Api.buildUrl(Api.notes_path)
url = url.replace(':id', project_id)
$.ajax(
url: url,
data:
private_token: gon.api_token
gfm: true
recent: true
dataType: "json"
).done (notes) ->
notes.sort (a, b) ->
return a.id - b.id
callback(notes)
user: (user_id, callback) ->
url = Api.buildUrl(Api.user_path)
url = url.replace(':id', user_id)
$.ajax(
url: url
data:
private_token: gon.api_token
dataType: "json"
).done (user) ->
callback(user)
# Return users list. Filtered by query
# Only active users retrieved
users: (query, callback) ->
url = Api.buildUrl(Api.users_path)
$.ajax(
url: url
data:
private_token: gon.api_token
search: query
per_page: 20
active: true
dataType: "json"
).done (users) ->
callback(users)
group: (group_id, callback) -> group: (group_id, callback) ->
url = Api.buildUrl(Api.group_path) url = Api.buildUrl(Api.group_path)
...@@ -80,23 +30,6 @@ ...@@ -80,23 +30,6 @@
).done (groups) -> ).done (groups) ->
callback(groups) callback(groups)
# Return project users list. Filtered by query
# Only active users retrieved
projectUsers: (project_id, query, callback) ->
url = Api.buildUrl(Api.project_users_path)
url = url.replace(':id', project_id)
$.ajax(
url: url
data:
private_token: gon.api_token
search: query
per_page: 20
active: true
dataType: "json"
).done (users) ->
callback(users)
# Return namespaces list. Filtered by query # Return namespaces list. Filtered by query
namespaces: (query, callback) -> namespaces: (query, callback) ->
url = Api.buildUrl(Api.namespaces_path) url = Api.buildUrl(Api.namespaces_path)
......
...@@ -127,7 +127,7 @@ class Dispatcher ...@@ -127,7 +127,7 @@ class Dispatcher
when 'show' when 'show'
new ProjectShow() new ProjectShow()
when 'issues', 'merge_requests' when 'issues', 'merge_requests'
new ProjectUsersSelect() new UsersSelect()
when 'wikis' when 'wikis'
new Wikis() new Wikis()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
......
...@@ -57,6 +57,7 @@ class @Notes ...@@ -57,6 +57,7 @@ class @Notes
@notes_forms = '.js-main-target-form textarea, .js-discussion-note-form textarea' @notes_forms = '.js-main-target-form textarea, .js-discussion-note-form textarea'
# Chrome doesn't fire keypress or keyup for Command+Enter, so we need keydown. # Chrome doesn't fire keypress or keyup for Command+Enter, so we need keydown.
$(document).on('keydown', @notes_forms, (e) -> $(document).on('keydown', @notes_forms, (e) ->
return if e.originalEvent.repeat
if e.keyCode == 10 || ((e.metaKey || e.ctrlKey) && e.keyCode == 13) if e.keyCode == 10 || ((e.metaKey || e.ctrlKey) && e.keyCode == 13)
$(@).parents('form').submit() $(@).parents('form').submit()
) )
......
class @ProjectUsersSelect
constructor: ->
$('.ajax-project-users-select').each (i, select) =>
project_id = $(select).data('project-id') || $('body').data('project-id')
$(select).select2
placeholder: $(select).data('placeholder') || "Search for a user"
multiple: $(select).hasClass('multiselect')
minimumInputLength: 0
query: (query) ->
Api.projectUsers project_id, query.term, (users) ->
data = { results: users }
if query.term.length == 0
nullUser = {
name: 'Unassigned',
avatar: null,
username: 'none',
id: -1
}
data.results.unshift(nullUser)
query.callback(data)
initSelection: (element, callback) ->
id = $(element).val()
if id != "" && id != "-1"
Api.user(id, callback)
formatResult: (args...) =>
@formatResult(args...)
formatSelection: (args...) =>
@formatSelection(args...)
dropdownCssClass: "ajax-project-users-dropdown"
dropdownAutoWidth: true
escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
m
formatResult: (user) ->
if user.avatar_url
avatar = user.avatar_url
else
avatar = gon.default_avatar_url
avatarMarkup = "<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>"
"<div class='user-result'>
#{avatarMarkup}
<div class='user-name'>#{user.name}</div>
<div class='user-username'>#{user.username}</div>
</div>"
formatSelection: (user) ->
user.name
class @UsersSelect class @UsersSelect
constructor: -> constructor: ->
@usersPath = "/autocomplete/users.json"
@userPath = "/autocomplete/users/:id.json"
$('.ajax-users-select').each (i, select) => $('.ajax-users-select').each (i, select) =>
@projectId = $(select).data('project-id')
@groupId = $(select).data('group-id')
showNullUser = $(select).data('null-user')
showAnyUser = $(select).data('any-user')
$(select).select2 $(select).select2
placeholder: "Search for a user" placeholder: "Search for a user"
multiple: $(select).hasClass('multiselect') multiple: $(select).hasClass('multiselect')
minimumInputLength: 0 minimumInputLength: 0
query: (query) -> query: (query) =>
Api.users query.term, (users) -> @users query.term, (users) =>
data = { results: users } data = { results: users }
if query.term.length == 0
anyUser = {
name: 'Any',
avatar: null,
username: 'none',
id: null
}
nullUser = {
name: 'Unassigned',
avatar: null,
username: 'none',
id: 0
}
if showNullUser
data.results.unshift(nullUser)
if showAnyUser
data.results.unshift(anyUser)
query.callback(data) query.callback(data)
initSelection: (element, callback) -> initSelection: (element, callback) =>
id = $(element).val() id = $(element).val()
if id isnt "" if id != "" && id != "0"
Api.user(id, callback) @user(id, callback)
formatResult: (args...) => formatResult: (args...) =>
@formatResult(args...) @formatResult(args...)
...@@ -38,3 +66,34 @@ class @UsersSelect ...@@ -38,3 +66,34 @@ class @UsersSelect
formatSelection: (user) -> formatSelection: (user) ->
user.name user.name
user: (user_id, callback) =>
url = @buildUrl(@userPath)
url = url.replace(':id', user_id)
$.ajax(
url: url
dataType: "json"
).done (user) ->
callback(user)
# Return users list. Filtered by query
# Only active users retrieved
users: (query, callback) =>
url = @buildUrl(@usersPath)
$.ajax(
url: url
data:
search: query
per_page: 20
active: true
project_id: @projectId
group_id: @groupId
dataType: "json"
).done (users) ->
callback(users)
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?
return url
.filter-item {
margin-right: 15px;
}
.issues-state-filters {
li.active a,
li.active a:hover {
background: #f5f5f5;
border-bottom: 1px solid #f5f5f5 !important;
}
}
.issues-details-filters {
font-size: 13px;
background: #f5f5f5;
margin: -10px 0;
padding: 10px 15px;
margin-top: -15px;
border-left: 1px solid #DDD;
border-right: 1px solid #DDD;
.btn {
font-size: 13px;
}
}
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
.select2-drop-active { .select2-drop-active {
border: 1px solid #BBB !important; border: 1px solid #BBB !important;
margin-top: 4px; margin-top: 4px;
font-size: 13px;
&.select2-drop-above { &.select2-drop-above {
margin-bottom: 8px; margin-bottom: 8px;
...@@ -106,3 +107,7 @@ ...@@ -106,3 +107,7 @@
font-weight: bolder; font-weight: bolder;
} }
} }
.ajax-users-dropdown {
min-width: 225px !important;
}
...@@ -41,12 +41,9 @@ ...@@ -41,12 +41,9 @@
} }
.check-all-holder { .check-all-holder {
height: 36px; line-height: 36px;
float: left; float: left;
margin-right: 12px; margin-right: 15px;
padding: 6px 15px;
border: 1px solid #ccc;
@include border-radius(4px);
} }
.issues_content { .issues_content {
...@@ -60,6 +57,7 @@ ...@@ -60,6 +57,7 @@
} }
@media (min-width: 800px) { @media (min-width: 800px) {
.issues-filters,
.issues_bulk_update { .issues_bulk_update {
select, .select2-container { select, .select2-container {
width: 120px !important; width: 120px !important;
...@@ -69,14 +67,16 @@ ...@@ -69,14 +67,16 @@
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
.issues-filters,
.issues_bulk_update { .issues_bulk_update {
select, .select2-container { select, .select2-container {
width: 160px !important; width: 150px !important;
display: inline-block; display: inline-block;
} }
} }
} }
.issues-filters,
.issues_bulk_update { .issues_bulk_update {
.select2-container .select2-choice { .select2-container .select2-choice {
color: #444 !important; color: #444 !important;
......
class AutocompleteController < ApplicationController
def users
@users =
if params[:project_id].present?
project = Project.find(params[:project_id])
if can?(current_user, :read_project, project)
project.team.users
end
elsif params[:group_id]
group = Group.find(params[:group_id])
if can?(current_user, :read_group, group)
group.users
end
else
User.all
end
@users = @users.search(params[:search]) if params[:search].present?
@users = @users.active
@users = @users.page(params[:page]).per(PER_PAGE)
render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
end
def user
@user = User.find(params[:id])
render json: @user, only: [:name, :username, :id], methods: [:avatar_url]
end
end
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
require_relative 'projects_finder' require_relative 'projects_finder'
class IssuableFinder class IssuableFinder
NONE = '0'
attr_accessor :current_user, :params attr_accessor :current_user, :params
def execute(current_user, params) def execute(current_user, params)
...@@ -112,7 +114,7 @@ class IssuableFinder ...@@ -112,7 +114,7 @@ class IssuableFinder
def by_milestone(items) def by_milestone(items)
if params[:milestone_id].present? if params[:milestone_id].present?
items = items.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id])) items = items.where(milestone_id: (params[:milestone_id] == NONE ? nil : params[:milestone_id]))
end end
items items
...@@ -120,7 +122,7 @@ class IssuableFinder ...@@ -120,7 +122,7 @@ class IssuableFinder
def by_assignee(items) def by_assignee(items)
if params[:assignee_id].present? if params[:assignee_id].present?
items = items.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id])) items = items.where(assignee_id: (params[:assignee_id] == NONE ? nil : params[:assignee_id]))
end end
items items
...@@ -128,7 +130,7 @@ class IssuableFinder ...@@ -128,7 +130,7 @@ class IssuableFinder
def by_author(items) def by_author(items)
if params[:author_id].present? if params[:author_id].present?
items = items.where(author_id: (params[:author_id] == '0' ? nil : params[:author_id])) items = items.where(author_id: (params[:author_id] == NONE ? nil : params[:author_id]))
end end
items items
......
...@@ -275,7 +275,9 @@ module ApplicationHelper ...@@ -275,7 +275,9 @@ module ApplicationHelper
'https://' + promo_host 'https://' + promo_host
end end
def page_filter_path(options={}) def page_filter_path(options = {})
without = options.delete(:without)
exist_opts = { exist_opts = {
state: params[:state], state: params[:state],
scope: params[:scope], scope: params[:scope],
...@@ -288,6 +290,12 @@ module ApplicationHelper ...@@ -288,6 +290,12 @@ module ApplicationHelper
options = exist_opts.merge(options) options = exist_opts.merge(options)
if without.present?
without.each do |key|
options.delete(key)
end
end
path = request.path path = request.path
path << "?#{options.to_param}" path << "?#{options.to_param}"
path path
......
...@@ -47,4 +47,8 @@ module LabelsHelper ...@@ -47,4 +47,8 @@ module LabelsHelper
"#FFF" "#FFF"
end end
end end
def project_labels_options(project)
options_from_collection_for_select(project.labels, 'name', 'name', params[:label_name])
end
end end
...@@ -19,4 +19,15 @@ module MilestonesHelper ...@@ -19,4 +19,15 @@ module MilestonesHelper
content_tag :div, nil, options content_tag :div, nil, options
end end
end end
def projects_milestones_options
milestones =
if @project
@project.milestones
else
Milestone.where(project_id: @projects)
end.active
options_from_collection_for_select(milestones, 'id', 'title', params[:milestone_id])
end
end end
...@@ -4,18 +4,27 @@ module SelectsHelper ...@@ -4,18 +4,27 @@ module SelectsHelper
css_class << "multiselect " if opts[:multiple] css_class << "multiselect " if opts[:multiple]
css_class << (opts[:class] || '') css_class << (opts[:class] || '')
value = opts[:selected] || '' value = opts[:selected] || ''
placeholder = opts[:placeholder] || 'Search for a user'
hidden_field_tag(id, value, class: css_class) null_user = opts[:null_user] || false
end any_user = opts[:any_user] || false
def project_users_select_tag(id, opts = {}) html = {
css_class = "ajax-project-users-select " class: css_class,
css_class << "multiselect " if opts[:multiple] 'data-placeholder' => placeholder,
css_class << (opts[:class] || '') 'data-null-user' => null_user,
value = opts[:selected] || '' 'data-any-user' => any_user,
placeholder = opts[:placeholder] || 'Select user' }
project_id = opts[:project_id] || @project.id
hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder, 'data-project-id' => project_id) unless opts[:scope] == :all
if @project
html['data-project-id'] = @project.id
elsif @group
html['data-group-id'] = @group.id
end
end
hidden_field_tag(id, value, html)
end end
def groups_select_tag(id, opts = {}) def groups_select_tag(id, opts = {})
......
...@@ -14,8 +14,8 @@ module Issues ...@@ -14,8 +14,8 @@ module Issues
issue.update_nth_task(params[:task_num].to_i, false) issue.update_nth_task(params[:task_num].to_i, false)
end end
params[:assignee_id] = "" if params[:assignee_id] == "-1" params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
params[:milestone_id] = "" if params[:milestone_id] == "-1" params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
old_labels = issue.labels.to_a old_labels = issue.labels.to_a
......
...@@ -23,8 +23,8 @@ module MergeRequests ...@@ -23,8 +23,8 @@ module MergeRequests
merge_request.update_nth_task(params[:task_num].to_i, false) merge_request.update_nth_task(params[:task_num].to_i, false)
end end
params[:assignee_id] = "" if params[:assignee_id] == "-1" params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
params[:milestone_id] = "" if params[:milestone_id] == "-1" params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
old_labels = merge_request.labels.to_a old_labels = merge_request.labels.to_a
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
%i.fa.fa-user %i.fa.fa-user
Assign to Assign to
.col-sm-10 .col-sm-10
= project_users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]", = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
placeholder: 'Select a user', class: 'custom-form-control', placeholder: 'Select a user', class: 'custom-form-control', null_user: true,
selected: issuable.assignee_id) selected: issuable.assignee_id)
&nbsp; &nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link' = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
- else - else
none none
- if can?(current_user, :modify_issue, @issue) - if can?(current_user, :modify_issue, @issue)
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id) = users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id, null_user: true)
%div.prepend-top-20.clearfix %div.prepend-top-20.clearfix
.issuable-context-title .issuable-context-title
...@@ -44,5 +44,3 @@ ...@@ -44,5 +44,3 @@
:coffeescript :coffeescript
new Subscription("#{toggle_subscription_namespace_project_issue_path(@issue.project.namespace, @project, @issue)}") new Subscription("#{toggle_subscription_namespace_project_issue_path(@issue.project.namespace, @project, @issue)}")
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
.issues_bulk_update.hide .issues_bulk_update.hide
= form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post do = form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post do
= select_tag('update[state_event]', options_for_select([['Open', 'reopen'], ['Closed', 'close']]), prompt: "Status", class: 'form-control') = select_tag('update[state_event]', options_for_select([['Open', 'reopen'], ['Closed', 'close']]), prompt: "Status", class: 'form-control')
= project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') = users_select_tag('update[assignee_id]', placeholder: 'Assignee', null_user: true)
= select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
= hidden_field_tag 'update[issues_ids]', [] = hidden_field_tag 'update[issues_ids]', []
= hidden_field_tag :state_event, params[:state_event] = hidden_field_tag :state_event, params[:state_event]
......
...@@ -13,5 +13,5 @@ ...@@ -13,5 +13,5 @@
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true}) $('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
$('.edit-issue.inline-update input[type="submit"]').hide(); $('.edit-issue.inline-update input[type="submit"]').hide();
new ProjectUsersSelect(); new UsersSelect()
new Issue(); new Issue();
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
%i.fa.fa-user %i.fa.fa-user
Assign to Assign to
.col-sm-10 .col-sm-10
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id, project_id: @merge_request.target_project_id) = users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id, project_id: @merge_request.target_project_id)
&nbsp; &nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link' = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group .form-group
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
none none
.issuable-context-selectbox .issuable-context-selectbox
- if can?(current_user, :modify_merge_request, @merge_request) - if can?(current_user, :modify_merge_request, @merge_request)
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id) = users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id, null_user: true)
%div.prepend-top-20.clearfix %div.prepend-top-20.clearfix
.issuable-context-title .issuable-context-title
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
$('.context').html("#{escape_javascript(render partial: 'projects/merge_requests/show/context', locals: { issue: @issue })}"); $('.context').html("#{escape_javascript(render partial: 'projects/merge_requests/show/context', locals: { issue: @issue })}");
$('.context').effect('highlight'); $('.context').effect('highlight');
new ProjectUsersSelect(); new UsersSelect()
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true}); $('select.select2').select2({width: 'resolve', dropdownAutoWidth: true});
merge_request = new MergeRequest(); merge_request = new MergeRequest();
= form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'form-horizontal users-project-form' } do |f| = form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'form-horizontal users-project-form' } do |f|
.form-group .form-group
= f.label :user_ids, "People", class: 'control-label' = f.label :user_ids, "People", class: 'control-label'
.col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large') .col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all)
.form-group .form-group
= f.label :access_level, "Project Access", class: 'control-label' = f.label :access_level, "Project Access", class: 'control-label'
......
...@@ -14,106 +14,35 @@ ...@@ -14,106 +14,35 @@
%i.fa.fa-compass %i.fa.fa-compass
All All
%div .issues-details-filters
- if controller.controller_name == 'issues' = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_id, :label_name]), method: :get, class: 'filter-form' do
.check-all-holder - if controller.controller_name == 'issues'
= check_box_tag "check_all_issues", nil, false, .check-all-holder
class: "check_all_issues left", = check_box_tag "check_all_issues", nil, false,
disabled: !can?(current_user, :modify_issue, @project) class: "check_all_issues left",
.issues-other-filters disabled: !can?(current_user, :modify_issue, @project)
.dropdown.inline.assignee-filter .issues-other-filters
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"} .filter-item.inline
%i.fa.fa-user = users_select_tag(:assignee_id, selected: params[:assignee_id],
%span.light assignee: placeholder: 'Assignee', class: 'trigger-submit', any_user: true, null_user: true)
- if @assignee.present?
%strong= @assignee.name
- elsif params[:assignee_id] == "0"
Unassigned
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to page_filter_path(assignee_id: nil) do
Any
= link_to page_filter_path(assignee_id: 0) do
Unassigned
- @assignees.sort_by(&:name).each do |user|
%li
= link_to page_filter_path(assignee_id: user.id) do
= image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
= user.name
.dropdown.inline.prepend-left-10.author-filter .filter-item.inline
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"} = users_select_tag(:author_id, selected: params[:author_id],
%i.fa.fa-user placeholder: 'Author', class: 'trigger-submit', any_user: true)
%span.light author:
- if @author.present?
%strong= @author.name
- elsif params[:author_id] == "0"
Unassigned
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to page_filter_path(author_id: nil) do
Any
= link_to page_filter_path(author_id: 0) do
Unassigned
- @authors.sort_by(&:name).each do |user|
%li
= link_to page_filter_path(author_id: user.id) do
= image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
= user.name
.dropdown.inline.prepend-left-10.milestone-filter .filter-item.inline.milestone-filter
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"} = select_tag('milestone_id', projects_milestones_options, class: "select2 trigger-submit", prompt: 'Milestone')
%i.fa.fa-clock-o
%span.light milestone:
- if @milestone.present?
%strong= @milestone.title
- elsif params[:milestone_id] == "0"
None (backlog)
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to page_filter_path(milestone_id: nil) do
Any
= link_to page_filter_path(milestone_id: 0) do
None (backlog)
- @milestones.each do |milestone|
%li
= link_to page_filter_path(milestone_id: milestone.id) do
%strong= milestone.title
%small.light= milestone.expires_at
- if @project - if @project
.dropdown.inline.prepend-left-10.labels-filter .filter-item.inline.labels-filter
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"} = select_tag('label_name', project_labels_options(@project), class: "select2 trigger-submit", prompt: 'Label')
%i.fa.fa-tags
%span.light label:
- if params[:label_name].present?
%strong= params[:label_name]
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to page_filter_path(label_name: nil) do
Any
- if @project.labels.any?
- @project.labels.each do |label|
%li
= link_to page_filter_path(label_name: label.name) do
= render_colored_label(label)
- else
%li
= link_to generate_namespace_project_labels_path(@project.namespace, @project, redirect: request.original_url), method: :post do
%i.fa.fa-plus-circle
Create default labels
.pull-right .pull-right
= render 'shared/sort_dropdown' = render 'shared/sort_dropdown'
:coffeescript
new UsersSelect()
$('form.filter-form').on 'submit', (event) ->
event.preventDefault()
Turbolinks.visit @.action + '&' + $(@).serialize()
...@@ -8,6 +8,11 @@ Gitlab::Application.routes.draw do ...@@ -8,6 +8,11 @@ Gitlab::Application.routes.draw do
authorizations: 'oauth/authorizations' authorizations: 'oauth/authorizations'
end end
# Autocomplete
get '/autocomplete/users' => 'autocomplete#users'
get '/autocomplete/users/:id' => 'autocomplete#user'
# Search # Search
get 'search' => 'search#show' get 'search' => 'search#show'
get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete
......
...@@ -68,6 +68,6 @@ You can't add the same deploy key twice with the 'New Deploy Key' option. ...@@ -68,6 +68,6 @@ You can't add the same deploy key twice with the 'New Deploy Key' option.
If you want to add the same key to another project, please enable it in the If you want to add the same key to another project, please enable it in the
list that says 'Deploy keys from projects available to you'. All the deploy list that says 'Deploy keys from projects available to you'. All the deploy
keys of all the projects you have access to are available. This project keys of all the projects you have access to are available. This project
access can happen through being a direct member of the projecti, or through access can happen through being a direct member of the project, or through
a group. See `def accessible_deploy_keys` in `app/models/user.rb` for more a group. See `def accessible_deploy_keys` in `app/models/user.rb` for more
information. information.
...@@ -10,10 +10,12 @@ Feature: Dashboard Issues ...@@ -10,10 +10,12 @@ Feature: Dashboard Issues
Scenario: I should see assigned issues Scenario: I should see assigned issues
Then I should see issues assigned to me Then I should see issues assigned to me
@javascript
Scenario: I should see authored issues Scenario: I should see authored issues
When I click "Authored by me" link When I click "Authored by me" link
Then I should see issues authored by me Then I should see issues authored by me
@javascript
Scenario: I should see all issues Scenario: I should see all issues
When I click "All" link When I click "All" link
Then I should see all issues Then I should see all issues
...@@ -10,10 +10,12 @@ Feature: Dashboard Merge Requests ...@@ -10,10 +10,12 @@ Feature: Dashboard Merge Requests
Scenario: I should see assigned merge_requests Scenario: I should see assigned merge_requests
Then I should see merge requests assigned to me Then I should see merge requests assigned to me
@javascript
Scenario: I should see authored merge_requests Scenario: I should see authored merge_requests
When I click "Authored by me" link When I click "Authored by me" link
Then I should see merge requests authored by me Then I should see merge requests authored by me
@javascript
Scenario: I should see all merge_requests Scenario: I should see all merge_requests
When I click "All" link When I click "All" link
Then I should see all merge requests Then I should see all merge requests
...@@ -8,11 +8,7 @@ Feature: Project Issues Filter Labels ...@@ -8,11 +8,7 @@ Feature: Project Issues Filter Labels
And project "Shop" has issue "Feature1" with labels: "feature" And project "Shop" has issue "Feature1" with labels: "feature"
Given I visit project "Shop" issues page Given I visit project "Shop" issues page
Scenario: I should see project issues @javascript
Then I should see "bug" in labels filter
And I should see "feature" in labels filter
And I should see "enhancement" in labels filter
Scenario: I filter by one label Scenario: I filter by one label
Given I click link "bug" Given I click link "bug"
Then I should see "Bugfix1" in issues list Then I should see "Bugfix1" in issues list
......
class Spinach::Features::DashboardIssues < Spinach::FeatureSteps class Spinach::Features::DashboardIssues < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedPaths include SharedPaths
include Select2Helper
step 'I should see issues assigned to me' do step 'I should see issues assigned to me' do
should_see(assigned_issue) should_see(assigned_issue)
...@@ -35,21 +36,13 @@ class Spinach::Features::DashboardIssues < Spinach::FeatureSteps ...@@ -35,21 +36,13 @@ class Spinach::Features::DashboardIssues < Spinach::FeatureSteps
end end
step 'I click "Authored by me" link' do step 'I click "Authored by me" link' do
within ".assignee-filter" do select2(current_user.id, from: "#author_id")
click_link "Any" select2(nil, from: "#assignee_id")
end
within ".author-filter" do
click_link current_user.name
end
end end
step 'I click "All" link' do step 'I click "All" link' do
within ".author-filter" do select2(nil, from: "#author_id")
click_link "Any" select2(nil, from: "#assignee_id")
end
within ".assignee-filter" do
click_link "Any"
end
end end
def should_see(issue) def should_see(issue)
......
class Spinach::Features::DashboardMergeRequests < Spinach::FeatureSteps class Spinach::Features::DashboardMergeRequests < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedPaths include SharedPaths
include Select2Helper
step 'I should see merge requests assigned to me' do step 'I should see merge requests assigned to me' do
should_see(assigned_merge_request) should_see(assigned_merge_request)
...@@ -39,21 +40,13 @@ class Spinach::Features::DashboardMergeRequests < Spinach::FeatureSteps ...@@ -39,21 +40,13 @@ class Spinach::Features::DashboardMergeRequests < Spinach::FeatureSteps
end end
step 'I click "Authored by me" link' do step 'I click "Authored by me" link' do
within ".assignee-filter" do select2(current_user.id, from: "#author_id")
click_link "Any" select2(nil, from: "#assignee_id")
end
within ".author-filter" do
click_link current_user.name
end
end end
step 'I click "All" link' do step 'I click "All" link' do
within ".author-filter" do select2(nil, from: "#author_id")
click_link "Any" select2(nil, from: "#assignee_id")
end
within ".assignee-filter" do
click_link "Any"
end
end end
def should_see(merge_request) def should_see(merge_request)
......
...@@ -2,24 +2,7 @@ class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps ...@@ -2,24 +2,7 @@ class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedProject include SharedProject
include SharedPaths include SharedPaths
include Select2Helper
step 'I should see "bug" in labels filter' do
within ".labels-filter" do
page.should have_content "bug"
end
end
step 'I should see "feature" in labels filter' do
within ".labels-filter" do
page.should have_content "feature"
end
end
step 'I should see "enhancement" in labels filter' do
within ".labels-filter" do
page.should have_content "enhancement"
end
end
step 'I should see "Bugfix1" in issues list' do step 'I should see "Bugfix1" in issues list' do
within ".issues-list" do within ".issues-list" do
...@@ -46,9 +29,7 @@ class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps ...@@ -46,9 +29,7 @@ class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps
end end
step 'I click link "bug"' do step 'I click link "bug"' do
within ".labels-filter" do select2('bug', from: "#label_name")
click_link "bug"
end
end end
step 'I click link "feature"' do step 'I click link "feature"' do
......
require 'spec_helper'
describe AutocompleteController do
let!(:project) { create(:project) }
let!(:user) { create(:user) }
let!(:user2) { create(:user) }
context 'project members' do
before do
sign_in(user)
project.team << [user, :master]
get(:users, project_id: project.id)
end
let(:body) { JSON.parse(response.body) }
it { body.should be_kind_of(Array) }
it { body.size.should eq(1) }
it { body.first["username"].should == user.username }
end
context 'group members' do
let(:group) { create(:group) }
before do
sign_in(user)
group.add_owner(user)
get(:users, group_id: group.id)
end
let(:body) { JSON.parse(response.body) }
it { body.should be_kind_of(Array) }
it { body.size.should eq(1) }
it { body.first["username"].should == user.username }
end
context 'all users' do
before do
sign_in(user)
get(:users)
end
let(:body) { JSON.parse(response.body) }
it { body.should be_kind_of(Array) }
it { body.size.should eq(User.count) }
end
end
...@@ -95,7 +95,7 @@ describe 'Issues', feature: true do ...@@ -95,7 +95,7 @@ describe 'Issues', feature: true do
let(:issue) { @issue } let(:issue) { @issue }
it 'should allow filtering by issues with no specified milestone' do it 'should allow filtering by issues with no specified milestone' do
visit namespace_project_issues_path(project.namespace, project, milestone_id: '0') visit namespace_project_issues_path(project.namespace, project, milestone_id: IssuableFinder::NONE)
expect(page).not_to have_content 'foobar' expect(page).not_to have_content 'foobar'
expect(page).to have_content 'barbaz' expect(page).to have_content 'barbaz'
...@@ -111,7 +111,7 @@ describe 'Issues', feature: true do ...@@ -111,7 +111,7 @@ describe 'Issues', feature: true do
end end
it 'should allow filtering by issues with no specified assignee' do it 'should allow filtering by issues with no specified assignee' do
visit namespace_project_issues_path(project.namespace, project, assignee_id: '0') visit namespace_project_issues_path(project.namespace, project, assignee_id: IssuableFinder::NONE)
expect(page).to have_content 'foobar' expect(page).to have_content 'foobar'
expect(page).not_to have_content 'barbaz' expect(page).not_to have_content 'barbaz'
......
...@@ -17,9 +17,9 @@ module Select2Helper ...@@ -17,9 +17,9 @@ module Select2Helper
selector = options[:from] selector = options[:from]
if options[:multiple] if options[:multiple]
execute_script("$('#{selector}').select2('val', ['#{value}']);") execute_script("$('#{selector}').select2('val', ['#{value}'], true);")
else else
execute_script("$('#{selector}').select2('val', '#{value}');") execute_script("$('#{selector}').select2('val', '#{value}', true);")
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment