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