KEYCLOAK-3507: Pagination for clients and roles in admin console
This commit is contained in:
parent
0e33e4035f
commit
7a6324e02c
7 changed files with 150 additions and 125 deletions
|
@ -2680,20 +2680,38 @@ module.directive('kcOnReadFile', function ($parse) {
|
|||
});
|
||||
|
||||
module.controller('PagingCtrl', function ($scope) {
|
||||
$scope.isLastPage = function()
|
||||
{
|
||||
if ($scope.currentPage === $scope.numberOfPages) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$scope.currentPageInput = 1;
|
||||
|
||||
$scope.firstPage = function() {
|
||||
if (!$scope.hasPrevious()) return;
|
||||
$scope.currentPage = 1;
|
||||
$scope.currentPageInput = 1;
|
||||
};
|
||||
|
||||
$scope.isFirstPage = function()
|
||||
{
|
||||
if ($scope.currentPage === 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
$scope.lastPage = function() {
|
||||
if (!$scope.hasNext()) return;
|
||||
$scope.currentPage = $scope.numberOfPages;
|
||||
$scope.currentPageInput = $scope.numberOfPages;
|
||||
};
|
||||
|
||||
$scope.previousPage = function() {
|
||||
if (!$scope.hasPrevious()) return;
|
||||
$scope.currentPage--;
|
||||
$scope.currentPageInput = $scope.currentPage;
|
||||
};
|
||||
|
||||
$scope.nextPage = function() {
|
||||
if (!$scope.hasNext()) return;
|
||||
$scope.currentPage++;
|
||||
$scope.currentPageInput = $scope.currentPage;
|
||||
};
|
||||
|
||||
$scope.hasNext = function() {
|
||||
return $scope.currentPage < $scope.numberOfPages;
|
||||
};
|
||||
|
||||
$scope.hasPrevious = function() {
|
||||
return $scope.currentPage > 1;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -2701,15 +2719,34 @@ module.directive('kcPaging', function () {
|
|||
return {
|
||||
scope: {
|
||||
currentPage: '=',
|
||||
currentPageInput: '=',
|
||||
numberOfPages: '='
|
||||
},
|
||||
restrict: 'A',
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
controller: 'PagingCtrl',
|
||||
templateUrl: resourceUrl + '/templates/kc-paging.html'
|
||||
}
|
||||
});
|
||||
|
||||
// Tests the page number input from currentPageInput to see
|
||||
// if it represents a valid page. If so, the current page is changed.
|
||||
module.directive('kcValidPage', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attrs, ctrl) {
|
||||
ctrl.$validators.inRange = function(modelValue, viewValue) {
|
||||
if (viewValue >= 1 && viewValue <= scope.numberOfPages) {
|
||||
scope.currentPage = viewValue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// filter used for paged tables
|
||||
module.filter('startFrom', function () {
|
||||
return function (input, start) {
|
||||
if (input) {
|
||||
|
|
|
@ -735,6 +735,7 @@ module.controller('ClientListCtrl', function($scope, realm, clients, Client, ser
|
|||
$scope.realm = realm;
|
||||
$scope.clients = clients;
|
||||
$scope.currentPage = 1;
|
||||
$scope.currentPageInput = 1;
|
||||
$scope.pageSize = 20;
|
||||
$scope.numberOfPages = Math.ceil($scope.clients.length/$scope.pageSize);
|
||||
|
||||
|
@ -743,6 +744,7 @@ module.controller('ClientListCtrl', function($scope, realm, clients, Client, ser
|
|||
$scope.totalItems = $scope.filtered.length;
|
||||
$scope.numberOfPages = Math.ceil($scope.totalItems/$scope.pageSize);
|
||||
$scope.currentPage = 1;
|
||||
$scope.currentPageInput = 1;
|
||||
}, true);
|
||||
|
||||
$scope.removeClient = function(client) {
|
||||
|
|
|
@ -1227,14 +1227,16 @@ module.controller('RoleListCtrl', function($scope, $route, Dialog, Notifications
|
|||
$scope.realm = realm;
|
||||
$scope.roles = roles;
|
||||
$scope.currentPage = 1;
|
||||
$scope.currentPageInput = 1;
|
||||
$scope.pageSize = 20;
|
||||
$scope.numberOfPages = Math.ceil($scope.roles.length/$scope.pageSize);
|
||||
|
||||
$scope.$watch('searchQuery', function (newVal, oldVal) {
|
||||
$scope.filtered = filterFilter($scope.roles, newVal);
|
||||
$scope.filtered = filterFilter($scope.roles, {name: newVal});
|
||||
$scope.totalItems = $scope.filtered.length;
|
||||
$scope.numberOfPages = Math.ceil($scope.totalItems/$scope.pageSize);
|
||||
$scope.currentPage = 1;
|
||||
$scope.currentPageInput = 1;
|
||||
}, true);
|
||||
|
||||
$scope.removeRole = function (role) {
|
||||
|
|
|
@ -4,59 +4,53 @@
|
|||
<kc-tooltip>{{:: 'clients.tooltip' | translate}}</kc-tooltip>
|
||||
</h1>
|
||||
|
||||
<table class="table table-striped table-bordered">
|
||||
<table class="datatable table table-striped table-bordered dataTable no-footer">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="6">
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search.clientId" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
|
||||
<div class="input-group-addon">
|
||||
<i class="fa fa-search" type="submit"></i>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="6">
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search.clientId" class="form-control search" onkeyup="if(event.keyCode === 13){$(this).next('I').click();}">
|
||||
<div class="input-group-addon">
|
||||
<i class="fa fa-search" type="submit"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" data-ng-show="access.manageClients">
|
||||
<a id="createClient" class="btn btn-default" href="#/create/client/{{realm.realm}}">{{:: 'create' | translate}}</a>
|
||||
<a id="importClient" class="btn btn-default" href="#/import/client/{{realm.realm}}" data-ng-show="importButton">{{:: 'import' | translate}}</a>
|
||||
<div class="pull-right" data-ng-show="access.manageClients">
|
||||
<a id="createClient" class="btn btn-default" href="#/create/client/{{realm.realm}}">{{:: 'create' | translate}}</a>
|
||||
<a id="importClient" class="btn btn-default" href="#/import/client/{{realm.realm}}" data-ng-show="importButton">{{:: 'import' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-hide="clients.length == 0">
|
||||
<th>{{:: 'client-id' | translate}}</th>
|
||||
<th>{{:: 'enabled' | translate}}</th>
|
||||
<th>{{:: 'base-url' | translate}}</th>
|
||||
<th colspan="3">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot data-ng-hide="(clients | filter:search).length == 0">
|
||||
<tr>
|
||||
<td class="kc-action-cell" colspan="6">
|
||||
<div kc-paging current-page='currentPage' number-of-pages='numberOfPages'></div>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tr data-ng-hide="clients.length == 0">
|
||||
<th>{{:: 'client-id' | translate}}</th>
|
||||
<th>{{:: 'enabled' | translate}}</th>
|
||||
<th>{{:: 'base-url' | translate}}</th>
|
||||
<th colspan="3">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="client in clients | filter:search | orderBy:'clientId' | startFrom:(currentPage-1)*pageSize | limitTo:pageSize">
|
||||
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></td>
|
||||
<td translate="{{client.enabled}}"></td>
|
||||
<td ng-class="{'text-muted': !client.baseUrl}">
|
||||
<a href="{{client.rootUrl}}{{client.baseUrl}}" target="_blank" data-ng-show="client.baseUrl">{{client.rootUrl}}{{client.baseUrl}}</a>
|
||||
<span data-ng-hide="client.baseUrl">{{:: 'not-defined' | translate}}</span>
|
||||
</td>
|
||||
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="exportClient(client)">{{:: 'export' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-show="access.manageClients" data-ng-click="removeClient(client)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="(clients | filter:search).length == 0">
|
||||
<td class="text-muted" colspan="4" data-ng-show="search.clientId">{{:: 'no-results' | translate}}</td>
|
||||
<td class="text-muted" colspan="4" data-ng-hide="search.clientId">{{:: 'no-clients-available' | translate}}</td>
|
||||
</tr>
|
||||
<tr ng-repeat="client in clients| filter:search | orderBy:'clientId' | startFrom:(currentPage - 1) * pageSize | limitTo:pageSize">
|
||||
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></td>
|
||||
<td translate="{{client.enabled}}"></td>
|
||||
<td ng-class="{'text-muted': !client.baseUrl}">
|
||||
<a href="{{client.rootUrl}}{{client.baseUrl}}" target="_blank" data-ng-show="client.baseUrl">{{client.rootUrl}}{{client.baseUrl}}</a>
|
||||
<span data-ng-hide="client.baseUrl">{{:: 'not-defined' | translate}}</span>
|
||||
</td>
|
||||
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/clients/{{client.id}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="exportClient(client)">{{:: 'export' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-show="access.manageClients" data-ng-click="removeClient(client)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="(clients | filter:search).length == 0">
|
||||
<td class="text-muted" colspan="4" data-ng-show="search.clientId">{{:: 'no-results' | translate}}</td>
|
||||
<td class="text-muted" colspan="4" data-ng-hide="search.clientId">{{:: 'no-clients-available' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<kc-paging current-page='currentPage' number-of-pages='numberOfPages' current-page-input='currentPageInput'></kc-paging>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -6,54 +6,48 @@
|
|||
<li><a href="#/realms/{{realm.realm}}/default-roles">{{:: 'default-roles' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<table class="table table-striped table-bordered">
|
||||
<table class="datatable table table-striped table-bordered dataTable no-footer">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="5">
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="searchQuery" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
|
||||
<div class="input-group-addon">
|
||||
<i class="fa fa-search" type="submit"></i>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="5">
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="searchQuery" class="form-control search" onkeyup="if (event.keyCode === 13){$(this).next('I').click(); }">
|
||||
<div class="input-group-addon">
|
||||
<i class="fa fa-search" type="submit"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" data-ng-show="access.manageRealm">
|
||||
<a id="createRole" class="btn btn-default" href="#/create/role/{{realm.realm}}">{{:: 'add-role' | translate}}</a>
|
||||
<div class="pull-right" data-ng-show="access.manageRealm">
|
||||
<a id="createRole" class="btn btn-default" href="#/create/role/{{realm.realm}}">{{:: 'add-role' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="roles && roles.length > 0">
|
||||
<th>{{:: 'role-name' | translate}}</th>
|
||||
<th>{{:: 'composite' | translate}}</th>
|
||||
<th>{{:: 'description' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot data-ng-hide="(roles | filter:{name: searchQuery}).length == 0">
|
||||
<tr>
|
||||
<td class="kc-action-cell" colspan="6">
|
||||
<div kc-paging current-page='currentPage' number-of-pages='numberOfPages'></div>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tr data-ng-show="roles && roles.length > 0">
|
||||
<th>{{:: 'role-name' | translate}}</th>
|
||||
<th>{{:: 'composite' | translate}}</th>
|
||||
<th>{{:: 'description' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="role in roles | filter:{name: searchQuery} | orderBy:'name'| startFrom:(currentPage-1)*pageSize | limitTo:pageSize">
|
||||
<td><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{role.name}}</a></td>
|
||||
<td translate="{{role.composite}}"></td>
|
||||
<td>{{role.description}}</td>
|
||||
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/roles/{{role.id}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="removeRole(role)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="(roles | filter:{name: searchQuery}).length == 0">
|
||||
<td class="text-muted" colspan="4" data-ng-show="searchQuery">{{:: 'no-results' | translate}}</td>
|
||||
<td class="text-muted" colspan="4" data-ng-hide="searchQuery">{{:: 'no-realm-roles-available' | translate}}</td>
|
||||
</tr>
|
||||
<tr ng-repeat="role in roles| filter:{name: searchQuery} | orderBy:'name'| startFrom:(currentPage - 1) * pageSize | limitTo:pageSize">
|
||||
<td><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{role.name}}</a></td>
|
||||
<td translate="{{role.composite}}"></td>
|
||||
<td>{{role.description}}</td>
|
||||
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/roles/{{role.id}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="removeRole(role)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr data-ng-show="(roles | filter:{name: searchQuery}).length == 0">
|
||||
<td class="text-muted" colspan="4" data-ng-show="searchQuery">{{:: 'no-results' | translate}}</td>
|
||||
<td class="text-muted" colspan="4" data-ng-hide="searchQuery">{{:: 'no-realm-roles-available' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<kc-paging current-page='currentPage' number-of-pages='numberOfPages' current-page-input='currentPageInput'></kc-paging>
|
||||
</div>
|
||||
|
||||
<kc-menu></kc-menu>
|
|
@ -1,19 +1,25 @@
|
|||
<div class="pull-right">
|
||||
<ul class="pagination">
|
||||
<li ng-class="{disabled: currentPage === 1}" ng-click="currentPage=1">
|
||||
<span class="i fa fa-angle-double-left"></span>
|
||||
</li>
|
||||
<li ng-class="{disabled: currentPage === 1}" ng-click="isFirstPage() || (currentPage=currentPage-1)">
|
||||
<span class="i fa fa-angle-left"></span>
|
||||
</li>
|
||||
<li>
|
||||
<span style="padding: 1px 15px 0;"><input ng-model="currentPage" ng-max="numberOfPages" class="kc-pagination"> of {{numberOfPages}}</span>
|
||||
</li>
|
||||
<li ng-class="{disabled: currentPage === numberOfPages}" ng-click="isLastPage() || (currentPage=currentPage+1)">
|
||||
<span class="i fa fa-angle-right" ></span>
|
||||
</li>
|
||||
<li ng-class="{disabled: currentPage === numberOfPages}" ng-click="currentPage=numberOfPages">
|
||||
<span class="i fa fa-angle-double-right"></span>
|
||||
<div ng-hide="numberOfPages < 2" class="dataTables_footer">
|
||||
<div class="dataTables_paginate paging_bootstrap_input">
|
||||
<ul class="pagination">
|
||||
<li class="first" ng-class="{disabled: !hasPrevious()}" ng-click="firstPage()">
|
||||
<span class="i fa fa-angle-double-left"></span>
|
||||
</li>
|
||||
<li class="prev" ng-class="{disabled: !hasPrevious()}" ng-click="previousPage()">
|
||||
<span class="i fa fa-angle-left"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pagination-input">
|
||||
<input ng-model="currentPageInput" kc-valid-page class="paginate_input" type="text">
|
||||
<span class="paginate_of">of <b>{{numberOfPages}}</b></span>
|
||||
</div>
|
||||
<ul class="pagination">
|
||||
<li class="next" ng-class="{disabled: !hasNext()}" ng-click="nextPage()">
|
||||
<span class="i fa fa-angle-right"></span>
|
||||
</li>
|
||||
<li class="last" ng-class="{disabled: !hasNext()}" ng-click="lastPage()">
|
||||
<span class="i fa fa-angle-double-right">
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
|
@ -379,14 +379,4 @@ h1 i {
|
|||
.ace_editor {
|
||||
height: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.kc-pagination {
|
||||
border: 1px solid #d1d1d1;
|
||||
font-size: 12px;
|
||||
height: 23px;
|
||||
margin-right: 10px;
|
||||
padding-right: 10px;
|
||||
text-align: right;
|
||||
width: 30px;
|
||||
}
|
Loading…
Reference in a new issue