admin: adds paging to global user list

Currently there is a limit of 1000 users in the global
user list. This change introduces paging so that an
admin can see all users and not just the first 1000.

Adds a new route to the api - /api/users/search that
returns a list of users and a total count. It takes
two parameters perpage and page that enable paging.

Fixes #7469
This commit is contained in:
Daniel Lee
2017-02-08 14:20:07 +01:00
committed by bergquist
parent e80f673264
commit 193d468ed3
15 changed files with 360 additions and 100 deletions

View File

@@ -113,6 +113,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/admin/users', {
templateUrl: 'public/app/features/admin/partials/users.html',
controller : 'AdminListUsersCtrl',
controllerAs: 'ctrl',
resolve: loadAdminBundle,
})
.when('/admin/users/create', {

View File

@@ -1,4 +1,4 @@
import './adminListUsersCtrl';
import AdminListUsersCtrl from './admin_list_users_ctrl';
import './adminListOrgsCtrl';
import './adminEditOrgCtrl';
import './adminEditUserCtrl';
@@ -37,3 +37,4 @@ export class AdminStatsCtrl {
coreModule.controller('AdminSettingsCtrl', AdminSettingsCtrl);
coreModule.controller('AdminHomeCtrl', AdminHomeCtrl);
coreModule.controller('AdminStatsCtrl', AdminStatsCtrl);
coreModule.controller('AdminListUsersCtrl', AdminListUsersCtrl);

View File

@@ -1,38 +0,0 @@
define([
'angular',
],
function (angular) {
'use strict';
var module = angular.module('grafana.controllers');
module.controller('AdminListUsersCtrl', function($scope, backendSrv) {
$scope.init = function() {
$scope.getUsers();
};
$scope.getUsers = function() {
backendSrv.get('/api/users').then(function(users) {
$scope.users = users;
});
};
$scope.deleteUser = function(user) {
$scope.appEvent('confirm-modal', {
title: 'Delete',
text: 'Do you want to delete ' + user.login + '?',
icon: 'fa-trash',
yesText: 'Delete',
onConfirm: function() {
backendSrv.delete('/api/admin/users/' + user.id).then(function() {
$scope.getUsers();
});
}
});
};
$scope.init();
});
});

View File

@@ -0,0 +1,49 @@
///<reference path="../../headers/common.d.ts" />
export default class AdminListUsersCtrl {
users: any;
pages = [];
perPage = 1000;
page = 1;
totalPages: number;
showPaging = false;
/** @ngInject */
constructor(private $scope, private backendSrv) {
this.getUsers();
}
getUsers() {
this.backendSrv.get(`/api/users/search?perpage=${this.perPage}&page=${this.page}`).then((result) => {
this.users = result.users;
this.page = result.page;
this.perPage = result.perPage;
this.totalPages = Math.ceil(result.totalCount / result.perPage);
this.showPaging = this.totalPages > 1;
this.pages = [];
for (var i = 1; i < this.totalPages+1; i++) {
this.pages.push({ page: i, current: i === this.page});
}
});
}
navigateToPage(page) {
this.page = page.page;
this.getUsers();
}
deleteUser(user) {
this.$scope.appEvent('confirm-modal', {
title: 'Delete',
text: 'Do you want to delete ' + user.login + '?',
icon: 'fa-trash',
yesText: 'Delete',
onConfirm: () => {
this.backendSrv.delete('/api/admin/users/' + user.id).then(() => {
this.getUsers();
});
}
});
}
}

View File

@@ -1,49 +1,62 @@
<navbar icon="fa fa-fw fa-cogs" title="Admin" title-url="admin">
<a href="admin/users" class="navbar-page-btn">
<i class="icon-gf icon-gf-users"></i>
Users
</a>
<a href="admin/users" class="navbar-page-btn">
<i class="icon-gf icon-gf-users"></i>
Users
</a>
</navbar>
<div class="page-container">
<div class="page-header">
<h1>Users</h1>
<div class="page-header">
<h1>Users</h1>
<a class="btn btn-success" href="admin/users/create">
<i class="fa fa-plus"></i>
Add new user
</a>
</div>
<a class="btn btn-success" href="admin/users/create">
<i class="fa fa-plus"></i>
Add new user
</a>
</div>
<div class="admin-list-table">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Login</th>
<th>Email</th>
<th style="white-space: nowrap">Grafana Admin</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in ctrl.users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.login}}</td>
<td>{{user.email}}</td>
<td>{{user.isAdmin}}</td>
<td class="text-right">
<a href="admin/users/edit/{{user.id}}" class="btn btn-inverse btn-small">
<i class="fa fa-edit"></i>
Edit
</a>
&nbsp;&nbsp;
<a ng-click="ctrl.deleteUser(user)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</tbody>
<table class="filter-table form-inline">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Login</th>
<th>Email</th>
<th style="white-space: nowrap">Grafana Admin</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.login}}</td>
<td>{{user.email}}</td>
<td>{{user.isAdmin}}</td>
<td class="text-right">
<a href="admin/users/edit/{{user.id}}" class="btn btn-inverse btn-small">
<i class="fa fa-edit"></i>
Edit
</a>
&nbsp;&nbsp;
<a ng-click="deleteUser(user)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</tbody>
</table>
</table>
</div>
<div class="admin-list-paging" ng-if="ctrl.showPaging">
<ol>
<li ng-repeat="page in ctrl.pages">
<button
class="btn btn-small"
ng-class="{'btn-secondary': page.current, 'btn-inverse': !page.current}"
ng-click="ctrl.navigateToPage(page)">{{page.page}}</button>
</li>
</ol>
</div>
</div>