#369: updated UI for Groups::Members

This commit is contained in:
Vokhmin Alexey V 2014-11-12 02:50:15 +03:00
parent a905237777
commit 1b5e94a2e1
19 changed files with 89 additions and 308 deletions

View File

@ -24,9 +24,6 @@ RosaABF.controller 'StatisticsController', ['$scope', '$http', '$timeout', ($sco
formatYear: 'yy'
startingDay: 1
$('#users_or_groups').on 'autocompleteselect', (e) ->
$timeout($scope.update, 100)
$scope.init = ->
$('#statistics-form .date_picker').datepicker
'dateFormat': 'yy-mm-dd'

View File

@ -1,163 +0,0 @@
RosaABF.controller 'StatisticsController', ['$scope', '$http', '$timeout', ($scope, $http, $timeout) ->
$scope.users_or_groups = null
$scope.range = 'last_30_days'
$scope.range_start = $('#range_start').attr('value')
$scope.range_end = $('#range_end').attr('value')
$scope.loading = false
$scope.statistics = {}
$scope.statistics_path = '/statistics'
$scope.colors = [
'56, 132, 158',
'77, 169, 68',
'241, 128, 73',
'174, 199, 232',
# '255, 187, 120',
# '152, 223, 138',
# '214, 39, 40',
# '31, 119, 180'
]
$scope.charts = {}
$('#users_or_groups').on 'autocompleteselect', (e) ->
$timeout($scope.update, 100)
$scope.init = ->
$('#statistics-form .date_picker').datepicker
'dateFormat': 'yy-mm-dd'
maxDate: 0
minDate: -366
showButtonPanel: true
$scope.update()
true
$scope.prepareRange = ->
range_start = new Date($scope.range_start)
range_end = new Date($scope.range_end)
if range_start > range_end
tmp = $scope.range_start
$scope.range_start = $scope.range_end
$scope.range_end = tmp
$scope.prepareUsersOrGroups = ->
if $scope.users_or_groups
items = _.uniq $('#users_or_groups').val().replace(/\s/g, '').split(/,/)
items = _.reject items, (i) ->
_.isEmpty(i)
$scope.users_or_groups = _.first(items, 3).join(', ') + ', '
$scope.update = ->
return if $scope.loading
$scope.loading = true
$scope.statistics = {}
$scope.prepareRange()
$scope.prepareUsersOrGroups()
$('.doughnut-legend').remove()
params =
range: $scope.range
range_start: $scope.range_start
range_end: $scope.range_end
users_or_groups: $scope.users_or_groups
format: 'json'
$http.get($scope.statistics_path, params: params).success (results) ->
$scope.statistics = results
$scope.loading = false
# BuildLists
if $scope.statistics.build_lists
$scope.initBuildListsChart()
# PullRequests
if $scope.statistics.pull_requests
$scope.initPullRequestsChart()
# Issues
if $scope.statistics.issues
$scope.initIssuesChart()
# Commits
if $scope.statistics.commits
$scope.initCommitsChart()
.error (data, status, headers, config) ->
console.log 'error:'
$scope.loading = false
$scope.dateChart = (id, collections) ->
new_collections = $.grep collections, ( c ) ->
return c
if collections.length == new_collections.length
$scope.charts[id].destroy() if $scope.charts[id]
points = collections[0]
factor = points.length // 45 + 1
tooltipTitles = []
labels = _.map points, (d, index) ->
x = d.x
tooltipTitles.push x
if index %% factor == 0
x
else
''
datasets = _.map collections, (collection, index) ->
data = _.map collection, (d) ->
d.y
dataset =
fillColor: "rgba(#{ $scope.colors[index] }, 0.1)"
strokeColor: "rgba(#{ $scope.colors[index] }, 1)"
pointColor: "rgba(#{ $scope.colors[index] }, 1)"
pointStrokeColor: "#fff"
data: data
data =
datasets: datasets
# We display only limited count of labels on X axis, but tooltips should have titles
# See: Chart.js "Added by avokhmin"
labels: labels
tooltipTitles: tooltipTitles
options =
responsive: true
context = $(id)[0].getContext('2d')
$scope.charts[id] = new Chart(context).Line(data, options)
$scope.initBuildListsChart = ->
$scope.dateChart '#build_lists_chart', [
$scope.statistics.build_lists.build_started,
$scope.statistics.build_lists.success,
$scope.statistics.build_lists.build_error,
$scope.statistics.build_lists.build_published
]
$scope.initCommitsChart = ->
$scope.dateChart '#commits_chart', [
$scope.statistics.commits.chart
]
$scope.initPullRequestsChart = ->
$scope.dateChart '#pull_requests_chart', [
$scope.statistics.pull_requests.open,
$scope.statistics.pull_requests.merged
$scope.statistics.pull_requests.closed,
]
$scope.initIssuesChart = ->
$scope.dateChart '#issues_chart', [
$scope.statistics.issues.open,
$scope.statistics.issues.reopen,
$scope.statistics.issues.closed
]
]

View File

@ -1,14 +0,0 @@
$(document).ready(function() {
$('#product_project').bind('railsAutocomplete.select', function(event, data){
var ppv = $("#product_project_version").empty().append('<option value=""></option>');
$(data.item.project_versions).each(function(k, i) {
var optgroup = $('<optgroup label="' + i[0] + '"></optgroup>');
$(i[1]).each(function(k, b) {
optgroup.append('<option value="' + b + '">' + b + '</option>');
});
ppv.append(optgroup);
});
});
});

View File

@ -6,7 +6,7 @@
// require jquery.dataTables
// require jquery.dataTables_ext
//= require autocomplete-rails
// require autocomplete-rails
// require extra/autocomplete-form
//= require bootstrap-sprockets

View File

@ -1,8 +1,6 @@
class AutocompletesController < ApplicationController
before_filter :authenticate_user!
autocomplete :group, :uname
def autocomplete_user_uname
results = User.opened.search(params[:query]).search_order.limit(5)
render json: results.map{ |u| { id: u.id, name: u.uname } }

View File

@ -1,4 +1,6 @@
class Groups::BaseController < ApplicationController
layout 'bootstrap'
before_filter :authenticate_user!
before_filter :find_group

View File

@ -6,36 +6,26 @@ class Groups::MembersController < Groups::BaseController
end
def update
params['user'].keys.each do |user_id|
role = params['user'][user_id]
if relation = @group.actors.where(actor_id: user_id, actor_type: 'User')
relation.update_all(role: role) if @group.owner.id.to_s != user_id
else
relation = @group.actors.build(actor_id: user_id, actor_type: 'User', role: role)
raise CanCan::AccessDenied if @group.owner_id.to_s == params[:member_id]
relation = @group.actors.where(actor_id: params[:member_id], actor_type: 'User').first
relation ||= @group.actors.build(actor_id: params[:member_id], actor_type: 'User')
relation.role = params[:role]
relation.save!
end
end if params['user']
if @group.save
flash[:notice] = t("flash.members.successfully_changed")
else
flash[:error] = t("flash.members.error_in_changing")
end
redirect_to group_members_path(@group)
end
def remove
all_user_ids = []
params['user_remove'].each do |user_id, remove|
all_user_ids << user_id if remove == ["1"]
end if params['user_remove']
User.where(id: all_user_ids).each do |user|
User.where(id: params[:members]).each do |user|
@group.remove_member(user)
end
redirect_to group_members_path(@group)
end
def add
@user = User.find_by uname: params[:user_uname]
@user = User.where(id: params[:member_id]).first
if !@user
flash[:error] = t("flash.collaborators.wrong_user", uname: params[:user_uname])
elsif @group.add_member(@user, params[:role])

View File

@ -1,6 +1,5 @@
class Groups::ProfileController < Groups::BaseController
include AvatarHelper
layout 'bootstrap'
load_and_authorize_resource class: Group, instance_name: 'group'
skip_before_filter :authenticate_user!, only: :show if APP_CONFIG['anonymous_access']

View File

@ -124,14 +124,9 @@ class Platforms::PlatformsController < Platforms::BaseController
end
def remove_members
user_ids = params[:user_remove] ?
params[:user_remove].map{ |k, v| k if v.first == '1' }.compact : []
User.where(id: user_ids).each{ |user| @platform.remove_member(user) }
redirect_to members_platform_path(@platform)
User.where(id: params[:members]).each do |user|
@platform.remove_member(user)
end
def remove_member
User.where(id: params[:member_id]).each{ |user| @platform.remove_member(user) }
redirect_to members_platform_path(@platform)
end

View File

@ -36,14 +36,9 @@ class Platforms::RepositoriesController < Platforms::BaseController
end
def remove_members
user_ids = params[:user_remove] ?
params[:user_remove].map{ |k, v| k if v.first == '1' }.compact : []
User.where(id: user_ids).each{ |user| @repository.remove_member(user) }
redirect_to edit_platform_repository_path(@platform, @repository)
User.where(id: params[:members]).each do |user|
@repository.remove_member(user)
end
def remove_member
User.where(id: params[:member_id]).each{ |user| @repository.remove_member(user) }
redirect_to edit_platform_repository_path(@platform, @repository)
end

View File

@ -53,11 +53,9 @@ module ProjectsHelper
end
def options_for_collaborators_roles_select
options_for_select(
Relation::ROLES.collect { |role|
Relation::ROLES.map do |role|
[t("layout.collaborators.role_names.#{ role }"), role]
}
)
end
end
def visibility_icon(visibility)

View File

@ -51,7 +51,7 @@ class Ability
if user.user?
can :edit, User, id: user.id
can [:read, :create], Group
can [:update, :manage_members, :members, :add_member, :remove_member, :update_member], Group do |group|
can [:update, :manage_members, :members, :add_member, :remove_members, :update_member], Group do |group|
group.actors.exists?(actor_type: 'User', actor_id: user.id, role: 'admin') # or group.owner_id = user.id
end
can :write, Group do |group|
@ -68,7 +68,7 @@ class Ability
# can([:read, :archive, :membered, :get_id], Project, read_relations_for('projects')) {|project| local_reader? project}
can([:read, :archive, :membered, :get_id], Project, read_relations_with_projects) {|project| local_reader? project}
can(:write, Project) {|project| local_writer? project} # for grack
can [:update, :sections, :manage_collaborators, :autocomplete_maintainers, :add_member, :remove_member, :update_member, :members, :schedule], Project do |project|
can [:update, :sections, :manage_collaborators, :autocomplete_maintainers, :add_member, :remove_members, :update_member, :members, :schedule], Project do |project|
local_admin? project
end
can(:fork, Project) {|project| can? :read, project}
@ -116,7 +116,7 @@ class Ability
can([:read, :related, :members], Platform, read_relations_for('platforms')) {|platform| local_reader? platform}
can [:read, :related], Platform, id: user.repositories.pluck(:platform_id)
can([:update, :destroy, :change_visibility], Platform) {|platform| owner?(platform) }
can([:local_admin_manage, :members, :add_member, :remove_member, :remove_members, :remove_file] , Platform) {|platform| owner?(platform) || local_admin?(platform) }
can([:local_admin_manage, :members, :add_member, :remove_members, :remove_file] , Platform) {|platform| owner?(platform) || local_admin?(platform) }
can([:create, :publish], MassBuild) {|mass_build| owner?(mass_build.save_to_platform) || local_admin?(mass_build.save_to_platform)}
can(:cancel, MassBuild) {|mass_build| (owner?(mass_build.save_to_platform) || local_admin?(mass_build.save_to_platform)) && !mass_build.stop_build}
@ -126,7 +126,7 @@ class Ability
can([:read, :projects_list, :projects], Repository, read_relations_for('repositories')) {|repository| can? :show, repository.platform}
can([:read, :projects_list, :projects], Repository, read_relations_for('repositories', 'platforms')) {|repository| local_reader? repository.platform}
can([:create, :edit, :update, :destroy, :projects_list, :projects, :add_project, :remove_project, :regenerate_metadata, :sync_lock_file, :add_repo_lock_file, :remove_repo_lock_file], Repository) {|repository| local_admin? repository.platform}
can([:remove_members, :remove_member, :add_member, :signatures, :packages], Repository) {|repository| owner?(repository.platform) || local_admin?(repository.platform)}
can([:remove_members, :add_member, :signatures, :packages], Repository) {|repository| owner?(repository.platform) || local_admin?(repository.platform)}
can([:add_project, :remove_project], Repository) {|repository| repository.members.exists?(id: user.id)}
can(:clear, Platform) {|platform| owner?(platform) && platform.personal?}
can(:regenerate_metadata, Platform) {|platform| owner?(platform) || local_admin?(platform)}
@ -169,12 +169,12 @@ class Ability
cannot [:regenerate_metadata, :destroy], Platform, platform_type: 'personal'
cannot [:create, :destroy], Repository, platform: {platform_type: 'personal'}, name: 'main'
cannot [:packages], Repository, platform: {platform_type: 'personal'}
cannot [:remove_members, :remove_member, :add_member, :sync_lock_file, :add_repo_lock_file, :remove_repo_lock_file], Repository, platform: {platform_type: 'personal'}
cannot [:remove_members, :add_member, :sync_lock_file, :add_repo_lock_file, :remove_repo_lock_file], Repository, platform: {platform_type: 'personal'}
cannot :clear, Platform, platform_type: 'main'
cannot :destroy, Issue
cannot [:members, :add_member, :remove_member, :remove_members], Platform, platform_type: 'personal'
cannot [:members, :add_member, :remove_members], Platform, platform_type: 'personal'
cannot [:create, :update, :destroy, :clone], Product, platform: {platform_type: 'personal'}
cannot [:clone], Platform, platform_type: 'personal'

View File

@ -1,13 +0,0 @@
.admin-preferences
- act = action_name.to_sym
- contr = controller_name.to_sym
%aside
.admin-preferences
%ul
- if can? :edit, @group
%li{class: (act == :edit && contr == :profile) ? 'active' : ''}
= link_to t("layout.groups.edit"), edit_group_path(@group)
- if can? :manage_members, @group
%li{class: (act == :index && contr == :members) ? 'active' : ''}
= link_to t("layout.groups.edit_members"), group_members_path(@group)

View File

@ -1,41 +0,0 @@
-set_meta_tags title: [title_object(@group), t('layout.groups.members')]
= form_tag group_members_path(@group), id: 'members_form', delete_url: remove_group_members_path(@group) do
= hidden_field_tag "_method", "post"
%table.tablesorter{cellpadding: "0", cellspacing: "0"}
%thead
%tr
%th
\ 
%th= t("layout.collaborators.members")
%th{colspan: "3"}= t("layout.collaborators.roles")
%tbody
- actors = @group.actors.where(actor_id: @members.map(&:id), actor_type: 'User')
- @members.each do |user|
%tr
%td
%span#niceCheckbox1.niceCheck-main= check_box_tag "user_remove[#{user.id}][]"
%td
.img= image_tag avatar_url(user)
.forimg= link_to user.fullname, user_path(user)
- Relation::ROLES.each_with_index do |role, i|
%td
- checked = actors.find{ |a| a.actor_id == user.id && a.role == role }
.radio= radio_button_tag "user[#{user.id}]", role, (checked ? :checked : nil), class: 'niceRadio'
.forradio= t("layout.collaborators.role_names.#{ role }")
= link_to_function t("layout.delete"), "deleteAdminMember();", class: 'button'
.both
.hr.top
= form_tag add_group_members_path(@group) do
.admin-search= autocomplete_field_tag 'user_uname', params[:user_uname], autocomplete_user_uname_autocompletes_path
.admin-role
.lineForm= select_tag 'role', options_for_collaborators_roles_select
.both
%br
= submit_tag t('layout.add'), class: 'button', data: {'disable-with' => t('layout.processing')}
.hr.bottom
.both
= link_to_function t("layout.save"), "saveAdminMember();", class: 'button'
- content_for :sidebar, render('sidebar')

View File

@ -0,0 +1,12 @@
-set_meta_tags title: [title_object(@group), t('layout.groups.members')]
= render 'groups/base/submenu'
.container.col-md-offset-2.col-md-8
.row
= render 'shared/members_table',
remove_members_path: remove_group_members_path(@group),
add_member_path: add_group_members_path(@group),
members: @members,
update_roles_path: group_members_path(@group),
editable_object: @group

View File

@ -5,7 +5,6 @@
.row
= render "shared/members_table",
remove_members_path: remove_members_platform_path(@platform),
remove_member_path: remove_member_platform_path(@platform),
add_member_path: add_member_platform_path(@platform),
members: @members.select{|u| u != @platform.owner},
editable_object: @platform

View File

@ -70,7 +70,6 @@
- if @platform.main?
= render "shared/members_table",
remove_members_path: remove_members_platform_repository_path(@platform, @repository),
remove_member_path: remove_member_platform_repository_path(@platform, @repository),
add_member_path: add_member_platform_repository_path(@platform, @repository),
members: @members,
editable_object: @repository

View File

@ -1,7 +1,5 @@
= form_tag remove_members_path, id: 'members_form', method: :post do
- update_roles_path ||= false
= form_tag remove_members_path, id: 'members_form', method: :delete do
table.table.table-striped
thead
tr
@ -9,25 +7,51 @@
th
th
= t("layout.collaborators.members")
- if can? :remove_member, editable_object
- if can? :remove_members, editable_object
- if update_roles_path
th.buttons.text-center colspan=3
= t("layout.collaborators.roles")
th.buttons
= t("layout.remove")
tbody
- members.each_with_index do |user, num|
tr id="admin-table-members-row#{num}"
- if update_roles_path
- actors = editable_object.actors.where(actor_id: members.map(&:id), actor_type: 'User').to_a
- members.each do |user|
tr
- if can? :remove_members, editable_object
td
= check_box_tag "user_remove[#{user.id}][]"
= check_box_tag "members[]", user.id
td
span
= image_tag avatar_url(user)
= image_tag avatar_url(user), size: '30x30'
| &nbsp;
= link_to user.fullname, user_path(user)
- if can? :remove_member, editable_object
- if can? :remove_members, editable_object
- if update_roles_path
- actor = actors.find{ |a| a.actor_id == user.id }
- Relation::ROLES.each_with_index do |role, i|
td ng-init="user_#{user.id}_role = '#{actor.role}'"
input[
type = 'radio'
ng-model = "user_#{user.id}_role"
value = role ]
| &nbsp;
= t("layout.collaborators.role_names.#{ role }")
td
= link_to "#{remove_member_path}?member_id=#{user.id}", method: :delete, data: { confirm: t("layout.confirm") } do
- if update_roles_path
- path = "#{update_roles_path}?member_id=#{user.id}"
a[
ng-href = "{{'#{path}&role=' + user_#{user.id}_role}}"
data-method = 'put'
data-confirm = t('layout.confirm') ]
span.glyphicon.glyphicon-ok
| &nbsp;
= link_to "#{remove_members_path}?members=#{user.id}", method: :delete, data: { confirm: t("layout.confirm") } do
span.glyphicon.glyphicon-remove
| &nbsp;
- if can? :remove_members, editable_object
= submit_tag t('layout.delete'), class: 'btn btn-danger', data: {'disable-with' => t('layout.processing')}
@ -44,5 +68,12 @@
'data-id' => '#member_id_field',
class: 'typeahead' }
- if update_roles_path
| &nbsp;
= f.input :role,
collection: options_for_collaborators_roles_select,
input_html: { name: :role },
include_blank: false
| &nbsp;
= f.button :submit, t('layout.add')

View File

@ -169,9 +169,8 @@ Rosa::Application.routes.draw do
put :clear
get :clone
get :members
post :remove_members # fixme: change post to delete
delete :remove_members
post :change_visibility
delete :remove_member
post :add_member
post :make_clone
get :advisories
@ -198,8 +197,7 @@ Rosa::Application.routes.draw do
get :remove_project
delete :remove_project
get :projects_list
post :remove_members # fixme: change post to delete
delete :remove_member
delete :remove_members
post :add_member
put :regenerate_metadata
put :sync_lock_file
@ -229,7 +227,6 @@ Rosa::Application.routes.draw do
resources :autocompletes, only: [] do
collection do
get :autocomplete_user_uname
get :autocomplete_group_uname
get :autocomplete_extra_build_list
get :autocomplete_extra_mass_build
get :autocomplete_extra_repositories
@ -268,7 +265,7 @@ Rosa::Application.routes.draw do
resources :members, only: [:index] do
collection do
post :add
post :update
put :update
delete :remove
end
end