mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
[feature] partial load of users list
This commit is contained in:
parent
26f0aa5e0d
commit
c8e9c6dae5
@ -105,8 +105,15 @@ class MembersController
|
||||
##
|
||||
# Controller used in the members/groups management page
|
||||
##
|
||||
Application.Controllers.controller "AdminMembersController", ["$scope", 'membersPromise', 'adminsPromise', 'growl', 'Admin', 'dialogs', '_t'
|
||||
, ($scope, membersPromise, adminsPromise, growl, Admin, dialogs, _t) ->
|
||||
Application.Controllers.controller "AdminMembersController", ["$scope", 'membersPromise', 'adminsPromise', 'growl', 'Admin', 'dialogs', '_t', 'Member'
|
||||
, ($scope, membersPromise, adminsPromise, growl, Admin, dialogs, _t, Member) ->
|
||||
|
||||
|
||||
|
||||
### PRIVATE STATIC CONSTANTS ###
|
||||
|
||||
# 10 users loaded each time we click on 'load more...'
|
||||
USERS_PER_PAGE = 10
|
||||
|
||||
|
||||
|
||||
@ -115,12 +122,19 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
|
||||
## members list
|
||||
$scope.members = membersPromise
|
||||
|
||||
$scope.member =
|
||||
## Members plain-text filtering. Default: not filtered
|
||||
searchText: ''
|
||||
## Members ordering/sorting. Default: not sorted
|
||||
order: 'id'
|
||||
## current displayed page of members
|
||||
page: 1
|
||||
## true when all members where loaded
|
||||
noMore: false
|
||||
|
||||
## admins list
|
||||
$scope.admins = adminsPromise.admins
|
||||
|
||||
## Members ordering/sorting. Default: not sorted
|
||||
$scope.orderMember = null
|
||||
|
||||
## Admins ordering/sorting. Default: not sorted
|
||||
$scope.orderAdmin = null
|
||||
|
||||
@ -131,10 +145,13 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
|
||||
# @param orderBy {string} ordering criterion
|
||||
##
|
||||
$scope.setOrderMember = (orderBy)->
|
||||
if $scope.orderMember == orderBy
|
||||
$scope.orderMember = '-'+orderBy
|
||||
if $scope.member.order == orderBy
|
||||
$scope.member.order = '-'+orderBy
|
||||
else
|
||||
$scope.orderMember = orderBy
|
||||
$scope.member.order = orderBy
|
||||
|
||||
resetSearchMember()
|
||||
memberSearch()
|
||||
|
||||
|
||||
|
||||
@ -169,6 +186,14 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
|
||||
growl.error(_t('unable_to_delete_the_administrator'))
|
||||
|
||||
|
||||
$scope.showNextMembers = ->
|
||||
$scope.member.page += 1
|
||||
memberSearch(true)
|
||||
|
||||
$scope.updateTextSearch = ->
|
||||
resetSearchMember()
|
||||
memberSearch()
|
||||
|
||||
|
||||
### PRIVATE SCOPE ###
|
||||
|
||||
@ -182,6 +207,32 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
|
||||
(admins.map (admin)->
|
||||
admin.id
|
||||
).indexOf(id)
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Reinitialize the context of members's search to display new results set
|
||||
##
|
||||
resetSearchMember = ->
|
||||
$scope.member.noMore = false
|
||||
$scope.member.page = 1
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Run a search query with the current parameters set ($scope.member[searchText,order,page])
|
||||
# and affect or append the result in $scope.members, depending on the concat parameter
|
||||
# @param concat {boolean} if true, the result will be append to $scope.members instead of being affected
|
||||
##
|
||||
memberSearch = (concat) ->
|
||||
Member.list { query: { search: $scope.member.searchText, order_by: $scope.member.order, page: $scope.member.page, size: USERS_PER_PAGE } }, (members) ->
|
||||
if (members.length < USERS_PER_PAGE)
|
||||
$scope.member.noMore = true
|
||||
|
||||
if concat
|
||||
$scope.members = $scope.members.concat(members)
|
||||
else
|
||||
$scope.members = members;
|
||||
]
|
||||
|
||||
|
||||
|
@ -692,7 +692,7 @@ angular.module('application.router', ['ui.router']).
|
||||
controller: 'AuthentificationController'
|
||||
resolve:
|
||||
membersPromise: ['Member', (Member)->
|
||||
Member.query({requested_attributes:'[profile,group,subscription]'}).$promise
|
||||
Member.list({ query: { search: '', order_by: 'id', page: 1, size: 10 } }).$promise
|
||||
]
|
||||
adminsPromise: ['Admin', (Admin)->
|
||||
Admin.query().$promise
|
||||
|
@ -13,4 +13,8 @@ Application.Services.factory 'Member', ["$resource", ($resource)->
|
||||
merge:
|
||||
method: 'PUT'
|
||||
url: '/api/members/:id/merge'
|
||||
list:
|
||||
url: '/api/members/list'
|
||||
method: 'POST'
|
||||
isArray: true
|
||||
]
|
||||
|
@ -24,7 +24,7 @@
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
|
||||
<input type="text" ng-model="searchMember" class="form-control" placeholder="{{ 'search_for_an_user' | translate }}">
|
||||
<input type="text" ng-model="member.searchText" class="form-control" placeholder="{{ 'search_for_an_user' | translate }}" ng-change="updateTextSearch()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -46,32 +46,32 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('last_name')">{{ 'surname' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderMember=='last_name', 'fa fa-sort-alpha-desc': orderMember=='-last_name', 'fa fa-arrows-v': orderMember }"></i></a></th>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('last_name')">{{ 'surname' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='last_name', 'fa fa-sort-alpha-desc': member.order=='-last_name', 'fa fa-arrows-v': member.order }"></i></a></th>
|
||||
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('first_name')">{{ 'first_name' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderMember=='first_name', 'fa fa-sort-alpha-desc': orderMember=='-first_name', 'fa fa-arrows-v': orderMember }"></i></a></th>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('first_name')">{{ 'first_name' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='first_name', 'fa fa-sort-alpha-desc': member.order=='-first_name', 'fa fa-arrows-v': member.order }"></i></a></th>
|
||||
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('email')">{{ 'email' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderMember=='email', 'fa fa-sort-alpha-desc': orderMember=='-email', 'fa fa-arrows-v': orderMember }"></i></a></th>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('email')">{{ 'email' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='email', 'fa fa-sort-alpha-desc': member.order=='-email', 'fa fa-arrows-v': member.order }"></i></a></th>
|
||||
|
||||
<th style="width:10%"><a href="" ng-click="setOrderMember('profile.phone')">{{ 'phone' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderMember=='profile.phone', 'fa fa-sort-numeric-desc': orderMember=='-profile.phone', 'fa fa-arrows-v': orderMember }"></i></a></th>
|
||||
<th style="width:10%"><a href="" ng-click="setOrderMember('phone')">{{ 'phone' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': member.order=='phone', 'fa fa-sort-numeric-desc': member.order=='-phone', 'fa fa-arrows-v': member.order }"></i></a></th>
|
||||
|
||||
<th style="width:20%"><a href="" ng-click="setOrderMember('group.name')">{{ 'user_type' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderMember=='group.name', 'fa fa-sort-alpha-desc': orderMember=='-group.name', 'fa fa-arrows-v': orderMember }"></i></a></th>
|
||||
<th style="width:20%"><a href="" ng-click="setOrderMember('group')">{{ 'user_type' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='group', 'fa fa-sort-alpha-desc': member.order=='-group', 'fa fa-arrows-v': member.order }"></i></a></th>
|
||||
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('subscribed_plan.base_name')">{{ 'subscription' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderMember=='subscribed_plan.base_name', 'fa fa-sort-alpha-desc': orderMember=='-subscribed_plan.base_name', 'fa fa-arrows-v': orderMember }"></i></a></th>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderMember('plan')">{{ 'subscription' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='plan', 'fa fa-sort-alpha-desc': member.order=='-plan', 'fa fa-arrows-v': member.order }"></i></a></th>
|
||||
|
||||
<th style="width:10%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="member in members | filter:searchMember | orderBy:orderMember">
|
||||
<td class="text-c">{{ member.profile.last_name }}</td>
|
||||
<td class="text-c">{{ member.profile.first_name }}</td>
|
||||
<td>{{ member.email }}</td>
|
||||
<td>{{ member.profile.phone }}</td>
|
||||
<td class="text-u-c text-sm">{{ member.group.name }}</td>
|
||||
<td>{{ member.subscribed_plan | humanReadablePlanName }}</td>
|
||||
<tr ng-repeat="m in members">
|
||||
<td class="text-c">{{ m.profile.last_name }}</td>
|
||||
<td class="text-c">{{ m.profile.first_name }}</td>
|
||||
<td>{{ m.email }}</td>
|
||||
<td>{{ m.profile.phone }}</td>
|
||||
<td class="text-u-c text-sm">{{ m.group.name }}</td>
|
||||
<td>{{ m.subscribed_plan | humanReadablePlanName }}</td>
|
||||
<td>
|
||||
<div class="buttons">
|
||||
<button class="btn btn-default" ui-sref="app.admin.members_edit({id: member.id})">
|
||||
<button class="btn btn-default" ui-sref="app.admin.members_edit({id: m.id})">
|
||||
<i class="fa fa-edit"></i> {{ 'edit' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
@ -79,6 +79,9 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-warning" ng-click="showNextMembers()" ng-hide="member.noMore"><i class="fa fa-search-plus" aria-hidden="true"></i> {{ 'display_more_users' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</uib-tab>
|
||||
|
||||
|
@ -131,6 +131,53 @@ class API::MembersController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
def list
|
||||
authorize User
|
||||
|
||||
p = params.require(:query).permit(:search, :order_by, :page, :size)
|
||||
|
||||
unless p[:page].is_a? Integer
|
||||
render json: {error: 'page must be an integer'}, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
unless p[:size].is_a? Integer
|
||||
render json: {error: 'size must be an integer'}, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
|
||||
direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC')
|
||||
order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by])
|
||||
|
||||
case order_key
|
||||
when 'last_name'
|
||||
order_key = 'profiles.last_name'
|
||||
when 'first_name'
|
||||
order_key = 'profiles.first_name'
|
||||
when 'email'
|
||||
order_key = 'users.email'
|
||||
when 'phone'
|
||||
order_key = 'profiles.phone'
|
||||
when 'group'
|
||||
order_key = 'groups.name'
|
||||
when 'plan'
|
||||
order_key = 'plans.base_name'
|
||||
else
|
||||
order_key = 'users.id'
|
||||
end
|
||||
|
||||
@members = User.includes(:profile, :group)
|
||||
.joins(:profile, :group, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" LEFT JOIN "plans" ON "plans"."id" = "subscriptions"."plan_id"')
|
||||
.order("#{order_key} #{direction}")
|
||||
.page(p[:page])
|
||||
.per(p[:size])
|
||||
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
@members = @members.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search OR profiles.phone ILIKE :search OR email ILIKE :search OR groups.name ILIKE :search OR plans.base_name ILIKE :search', search: "%#{p[:search]}%") if p[:search].size > 0
|
||||
|
||||
@members
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
def set_member
|
||||
@member = User.find(params[:id])
|
||||
|
@ -28,4 +28,8 @@ class UserPolicy < ApplicationPolicy
|
||||
def merge?
|
||||
user.id == record.id
|
||||
end
|
||||
|
||||
def list?
|
||||
user.is_admin?
|
||||
end
|
||||
end
|
||||
|
15
app/views/api/members/list.json.jbuilder
Normal file
15
app/views/api/members/list.json.jbuilder
Normal file
@ -0,0 +1,15 @@
|
||||
json.array!(@members) do |member|
|
||||
json.id member.id
|
||||
json.email member.email if current_user
|
||||
json.profile do
|
||||
json.first_name member.profile.first_name
|
||||
json.last_name member.profile.last_name
|
||||
json.phone member.profile.phone
|
||||
end
|
||||
json.group do
|
||||
json.name member.group.name
|
||||
end
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: member.subscribed_plan
|
||||
end if member.subscribed_plan
|
||||
end
|
@ -265,6 +265,7 @@ en:
|
||||
email: "Email"
|
||||
phone: "Phone"
|
||||
user_type: "User type"
|
||||
display_more_users: "Display more users..."
|
||||
administrators: "Administrators"
|
||||
search_for_an_administrator: "Search for an administrator"
|
||||
add_a_new_administrator: "Add a new administrator"
|
||||
|
@ -265,6 +265,7 @@ fr:
|
||||
email: "Courriel"
|
||||
phone: "Tel."
|
||||
user_type: "Type utilisateur"
|
||||
display_more_users: "Afficher plus d'utilisateurs ..."
|
||||
administrators: "Administrateurs"
|
||||
search_for_an_administrator: "Recherchez un administrateur"
|
||||
add_a_new_administrator: "Ajouter un nouvel administrateur"
|
||||
|
@ -40,6 +40,7 @@ Rails.application.routes.draw do
|
||||
get '/export_reservations', action: 'export_reservations', on: :collection
|
||||
get '/export_members', action: 'export_members', on: :collection
|
||||
put ':id/merge', action: 'merge', on: :collection
|
||||
post 'list', action: 'list', on: :collection
|
||||
end
|
||||
resources :reservations, only: [:show, :create, :index, :update]
|
||||
resources :notifications, only: [:index, :show, :update] do
|
||||
|
Loading…
x
Reference in New Issue
Block a user