From 52d2fd49b5d913d40259161e44579b715b4a383c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 31 Aug 2016 15:28:58 +0100 Subject: [PATCH 01/41] Updated members UI --- app/assets/javascripts/dispatcher.js | 2 +- app/assets/javascripts/project_members.js | 10 ---- app/assets/javascripts/project_members.js.es6 | 36 +++++++++++++ app/assets/stylesheets/framework/selects.scss | 6 ++- app/assets/stylesheets/pages/members.scss | 22 ++++++++ .../_new_project_member.html.haml | 35 ++++++------ .../projects/project_members/_team.html.haml | 2 +- .../projects/project_members/index.html.haml | 23 ++++---- app/views/shared/members/_member.html.haml | 54 +++++++------------ 9 files changed, 111 insertions(+), 79 deletions(-) delete mode 100644 app/assets/javascripts/project_members.js create mode 100644 app/assets/javascripts/project_members.js.es6 create mode 100644 app/assets/stylesheets/pages/members.scss diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 99b16f7d59b..c95aaf61443 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -132,7 +132,7 @@ break; case 'projects:project_members:index': new gl.MemberExpirationDate(); - new ProjectMembers(); + new gl.ProjectMembers(); new UsersSelect(); break; case 'groups:new': diff --git a/app/assets/javascripts/project_members.js b/app/assets/javascripts/project_members.js deleted file mode 100644 index 78f7b48bc7d..00000000000 --- a/app/assets/javascripts/project_members.js +++ /dev/null @@ -1,10 +0,0 @@ -(function() { - this.ProjectMembers = (function() { - function ProjectMembers() { - $('li.project_member').bind('ajax:success', function() { - return $(this).fadeOut(); - }); - } - return ProjectMembers; - })(); -}).call(this); diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/project_members.js.es6 new file mode 100644 index 00000000000..74cedfd5006 --- /dev/null +++ b/app/assets/javascripts/project_members.js.es6 @@ -0,0 +1,36 @@ +((w) => { + window.gl = window.gl || {}; + + class ProjectMembers { + constructor() { + this.removeListeners(); + this.addListeners(); + } + + removeListeners() { + $('.project_member').off('ajax:success'); + $('.js-member-update-control').off('change'); + } + + addListeners() { + $('.project_member').on('ajax:success', this.removeRow); + $('.js-member-update-control').on('change', function () { + console.log($(this).val()); + }); + } + + removeRow(e) { + const $target = $(e.target); + + if ($target.hasClass('btn-remove')) { + $target.fadeOut(); + } + } + + submitForm() { + + } + } + + gl.ProjectMembers = ProjectMembers; +})(window); diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index c75dacf95d9..746ab89abd2 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -86,7 +86,7 @@ background: none; .select2-search-field input { - padding: $gl-padding / 2; + padding: 5px $gl-padding / 2; font-size: 13px; height: auto; font-family: inherit; @@ -191,6 +191,10 @@ &.input-clamp { max-width: 100%; } + + &.input-full { + width: 100%; + } } .select2-highlighted { diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss new file mode 100644 index 00000000000..9583d7c6161 --- /dev/null +++ b/app/assets/stylesheets/pages/members.scss @@ -0,0 +1,22 @@ +.project-members-new { + > h5 { + font-weight: normal; + } +} + +.member { + .controls { + display: flex; + width: 400px; + } + + .form-horizontal { + display: flex; + flex: 1; + margin-top: 3px; + } + + .member-form-control { + width: 50%; + } +} diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index fa8cbf71733..c0b187fb460 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -1,27 +1,22 @@ -= 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 - = f.label :user_ids, "People", class: 'control-label' - .col-sm-10 - = users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all, email_user: true) - .help-block += form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project) do |f| + .row + .col-md-4.col-lg-6 + = users_select_tag(:user_ids, multiple: true, class: "input-full", scope: :all, email_user: true) + .help-block.append-bottom-10 Search for users by name, username, or email, or invite new ones using their email address. - .form-group - = f.label :access_level, "Project Access", class: 'control-label' - .col-sm-10 - = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "project-access-select select2" - .help-block - Read more about role permissions - %strong= link_to "here", help_page_path("user/permissions"), class: "vlink" + .col-md-3.col-lg-2 + = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "form-control project-access-select" + .help-block.append-bottom-10 + = link_to "Read more", help_page_path("user/permissions"), class: "vlink" + about role permissions - .form-group - = f.label :expires_at, 'Access expiration date', class: 'control-label' - .col-sm-10 + .col-md-3.col-lg-2 .clearable-input - = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Select access expiration date' + = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' %i.clear-icon.js-clear-input - .help-block + .help-block.append-bottom-10 On this date, the user(s) will automatically lose access to this project. - .form-actions - = f.submit 'Add users to project', class: "btn btn-create" + .col-md-2 + = f.submit "Add to project", class: "btn btn-create btn-block" diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index b0bfdd235f7..db6c1194da7 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -1,7 +1,7 @@ .panel.panel-default .panel-heading + Users with access to %strong #{@project.name} - project members %span.badge= members.size .controls = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 9d063b3081f..9d47e7d725c 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,20 +1,21 @@ - page_title "Members" .project-members-page.js-project-members-page.prepend-top-default + %h4 + Members + %hr - if can?(current_user, :admin_project_member, @project) - .panel.panel-default - .panel-heading - Add new user to project - .controls - = link_to import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do - Import members - .panel-body - %p.light - Users with access to this project are listed below. - = render "new_project_member" + .project-members-new.append-bottom-default + %h5.clearfix + Add new user to + %strong= @project.name + -# = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default pull-right", title: "Import members from another project" + = render "new_project_member" - = render 'shared/members/requests', membership_source: @project, requesters: @requesters + = render 'shared/members/requests', membership_source: @project, requesters: @requesters + %h5.append-bottom-default + Existing users and groups = render 'team', members: @project_members - if @group diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 5f20e4bd42a..fd9b688dc20 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -2,27 +2,28 @@ - show_controls = local_assigns.fetch(:show_controls, true) - user = member.user -%li.js-toggle-container{ class: dom_class(member), id: dom_id(member) } +%li.member{ class: dom_class(member), id: dom_id(member) } - if show_roles .controls - %strong.control-text= member.human_access - if show_controls - - if !user && can?(current_user, action_member_permission(:admin, member), member.source) - = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), - method: :post, - class: 'btn' - - - if can?(current_user, action_member_permission(:update, member), member) - = button_tag icon('pencil'), - type: 'button', - class: 'btn inline js-toggle-button', - title: 'Edit' - - - if member.request? - = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), + - if @project.owner != user + = form_for member, remote: true, html: { class: 'form-horizontal' } do |f| + = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + .prepend-left-5.append-right-10.clearable-input.member-form-control + = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + %i.clear-icon.js-clear-input + - if !user && can?(current_user, action_member_permission(:admin, member), member.source) + = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), method: :post, - class: 'btn btn-success', - title: 'Grant access' + class: 'btn' + - else + Owner + + - if member.request? && can?(current_user, action_member_permission(:update, member), member) + = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), + method: :post, + class: 'btn btn-success', + title: 'Grant access' - if can?(current_user, action_member_permission(:destroy, member), member) - if current_user == user @@ -44,7 +45,7 @@ = image_tag avatar_icon(user, 40), class: "avatar s40", alt: '' %strong = link_to user.name, user_path(user) - %span.cgray= user.username + %span.cgray= user.to_reference - if user == current_user %span.label.label-success It's you @@ -73,20 +74,3 @@ by = link_to member.created_by.name, user_path(member.created_by) = time_ago_with_tooltip(member.created_at) - - - if show_roles - .edit-member.hide.js-toggle-content - %br - = form_for member, remote: true, html: { class: 'form-horizontal' } do |f| - .form-group - = label_tag "member_access_level_#{member.id}", 'Project access', class: 'control-label' - .col-sm-10 - = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control', id: "member_access_level_#{member.id}" - .form-group - = label_tag "member_expires_at_#{member.id}", 'Access expiration date', class: 'control-label' - .col-sm-10 - .clearable-input - = f.text_field :expires_at, class: 'form-control js-access-expiration-date', placeholder: 'Select access expiration date', id: "member_expires_at_#{member.id}" - %i.clear-icon.js-clear-input - .prepend-top-10 - = f.submit 'Save', class: 'btn btn-save btn-sm' From 87a0501ded0d08ae718b6f3f6feb4ac2c9c6b016 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Sep 2016 11:56:21 +0100 Subject: [PATCH 02/41] Updates the member row when values changed --- app/assets/javascripts/member_expiration_date.js | 8 ++++++-- app/assets/javascripts/project_members.js.es6 | 5 +++-- app/views/projects/project_members/update.js.haml | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js index 1935af491f7..e1532fd9ec4 100644 --- a/app/assets/javascripts/member_expiration_date.js +++ b/app/assets/javascripts/member_expiration_date.js @@ -14,14 +14,18 @@ inputs.datepicker({ dateFormat: 'yy-mm-dd', minDate: 1, - onSelect: toggleClearInput + onSelect: function () { + $(this).trigger('change'); + toggleClearInput.call(this); + } }); inputs.next('.js-clear-input').on('click', function(event) { event.preventDefault(); var input = $(this).closest('.clearable-input').find('.js-access-expiration-date'); - input.datepicker('setDate', null); + input.datepicker('setDate', null) + .trigger('change'); toggleClearInput.call(input); }); diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/project_members.js.es6 index 74cedfd5006..659c57d8b6c 100644 --- a/app/assets/javascripts/project_members.js.es6 +++ b/app/assets/javascripts/project_members.js.es6 @@ -15,7 +15,8 @@ addListeners() { $('.project_member').on('ajax:success', this.removeRow); $('.js-member-update-control').on('change', function () { - console.log($(this).val()); + $(this).closest('form') + .trigger("submit.rails"); }); } @@ -28,7 +29,7 @@ } submitForm() { - + } } diff --git a/app/views/projects/project_members/update.js.haml b/app/views/projects/project_members/update.js.haml index 37e55dc72a3..91927181efb 100644 --- a/app/views/projects/project_members/update.js.haml +++ b/app/views/projects/project_members/update.js.haml @@ -1,3 +1,3 @@ :plain - $("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render('shared/members/member', member: @project_member))}'); - new gl.MemberExpirationDate(); + var $listItem = $('#{escape_javascript(render('shared/members/member', member: @project_member))}'); + $("##{dom_id(@project_member)} .list-item-name").replaceWith($listItem.find('.list-item-name')); From 4afd17b2786b5bca075ac7508979fad582c65bc9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Sep 2016 13:48:20 +0100 Subject: [PATCH 03/41] Included groups on project_members page --- app/assets/stylesheets/framework/lists.scss | 8 +++ app/assets/stylesheets/pages/groups.scss | 2 - app/assets/stylesheets/pages/members.scss | 9 +++ .../projects/group_links_controller.rb | 12 ++++ .../projects/project_members_controller.rb | 1 + app/views/projects/group_links/update.js.haml | 3 + .../project_members/_group_members.html.haml | 2 +- .../project_members/_groups.html.haml | 9 +++ .../projects/project_members/_team.html.haml | 12 ---- .../projects/project_members/index.html.haml | 14 ++-- app/views/shared/members/_group.html.haml | 23 +++++++ app/views/shared/members/_member.html.haml | 69 +++++++++---------- config/routes.rb | 2 +- 13 files changed, 108 insertions(+), 58 deletions(-) create mode 100644 app/views/projects/group_links/update.js.haml create mode 100644 app/views/projects/project_members/_groups.html.haml create mode 100644 app/views/shared/members/_group.html.haml diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 965fcc06518..dfdfe4a3c89 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -164,6 +164,14 @@ ul.content-list { } } + .member-controls { + float: none; + + @media (min-width: $screen-md-min) { + float: right; + } + } + // When dragging a list item &.ui-sortable-helper { border-bottom: none; diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index b657ca47d38..a27f7a2fd77 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -1,6 +1,4 @@ .member-search-form { - float: left; - input[type='search'] { width: 225px; vertical-align: bottom; diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index 9583d7c6161..4bc34ac15df 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -5,6 +5,15 @@ } .member { + .list-item-name { + float: none; + + @media (min-width: $screen-md-min) { + float: left; + width: 50%; + } + } + .controls { display: flex; width: 400px; diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index d0c4550733c..57c54bf625a 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -19,9 +19,21 @@ class Projects::GroupLinksController < Projects::ApplicationController redirect_to namespace_project_group_links_path(project.namespace, project) end + def update + @group_link = @project.project_group_links.find(params[:id]) + + @group_link.update_attributes(group_link_params) + end + def destroy project.project_group_links.find(params[:id]).destroy redirect_to namespace_project_group_links_path(project.namespace, project) end + + protected + + def group_link_params + params.require(:group_link).permit(:group_access, :expires_at) + end end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 42a7e5a2c30..d83e95cf097 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -5,6 +5,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] def index + @groups = @project.project_group_links.all @project_members = @project.project_members @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) diff --git a/app/views/projects/group_links/update.js.haml b/app/views/projects/group_links/update.js.haml new file mode 100644 index 00000000000..d3a37847f58 --- /dev/null +++ b/app/views/projects/group_links/update.js.haml @@ -0,0 +1,3 @@ +:plain + var $listItem = $('#{escape_javascript(render('shared/members/group', group_link: @group_link, group: @group_link.group))}'); + $("##{dom_id(@group_link.group)} .list-item-name").replaceWith($listItem.find('.list-item-name')); diff --git a/app/views/projects/project_members/_group_members.html.haml b/app/views/projects/project_members/_group_members.html.haml index e783d8c72c5..9738f369a35 100644 --- a/app/views/projects/project_members/_group_members.html.haml +++ b/app/views/projects/project_members/_group_members.html.haml @@ -1,7 +1,7 @@ .panel.panel-default .panel-heading + Group members with access to %strong #{@group.name} - group members %span.badge= members.size - if can?(current_user, :admin_group_member, @group) .controls diff --git a/app/views/projects/project_members/_groups.html.haml b/app/views/projects/project_members/_groups.html.haml new file mode 100644 index 00000000000..79791af7963 --- /dev/null +++ b/app/views/projects/project_members/_groups.html.haml @@ -0,0 +1,9 @@ +.panel.panel-default + .panel-heading + Groups with access to + %strong #{@project.name} + %span.badge= groups.size + %ul.content-list + - @groups.each do |group_link| + - group = group_link.group + = render 'shared/members/group', group_link: group_link, group: group diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index db6c1194da7..6a8b28d3886 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -3,17 +3,5 @@ Users with access to %strong #{@project.name} %span.badge= members.size - .controls - = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do - .form-group - = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false } - = button_tag class: 'btn', title: 'Search' do - = icon("search") %ul.content-list = render partial: 'shared/members/member', collection: members, as: :member - -:javascript - $('form.member-search-form').on('submit', function (event) { - event.preventDefault(); - Turbolinks.visit(this.action + '?' + $(this).serialize()); - }); diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 9d47e7d725c..db8a060d170 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -14,12 +14,16 @@ = render 'shared/members/requests', membership_source: @project, requesters: @requesters - %h5.append-bottom-default - Existing users and groups + .append-bottom-default.clearfix + %h5.pull-left + Existing users and groups + = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form pull-right hidden-xs hidden-sm' do + .form-group + = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } + = icon("search") + - if @grups + = render 'groups', groups: @groups = render 'team', members: @project_members - if @group = render "group_members", members: @group_members - - - if @project_group_links.any? && @project.allowed_to_share_with_group? - = render "shared_group_members" diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml new file mode 100644 index 00000000000..0502de5210b --- /dev/null +++ b/app/views/shared/members/_group.html.haml @@ -0,0 +1,23 @@ +- group = local_assigns[:group] +- group_link = local_assigns[:group_link] +%li.member{ class: dom_class(group), id: dom_id(group) } + %span{ class: "list-item-name" } + = image_tag group_icon(group), class: "avatar s40", alt: '' + %strong + = link_to group.name, group_path(group) + .cgray + Joined #{time_ago_with_tooltip(group.created_at)} + - if group_link.expires? + · + %span{ class: ('text-warning' if group_link.expires_soon?) } + Expires in #{distance_of_time_in_words_to_now(group_link.expires_at)} + .controls.member-controls + = form_tag namespace_project_group_link_path(@project.namespace, @project, group_link), method: :put, remote: true, class: 'form-horizontal' do + = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}" + .prepend-left-5.append-right-10.clearable-input.member-form-control + = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}" + %i.clear-icon.js-clear-input + = link_to icon('trash'), namespace_project_group_link_path(@project.namespace, @project, group_link), + remote: true, + method: :delete, + class: 'btn btn-remove' diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index fd9b688dc20..800badc051a 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -3,43 +3,6 @@ - user = member.user %li.member{ class: dom_class(member), id: dom_id(member) } - - if show_roles - .controls - - if show_controls - - if @project.owner != user - = form_for member, remote: true, html: { class: 'form-horizontal' } do |f| - = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) - .prepend-left-5.append-right-10.clearable-input.member-form-control - = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) - %i.clear-icon.js-clear-input - - if !user && can?(current_user, action_member_permission(:admin, member), member.source) - = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), - method: :post, - class: 'btn' - - else - Owner - - - if member.request? && can?(current_user, action_member_permission(:update, member), member) - = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), - method: :post, - class: 'btn btn-success', - title: 'Grant access' - - - if can?(current_user, action_member_permission(:destroy, member), member) - - if current_user == user - = link_to icon('sign-out', text: 'Leave'), polymorphic_path([:leave, member.source, :members]), - method: :delete, - data: { confirm: leave_confirmation_message(member.source) }, - class: 'btn btn-remove' - - else - = link_to icon('trash'), member, - remote: true, - method: :delete, - data: { confirm: remove_member_message(member) }, - class: 'btn btn-remove', - title: remove_member_title(member) - - %span{ class: ("list-item-name" if show_controls) } - if user = image_tag avatar_icon(user, 40), class: "avatar s40", alt: '' @@ -74,3 +37,35 @@ by = link_to member.created_by.name, user_path(member.created_by) = time_ago_with_tooltip(member.created_at) + - if show_roles + .controls.member-controls + - if show_controls + = form_for member, remote: true, html: { class: 'form-horizontal' } do |f| + = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + .prepend-left-5.append-right-10.clearable-input.member-form-control + = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + %i.clear-icon.js-clear-input + - if !user && can?(current_user, action_member_permission(:admin, member), member.source) + = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), + method: :post, + class: 'btn' + + - if member.request? && can?(current_user, action_member_permission(:update, member), member) + = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), + method: :post, + class: 'btn btn-success', + title: 'Grant access' + + - if can?(current_user, action_member_permission(:destroy, member), member) + - if current_user == user + = link_to icon('sign-out', text: 'Leave'), polymorphic_path([:leave, member.source, :members]), + method: :delete, + data: { confirm: leave_confirmation_message(member.source) }, + class: 'btn btn-remove' + - else + = link_to icon('trash'), member, + remote: true, + method: :delete, + data: { confirm: remove_member_message(member) }, + class: 'btn btn-remove', + title: remove_member_title(member) diff --git a/config/routes.rb b/config/routes.rb index 068c92d1400..441f7249aa8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -867,7 +867,7 @@ Rails.application.routes.draw do end end - resources :group_links, only: [:index, :create, :destroy], constraints: { id: /\d+/ } + resources :group_links, only: [:index, :create, :update, :destroy], constraints: { id: /\d+/ } resources :notes, only: [:index, :create, :destroy, :update], constraints: { id: /\d+/ } do member do From 23993147fbf24e868d33927dc1194b60a106076d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Sep 2016 14:13:49 +0100 Subject: [PATCH 04/41] Fixed issue with groups not displaying --- .../projects/project_members_controller.rb | 14 -------------- app/views/projects/project_members/index.html.haml | 6 ++---- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index d83e95cf097..6060ddf025b 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -16,20 +16,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController @project_members = @project_members.order('access_level DESC') - @group = @project.group - - if @group - @group_members = @group.group_members - @group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group) - - if params[:search].present? - users = @group.users.search(params[:search]).to_a - @group_members = @group_members.where(user_id: users) - end - - @group_members = @group_members.order('access_level DESC') - end - @requesters = @project.requesters if can?(current_user, :admin_project, @project) @project_member = @project.project_members.new diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index db8a060d170..42a23057ff1 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -21,9 +21,7 @@ .form-group = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } = icon("search") - - if @grups + - if @groups.size > 0 = render 'groups', groups: @groups - = render 'team', members: @project_members - - if @group - = render "group_members", members: @group_members + = render 'team', members: @project_members From e33cda96cb20f47fdde4314f6bb00e43bbf5aeb4 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Sep 2016 15:27:42 +0100 Subject: [PATCH 05/41] Fixed group members not deleting Combine both group members & project members in project members list --- app/assets/javascripts/project_members.js.es6 | 7 ++++--- app/controllers/projects/project_members_controller.rb | 9 +++++---- app/views/projects/project_members/_team.html.haml | 6 ++++-- app/views/projects/project_members/index.html.haml | 1 + 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/project_members.js.es6 index 659c57d8b6c..8b5cb17ac2d 100644 --- a/app/assets/javascripts/project_members.js.es6 +++ b/app/assets/javascripts/project_members.js.es6 @@ -8,12 +8,12 @@ } removeListeners() { - $('.project_member').off('ajax:success'); + $('.project_member, .group_member').off('ajax:success'); $('.js-member-update-control').off('change'); } addListeners() { - $('.project_member').on('ajax:success', this.removeRow); + $('.project_member, .group_member').on('ajax:success', this.removeRow); $('.js-member-update-control').on('change', function () { $(this).closest('form') .trigger("submit.rails"); @@ -24,7 +24,8 @@ const $target = $(e.target); if ($target.hasClass('btn-remove')) { - $target.fadeOut(); + console.log('a'); + $target.closest('.member').fadeOut(); } } diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 6060ddf025b..abb92938211 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,15 +6,16 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @groups = @project.project_group_links.all - @project_members = @project.project_members + @project_members = @project.team.members.all + @project_members_size = @project_members.size + @group_members = @project.group.group_members @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? - users = @project.users.search(params[:search]).to_a - @project_members = @project_members.where(user_id: users) + @project_members = @project_members.search(params[:search]) end - @project_members = @project_members.order('access_level DESC') + @project_members = @project_members.page(params[:page]) @requesters = @project.requesters if can?(current_user, :admin_project, @project) diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 6a8b28d3886..23c35f91b6b 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -2,6 +2,8 @@ .panel-heading Users with access to %strong #{@project.name} - %span.badge= members.size + %span.badge= @project_members_size %ul.content-list - = render partial: 'shared/members/member', collection: members, as: :member + - members.each do |user| + - member = @project.team.find_member(user.id) + = render 'shared/members/member', member: member diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 42a23057ff1..85e512a75f4 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -25,3 +25,4 @@ = render 'groups', groups: @groups = render 'team', members: @project_members + = paginate @project_members, theme: "gitlab" From 843dd24bdf063bb199c841cd6a08643344ae7598 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Sep 2016 16:22:53 +0100 Subject: [PATCH 06/41] Mobile improvements Added group name to members row Fixed saving group member --- app/assets/javascripts/project_members.js.es6 | 7 +++- app/assets/stylesheets/framework/lists.scss | 8 +++- app/assets/stylesheets/pages/members.scss | 42 +++++++++++++++---- app/views/groups/group_members/update.js.haml | 4 +- .../projects/project_members/_team.html.haml | 2 +- app/views/shared/members/_group.html.haml | 7 +++- app/views/shared/members/_member.html.haml | 28 +++++++++---- 7 files changed, 74 insertions(+), 24 deletions(-) diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/project_members.js.es6 index 8b5cb17ac2d..d11467cf6eb 100644 --- a/app/assets/javascripts/project_members.js.es6 +++ b/app/assets/javascripts/project_members.js.es6 @@ -1,5 +1,5 @@ ((w) => { - window.gl = window.gl || {}; + w.gl = w.gl || {}; class ProjectMembers { constructor() { @@ -10,6 +10,7 @@ removeListeners() { $('.project_member, .group_member').off('ajax:success'); $('.js-member-update-control').off('change'); + $('.js-edit-member-form').off('ajax:success'); } addListeners() { @@ -17,6 +18,10 @@ $('.js-member-update-control').on('change', function () { $(this).closest('form') .trigger("submit.rails"); + $(this).disable(); + }); + $('.js-edit-member-form').on('ajax:success', function () { + $(this).find('.js-member-update-control').enable(); }); } diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index dfdfe4a3c89..272d37763c1 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -128,6 +128,10 @@ ul.content-list { color: $gl-dark-link-color; } + .member-group-link { + color: $blue-normal; + } + .description { p { @include str-truncated; @@ -166,8 +170,8 @@ ul.content-list { .member-controls { float: none; - - @media (min-width: $screen-md-min) { + + @media (min-width: $screen-sm-min) { float: right; } } diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index 4bc34ac15df..a69af862348 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -8,24 +8,52 @@ .list-item-name { float: none; - @media (min-width: $screen-md-min) { + @media (min-width: $screen-sm-min) { float: left; width: 50%; } } .controls { - display: flex; - width: 400px; + @media (min-width: $screen-sm-min) { + display: flex; + width: 400px; + max-width: 50%; + } } .form-horizontal { - display: flex; - flex: 1; - margin-top: 3px; + margin-top: 5px; + + @media (min-width: $screen-sm-min) { + display: flex; + flex: 1; + margin-top: 3px; + } } - .member-form-control { + .btn-remove { + width: 100%; + + @media (min-width: $screen-sm-min) { + width: auto; + } + } +} + +.member-form-control { + @media (max-width: $screen-xs-max) { + padding: 5px 0; + margin-left: 0; + margin-right: 0; + } + + @media (min-width: $screen-sm-min) { width: 50%; } } + +.member-access-text { + margin-left: auto; + line-height: 43px; +} diff --git a/app/views/groups/group_members/update.js.haml b/app/views/groups/group_members/update.js.haml index 3be7ed8432c..de8f53b6b52 100644 --- a/app/views/groups/group_members/update.js.haml +++ b/app/views/groups/group_members/update.js.haml @@ -1,3 +1,3 @@ :plain - $("##{dom_id(@group_member)}").replaceWith('#{escape_javascript(render('shared/members/member', member: @group_member))}'); - new gl.MemberExpirationDate(); + var $listItem = $('#{escape_javascript(render('shared/members/member', member: @group_member))}'); + $("##{dom_id(@group_member)} .list-item-name").replaceWith($listItem.find('.list-item-name')); diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 23c35f91b6b..2af9fe0519c 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -6,4 +6,4 @@ %ul.content-list - members.each do |user| - member = @project.team.find_member(user.id) - = render 'shared/members/member', member: member + = render 'shared/members/member', member: member, user: user diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index 0502de5210b..5d54195646c 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -17,7 +17,10 @@ .prepend-left-5.append-right-10.clearable-input.member-form-control = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}" %i.clear-icon.js-clear-input - = link_to icon('trash'), namespace_project_group_link_path(@project.namespace, @project, group_link), + = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), remote: true, method: :delete, - class: 'btn btn-remove' + class: 'btn btn-remove' do + %span.visible-xs-block + Delete + = icon('trash', class: 'hidden-xs') diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 800badc051a..4518e84fe34 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -1,6 +1,6 @@ - show_roles = local_assigns.fetch(:show_roles, true) - show_controls = local_assigns.fetch(:show_controls, true) -- user = member.user +- user = local_assigns.fetch(:user, member.user) %li.member{ class: dom_class(member), id: dom_id(member) } %span{ class: ("list-item-name" if show_controls) } @@ -11,12 +11,16 @@ %span.cgray= user.to_reference - if user == current_user - %span.label.label-success It's you + %span.label.label-success.prepend-left-5 It's you - if user.blocked? %label.label.label-danger %strong Blocked + - if member.respond_to?(:group) && !@group + = link_to member.group, class: "member-group-link prepend-left-5" do + = "· #{member.group.name}" + .cgray - if member.request? Requested @@ -40,11 +44,14 @@ - if show_roles .controls.member-controls - if show_controls - = form_for member, remote: true, html: { class: 'form-horizontal' } do |f| - = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) - .prepend-left-5.append-right-10.clearable-input.member-form-control - = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) - %i.clear-icon.js-clear-input + - if user != current_user + = form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f| + = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + .prepend-left-5.append-right-10.clearable-input.member-form-control + = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + %i.clear-icon.js-clear-input + - else + %span.member-access-text= member.human_access - if !user && can?(current_user, action_member_permission(:admin, member), member.source) = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), method: :post, @@ -63,9 +70,12 @@ data: { confirm: leave_confirmation_message(member.source) }, class: 'btn btn-remove' - else - = link_to icon('trash'), member, + = link_to member, remote: true, method: :delete, data: { confirm: remove_member_message(member) }, class: 'btn btn-remove', - title: remove_member_title(member) + title: remove_member_title(member) do + %span.visible-xs-block + Delete + = icon('trash', class: 'hidden-xs') From 49a31e64b76b351c1bad91459991a69f0e0fb296 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Sep 2016 17:04:46 +0100 Subject: [PATCH 07/41] Removed console log Hides time on mobile --- app/assets/javascripts/project_members.js.es6 | 1 - app/views/shared/members/_member.html.haml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/project_members.js.es6 index d11467cf6eb..f525bdbb1ea 100644 --- a/app/assets/javascripts/project_members.js.es6 +++ b/app/assets/javascripts/project_members.js.es6 @@ -29,7 +29,6 @@ const $target = $(e.target); if ($target.hasClass('btn-remove')) { - console.log('a'); $target.closest('.member').fadeOut(); } } diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 4518e84fe34..ab4f1f1382b 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -21,7 +21,7 @@ = link_to member.group, class: "member-group-link prepend-left-5" do = "· #{member.group.name}" - .cgray + .hidden-xs.cgray - if member.request? Requested = time_ago_with_tooltip(member.requested_at) From 15a3111a6663894d952103e7395f2f56408f88ce Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 09:04:28 +0100 Subject: [PATCH 08/41] Mobile spacing improvements --- app/assets/stylesheets/framework/forms.scss | 4 --- app/assets/stylesheets/pages/groups.scss | 12 ------- app/assets/stylesheets/pages/members.scss | 36 +++++++++++++++++++ .../projects/project_members/index.html.haml | 7 ++-- app/views/shared/members/_group.html.haml | 2 +- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index 37ff7e22ed1..d1f1a372c06 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -125,7 +125,3 @@ label { border-right: 0; } } - -.help-block { - margin-bottom: 0; -} diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index a27f7a2fd77..cc1c0249df3 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -1,15 +1,3 @@ -.member-search-form { - input[type='search'] { - width: 225px; - vertical-align: bottom; - - @media (max-width: $screen-xs-max) { - width: 100px; - vertical-align: bottom; - } - } -} - .milestone-row { @include str-truncated(90%); } diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index a69af862348..a7f1324f69a 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -57,3 +57,39 @@ margin-left: auto; line-height: 43px; } + +.member.existing-title { + @media (min-width: $screen-sm-min) { + float: left; + } +} + +.member-search-form { + position: relative; + + @media (min-width: $screen-sm-min) { + float: right; + } + + .form-control { + width: 100%; + padding-right: 35px; + + @media (min-width: $screen-sm-min) { + width: 350px; + } + } +} + +.member-search-btn { + position: absolute; + right: 0; + top: 0; + height: 35px; + padding-left: 10px; + padding-right: 10px; + color: $gray-darkest; + background: transparent; + border: 0; + outline: 0; +} diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 85e512a75f4..abe10433387 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -15,12 +15,13 @@ = render 'shared/members/requests', membership_source: @project, requesters: @requesters .append-bottom-default.clearfix - %h5.pull-left + %h5.member.existing-title Existing users and groups - = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form pull-right hidden-xs hidden-sm' do + = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do .form-group = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } - = icon("search") + %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } + = icon("search") - if @groups.size > 0 = render 'groups', groups: @groups diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index 5d54195646c..e545aec80a9 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -12,7 +12,7 @@ %span{ class: ('text-warning' if group_link.expires_soon?) } Expires in #{distance_of_time_in_words_to_now(group_link.expires_at)} .controls.member-controls - = form_tag namespace_project_group_link_path(@project.namespace, @project, group_link), method: :put, remote: true, class: 'form-horizontal' do + = form_tag namespace_project_group_link_path(@project.namespace, @project, group_link), method: :put, remote: true, class: 'form-horizontal js-edit-member-form' do = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}" .prepend-left-5.append-right-10.clearable-input.member-form-control = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}" From e477ad44565dbe69e3f0200f4f4f7bebbd48cb15 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 09:25:53 +0100 Subject: [PATCH 09/41] Removes row from dom when deleting Fixed spacing with buttons Disables group form when user doesnt have correct permissions --- app/assets/javascripts/project_members.js.es6 | 5 ++++- .../projects/project_members_controller.rb | 7 ++----- app/models/project_team.rb | 8 +++---- app/views/shared/members/_group.html.haml | 21 ++++++++++--------- app/views/shared/members/_member.html.haml | 10 ++++----- app/views/shared/members/_requests.html.haml | 2 +- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/project_members.js.es6 index f525bdbb1ea..56bc98d1076 100644 --- a/app/assets/javascripts/project_members.js.es6 +++ b/app/assets/javascripts/project_members.js.es6 @@ -29,7 +29,10 @@ const $target = $(e.target); if ($target.hasClass('btn-remove')) { - $target.closest('.member').fadeOut(); + $target.closest('.member') + .fadeOut(function () { + $(this).remove(); + }); } } diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index abb92938211..cd31653698c 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -5,11 +5,9 @@ class Projects::ProjectMembersController < Projects::ApplicationController before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] def index - @groups = @project.project_group_links.all - @project_members = @project.team.members.all + @groups = @project.project_group_links + @project_members = @project.team.members(can?(current_user, :admin_project, @project)) @project_members_size = @project_members.size - @group_members = @project.group.group_members - @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? @project_members = @project_members.search(params[:search]) @@ -20,7 +18,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController @requesters = @project.requesters if can?(current_user, :admin_project, @project) @project_member = @project.project_members.new - @project_group_links = @project.project_group_links end def create diff --git a/app/models/project_team.rb b/app/models/project_team.rb index ab6ea2aae36..57925a0861a 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -52,8 +52,8 @@ class ProjectTeam ProjectMember.truncate_team(project) end - def members - @members ||= fetch_members + def members(non_invite) + @members ||= fetch_members(nil, non_invite) end alias_method :users, :members @@ -197,7 +197,7 @@ class ProjectTeam access.each { |key, value| access[key] = [value, capped_access_level].min } end - def fetch_members(level = nil) + def fetch_members(level = nil, non_invite = false) project_members = project.members group_members = group ? group.members : [] invited_members = [] @@ -236,7 +236,7 @@ class ProjectTeam end user_ids = project_members.pluck(:user_id) - user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? + user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? && !non_invite user_ids.push(*group_members.pluck(:user_id)) if group User.where(id: user_ids) diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index e545aec80a9..19b58ef20ae 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -13,14 +13,15 @@ Expires in #{distance_of_time_in_words_to_now(group_link.expires_at)} .controls.member-controls = form_tag namespace_project_group_link_path(@project.namespace, @project, group_link), method: :put, remote: true, class: 'form-horizontal js-edit-member-form' do - = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}" - .prepend-left-5.append-right-10.clearable-input.member-form-control - = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}" + = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}", disabled: !can?(current_user, action_member_permission(:admin, group), group) + .prepend-left-5.clearable-input.member-form-control + = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}", disabled: !can?(current_user, action_member_permission(:admin, group), group) %i.clear-icon.js-clear-input - = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), - remote: true, - method: :delete, - class: 'btn btn-remove' do - %span.visible-xs-block - Delete - = icon('trash', class: 'hidden-xs') + - if can?(current_user, action_member_permission(:admin, group), group) + = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), + remote: true, + method: :delete, + class: 'btn btn-remove prepend-left-10' do + %span.visible-xs-block + Delete + = icon('trash', class: 'hidden-xs') diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index ab4f1f1382b..2d4853eef92 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -47,7 +47,7 @@ - if user != current_user = form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f| = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) - .prepend-left-5.append-right-10.clearable-input.member-form-control + .prepend-left-5.clearable-input.member-form-control = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) %i.clear-icon.js-clear-input - else @@ -55,12 +55,12 @@ - if !user && can?(current_user, action_member_permission(:admin, member), member.source) = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), method: :post, - class: 'btn' + class: 'btn btn-default prepend-left-10' - if member.request? && can?(current_user, action_member_permission(:update, member), member) = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), method: :post, - class: 'btn btn-success', + class: 'btn btn-success prepend-left-10', title: 'Grant access' - if can?(current_user, action_member_permission(:destroy, member), member) @@ -68,13 +68,13 @@ = link_to icon('sign-out', text: 'Leave'), polymorphic_path([:leave, member.source, :members]), method: :delete, data: { confirm: leave_confirmation_message(member.source) }, - class: 'btn btn-remove' + class: 'btn btn-remove prepend-left-10' - else = link_to member, remote: true, method: :delete, data: { confirm: remove_member_message(member) }, - class: 'btn btn-remove', + class: 'btn btn-remove prepend-left-10', title: remove_member_title(member) do %span.visible-xs-block Delete diff --git a/app/views/shared/members/_requests.html.haml b/app/views/shared/members/_requests.html.haml index 40b39e850b0..10050adfda5 100644 --- a/app/views/shared/members/_requests.html.haml +++ b/app/views/shared/members/_requests.html.haml @@ -1,8 +1,8 @@ - if requesters.any? .panel.panel-default .panel-heading + Users requesting access to %strong= membership_source.name - access requests %span.badge= requesters.size %ul.content-list = render partial: 'shared/members/member', collection: requesters, as: :member From b3d75ac5135130522f253d4b09f72a7c0a8e2f80 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 09:28:25 +0100 Subject: [PATCH 10/41] Return 403 if user can't update group --- app/controllers/projects/group_links_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 57c54bf625a..b5e314dced3 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -21,6 +21,7 @@ class Projects::GroupLinksController < Projects::ApplicationController def update @group_link = @project.project_group_links.find(params[:id]) + return render_403 unless can?(current_user, action_member_permission(:admin, @group_link.group), @group_link.group) @group_link.update_attributes(group_link_params) end From cdc55db3452ca82f0dbdcdb631a1fc48abdf1f84 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 10:13:49 +0100 Subject: [PATCH 11/41] Fixed members error --- app/controllers/projects/project_members_controller.rb | 2 +- app/models/project_team.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index cd31653698c..617dd9823b9 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,7 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @groups = @project.project_group_links - @project_members = @project.team.members(can?(current_user, :admin_project, @project)) + @project_members = @project.team.members(!can?(current_user, :admin_project, @project)) @project_members_size = @project_members.size if params[:search].present? diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 57925a0861a..a58c56288dd 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -52,7 +52,7 @@ class ProjectTeam ProjectMember.truncate_team(project) end - def members(non_invite) + def members(non_invite = false) @members ||= fetch_members(nil, non_invite) end alias_method :users, :members @@ -236,7 +236,7 @@ class ProjectTeam end user_ids = project_members.pluck(:user_id) - user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? && !non_invite + user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? && non_invite user_ids.push(*group_members.pluck(:user_id)) if group User.where(id: user_ids) From 3e19f1976f9a13fc1b13ec49b3ce31c3e114a454 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 10:50:06 +0100 Subject: [PATCH 12/41] Fixed issue with invited users not showing up --- .../projects/project_members_controller.rb | 14 +++++++++++++- app/models/project_team.rb | 8 ++++---- app/views/projects/project_members/_team.html.haml | 5 ++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 617dd9823b9..2175a5d8dcb 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,7 +6,19 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @groups = @project.project_group_links - @project_members = @project.team.members(!can?(current_user, :admin_project, @project)) + + members = [] + project_members = @project.project_members + project_members = project_members.non_invite unless can?(current_user, :admin_project, @project) + members << project_members.pluck(:id) + + if @project.group + group_members = @project.group.group_members + group_members = group_members.non_invite unless can?(current_user, :admin_project, @project) + members << group_members.pluck(:id) + end + + @project_members = Member.where(id: members) @project_members_size = @project_members.size if params[:search].present? diff --git a/app/models/project_team.rb b/app/models/project_team.rb index a58c56288dd..ab6ea2aae36 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -52,8 +52,8 @@ class ProjectTeam ProjectMember.truncate_team(project) end - def members(non_invite = false) - @members ||= fetch_members(nil, non_invite) + def members + @members ||= fetch_members end alias_method :users, :members @@ -197,7 +197,7 @@ class ProjectTeam access.each { |key, value| access[key] = [value, capped_access_level].min } end - def fetch_members(level = nil, non_invite = false) + def fetch_members(level = nil) project_members = project.members group_members = group ? group.members : [] invited_members = [] @@ -236,7 +236,7 @@ class ProjectTeam end user_ids = project_members.pluck(:user_id) - user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? && non_invite + user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? user_ids.push(*group_members.pluck(:user_id)) if group User.where(id: user_ids) diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 2af9fe0519c..867cb2b97e4 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -4,6 +4,5 @@ %strong #{@project.name} %span.badge= @project_members_size %ul.content-list - - members.each do |user| - - member = @project.team.find_member(user.id) - = render 'shared/members/member', member: member, user: user + - members.each do |member| + = render 'shared/members/member', member: member From 931d09f481d5e174a984c6f874e67273ba2864f0 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 10:52:17 +0100 Subject: [PATCH 13/41] Fixed search --- .../projects/project_members_controller.rb | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 2175a5d8dcb..7581833eacc 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -10,21 +10,30 @@ class Projects::ProjectMembersController < Projects::ApplicationController members = [] project_members = @project.project_members project_members = project_members.non_invite unless can?(current_user, :admin_project, @project) + + if params[:search].present? + users = @project.users.search(params[:search]).to_a + project_members = project_members.where(user_id: users) + end + members << project_members.pluck(:id) - if @project.group - group_members = @project.group.group_members + @group = @project.group + if @group + group_members = @group.group_members group_members = group_members.non_invite unless can?(current_user, :admin_project, @project) + + if params[:search].present? + users = @group.users.search(params[:search]).to_a + group_members = group_members.where(user_id: users) + end + members << group_members.pluck(:id) end @project_members = Member.where(id: members) @project_members_size = @project_members.size - if params[:search].present? - @project_members = @project_members.search(params[:search]) - end - @project_members = @project_members.page(params[:page]) @requesters = @project.requesters if can?(current_user, :admin_project, @project) From 999f18480511d81b1499b502cbc89a5b34e54544 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 13:35:43 +0100 Subject: [PATCH 14/41] Tests update --- .../projects/project_members/_groups.html.haml | 2 +- .../project_members/_new_project_member.html.haml | 2 +- app/views/shared/members/_member.html.haml | 2 ++ features/steps/admin/projects.rb | 2 +- features/steps/group/members.rb | 4 ++-- features/steps/project/team_management.rb | 15 +++++++-------- .../members/owner_manages_access_requests_spec.rb | 2 +- .../master_manages_access_requests_spec.rb | 2 +- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/views/projects/project_members/_groups.html.haml b/app/views/projects/project_members/_groups.html.haml index 79791af7963..340e4cd06b8 100644 --- a/app/views/projects/project_members/_groups.html.haml +++ b/app/views/projects/project_members/_groups.html.haml @@ -1,4 +1,4 @@ -.panel.panel-default +.panel.panel-default.project-members-groups .panel-heading Groups with access to %strong #{@project.name} diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index c0b187fb460..26e06a14c07 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -1,4 +1,4 @@ -= form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project) do |f| += form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'users-project-form' } do |f| .row .col-md-4.col-lg-6 = users_select_tag(:user_ids, multiple: true, class: "input-full", scope: :all, email_user: true) diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 2d4853eef92..2f98eeff658 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -79,3 +79,5 @@ %span.visible-xs-block Delete = icon('trash', class: 'hidden-xs') + - else + %span.member-access-text= member.human_access diff --git a/features/steps/admin/projects.rb b/features/steps/admin/projects.rb index d77945a6b9c..2b8cd030ace 100644 --- a/features/steps/admin/projects.rb +++ b/features/steps/admin/projects.rb @@ -70,7 +70,7 @@ class Spinach::Features::AdminProjects < Spinach::FeatureSteps select "Developer", from: "access_level" end - click_button "Add users to project" + click_button "Add to project" end step 'I should see current user as "Developer"' do diff --git a/features/steps/group/members.rb b/features/steps/group/members.rb index e9b45823c67..4aec3d03ef6 100644 --- a/features/steps/group/members.rb +++ b/features/steps/group/members.rb @@ -1,4 +1,5 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps + include WaitForAjax include SharedAuthentication include SharedPaths include SharedGroup @@ -116,9 +117,8 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps member = mary_jane_member page.within "#group_member_#{member.id}" do - click_button 'Edit' select 'Developer', from: "member_access_level_#{member.id}" - click_on 'Save' + wait_for_ajax end end diff --git a/features/steps/project/team_management.rb b/features/steps/project/team_management.rb index e920f5a706b..49821b85922 100644 --- a/features/steps/project/team_management.rb +++ b/features/steps/project/team_management.rb @@ -22,7 +22,7 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps select2(user.id, from: "#user_ids", multiple: true) select "Reporter", from: "access_level" end - click_button "Add users to project" + click_button "Add to project" end step 'I should see "Mike" in team list as "Reporter"' do @@ -36,10 +36,10 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps step 'I select "sjobs@apple.com" as "Reporter"' do page.within ".users-project-form" do - select2("sjobs@apple.com", from: "#user_ids", multiple: true) + find('#user_ids', visible: false).set('sjobs@apple.com') select "Reporter", from: "access_level" end - click_button "Add users to project" + click_button "Add to project" end step 'I should see "sjobs@apple.com" in team list as invited "Reporter"' do @@ -65,9 +65,7 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps user = User.find_by(name: 'Dmitriy') project_member = project.project_members.find_by(user_id: user.id) page.within "#project_member_#{project_member.id}" do - click_button 'Edit' select "Reporter", from: "member_access_level_#{project_member.id}" - click_button "Save" end end @@ -144,8 +142,9 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps end step 'I should see "Opensource" group user listing' do - expect(page).to have_content("Shared with OpenSource group, members with Master role (2)") - expect(page).to have_content(@os_user1.name) - expect(page).to have_content(@os_user2.name) + page.within '.project-members-groups' do + expect(page).to have_content('OpenSource') + expect(find('select').value).to eq('40') + end end end diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/owner_manages_access_requests_spec.rb index 10d3713f19f..d811b05b0c3 100644 --- a/spec/features/groups/members/owner_manages_access_requests_spec.rb +++ b/spec/features/groups/members/owner_manages_access_requests_spec.rb @@ -41,7 +41,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do def expect_visible_access_request(group, user) expect(group.requesters.exists?(user_id: user)).to be_truthy - expect(page).to have_content "#{group.name} access requests 1" + expect(page).to have_content "Users requesting access to #{group.name} 1" expect(page).to have_content user.name end end diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index f7fcd9b6731..d15376931c3 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -41,7 +41,7 @@ feature 'Projects > Members > Master manages access requests', feature: true do def expect_visible_access_request(project, user) expect(project.requesters.exists?(user_id: user)).to be_truthy - expect(page).to have_content "#{project.name} access requests 1" + expect(page).to have_content "Users requesting access to #{project.name} 1" expect(page).to have_content user.name end end From a56216c8bd1ef82c09c7ce39596e4b6436ebb7fa Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 14:06:20 +0100 Subject: [PATCH 15/41] Added import button back in --- app/views/projects/project_members/index.html.haml | 4 ++-- features/steps/project/team_management.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index abe10433387..d289d75454d 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,15 +1,15 @@ - page_title "Members" .project-members-page.js-project-members-page.prepend-top-default - %h4 + %h4.clearfix Members + = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default pull-right hidden-xs", title: "Import members from another project" %hr - if can?(current_user, :admin_project_member, @project) .project-members-new.append-bottom-default %h5.clearfix Add new user to %strong= @project.name - -# = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default pull-right", title: "Import members from another project" = render "new_project_member" = render 'shared/members/requests', membership_source: @project, requesters: @requesters diff --git a/features/steps/project/team_management.rb b/features/steps/project/team_management.rb index 49821b85922..b21d0849ad1 100644 --- a/features/steps/project/team_management.rb +++ b/features/steps/project/team_management.rb @@ -110,7 +110,7 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps end step 'I click link "Import team from another project"' do - click_link "Import members from another project" + click_link "Import" end When 'I submit "Website" project for import team' do From ccf76831da422298242ce3d8d11f72ab50454c85 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 14:19:11 +0100 Subject: [PATCH 16/41] Updated groups member UI to match --- app/assets/javascripts/dispatcher.js | 4 +- app/assets/javascripts/groups.js | 13 ------ ...{project_members.js.es6 => members.js.es6} | 4 +- .../group_members/_new_group_member.html.haml | 35 +++++++--------- .../groups/group_members/index.html.haml | 40 +++++++++---------- .../projects/project_members/index.html.haml | 2 +- 6 files changed, 38 insertions(+), 60 deletions(-) delete mode 100644 app/assets/javascripts/groups.js rename app/assets/javascripts/{project_members.js.es6 => members.js.es6} (94%) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index c95aaf61443..da3757d8992 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -127,12 +127,12 @@ break; case 'groups:group_members:index': new gl.MemberExpirationDate(); - new GroupMembers(); + new gl.Members(); new UsersSelect(); break; case 'projects:project_members:index': new gl.MemberExpirationDate(); - new gl.ProjectMembers(); + new gl.Members(); new UsersSelect(); break; case 'groups:new': diff --git a/app/assets/javascripts/groups.js b/app/assets/javascripts/groups.js deleted file mode 100644 index 4382dd6860f..00000000000 --- a/app/assets/javascripts/groups.js +++ /dev/null @@ -1,13 +0,0 @@ -(function() { - this.GroupMembers = (function() { - function GroupMembers() { - $('li.group_member').bind('ajax:success', function() { - return $(this).fadeOut(); - }); - } - - return GroupMembers; - - })(); - -}).call(this); diff --git a/app/assets/javascripts/project_members.js.es6 b/app/assets/javascripts/members.js.es6 similarity index 94% rename from app/assets/javascripts/project_members.js.es6 rename to app/assets/javascripts/members.js.es6 index 56bc98d1076..fa259520810 100644 --- a/app/assets/javascripts/project_members.js.es6 +++ b/app/assets/javascripts/members.js.es6 @@ -1,7 +1,7 @@ ((w) => { w.gl = w.gl || {}; - class ProjectMembers { + class Members { constructor() { this.removeListeners(); this.addListeners(); @@ -41,5 +41,5 @@ } } - gl.ProjectMembers = ProjectMembers; + gl.Members = Members; })(window); diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml index 2fb3190ab11..2987befd2a4 100644 --- a/app/views/groups/group_members/_new_group_member.html.haml +++ b/app/views/groups/group_members/_new_group_member.html.haml @@ -1,27 +1,22 @@ -= form_for @group_member, url: group_group_members_path(@group), html: { class: 'form-horizontal users-group-form' } do |f| - .form-group - = f.label :user_ids, "People", class: 'control-label' - .col-sm-10 - = users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all, email_user: true) - .help-block += form_for @group_member, url: group_group_members_path(@group), html: { class: 'users-project-form users-group-form' } do |f| + .row + .col-md-4.col-lg-6 + = users_select_tag(:user_ids, multiple: true, class: 'input-full', scope: :all, email_user: true) + .help-block.append-bottom-10 Search for users by name, username, or email, or invite new ones using their email address. - .form-group - = f.label :access_level, "Group Access", class: 'control-label' - .col-sm-10 - = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "project-access-select select2" - .help-block - Read more about role permissions - %strong= link_to "here", help_page_path("user/permissions"), class: "vlink" + .col-md-3.col-lg-2 + = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "form-control project-access-select" + .help-block.append-bottom-10 + = link_to "Read more", help_page_path("user/permissions"), class: "vlink" + about role permissions - .form-group - = f.label :expires_at, 'Access expiration date', class: 'control-label' - .col-sm-10 + .col-md-3.col-lg-2 .clearable-input - = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Select access expiration date' + = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' %i.clear-icon.js-clear-input - .help-block + .help-block.append-bottom-10 On this date, the user(s) will automatically lose access to this group and all of its projects. - .form-actions - = f.submit 'Add users to group', class: "btn btn-create" + .col-md-2 + = f.submit 'Add to group', class: "btn btn-create btn-block" diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index f789796e942..d2c7ec2e821 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -1,35 +1,31 @@ - page_title "Members" -.group-members-page.prepend-top-default +.project-members-page.prepend-top-default + %h4 + Members + %hr - if can?(current_user, :admin_group_member, @group) - .panel.panel-default - .panel-heading - Add new user to group - .panel-body - %p.light - Members of group have access to all group projects. - .new-group-member-holder - = render "new_group_member" + .project-members-new.append-bottom-default + %h5.clearfix + Add new user to + %strong= @group.name + = render "new_group_member" = render 'shared/members/requests', membership_source: @group, requesters: @requesters + .append-bottom-default.clearfix + %h5.member.existing-title + Existing users + = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do + .form-group + = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } + %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } + = icon("search") .panel.panel-default .panel-heading + Users with access to %strong #{@group.name} - group members %span.badge= @members.total_count - .controls - = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do - .form-group - = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false } - = button_tag class: 'btn', title: 'Search' do - = icon("search") %ul.content-list = render partial: 'shared/members/member', collection: @members, as: :member = paginate @members, theme: 'gitlab' - -:javascript - $('form.member-search-form').on('submit', function(event) { - event.preventDefault(); - Turbolinks.visit(this.action + '?' + $(this).serialize()); - }); diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index d289d75454d..a90de32bd47 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,6 +1,6 @@ - page_title "Members" -.project-members-page.js-project-members-page.prepend-top-default +.project-members-page.prepend-top-default %h4.clearfix Members = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default pull-right hidden-xs", title: "Import members from another project" From 2c3fa33ca2e75792d1027eb73e2f69fed67bc435 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 15:10:22 +0100 Subject: [PATCH 17/41] Updated some specs Fixed issue with group name not showing --- .../projects/project_members_controller.rb | 19 +++++++++---------- .../projects/project_members/_team.html.haml | 2 +- .../projects/project_members/index.html.haml | 4 ++-- app/views/shared/members/_member.html.haml | 7 ++++--- features/steps/group/members.rb | 8 ++++---- ...r_adds_member_with_expiration_date_spec.rb | 8 ++++---- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 7581833eacc..bf6ac25266a 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -7,7 +7,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @groups = @project.project_group_links - members = [] project_members = @project.project_members project_members = project_members.non_invite unless can?(current_user, :admin_project, @project) @@ -16,25 +15,25 @@ class Projects::ProjectMembersController < Projects::ApplicationController project_members = project_members.where(user_id: users) end - members << project_members.pluck(:id) + members_ids = project_members.pluck(:id) - @group = @project.group - if @group - group_members = @group.group_members + group = @project.group + if group + group_members = group.group_members group_members = group_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? - users = @group.users.search(params[:search]).to_a + users = group.users.search(params[:search]).to_a group_members = group_members.where(user_id: users) end - members << group_members.pluck(:id) + members_ids << group_members.pluck(:id) end - @project_members = Member.where(id: members) - @project_members_size = @project_members.size + @members = Member.where(id: members_ids.flatten) + @members_size = @members.size - @project_members = @project_members.page(params[:page]) + @members = @members.page(params[:page]) @requesters = @project.requesters if can?(current_user, :admin_project, @project) diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 867cb2b97e4..d9799033e17 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -2,7 +2,7 @@ .panel-heading Users with access to %strong #{@project.name} - %span.badge= @project_members_size + %span.badge= @members_size %ul.content-list - members.each do |member| = render 'shared/members/member', member: member diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index a90de32bd47..80882d0c11c 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -25,5 +25,5 @@ - if @groups.size > 0 = render 'groups', groups: @groups - = render 'team', members: @project_members - = paginate @project_members, theme: "gitlab" + = render 'team', members: @members + = paginate @members, theme: "gitlab" diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 2f98eeff658..6f8c3c4da2e 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -1,6 +1,7 @@ - show_roles = local_assigns.fetch(:show_roles, true) - show_controls = local_assigns.fetch(:show_controls, true) - user = local_assigns.fetch(:user, member.user) +- source = member.source %li.member{ class: dom_class(member), id: dom_id(member) } %span{ class: ("list-item-name" if show_controls) } @@ -17,9 +18,9 @@ %label.label.label-danger %strong Blocked - - if member.respond_to?(:group) && !@group - = link_to member.group, class: "member-group-link prepend-left-5" do - = "· #{member.group.name}" + - if source.instance_of?(Group) && !@group + = link_to source, class: "member-group-link prepend-left-5" do + = "· #{source.name}" .hidden-xs.cgray - if member.request? diff --git a/features/steps/group/members.rb b/features/steps/group/members.rb index 4aec3d03ef6..e54add1d568 100644 --- a/features/steps/group/members.rb +++ b/features/steps/group/members.rb @@ -14,7 +14,7 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps select "Reporter", from: "access_level" end - click_button "Add users to group" + click_button "Add to group" end step 'I select "Mike" as "Master"' do @@ -25,7 +25,7 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps select "Master", from: "access_level" end - click_button "Add users to group" + click_button "Add to group" end step 'I should see "Mike" in team list as "Reporter"' do @@ -48,7 +48,7 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps select "Reporter", from: "access_level" end - click_button "Add users to group" + click_button "Add to group" end step 'I should see "sjobs@apple.com" in team list as invited "Reporter"' do @@ -67,7 +67,7 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps select "Reporter", from: "access_level" end - click_button "Add users to group" + click_button "Add to group" end step 'I should see user "John Doe" in team list' do diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 430c384ac2e..27a83fdcd1f 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' feature 'Projects > Members > Master adds member with expiration date', feature: true, js: true do + include WaitForAjax include Select2Helper include ActiveSupport::Testing::TimeHelpers @@ -20,7 +21,7 @@ feature 'Projects > Members > Master adds member with expiration date', feature: page.within '.users-project-form' do select2(new_member.id, from: '#user_ids', multiple: true) fill_in 'expires_at', with: '2016-08-10' - click_on 'Add users to project' + click_on 'Add to project' end page.within '.project_member:first-child' do @@ -35,9 +36,8 @@ feature 'Projects > Members > Master adds member with expiration date', feature: visit namespace_project_project_members_path(project.namespace, project) page.within '.project_member:first-child' do - click_on 'Edit' - fill_in 'Access expiration date', with: '2016-08-09' - click_on 'Save' + find('.js-access-expiration-date').set '2016-08-09' + wait_for_ajax expect(page).to have_content('Expires in 3 days') end end From 638376c35494860936bf2858c01115dc4afe0bfe Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 15:44:46 +0100 Subject: [PATCH 18/41] Fixed group tests --- features/steps/admin/groups.rb | 2 +- features/steps/group/members.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/admin/groups.rb b/features/steps/admin/groups.rb index 0c89a3db9ad..9396a76f0a2 100644 --- a/features/steps/admin/groups.rb +++ b/features/steps/admin/groups.rb @@ -105,7 +105,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps select "Developer", from: "access_level" end - click_button "Add users to group" + click_button "Add to group" end step 'I should see current user as "Developer"' do diff --git a/features/steps/group/members.rb b/features/steps/group/members.rb index e54add1d568..cefc55d07ab 100644 --- a/features/steps/group/members.rb +++ b/features/steps/group/members.rb @@ -109,7 +109,7 @@ class Spinach::Features::GroupMembers < Spinach::FeatureSteps step 'I search for \'Mary\' member' do page.within '.member-search-form' do fill_in 'search', with: 'Mary' - click_button 'Search' + find('.member-search-btn').click end end From 97a51817bf1e6b0504bb84b686daf7e931ded2da Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Sep 2016 17:39:16 +0100 Subject: [PATCH 19/41] Fixed error when updating groups --- app/controllers/projects/group_links_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index b5e314dced3..3574ecf2811 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -21,7 +21,7 @@ class Projects::GroupLinksController < Projects::ApplicationController def update @group_link = @project.project_group_links.find(params[:id]) - return render_403 unless can?(current_user, action_member_permission(:admin, @group_link.group), @group_link.group) + return render_403 unless can?(current_user, :admin_group, @group_link.group) @group_link.update_attributes(group_link_params) end From e747626fad5c0e675d6a5cd5b6fcd482f10dad90 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 5 Sep 2016 09:24:47 +0100 Subject: [PATCH 20/41] Added test for updating groups permissions --- .../projects/group_links_controller.rb | 2 +- app/views/shared/members/_group.html.haml | 6 +-- .../projects/members/group_links_spec.rb | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 spec/features/projects/members/group_links_spec.rb diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 3574ecf2811..7b4c39cdb8f 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -21,7 +21,7 @@ class Projects::GroupLinksController < Projects::ApplicationController def update @group_link = @project.project_group_links.find(params[:id]) - return render_403 unless can?(current_user, :admin_group, @group_link.group) + return render_403 unless can?(current_user, :admin_project_member, @project) @group_link.update_attributes(group_link_params) end diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index 19b58ef20ae..56d31a949ff 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -13,11 +13,11 @@ Expires in #{distance_of_time_in_words_to_now(group_link.expires_at)} .controls.member-controls = form_tag namespace_project_group_link_path(@project.namespace, @project, group_link), method: :put, remote: true, class: 'form-horizontal js-edit-member-form' do - = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}", disabled: !can?(current_user, action_member_permission(:admin, group), group) + = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}", disabled: !can?(current_user, :admin_project_member, @project) .prepend-left-5.clearable-input.member-form-control - = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}", disabled: !can?(current_user, action_member_permission(:admin, group), group) + = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}", disabled: !can?(current_user, :admin_project_member, @project) %i.clear-icon.js-clear-input - - if can?(current_user, action_member_permission(:admin, group), group) + - if can?(current_user, :admin_project_member, @project) = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), remote: true, method: :delete, diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb new file mode 100644 index 00000000000..3d59df20197 --- /dev/null +++ b/spec/features/projects/members/group_links_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +feature 'Projects > Members > Anonymous user sees members', feature: true, js: true do + include WaitForAjax + + let(:user) { create(:user) } + let(:group) { create(:group, :public) } + let(:project) { create(:empty_project, :public) } + + background do + project.team << [user, :master] + @group_link = create(:project_group_link, project: project, group: group) + + login_as(user) + visit namespace_project_project_members_path(project.namespace, project) + end + + it 'updates group access level' do + select 'Guest', from: "member_access_level_#{group.id}" + wait_for_ajax + + visit namespace_project_project_members_path(project.namespace, project) + + expect(page).to have_select("member_access_level_#{group.id}", selected: 'Guest') + end + + it 'updates expiry date' do + tomorrow = Date.today + 3 + + fill_in "member_expires_at_#{group.id}", with: tomorrow.strftime("%F") + wait_for_ajax + + page.within(first('li.member')) do + expect(page).to have_content('Expires in 3 days') + end + end +end From fe71edc3336ae662997ebbad3b4c46b2a2b4927c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 5 Sep 2016 15:11:45 +0100 Subject: [PATCH 21/41] JS update --- app/assets/javascripts/members.js.es6 | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js.es6 index fa259520810..7986987e49a 100644 --- a/app/assets/javascripts/members.js.es6 +++ b/app/assets/javascripts/members.js.es6 @@ -15,14 +15,8 @@ addListeners() { $('.project_member, .group_member').on('ajax:success', this.removeRow); - $('.js-member-update-control').on('change', function () { - $(this).closest('form') - .trigger("submit.rails"); - $(this).disable(); - }); - $('.js-edit-member-form').on('ajax:success', function () { - $(this).find('.js-member-update-control').enable(); - }); + $('.js-member-update-control').on('change', this.formSubmit); + $('.js-edit-member-form').on('ajax:success', this.formSuccess); } removeRow(e) { @@ -36,8 +30,16 @@ } } - submitForm() { + formSubmit() { + const $this = $(this); + $this.disable() + .closest('form') + .trigger("submit.rails"); + } + + formSuccess() { + $(this).find('.js-member-update-control').enable(); } } From 3354bfd8f92ba034816890f0ea89bca630405103 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 5 Sep 2016 15:45:23 +0100 Subject: [PATCH 22/41] CSS cleanup --- app/assets/stylesheets/framework/selects.scss | 4 ---- app/assets/stylesheets/pages/members.scss | 10 +++------- .../groups/group_members/_new_group_member.html.haml | 2 +- app/views/groups/group_members/index.html.haml | 2 +- .../project_members/_new_project_member.html.haml | 2 +- app/views/projects/project_members/index.html.haml | 2 +- 6 files changed, 7 insertions(+), 15 deletions(-) diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index 746ab89abd2..b309e2ad9f4 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -191,10 +191,6 @@ &.input-clamp { max-width: 100%; } - - &.input-full { - width: 100%; - } } .select2-highlighted { diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index a7f1324f69a..72f31cb1168 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -1,9 +1,3 @@ -.project-members-new { - > h5 { - font-weight: normal; - } -} - .member { .list-item-name { float: none; @@ -16,6 +10,7 @@ .controls { @media (min-width: $screen-sm-min) { + display: -webkit-flex; display: flex; width: 400px; max-width: 50%; @@ -26,8 +21,9 @@ margin-top: 5px; @media (min-width: $screen-sm-min) { + display: -webkit-flex; display: flex; - flex: 1; + width: 100%; margin-top: 3px; } } diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml index 2987befd2a4..b185b81db7f 100644 --- a/app/views/groups/group_members/_new_group_member.html.haml +++ b/app/views/groups/group_members/_new_group_member.html.haml @@ -1,7 +1,7 @@ = form_for @group_member, url: group_group_members_path(@group), html: { class: 'users-project-form users-group-form' } do |f| .row .col-md-4.col-lg-6 - = users_select_tag(:user_ids, multiple: true, class: 'input-full', scope: :all, email_user: true) + = users_select_tag(:user_ids, multiple: true, class: 'input-clamp', scope: :all, email_user: true) .help-block.append-bottom-10 Search for users by name, username, or email, or invite new ones using their email address. diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index d2c7ec2e821..ebf9aca7700 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -6,7 +6,7 @@ %hr - if can?(current_user, :admin_group_member, @group) .project-members-new.append-bottom-default - %h5.clearfix + %p.clearfix Add new user to %strong= @group.name = render "new_group_member" diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 26e06a14c07..79dcd7a6ee9 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -1,7 +1,7 @@ = form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'users-project-form' } do |f| .row .col-md-4.col-lg-6 - = users_select_tag(:user_ids, multiple: true, class: "input-full", scope: :all, email_user: true) + = users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true) .help-block.append-bottom-10 Search for users by name, username, or email, or invite new ones using their email address. diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 80882d0c11c..86b2752cc0b 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -7,7 +7,7 @@ %hr - if can?(current_user, :admin_project_member, @project) .project-members-new.append-bottom-default - %h5.clearfix + %p.clearfix Add new user to %strong= @project.name = render "new_project_member" From 68c7b52364307e26ef7a85b80aa11242abbfa5b6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 5 Sep 2016 17:14:42 +0100 Subject: [PATCH 23/41] Fixed fields not being sent --- app/assets/javascripts/members.js.es6 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js.es6 index 7986987e49a..12d212ca185 100644 --- a/app/assets/javascripts/members.js.es6 +++ b/app/assets/javascripts/members.js.es6 @@ -33,9 +33,10 @@ formSubmit() { const $this = $(this); - $this.disable() - .closest('form') + $this.closest('form') .trigger("submit.rails"); + + $this.disable(); } formSuccess() { From 11c0c6509251a280f46c6be74da64a1cd7a5e190 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 6 Sep 2016 10:06:13 +0100 Subject: [PATCH 24/41] Expires in test update --- spec/features/projects/members/group_links_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index 3d59df20197..2085e875f12 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -31,7 +31,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t wait_for_ajax page.within(first('li.member')) do - expect(page).to have_content('Expires in 3 days') + expect(page).to have_content('Expires in') end end end From 73c4da1780c5086543eb998d5bc9cbd632ef6576 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 6 Sep 2016 16:20:20 +0100 Subject: [PATCH 25/41] Fixed removing groups --- app/controllers/projects/group_links_controller.rb | 7 ++++++- app/views/shared/members/_group.html.haml | 3 ++- spec/features/projects/members/group_links_spec.rb | 9 +++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 7b4c39cdb8f..7b6f07465e0 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -29,7 +29,12 @@ class Projects::GroupLinksController < Projects::ApplicationController def destroy project.project_group_links.find(params[:id]).destroy - redirect_to namespace_project_group_links_path(project.namespace, project) + respond_to do |format| + format.html do + redirect_to namespace_project_group_links_path(project.namespace, project) + end + format.js { head :ok } + end end protected diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index 56d31a949ff..171a388b233 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -1,6 +1,6 @@ - group = local_assigns[:group] - group_link = local_assigns[:group_link] -%li.member{ class: dom_class(group), id: dom_id(group) } +%li.member.group_member{ id: "group_member_#{group_link.id}" } %span{ class: "list-item-name" } = image_tag group_icon(group), class: "avatar s40", alt: '' %strong @@ -21,6 +21,7 @@ = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), remote: true, method: :delete, + data: { confirm: "Are you sure you want to remove #{group.name}?" }, class: 'btn btn-remove prepend-left-10' do %span.visible-xs-block Delete diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index 2085e875f12..7870bc663b1 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -34,4 +34,13 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t expect(page).to have_content('Expires in') end end + + it 'deletes group link' do + page.within(first('.group_member')) do + find('.btn-remove').click + end + wait_for_ajax + + expect(page).not_to have_selector('.group_member') + end end From 2b41db9215f322ba61113a7bef2f49da157bbd53 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 6 Sep 2016 16:48:48 +0100 Subject: [PATCH 26/41] Search project groups --- .../projects/project_members_controller.rb | 53 +++++++++++++++---- .../projects/members/group_links_spec.rb | 20 +++++++ 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index bf6ac25266a..ac83377148a 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -10,23 +10,30 @@ class Projects::ProjectMembersController < Projects::ApplicationController project_members = @project.project_members project_members = project_members.non_invite unless can?(current_user, :admin_project, @project) + group = @project.group + + if group + group_members = group.group_members + group_members = group_members.non_invite unless can?(current_user, :admin_project, @project) + end + if params[:search].present? + groups_id = @groups.pluck(:group_id) + groups = Group.where(id: groups_id).search(params[:search]).to_a + @groups = @project.project_group_links.where(group_id: groups) + users = @project.users.search(params[:search]).to_a project_members = project_members.where(user_id: users) + + if group_members + users = group.users.search(params[:search]).to_a + group_members = group_members.where(user_id: users) + end end members_ids = project_members.pluck(:id) - group = @project.group - if group - group_members = group.group_members - group_members = group_members.non_invite unless can?(current_user, :admin_project, @project) - - if params[:search].present? - users = group.users.search(params[:search]).to_a - group_members = group_members.where(user_id: users) - end - + if group_members members_ids << group_members.pluck(:id) end @@ -48,6 +55,17 @@ class Projects::ProjectMembersController < Projects::ApplicationController current_user: current_user ) + group_ids = params[:group_ids].split(',') + groups = Group.where(id: group_ids) + + groups.each do |group| + project.project_group_links.create( + group: group, + group_access: params[:access_level], + expires_at: params[:expires_at] + ) + end + redirect_to namespace_project_project_members_path(@project.namespace, @project) end @@ -101,6 +119,21 @@ class Projects::ProjectMembersController < Projects::ApplicationController notice: notice) end + def options + users = User.all + users = users.search(params[:search]) if params[:search].present? + users = users.page(1) + + groups = Group.all + groups = groups.search(params[:search]) if params[:search].present? + groups = groups.page(1) + + render json: { + Groups: groups.as_json(only: [:id, :name], methods: [:avatar_url]), + Users: users.as_json(only: [:id, :name, :username], methods: [:avatar_url]), + } + end + protected def member_params diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index 7870bc663b1..14ab7541fad 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -43,4 +43,24 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t expect(page).not_to have_selector('.group_member') end + + context 'search' do + it 'finds no results' do + page.within '.member-search-form' do + fill_in 'search', with: 'testing 123' + find('.member-search-btn').click + end + + expect(page).not_to have_selector('.group_member') + end + + it 'finds results' do + page.within '.member-search-form' do + fill_in 'search', with: group.name + find('.member-search-btn').click + end + + expect(page).to have_selector('.group_member', count: 1) + end + end end From 401b797671b9b67ef40c4afa75acdeca83b6a6de Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 6 Sep 2016 17:11:58 +0100 Subject: [PATCH 27/41] Fixed bug when group_ids not present when creating --- .../projects/project_members_controller.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index ac83377148a..d49598d2786 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -55,15 +55,17 @@ class Projects::ProjectMembersController < Projects::ApplicationController current_user: current_user ) - group_ids = params[:group_ids].split(',') - groups = Group.where(id: group_ids) + if params[:group_ids].present? + group_ids = params[:group_ids].split(',') + groups = Group.where(id: group_ids) - groups.each do |group| - project.project_group_links.create( - group: group, - group_access: params[:access_level], - expires_at: params[:expires_at] - ) + groups.each do |group| + project.project_group_links.create( + group: group, + group_access: params[:access_level], + expires_at: params[:expires_at] + ) + end end redirect_to namespace_project_project_members_path(@project.namespace, @project) From ecf7640b28562468880dda97ba42e5fd18c0859f Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 7 Sep 2016 10:58:52 +0100 Subject: [PATCH 28/41] Fixed group_links expire date not updating in view --- app/views/projects/group_links/update.js.haml | 2 +- spec/features/projects/members/group_links_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/group_links/update.js.haml b/app/views/projects/group_links/update.js.haml index d3a37847f58..231d5a79723 100644 --- a/app/views/projects/group_links/update.js.haml +++ b/app/views/projects/group_links/update.js.haml @@ -1,3 +1,3 @@ :plain var $listItem = $('#{escape_javascript(render('shared/members/group', group_link: @group_link, group: @group_link.group))}'); - $("##{dom_id(@group_link.group)} .list-item-name").replaceWith($listItem.find('.list-item-name')); + $("#group_member_#{@group_link.id} .list-item-name").replaceWith($listItem.find('.list-item-name')); diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index 14ab7541fad..cc2f695211c 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -30,7 +30,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t fill_in "member_expires_at_#{group.id}", with: tomorrow.strftime("%F") wait_for_ajax - page.within(first('li.member')) do + page.within(find('li.group_member')) do expect(page).to have_content('Expires in') end end From d8fee09e338006acb09c80ebcb032b6a75f3d7cd Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 7 Sep 2016 12:36:21 +0100 Subject: [PATCH 29/41] Fixed jQuery chaining --- app/assets/javascripts/members.js.es6 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js.es6 index 12d212ca185..1b4b3f38838 100644 --- a/app/assets/javascripts/members.js.es6 +++ b/app/assets/javascripts/members.js.es6 @@ -31,12 +31,10 @@ } formSubmit() { - const $this = $(this); - - $this.closest('form') - .trigger("submit.rails"); - - $this.disable(); + $(this).closest('form') + .trigger("submit.rails") + .end() + .disable(); } formSuccess() { From 2abbb0980f061d4297aab02f914c324c7fbe073b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 7 Sep 2016 14:26:07 +0100 Subject: [PATCH 30/41] Removed group members from the list for now --- .../projects/project_members_controller.rb | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index d49598d2786..64cbc76da6f 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -10,33 +10,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController project_members = @project.project_members project_members = project_members.non_invite unless can?(current_user, :admin_project, @project) - group = @project.group - - if group - group_members = group.group_members - group_members = group_members.non_invite unless can?(current_user, :admin_project, @project) - end - - if params[:search].present? - groups_id = @groups.pluck(:group_id) - groups = Group.where(id: groups_id).search(params[:search]).to_a - @groups = @project.project_group_links.where(group_id: groups) - - users = @project.users.search(params[:search]).to_a - project_members = project_members.where(user_id: users) - - if group_members - users = group.users.search(params[:search]).to_a - group_members = group_members.where(user_id: users) - end - end - members_ids = project_members.pluck(:id) - if group_members - members_ids << group_members.pluck(:id) - end - @members = Member.where(id: members_ids.flatten) @members_size = @members.size From 7cca8ffe60f4cdc7ca012cf223c6d7855b928685 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 8 Sep 2016 10:45:53 +0100 Subject: [PATCH 31/41] Ruby update --- .../projects/project_members_controller.rb | 14 +++++++------- app/views/projects/project_members/_team.html.haml | 2 +- app/views/projects/project_members/index.html.haml | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 64cbc76da6f..1c49ebfb99d 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -7,15 +7,15 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @groups = @project.project_group_links - project_members = @project.project_members - project_members = project_members.non_invite unless can?(current_user, :admin_project, @project) + @project_members = @project.project_members + @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) - members_ids = project_members.pluck(:id) + if params[:search].present? + users = @project.users.search(params[:search]).to_a + @project_members = @project_members.where(user_id: users) + end - @members = Member.where(id: members_ids.flatten) - @members_size = @members.size - - @members = @members.page(params[:page]) + @project_members = @project_members.page(params[:page]) @requesters = @project.requesters if can?(current_user, :admin_project, @project) diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index d9799033e17..ff54035cfe1 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -2,7 +2,7 @@ .panel-heading Users with access to %strong #{@project.name} - %span.badge= @members_size + %span.badge= @project_members.total_count %ul.content-list - members.each do |member| = render 'shared/members/member', member: member diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 86b2752cc0b..f566748e95a 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -25,5 +25,5 @@ - if @groups.size > 0 = render 'groups', groups: @groups - = render 'team', members: @members - = paginate @members, theme: "gitlab" + = render 'team', members: @project_members + = paginate @project_members, theme: "gitlab" From b61cd8a3930f194333ea417a03d53a0ad91efa42 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 9 Sep 2016 10:45:55 +0100 Subject: [PATCH 32/41] Added back ordering --- app/controllers/projects/project_members_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 1c49ebfb99d..5fd2e77a51a 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -15,6 +15,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController @project_members = @project_members.where(user_id: users) end + @project_members = @project_members.order('access_level DESC') @project_members = @project_members.page(params[:page]) @requesters = @project.requesters if can?(current_user, :admin_project, @project) From aac80d76c272523a1ee7c9ef751034e955dfab9e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 9 Sep 2016 11:31:57 +0100 Subject: [PATCH 33/41] Group links search test fix --- app/controllers/projects/project_members_controller.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 5fd2e77a51a..4d27617608d 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -13,6 +13,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController if params[:search].present? users = @project.users.search(params[:search]).to_a @project_members = @project_members.where(user_id: users) + + group_ids = @groups.pluck(:group_id) + group_ids = Group.where(id: group_ids).search(params[:search]).to_a + @groups = @project.project_group_links.where(group_id: group_ids) end @project_members = @project_members.order('access_level DESC') From b8d41220bde1b5c1f0e86a3346959fc7b760ccf5 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 12 Sep 2016 15:34:54 +0100 Subject: [PATCH 34/41] Admin group members UI fix --- app/views/shared/members/_member.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 6f8c3c4da2e..80e52bf5637 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -4,7 +4,7 @@ - source = member.source %li.member{ class: dom_class(member), id: dom_id(member) } - %span{ class: ("list-item-name" if show_controls) } + %span.list-item-name - if user = image_tag avatar_icon(user, 40), class: "avatar s40", alt: '' %strong From a34c0e5490c78402b72fab7196d43352ff719cbb Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 4 Oct 2016 10:32:24 +0100 Subject: [PATCH 35/41] Border instead of hr --- app/assets/stylesheets/pages/members.scss | 5 +++++ app/views/projects/project_members/index.html.haml | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index 72f31cb1168..187151fe26c 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -1,3 +1,8 @@ +.project-members-title { + padding-bottom: 10px; + border-bottom: 1px solid $border-color; +} + .member { .list-item-name { float: none; diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index f566748e95a..24e5a8e4015 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,10 +1,9 @@ - page_title "Members" .project-members-page.prepend-top-default - %h4.clearfix + %h4.project-members-title.clearfix Members = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default pull-right hidden-xs", title: "Import members from another project" - %hr - if can?(current_user, :admin_project_member, @project) .project-members-new.append-bottom-default %p.clearfix From c2602aaff3f78ad12e1cc06136a7345699951454 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 4 Oct 2016 14:40:03 +0100 Subject: [PATCH 36/41] Updated Ruby --- app/controllers/projects/group_links_controller.rb | 2 +- app/controllers/projects/project_members_controller.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 7b6f07465e0..2994d8c9666 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -1,6 +1,7 @@ class Projects::GroupLinksController < Projects::ApplicationController layout 'project_settings' before_action :authorize_admin_project! + before_action :authorize_admin_project_member!, only: [:update] def index @group_links = project.project_group_links.all @@ -21,7 +22,6 @@ class Projects::GroupLinksController < Projects::ApplicationController def update @group_link = @project.project_group_links.find(params[:id]) - return render_403 unless can?(current_user, :admin_project_member, @project) @group_link.update_attributes(group_link_params) end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index eb1bf445a7d..870dc8abbd4 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -19,8 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController @groups = @project.project_group_links.where(group_id: group_ids) end - @project_members = @project_members.order('access_level DESC') - @project_members = @project_members.page(params[:page]) + @project_members = @project_members.order(access_level: :desc).page(params[:page]) @requesters = AccessRequestsFinder.new(@project).execute(current_user) @@ -40,6 +39,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController groups = Group.where(id: group_ids) groups.each do |group| + next unless can?(current_user, :read_group, group) + project.project_group_links.create( group: group, group_access: params[:access_level], From a0eaff14124b829ccc02df951bd7cb7d3abb7708 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 5 Oct 2016 14:37:03 +0100 Subject: [PATCH 37/41] Updated Ruby variable name Fixed Ruby code based on review feedback --- app/controllers/projects/project_members_controller.rb | 8 +++----- app/views/projects/project_members/_groups.html.haml | 4 ++-- app/views/projects/project_members/index.html.haml | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 870dc8abbd4..b2c8656d124 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -5,7 +5,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] def index - @groups = @project.project_group_links + @group_links = @project.project_group_links @project_members = @project.project_members @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) @@ -14,9 +14,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController users = @project.users.search(params[:search]).to_a @project_members = @project_members.where(user_id: users) - group_ids = @groups.pluck(:group_id) - group_ids = Group.where(id: group_ids).search(params[:search]).to_a - @groups = @project.project_group_links.where(group_id: group_ids) + @group_links = @project.project_group_links.where(group_id: @project.invited_groups.search(params[:search]).select(:id)) end @project_members = @project_members.order(access_level: :desc).page(params[:page]) @@ -40,7 +38,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController groups.each do |group| next unless can?(current_user, :read_group, group) - + project.project_group_links.create( group: group, group_access: params[:access_level], diff --git a/app/views/projects/project_members/_groups.html.haml b/app/views/projects/project_members/_groups.html.haml index 340e4cd06b8..11f896006da 100644 --- a/app/views/projects/project_members/_groups.html.haml +++ b/app/views/projects/project_members/_groups.html.haml @@ -2,8 +2,8 @@ .panel-heading Groups with access to %strong #{@project.name} - %span.badge= groups.size + %span.badge= group_links.size %ul.content-list - - @groups.each do |group_link| + - group_links.each do |group_link| - group = group_link.group = render 'shared/members/group', group_link: group_link, group: group diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 24e5a8e4015..f1461444241 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -21,8 +21,8 @@ = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } = icon("search") - - if @groups.size > 0 - = render 'groups', groups: @groups + - if @group_links.size > 0 + = render 'groups', group_links: @group_links = render 'team', members: @project_members = paginate @project_members, theme: "gitlab" From 6865c46c6649118e09e60dd29dfa060470010aa9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 6 Oct 2016 15:41:00 +0100 Subject: [PATCH 38/41] Changed how collections are rendered Used variables in haml for replicated checks Fixed broken conflict --- .../projects/project_members_controller.rb | 15 - app/views/projects/group_links/update.js.haml | 2 +- .../project_members/_groups.html.haml | 4 +- .../projects/project_members/_team.html.haml | 3 +- .../projects/project_members/index.html.haml | 2 +- app/views/shared/members/_group.html.haml | 9 +- app/views/shared/members/_member.html.haml | 10 +- config/routes.rb | 794 ------------------ 8 files changed, 15 insertions(+), 824 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 67b41c4573a..37a86ed0523 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -98,21 +98,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController notice: notice) end - def options - users = User.all - users = users.search(params[:search]) if params[:search].present? - users = users.page(1) - - groups = Group.all - groups = groups.search(params[:search]) if params[:search].present? - groups = groups.page(1) - - render json: { - Groups: groups.as_json(only: [:id, :name], methods: [:avatar_url]), - Users: users.as_json(only: [:id, :name, :username], methods: [:avatar_url]), - } - end - protected def member_params diff --git a/app/views/projects/group_links/update.js.haml b/app/views/projects/group_links/update.js.haml index 231d5a79723..af9a5b19060 100644 --- a/app/views/projects/group_links/update.js.haml +++ b/app/views/projects/group_links/update.js.haml @@ -1,3 +1,3 @@ :plain - var $listItem = $('#{escape_javascript(render('shared/members/group', group_link: @group_link, group: @group_link.group))}'); + var $listItem = $('#{escape_javascript(render('shared/members/group', group_link: @group_link))}'); $("#group_member_#{@group_link.id} .list-item-name").replaceWith($listItem.find('.list-item-name')); diff --git a/app/views/projects/project_members/_groups.html.haml b/app/views/projects/project_members/_groups.html.haml index 11f896006da..d7f5fa96527 100644 --- a/app/views/projects/project_members/_groups.html.haml +++ b/app/views/projects/project_members/_groups.html.haml @@ -4,6 +4,4 @@ %strong #{@project.name} %span.badge= group_links.size %ul.content-list - - group_links.each do |group_link| - - group = group_link.group - = render 'shared/members/group', group_link: group_link, group: group + = render partial: 'shared/members/group', collection: group_links, as: :group_link diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index ff54035cfe1..c1e894d8f40 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -4,5 +4,4 @@ %strong #{@project.name} %span.badge= @project_members.total_count %ul.content-list - - members.each do |member| - = render 'shared/members/member', member: member + = render partial: 'shared/members/member', collection: members, as: :member diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index f1461444241..bdeb704b6da 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -21,7 +21,7 @@ = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } = icon("search") - - if @group_links.size > 0 + - if @group_links.any? = render 'groups', group_links: @group_links = render 'team', members: @project_members diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index 171a388b233..1c0346bbc78 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -1,5 +1,6 @@ -- group = local_assigns[:group] - group_link = local_assigns[:group_link] +- group = group_link.group +- can_admin_member = can?(current_user, :admin_project_member, @project) %li.member.group_member{ id: "group_member_#{group_link.id}" } %span{ class: "list-item-name" } = image_tag group_icon(group), class: "avatar s40", alt: '' @@ -13,11 +14,11 @@ Expires in #{distance_of_time_in_words_to_now(group_link.expires_at)} .controls.member-controls = form_tag namespace_project_group_link_path(@project.namespace, @project, group_link), method: :put, remote: true, class: 'form-horizontal js-edit-member-form' do - = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}", disabled: !can?(current_user, :admin_project_member, @project) + = select_tag 'group_link[group_access]', options_for_select(ProjectGroupLink.access_options, group_link.group_access), class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{group.id}", disabled: !can_admin_member .prepend-left-5.clearable-input.member-form-control - = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}", disabled: !can?(current_user, :admin_project_member, @project) + = text_field_tag 'group_link[expires_at]', group_link.expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{group.id}", disabled: !can_admin_member %i.clear-icon.js-clear-input - - if can?(current_user, :admin_project_member, @project) + - if can_admin_member = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), remote: true, method: :delete, diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 80e52bf5637..432047a1c4e 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -2,6 +2,7 @@ - show_controls = local_assigns.fetch(:show_controls, true) - user = local_assigns.fetch(:user, member.user) - source = member.source +- can_admin_member = can?(current_user, action_member_permission(:update, member), member) %li.member{ class: dom_class(member), id: dom_id(member) } %span.list-item-name @@ -47,18 +48,19 @@ - if show_controls - if user != current_user = form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f| - = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + = f.select :access_level, options_for_select(member.class.access_level_roles, member.access_level), {}, class: 'form-control member-form-control append-right-5 js-member-update-control', id: "member_access_level_#{member.id}", disabled: !can_admin_member .prepend-left-5.clearable-input.member-form-control - = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can?(current_user, action_member_permission(:update, member), member) + = f.text_field :expires_at, class: 'form-control js-access-expiration-date js-member-update-control', placeholder: 'Expiration date', id: "member_expires_at_#{member.id}", disabled: !can_admin_member %i.clear-icon.js-clear-input - else %span.member-access-text= member.human_access - - if !user && can?(current_user, action_member_permission(:admin, member), member.source) + + - if member.invite? && can?(current_user, action_member_permission(:admin, member), member.source) = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), method: :post, class: 'btn btn-default prepend-left-10' - - if member.request? && can?(current_user, action_member_permission(:update, member), member) + - elsif member.request? && can_admin_member = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), method: :post, class: 'btn btn-success prepend-left-10', diff --git a/config/routes.rb b/config/routes.rb index f93c406e692..bf7c5b76128 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -74,799 +74,6 @@ Rails.application.routes.draw do # Notification settings resources :notification_settings, only: [:create, :update] -<<<<<<< HEAD - # - # Import - # - namespace :import do - resource :github, only: [:create, :new], controller: :github do - post :personal_access_token - get :status - get :callback - get :jobs - end - - resource :gitlab, only: [:create], controller: :gitlab do - get :status - get :callback - get :jobs - end - - resource :bitbucket, only: [:create], controller: :bitbucket do - get :status - get :callback - get :jobs - end - - resource :google_code, only: [:create, :new], controller: :google_code do - get :status - post :callback - get :jobs - - get :new_user_map, path: :user_map - post :create_user_map, path: :user_map - end - - resource :fogbugz, only: [:create, :new], controller: :fogbugz do - get :status - post :callback - get :jobs - - get :new_user_map, path: :user_map - post :create_user_map, path: :user_map - end - - resource :gitlab_project, only: [:create, :new] do - post :create - end - end - - # - # Uploads - # - - scope path: :uploads do - # Note attachments and User/Group/Project avatars - get ":model/:mounted_as/:id/:filename", - to: "uploads#show", - constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: /[^\/]+/ } - - # Appearance - get ":model/:mounted_as/:id/:filename", - to: "uploads#show", - constraints: { model: /appearance/, mounted_as: /logo|header_logo/, filename: /.+/ } - - # Project markdown uploads - get ":namespace_id/:project_id/:secret/:filename", - to: "projects/uploads#show", - constraints: { namespace_id: /[a-zA-Z.0-9_\-]+/, project_id: /[a-zA-Z.0-9_\-]+/, filename: /[^\/]+/ } - end - - # Redirect old note attachments path to new uploads path. - get "files/note/:id/:filename", - to: redirect("uploads/note/attachment/%{id}/%{filename}"), - constraints: { filename: /[^\/]+/ } - - # - # Explore area - # - namespace :explore do - resources :projects, only: [:index] do - collection do - get :trending - get :starred - end - end - - resources :groups, only: [:index] - resources :snippets, only: [:index] - root to: 'projects#trending' - end - - # Compatibility with old routing - get 'public' => 'explore/projects#index' - get 'public/projects' => 'explore/projects#index' - - # - # Admin Area - # - namespace :admin do - resources :users, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do - resources :keys, only: [:show, :destroy] - resources :identities, except: [:show] - - member do - get :projects - get :keys - get :groups - put :block - put :unblock - put :unlock - put :confirm - post :impersonate - patch :disable_two_factor - delete 'remove/:email_id', action: 'remove_email', as: 'remove_email' - end - end - - resource :impersonation, only: :destroy - - resources :abuse_reports, only: [:index, :destroy] - resources :spam_logs, only: [:index, :destroy] do - member do - post :mark_as_ham - end - end - - resources :applications - - resources :groups, constraints: { id: /[^\/]+/ } do - member do - put :members_update - end - end - - resources :deploy_keys, only: [:index, :new, :create, :destroy] - - resources :hooks, only: [:index, :create, :destroy] do - get :test - end - - resources :broadcast_messages, only: [:index, :edit, :create, :update, :destroy] do - post :preview, on: :collection - end - - resource :logs, only: [:show] - resource :health_check, controller: 'health_check', only: [:show] - resource :background_jobs, controller: 'background_jobs', only: [:show] - resource :system_info, controller: 'system_info', only: [:show] - resources :requests_profiles, only: [:index, :show], param: :name, constraints: { name: /.+\.html/ } - - resources :namespaces, path: '/projects', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do - root to: 'projects#index', as: :projects - - resources(:projects, - path: '/', - constraints: { id: /[a-zA-Z.0-9_\-]+/ }, - only: [:index, :show]) do - root to: 'projects#show' - - member do - put :transfer - post :repository_check - end - - resources :runner_projects, only: [:create, :destroy] - end - end - - resource :appearances, only: [:show, :create, :update], path: 'appearance' do - member do - get :preview - delete :logo - delete :header_logos - end - end - - resource :application_settings, only: [:show, :update] do - resources :services, only: [:index, :edit, :update] - put :reset_runners_token - put :reset_health_check_token - put :clear_repository_check_states - end - - resources :labels - - resources :runners, only: [:index, :show, :update, :destroy] do - member do - get :resume - get :pause - end - end - - resources :builds, only: :index do - collection do - post :cancel_all - end - end - - root to: 'dashboard#index' - end - - # - # Profile Area - # - resource :profile, only: [:show, :update] do - member do - get :audit_log - get :applications, to: 'oauth/applications#index' - - put :reset_private_token - put :update_username - end - - scope module: :profiles do - resource :account, only: [:show] do - member do - delete :unlink - end - end - resource :notifications, only: [:show, :update] - resource :password, only: [:new, :create, :edit, :update] do - member do - put :reset - end - end - resource :preferences, only: [:show, :update] - resources :keys, only: [:index, :show, :new, :create, :destroy] - resources :emails, only: [:index, :create, :destroy] - resource :avatar, only: [:destroy] - - resources :personal_access_tokens, only: [:index, :create] do - member do - put :revoke - end - end - - resource :two_factor_auth, only: [:show, :create, :destroy] do - member do - post :create_u2f - post :codes - patch :skip - end - end - - resources :u2f_registrations, only: [:destroy] - end - end - - scope(path: 'u/:username', - as: :user, - constraints: { username: /[a-zA-Z.0-9_\-]+(? 'omniauth_callbacks#omniauth_error', as: :omniauth_error - get '/users/almost_there' => 'confirmations#almost_there' - end - - root to: "root#index" - - # - # Project Area - # - resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do - resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(? 'templates#show', as: :template - - scope do - get( - '/blob/*id/diff', - to: 'blob#diff', - constraints: { id: /.+/, format: false }, - as: :blob_diff - ) - get( - '/blob/*id', - to: 'blob#show', - constraints: { id: /.+/, format: false }, - as: :blob - ) - delete( - '/blob/*id', - to: 'blob#destroy', - constraints: { id: /.+/, format: false } - ) - put( - '/blob/*id', - to: 'blob#update', - constraints: { id: /.+/, format: false } - ) - post( - '/blob/*id', - to: 'blob#create', - constraints: { id: /.+/, format: false } - ) - end - - scope do - get( - '/raw/*id', - to: 'raw#show', - constraints: { id: /.+/, format: /(html|js)/ }, - as: :raw - ) - end - - scope do - get( - '/tree/*id', - to: 'tree#show', - constraints: { id: /.+/, format: /(html|js)/ }, - as: :tree - ) - end - - scope do - get( - '/find_file/*id', - to: 'find_file#show', - constraints: { id: /.+/, format: /html/ }, - as: :find_file - ) - end - - scope do - get( - '/files/*id', - to: 'find_file#list', - constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ }, - as: :files - ) - end - - scope do - post( - '/create_dir/*id', - to: 'tree#create_dir', - constraints: { id: /.+/ }, - as: 'create_dir' - ) - end - - scope do - get( - '/blame/*id', - to: 'blame#show', - constraints: { id: /.+/, format: /(html|js)/ }, - as: :blame - ) - end - - scope do - get( - '/commits/*id', - to: 'commits#show', - constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }, - as: :commits - ) - end - - resource :avatar, only: [:show, :destroy] - resources :commit, only: [:show], constraints: { id: /\h{7,40}/ } do - member do - get :branches - get :builds - get :pipelines - post :cancel_builds - post :retry_builds - post :revert - post :cherry_pick - get :diff_for_path - end - end - - resources :compare, only: [:index, :create] do - collection do - get :diff_for_path - end - end - - get '/compare/:from...:to', to: 'compare#show', as: 'compare', constraints: { from: /.+/, to: /.+/ } - - # Don't use format parameter as file extension (old 3.0.x behavior) - # See http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments - scope format: false do - resources :network, only: [:show], constraints: { id: Gitlab::Regex.git_reference_regex } - - resources :graphs, only: [:show], constraints: { id: Gitlab::Regex.git_reference_regex } do - member do - get :commits - get :ci - get :languages - end - end - end - - resources :snippets, concerns: :awardable, constraints: { id: /\d+/ } do - member do - get 'raw' - end - end - - WIKI_SLUG_ID = { id: /\S+/ } unless defined? WIKI_SLUG_ID - - scope do - # Order matters to give priority to these matches - get '/wikis/git_access', to: 'wikis#git_access' - get '/wikis/pages', to: 'wikis#pages', as: 'wiki_pages' - post '/wikis', to: 'wikis#create' - - get '/wikis/*id/history', to: 'wikis#history', as: 'wiki_history', constraints: WIKI_SLUG_ID - get '/wikis/*id/edit', to: 'wikis#edit', as: 'wiki_edit', constraints: WIKI_SLUG_ID - - get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID - delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID - put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID - post '/wikis/*id/preview_markdown', to: 'wikis#preview_markdown', constraints: WIKI_SLUG_ID, as: 'wiki_preview_markdown' - end - - resource :repository, only: [:create] do - member do - get 'archive', constraints: { format: Gitlab::Regex.archive_formats_regex } - end - end - - resources :services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do - member do - get :test - end - end - - resources :deploy_keys, constraints: { id: /\d+/ }, only: [:index, :new, :create] do - member do - put :enable - put :disable - end - end - - resources :forks, only: [:index, :new, :create] - resource :import, only: [:new, :create, :show] - - resources :refs, only: [] do - collection do - get 'switch' - end - - member do - # tree viewer logs - get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex } - # Directories with leading dots erroneously get rejected if git - # ref regex used in constraints. Regex verification now done in controller. - get 'logs_tree/*path' => 'refs#logs_tree', as: :logs_file, constraints: { - id: /.*/, - path: /.*/ - } - end - end - - resources :merge_requests, concerns: :awardable, constraints: { id: /\d+/ } do - member do - get :commits - get :diffs - get :conflicts - get :builds - get :pipelines - get :merge_check - post :merge - post :cancel_merge_when_build_succeeds - get :ci_status - post :toggle_subscription - post :remove_wip - get :diff_for_path - post :resolve_conflicts - end - - collection do - get :branch_from - get :branch_to - get :update_branches - get :diff_for_path - post :bulk_update - end - - resources :discussions, only: [], constraints: { id: /\h{40}/ } do - member do - post :resolve - delete :resolve, action: :unresolve - end - end - end - - resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } - resources :tags, only: [:index, :show, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } do - resource :release, only: [:edit, :update] - end - - resources :protected_branches, only: [:index, :show, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } - resources :variables, only: [:index, :show, :update, :create, :destroy] - resources :triggers, only: [:index, :create, :destroy] - - resources :pipelines, only: [:index, :new, :create, :show] do - collection do - resource :pipelines_settings, path: 'settings', only: [:show, :update] - end - - member do - post :cancel - post :retry - end - end - - resources :environments - - resource :cycle_analytics, only: [:show] - - resources :builds, only: [:index, :show], constraints: { id: /\d+/ } do - collection do - post :cancel_all - - resources :artifacts, only: [] do - collection do - get :latest_succeeded, - path: '*ref_name_and_path', - format: false - end - end - end - - member do - get :status - post :cancel - post :retry - post :play - post :erase - get :trace - get :raw - end - - resource :artifacts, only: [] do - get :download - get :browse, path: 'browse(/*path)', format: false - get :file, path: 'file/*path', format: false - post :keep - end - end - - resources :hooks, only: [:index, :create, :destroy], constraints: { id: /\d+/ } do - member do - get :test - end - end - - resources :container_registry, only: [:index, :destroy], constraints: { id: Gitlab::Regex.container_registry_reference_regex } - - resources :milestones, constraints: { id: /\d+/ } do - member do - put :sort_issues - put :sort_merge_requests - end - end - - resources :labels, except: [:show], constraints: { id: /\d+/ } do - collection do - post :generate - post :set_priorities - end - - member do - post :toggle_subscription - delete :remove_priority - end - end - - resources :issues, concerns: :awardable, constraints: { id: /\d+/ } do - member do - post :toggle_subscription - post :mark_as_spam - get :referenced_merge_requests - get :related_branches - get :can_create_branch - end - collection do - post :bulk_update - end - end - - resources :project_members, except: [:show, :new, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ }, concerns: :access_requestable do - collection do - delete :leave - - # Used for import team - # from another project - get :import - post :apply_import - end - - member do - post :resend_invite - end - end - - resources :group_links, only: [:index, :create, :update, :destroy], constraints: { id: /\d+/ } - - resources :notes, only: [:index, :create, :destroy, :update], concerns: :awardable, constraints: { id: /\d+/ } do - member do - delete :delete_attachment - post :resolve - delete :resolve, action: :unresolve - end - end - - resource :board, only: [:show] do - scope module: :boards do - resources :issues, only: [:update] - - resources :lists, only: [:index, :create, :update, :destroy] do - collection do - post :generate - end - - resources :issues, only: [:index] - end - end - end - - resources :todos, only: [:create] - - resources :uploads, only: [:create] do - collection do - get ":secret/:filename", action: :show, as: :show, constraints: { filename: /[^\/]+/ } - end - end - - resources :runners, only: [:index, :edit, :update, :destroy, :show] do - member do - get :resume - get :pause - end - - collection do - post :toggle_shared_runners - end - end - - resources :runner_projects, only: [:create, :destroy] - resources :badges, only: [:index] do - collection do - scope '*ref', constraints: { ref: Gitlab::Regex.git_reference_regex } do - constraints format: /svg/ do - get :build - get :coverage - end - end - end - end - end - end - end -======= draw :import draw :uploads draw :explore @@ -876,7 +83,6 @@ Rails.application.routes.draw do draw :group draw :user draw :project ->>>>>>> master # Get all keys of user get ':username.keys' => 'profiles/keys#get_keys', constraints: { username: /.*/ } From b2e5240af3d14bd67900ef194226274639537888 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 6 Oct 2016 15:42:48 +0100 Subject: [PATCH 39/41] Changed jQuery to be in single line Removed un-required CSS --- app/assets/javascripts/members.js.es6 | 5 +---- app/assets/stylesheets/pages/members.scss | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js.es6 index 1b4b3f38838..5dc6990bdb6 100644 --- a/app/assets/javascripts/members.js.es6 +++ b/app/assets/javascripts/members.js.es6 @@ -31,10 +31,7 @@ } formSubmit() { - $(this).closest('form') - .trigger("submit.rails") - .end() - .disable(); + $(this).closest('form').trigger("submit.rails").end().disable(); } formSuccess() { diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index 187151fe26c..ff4fd751f26 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -5,8 +5,6 @@ .member { .list-item-name { - float: none; - @media (min-width: $screen-sm-min) { float: left; width: 50%; From 96ee975805dd9bbb20bd26edf2dcc7bfdc858c78 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 13 Oct 2016 10:25:38 +0100 Subject: [PATCH 40/41] Moved how we remove event listeners --- app/assets/javascripts/members.js.es6 | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js.es6 index 5dc6990bdb6..a0cd20f21e8 100644 --- a/app/assets/javascripts/members.js.es6 +++ b/app/assets/javascripts/members.js.es6 @@ -3,20 +3,13 @@ class Members { constructor() { - this.removeListeners(); this.addListeners(); } - removeListeners() { - $('.project_member, .group_member').off('ajax:success'); - $('.js-member-update-control').off('change'); - $('.js-edit-member-form').off('ajax:success'); - } - addListeners() { - $('.project_member, .group_member').on('ajax:success', this.removeRow); - $('.js-member-update-control').on('change', this.formSubmit); - $('.js-edit-member-form').on('ajax:success', this.formSuccess); + $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); + $('.js-member-update-control').off('change').on('change', this.formSubmit); + $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess); } removeRow(e) { From 9ec7aeac2362151e15e59531f347f2d7924437f8 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 13 Oct 2016 11:18:56 +0100 Subject: [PATCH 41/41] Tweaked position of badge in panel headings Various UI tweaks --- app/assets/stylesheets/framework/panels.scss | 5 +++++ app/assets/stylesheets/framework/selects.scss | 2 +- app/assets/stylesheets/pages/members.scss | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss index c6f30e144fd..5ba0486177f 100644 --- a/app/assets/stylesheets/framework/panels.scss +++ b/app/assets/stylesheets/framework/panels.scss @@ -13,6 +13,11 @@ .dropdown-menu-toggle { line-height: 20px; } + + .badge { + margin-top: -2px; + margin-left: 5px; + } } .panel-body { diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index b309e2ad9f4..58f9db0fb21 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -94,7 +94,7 @@ } .select2-search-choice { - margin: 8px 0 0 8px; + margin: 5px 0 0 8px; box-shadow: none; border-color: $input-border; color: $gl-text-color; diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index ff4fd751f26..756efa9c7fa 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -9,6 +9,10 @@ float: left; width: 50%; } + + strong { + font-weight: 600; + } } .controls {