[KEYCLOAK-4125] - Fixing when running in a cluster

This commit is contained in:
Pedro Igor 2016-12-21 20:04:08 -02:00
parent 3e8d4e4eb6
commit df7a68b709
9 changed files with 98 additions and 135 deletions

View file

@ -21,6 +21,7 @@ package org.keycloak.models.authorization.infinispan;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -51,7 +52,7 @@ public class CachedPolicyStore implements PolicyStore {
private static final String POLICY_ID_CACHE_PREFIX = "policy-id-";
private final Cache<String, List<CachedPolicy>> cache;
private final Cache<String, Map<String, List<CachedPolicy>>> cache;
private final KeycloakSession session;
private final CacheTransaction transaction;
private final List<String> cacheKeys;
@ -78,7 +79,7 @@ public class CachedPolicyStore implements PolicyStore {
String id = policy.getId();
this.transaction.whenRollback(() -> {
cache.remove(getCacheKeyForPolicy(id));
resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForPolicy(id));
});
this.transaction.whenCommit(() -> {
@ -90,14 +91,13 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public void delete(String id) {
Policy policy = findById(id, null);
Policy policy = getDelegate().findById(id, null);
if (policy == null) {
return;
}
ResourceServer resourceServer = policy.getResourceServer();
getDelegate().delete(id);
this.transaction.whenCommit(() -> {
cache.remove(getCacheKeyForPolicy(id));
invalidateCache(resourceServer.getId());
});
}
@ -105,13 +105,15 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public Policy findById(String id, String resourceServerId) {
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
List<CachedPolicy> cached = this.cache.get(cacheKeyForPolicy);
List<CachedPolicy> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForPolicy);
if (cached == null) {
Policy policy = getDelegate().findById(id, resourceServerId);
if (policy != null) {
return createAdapter(updatePolicyCache(policy));
CachedPolicy cachedPolicy = new CachedPolicy(policy);
resolveResourceServerCache(resourceServerId).put(cacheKeyForPolicy, Arrays.asList(cachedPolicy));
return createAdapter(cachedPolicy);
}
return null;
@ -137,12 +139,12 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public List<Policy> findByResource(String resourceId, String resourceServerId) {
return cacheResult(new StringBuilder("findByResource").append(resourceServerId).append(resourceId).toString(), () -> getDelegate().findByResource(resourceId, resourceServerId));
return cacheResult(resourceServerId, new StringBuilder("findByResource").append(resourceId).toString(), () -> getDelegate().findByResource(resourceId, resourceServerId));
}
@Override
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
return cacheResult(new StringBuilder("findByResourceType").append(resourceServerId).append(resourceType).toString(), () -> getDelegate().findByResourceType(resourceType, resourceServerId));
return cacheResult(resourceServerId, new StringBuilder("findByResourceType").append(resourceType).toString(), () -> getDelegate().findByResourceType(resourceType, resourceServerId));
}
@Override
@ -150,7 +152,7 @@ public class CachedPolicyStore implements PolicyStore {
List<Policy> policies = new ArrayList<>();
for (String scopeId : scopeIds) {
policies.addAll(cacheResult(new StringBuilder("findByScopeIds").append(resourceServerId).append(scopeId).toString(), () -> getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId)));
policies.addAll(cacheResult(resourceServerId, new StringBuilder("findByScopeIds").append(scopeId).toString(), () -> getDelegate().findByScopeIds(Arrays.asList(scopeId), resourceServerId)));
}
return policies;
@ -158,7 +160,7 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public List<Policy> findByType(String type, String resourceServerId) {
return cacheResult(new StringBuilder("findByType").append(resourceServerId).append(type).toString(), () -> getDelegate().findByType(type, resourceServerId));
return cacheResult(resourceServerId, new StringBuilder("findByType").append(type).toString(), () -> getDelegate().findByType(type, resourceServerId));
}
@Override
@ -388,11 +390,10 @@ public class CachedPolicyStore implements PolicyStore {
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
transaction.whenCommit(() -> {
cache.remove(getCacheKeyForPolicy(getId()));
invalidateCache(cached.getResourceServerId());
});
transaction.whenRollback(() -> {
cache.remove(getCacheKeyForPolicy(getId()));
resolveResourceServerCache(cached.getResourceServerId()).remove(getCacheKeyForPolicy(getId()));
});
}
@ -408,23 +409,12 @@ public class CachedPolicyStore implements PolicyStore {
return cachedStoreFactory;
}
private CachedPolicy updatePolicyCache(Policy policy) {
CachedPolicy cached = new CachedPolicy(policy);
List<CachedPolicy> cache = new ArrayList<>();
cache.add(cached);
this.cache.put(getCacheKeyForPolicy(policy.getId()), cache);
return cached;
}
private void invalidateCache(String resourceServerId) {
cacheKeys.forEach(cacheKey -> cache.keySet().stream().filter(key -> key.startsWith(cacheKey + resourceServerId)).forEach(cache::remove));
cache.remove(resourceServerId);
}
private List<Policy> cacheResult(String key, Supplier<List<Policy>> provider) {
List<CachedPolicy> cached = cache.computeIfAbsent(key, (Function<String, List<CachedPolicy>>) o -> {
private List<Policy> cacheResult(String resourceServerId, String key, Supplier<List<Policy>> provider) {
List<CachedPolicy> cached = resolveResourceServerCache(resourceServerId).computeIfAbsent(key, (Function<String, List<CachedPolicy>>) o -> {
List<Policy> result = provider.get();
if (result.isEmpty()) {
@ -440,4 +430,8 @@ public class CachedPolicyStore implements PolicyStore {
return cached.stream().map(cachedPolicy -> createAdapter(cachedPolicy)).collect(Collectors.toList());
}
private Map<String, List<CachedPolicy>> resolveResourceServerCache(String id) {
return cache.computeIfAbsent(id, key -> new HashMap<>());
}
}

View file

@ -18,9 +18,10 @@
package org.keycloak.models.authorization.infinispan;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.infinispan.Cache;
import org.keycloak.authorization.model.ResourceServer;
@ -44,7 +45,7 @@ public class CachedResourceServerStore implements ResourceServerStore {
private final CacheTransaction transaction;
private StoreFactory storeFactory;
private ResourceServerStore delegate;
private final Cache<String, List> cache;
private final Cache<String, Map<String, List<CachedResourceServer>>> cache;
public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
this.session = session;
@ -58,34 +59,33 @@ public class CachedResourceServerStore implements ResourceServerStore {
public ResourceServer create(String clientId) {
ResourceServer resourceServer = getDelegate().create(clientId);
this.transaction.whenRollback(() -> cache.remove(getCacheKeyForResourceServer(resourceServer.getId())));
this.transaction.whenRollback(() -> resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForResourceServer(resourceServer.getId())));
return createAdapter(new CachedResourceServer(resourceServer));
}
@Override
public void delete(String id) {
ResourceServer resourceServer = getDelegate().findById(id);
getDelegate().delete(id);
this.transaction.whenCommit(() -> {
List<CachedResourceServer> servers = cache.remove(getCacheKeyForResourceServer(id));
if (servers != null) {
CachedResourceServer entry = servers.get(0);
cache.remove(getCacheKeyForResourceServerClientId(entry.getClientId()));
}
cache.remove(id);
cache.remove(resourceServer.getClientId());
});
}
@Override
public ResourceServer findById(String id) {
String cacheKeyForResourceServer = getCacheKeyForResourceServer(id);
List<ResourceServer> cached = this.cache.get(cacheKeyForResourceServer);
List<CachedResourceServer> cached = resolveResourceServerCache(id).get(cacheKeyForResourceServer);
if (cached == null) {
ResourceServer resourceServer = getDelegate().findById(id);
if (resourceServer != null) {
return createAdapter(updateResourceServerCache(resourceServer));
CachedResourceServer cachedResourceServer = new CachedResourceServer(resourceServer);
resolveResourceServerCache(id).put(cacheKeyForResourceServer, Arrays.asList(cachedResourceServer));
return createAdapter(cachedResourceServer);
}
return null;
@ -97,20 +97,20 @@ public class CachedResourceServerStore implements ResourceServerStore {
@Override
public ResourceServer findByClient(String id) {
String cacheKeyForResourceServer = getCacheKeyForResourceServerClientId(id);
List<String> cached = this.cache.get(cacheKeyForResourceServer);
List<CachedResourceServer> cached = resolveResourceServerCache(id).get(cacheKeyForResourceServer);
if (cached == null) {
ResourceServer resourceServer = getDelegate().findByClient(id);
if (resourceServer != null) {
cache.put(cacheKeyForResourceServer, Arrays.asList(resourceServer.getId()));
resolveResourceServerCache(cacheKeyForResourceServer).put(cacheKeyForResourceServer, Arrays.asList(new CachedResourceServer(resourceServer)));
return findById(resourceServer.getId());
}
return null;
}
return findById(cached.get(0));
return createAdapter(cached.get(0));
}
private String getCacheKeyForResourceServer(String id) {
@ -173,7 +173,10 @@ public class CachedResourceServerStore implements ResourceServerStore {
if (this.updated == null) {
this.updated = getDelegate().findById(getId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
transaction.whenCommit(() -> cache.remove(getCacheKeyForResourceServer(getId())));
transaction.whenCommit(() -> {
cache.remove(getId());
cache.remove(getClientId());
});
}
return this.updated;
@ -181,14 +184,7 @@ public class CachedResourceServerStore implements ResourceServerStore {
};
}
private CachedResourceServer updateResourceServerCache(ResourceServer resourceServer) {
CachedResourceServer cached = new CachedResourceServer(resourceServer);
List<ResourceServer> cache = new ArrayList<>();
cache.add(cached);
this.cache.put(getCacheKeyForResourceServer(resourceServer.getId()), cache);
return cached;
private Map<String, List<CachedResourceServer>> resolveResourceServerCache(String id) {
return cache.computeIfAbsent(id, key -> new HashMap<>());
}
}

View file

@ -21,6 +21,7 @@ package org.keycloak.models.authorization.infinispan;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -53,7 +54,7 @@ public class CachedResourceStore implements ResourceStore {
private final List<String> cacheKeys;
private StoreFactory storeFactory;
private ResourceStore delegate;
private final Cache<String, List<CachedResource>> cache;
private final Cache<String, Map<String, List<CachedResource>>> cache;
public CachedResourceStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
this.session = session;
@ -63,6 +64,7 @@ public class CachedResourceStore implements ResourceStore {
cacheKeys = new ArrayList<>();
cacheKeys.add("findByOwner");
cacheKeys.add("findByUri");
cacheKeys.add("findByName");
this.storeFactory = storeFactory;
}
@ -71,12 +73,11 @@ public class CachedResourceStore implements ResourceStore {
Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
this.transaction.whenRollback(() -> {
cache.remove(getCacheKeyForResource(resource.getId()));
resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForResource(resource.getId()));
});
this.transaction.whenCommit(() -> {
invalidateCache(resourceServer.getId());
getCachedStoreFactory().getPolicyStore().notifyChange(resource);
});
return createAdapter(new CachedResource(resource));
@ -84,35 +85,29 @@ public class CachedResourceStore implements ResourceStore {
@Override
public void delete(String id) {
Resource resource = findById(id, null);
Resource resource = getDelegate().findById(id, null);
if (resource == null) {
return;
}
ResourceServer resourceServer = resource.getResourceServer();
getDelegate().delete(id);
this.transaction.whenCommit(() -> {
List<CachedResource> resources = cache.remove(getCacheKeyForResource(id));
if (resources != null) {
CachedResource entry = resources.get(0);
cache.remove(getCacheKeyForResourceName(entry.getName(), entry.getResourceServerId()));
}
invalidateCache(resourceServer.getId());
getCachedStoreFactory().getPolicyStore().notifyChange(resource);
});
}
@Override
public Resource findById(String id, String resourceServerId) {
String cacheKeyForResource = getCacheKeyForResource(id);
List<CachedResource> cached = this.cache.get(cacheKeyForResource);
List<CachedResource> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForResource);
if (cached == null) {
Resource resource = getDelegate().findById(id, resourceServerId);
if (resource != null) {
return createAdapter(updateResourceCache(resource));
CachedResource cachedResource = new CachedResource(resource);
resolveResourceServerCache(resourceServerId).put(cacheKeyForResource, Arrays.asList(cachedResource));
return createAdapter(cachedResource);
}
return null;
@ -123,12 +118,12 @@ public class CachedResourceStore implements ResourceStore {
@Override
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
return cacheResult(new StringBuilder("findByOwner").append(resourceServerId).append(ownerId).toString(), () -> getDelegate().findByOwner(ownerId, resourceServerId));
return cacheResult(resourceServerId, new StringBuilder("findByOwner").append(ownerId).toString(), () -> getDelegate().findByOwner(ownerId, resourceServerId));
}
@Override
public List<Resource> findByUri(String uri, String resourceServerId) {
return cacheResult(new StringBuilder("findByUri").append(resourceServerId).append(uri).toString(), () -> getDelegate().findByUri(uri, resourceServerId));
return cacheResult(resourceServerId, new StringBuilder("findByUri").append(uri).toString(), () -> getDelegate().findByUri(uri, resourceServerId));
}
@Override
@ -149,13 +144,14 @@ public class CachedResourceStore implements ResourceStore {
@Override
public Resource findByName(String name, String resourceServerId) {
String cacheKeyForResource = getCacheKeyForResourceName(name, resourceServerId);
List<CachedResource> cached = this.cache.get(cacheKeyForResource);
List<CachedResource> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForResource);
if (cached == null) {
Resource resource = getDelegate().findByName(name, resourceServerId);
if (resource != null) {
cache.put(cacheKeyForResource, Arrays.asList(new CachedResource(resource)));
invalidateCache(resourceServerId);
resolveResourceServerCache(resourceServerId).put(cacheKeyForResource, Arrays.asList(new CachedResource(resource)));
return findById(resource.getId(), resourceServerId);
}
@ -280,15 +276,14 @@ public class CachedResourceStore implements ResourceStore {
private Resource getDelegateForUpdate() {
if (this.updated == null) {
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
String resourceServerId = cached.getResourceServerId();
this.updated = getDelegate().findById(getId(), resourceServerId);
if (this.updated == null) throw new IllegalStateException("Not found in database");
transaction.whenCommit(() -> {
cache.remove(getCacheKeyForResource(cached.getId()));
invalidateCache(cached.getResourceServerId());
getCachedStoreFactory().getPolicyStore().notifyChange(updated);
invalidateCache(resourceServerId);
});
transaction.whenRollback(() -> {
cache.remove(getCacheKeyForResource(cached.getId()));
resolveResourceServerCache(resourceServerId).remove(getCacheKeyForResource(cached.getId()));
});
}
@ -301,19 +296,8 @@ public class CachedResourceStore implements ResourceStore {
return session.getProvider(CachedStoreFactoryProvider.class);
}
private CachedResource updateResourceCache(Resource resource) {
CachedResource cached = new CachedResource(resource);
List cache = new ArrayList<>();
cache.add(cached);
this.cache.put(getCacheKeyForResource(resource.getId()), cache);
return cached;
}
private List<Resource> cacheResult(String key, Supplier<List<Resource>> provider) {
List<CachedResource> cached = cache.computeIfAbsent(key, (Function<String, List<CachedResource>>) o -> {
private List<Resource> cacheResult(String resourceServerId, String key, Supplier<List<Resource>> provider) {
List<CachedResource> cached = resolveResourceServerCache(resourceServerId).computeIfAbsent(key, (Function<String, List<CachedResource>>) o -> {
List<Resource> result = provider.get();
if (result.isEmpty()) {
@ -327,10 +311,20 @@ public class CachedResourceStore implements ResourceStore {
return Collections.emptyList();
}
return cached.stream().map(this::createAdapter).collect(Collectors.toList());
List<Resource> adapters = new ArrayList<>();
for (CachedResource resource : cached) {
adapters.add(createAdapter(resource));
}
return adapters;
}
private void invalidateCache(String resourceServerId) {
cacheKeys.forEach(cacheKey -> cache.keySet().stream().filter(key -> key.startsWith(cacheKey + resourceServerId)).forEach(cache::remove));
cache.remove(resourceServerId);
}
private Map<String, List<CachedResource>> resolveResourceServerCache(String id) {
return cache.computeIfAbsent(id, key -> new HashMap<>());
}
}

View file

@ -18,13 +18,12 @@
package org.keycloak.models.authorization.infinispan;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.infinispan.Cache;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.model.Scope;
import org.keycloak.authorization.store.ScopeStore;
@ -43,7 +42,7 @@ public class CachedScopeStore implements ScopeStore {
private static final String SCOPE_ID_CACHE_PREFIX = "scp-id-";
private static final String SCOPE_NAME_CACHE_PREFIX = "scp-name-";
private final Cache<String, List> cache;
private final Cache<String, Map<String, List<CachedScope>>> cache;
private final KeycloakSession session;
private final CacheTransaction transaction;
private ScopeStore delegate;
@ -61,9 +60,9 @@ public class CachedScopeStore implements ScopeStore {
public Scope create(String name, ResourceServer resourceServer) {
Scope scope = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
this.transaction.whenRollback(() -> cache.remove(getCacheKeyForScope(scope.getId())));
this.transaction.whenRollback(() -> resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForScope(scope.getId())));
this.transaction.whenCommit(() -> {
getCachedStoreFactory().getPolicyStore().notifyChange(scope);
invalidateCache(resourceServer.getId());
});
return createAdapter(new CachedScope(scope));
@ -71,33 +70,29 @@ public class CachedScopeStore implements ScopeStore {
@Override
public void delete(String id) {
Scope scope = findById(id, null);
Scope scope = getDelegate().findById(id, null);
if (scope == null) {
return;
}
ResourceServer resourceServer = scope.getResourceServer();
getDelegate().delete(id);
this.transaction.whenCommit(() -> {
List<CachedScope> scopes = cache.remove(getCacheKeyForScope(id));
if (scopes != null) {
CachedScope entry = scopes.get(0);
cache.remove(getCacheKeyForScopeName(entry.getName(), entry.getResourceServerId()));
}
getCachedStoreFactory().getPolicyStore().notifyChange(scope);
invalidateCache(resourceServer.getId());
});
}
@Override
public Scope findById(String id, String resourceServerId) {
String cacheKeyForScope = getCacheKeyForScope(id);
List<CachedScope> cached = this.cache.get(cacheKeyForScope);
List<CachedScope> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForScope);
if (cached == null) {
Scope scope = getDelegate().findById(id, resourceServerId);
if (scope != null) {
return createAdapter(updateScopeCache(scope));
CachedScope cachedScope = new CachedScope(scope);
resolveResourceServerCache(resourceServerId).put(cacheKeyForScope, Arrays.asList(cachedScope));
return createAdapter(cachedScope);
}
return null;
@ -108,21 +103,21 @@ public class CachedScopeStore implements ScopeStore {
@Override
public Scope findByName(String name, String resourceServerId) {
String cacheKeyForScope = getCacheKeyForScopeName(name, resourceServerId);
List<String> cached = this.cache.get(cacheKeyForScope);
String cacheKeyForScope = getCacheKeyForScopeName(name);
List<CachedScope> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForScope);
if (cached == null) {
Scope scope = getDelegate().findByName(name, resourceServerId);
if (scope != null) {
cache.put(cacheKeyForScope, Arrays.asList(scope.getId()));
resolveResourceServerCache(resourceServerId).put(cacheKeyForScope, Arrays.asList(new CachedScope(scope)));
return findById(scope.getId(), resourceServerId);
}
return null;
}
return findById(cached.get(0), resourceServerId);
return createAdapter(cached.get(0));
}
@Override
@ -139,8 +134,8 @@ public class CachedScopeStore implements ScopeStore {
return SCOPE_ID_CACHE_PREFIX + id;
}
private String getCacheKeyForScopeName(String name, String resourceServerId) {
return SCOPE_NAME_CACHE_PREFIX + name + "-" + resourceServerId;
private String getCacheKeyForScopeName(String name) {
return SCOPE_NAME_CACHE_PREFIX + name;
}
private ScopeStore getDelegate() {
@ -197,11 +192,11 @@ public class CachedScopeStore implements ScopeStore {
this.updated = getDelegate().findById(getId(), cached.getResourceServerId());
if (this.updated == null) throw new IllegalStateException("Not found in database");
transaction.whenCommit(() -> {
cache.remove(getCacheKeyForScope(getId()));
getCachedStoreFactory().getPolicyStore().notifyChange(updated);
invalidateCache(cached.getResourceServerId());
});
transaction.whenRollback(() -> {
cache.remove(getCacheKeyForScope(cached.getId()));
resolveResourceServerCache(cached.getResourceServerId()).remove(getCacheKeyForScope(cached.getId()));
resolveResourceServerCache(cached.getResourceServerId()).remove(getCacheKeyForScopeName(cached.getName()));
});
}
@ -214,15 +209,11 @@ public class CachedScopeStore implements ScopeStore {
return session.getProvider(CachedStoreFactoryProvider.class);
}
private CachedScope updateScopeCache(Scope scope) {
CachedScope cached = new CachedScope(scope);
private void invalidateCache(String resourceServerId) {
cache.remove(resourceServerId);
}
List cache = new ArrayList();
cache.add(cached);
this.transaction.whenCommit(() -> this.cache.put(getCacheKeyForScope(scope.getId()), cache));
return cached;
private Map<String, List<CachedScope>> resolveResourceServerCache(String id) {
return cache.computeIfAbsent(id, key -> new HashMap<>());
}
}

View file

@ -56,6 +56,6 @@ public class InfinispanStoreProviderFactory implements CachedStoreProviderFactor
@Override
public boolean isSupported() {
return false;
return true;
}
}

View file

@ -58,9 +58,6 @@
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
<button data-ng-click="nextPage()" class="next" ng-disabled="policies.length < query.max">{{:: 'next-page' | translate}}</button>
<select class="first" data-ng-model="query.max"
ng-options="size for size in listSizes" data-ng-change="firstPage()">
</select>
</div>
</td>
</tr>

View file

@ -60,9 +60,6 @@
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
<button data-ng-click="nextPage()" class="next" ng-disabled="policies.length < query.max">{{:: 'next-page' | translate}}</button>
<select class="first" data-ng-model="query.max"
ng-options="size for size in listSizes" data-ng-change="firstPage()">
</select>
</div>
</td>
</tr>

View file

@ -67,9 +67,6 @@
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
<button data-ng-click="nextPage()" class="next" ng-disabled="resources.length < query.max">{{:: 'next-page' | translate}}</button>
<select class="first" data-ng-model="query.max"
ng-options="size for size in listSizes" data-ng-change="firstPage()">
</select>
</div>
</td>
</tr>

View file

@ -39,9 +39,6 @@
<button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0">{{:: 'first-page' | translate}}</button>
<button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0">{{:: 'previous-page' | translate}}</button>
<button data-ng-click="nextPage()" class="next" ng-disabled="scopes.length < query.max">{{:: 'next-page' | translate}}</button>
<select class="first" data-ng-model="query.max"
ng-options="size for size in listSizes" data-ng-change="firstPage()">
</select>
</div>
</td>
</tr>