[KEYCLOAK-7082] - Making lists more aligned with patternfly listview component

This commit is contained in:
Pedro Igor 2018-05-21 10:54:13 -03:00
parent 08c22416a2
commit f800290d89
12 changed files with 353 additions and 325 deletions

View file

@ -65,11 +65,11 @@ public class PermissionsTable extends DataTable {
public PolicyRepresentation toRepresentation(WebElement row) {
PolicyRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (!(tds.isEmpty() || tds.get(1).getText().isEmpty())) {
representation = new PolicyRepresentation();
representation.setName(tds.get(0).getText());
representation.setDescription(tds.get(1).getText());
representation.setType(tds.get(2).getText());
representation.setName(tds.get(1).getText());
representation.setDescription(tds.get(2).getText());
representation.setType(tds.get(3).getText());
}
return representation;
}

View file

@ -65,11 +65,11 @@ public class PoliciesTable extends DataTable {
public PolicyRepresentation toRepresentation(WebElement row) {
PolicyRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (!(tds.isEmpty() || tds.get(1).getText().isEmpty())) {
representation = new PolicyRepresentation();
representation.setName(tds.get(0).getText());
representation.setDescription(tds.get(1).getText());
representation.setType(tds.get(2).getText());
representation.setName(tds.get(1).getText());
representation.setDescription(tds.get(2).getText());
representation.setType(tds.get(3).getText());
}
return representation;
}

View file

@ -21,6 +21,7 @@ import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.testsuite.console.page.fragment.ModalDialog;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@ -81,7 +82,12 @@ public class Resources extends Form {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("td")).get(6).click();
WebElement td = row.findElements(tagName("td")).get(5);
td.findElement(By.className("dropdown-toggle")).click();
WebElement actions = td.findElement(By.className("dropdown-menu"));
actions.findElement(By.linkText("Delete")).click();
modalDialog.confirmDeletion();
return;
}

View file

@ -67,13 +67,13 @@ public class ResourcesTable extends DataTable {
ResourceRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
try {
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (!(tds.isEmpty() || tds.get(1).getText().isEmpty())) {
representation = new ResourceRepresentation();
representation.setName(tds.get(0).getText());
representation.setType(tds.get(1).getText());
representation.setUri(tds.get(2).getText());
representation.setName(tds.get(1).getText());
representation.setType(tds.get(2).getText());
representation.setUri(tds.get(3).getText());
ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation();
owner.setName(tds.get(3).getText());
owner.setName(tds.get(4).getText());
representation.setOwner(owner);
}
} catch (IndexOutOfBoundsException cause) {

View file

@ -20,11 +20,11 @@ import static org.keycloak.testsuite.util.UIUtils.clickLink;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.console.page.fragment.ModalDialog;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@ -78,7 +78,12 @@ public class Scopes extends Form {
for (WebElement row : scopes().rows()) {
ScopeRepresentation actual = scopes().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("td")).get(3).click();
WebElement td = row.findElements(tagName("td")).get(2);
td.findElement(By.className("dropdown-toggle")).click();
WebElement actions = td.findElement(By.className("dropdown-menu"));
actions.findElement(By.linkText("Delete")).click();
modalDialog.confirmDeletion();
}
}

View file

@ -65,9 +65,9 @@ public class ScopesTable extends DataTable {
public ScopeRepresentation toRepresentation(WebElement row) {
ScopeRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
if (!(tds.isEmpty() || tds.get(1).getText().isEmpty())) {
representation = new ScopeRepresentation();
representation.setName(tds.get(0).getText());
representation.setName(tds.get(1).getText());
}
return representation;
}

View file

@ -144,7 +144,7 @@ var Policies = {
}
}
module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client, AuthzDialog, Notifications) {
module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client, AuthzDialog, Notifications, viewState) {
$scope.realm = realm;
$scope.client = client;
@ -165,6 +165,8 @@ module.controller('ResourceServerResourceCtrl', function($scope, $http, $route,
$scope.server = data;
$scope.createPolicy = function(resource) {
viewState.state = {};
viewState.state.previousUrl = '/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/resource';
$location.path('/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/permission/resource/create').search({rsrid: resource._id});
}
@ -438,7 +440,7 @@ var Scopes = {
}
}
module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope,client, AuthzDialog, Notifications) {
module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope,client, AuthzDialog, Notifications, viewState) {
$scope.realm = realm;
$scope.client = client;
@ -459,6 +461,8 @@ module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $lo
$scope.server = data;
$scope.createPolicy = function(scope) {
viewState.state = {};
viewState.state.previousUrl = '/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/scope';
$location.path('/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/permission/scope/create').search({scpid: scope.id});
}
@ -894,7 +898,7 @@ module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http
}, realm, client, $scope);
});
module.controller('ResourceServerPolicyResourceDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPermission, ResourceServerResource, policyState) {
module.controller('ResourceServerPolicyResourceDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPermission, ResourceServerResource, policyViewState) {
PolicyController.onInit({
getPolicyType : function() {
return "resource";
@ -1032,7 +1036,7 @@ module.controller('ResourceServerPolicyResourceDetailCtrl', function($scope, $ro
},
onInitCreate : function(newPolicy) {
policyState.state.previousPage.name = 'authz-add-resource-permission';
policyViewState.state.previousPage.name = 'authz-add-resource-permission';
$scope.selectedResource = null;
var copy = angular.copy($scope.selectedResource);
$scope.$watch('selectedResource', function() {
@ -1084,19 +1088,19 @@ module.controller('ResourceServerPolicyResourceDetailCtrl', function($scope, $ro
},
onSaveState : function(policy) {
policyState.state.selectedResource = $scope.selectedResource;
policyState.state.applyToResourceTypeFlag = $scope.applyToResourceTypeFlag;
policyViewState.state.selectedResource = $scope.selectedResource;
policyViewState.state.applyToResourceTypeFlag = $scope.applyToResourceTypeFlag;
},
onRestoreState : function(policy) {
$scope.selectedResource = policyState.state.selectedResource;
$scope.applyToResourceTypeFlag = policyState.state.applyToResourceTypeFlag;
policy.resourceType = policyState.state.policy.resourceType;
$scope.selectedResource = policyViewState.state.selectedResource;
$scope.applyToResourceTypeFlag = policyViewState.state.applyToResourceTypeFlag;
policy.resourceType = policyViewState.state.policy.resourceType;
}
}, realm, client, $scope);
});
module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPolicy, ResourceServerResource, ResourceServerScope, policyState) {
module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPolicy, ResourceServerResource, ResourceServerScope, policyViewState) {
PolicyController.onInit({
getPolicyType : function() {
return "scope";
@ -1343,7 +1347,7 @@ module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route
},
onInitCreate : function(newPolicy) {
policyState.state.previousPage.name = 'authz-add-scope-permission';
policyViewState.state.previousPage.name = 'authz-add-scope-permission';
var scopeId = $location.search()['scpid'];
if (scopeId) {
@ -1391,15 +1395,15 @@ module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route
},
onSaveState : function(policy) {
policyState.state.selectedScopes = $scope.selectedScopes;
policyState.state.selectedResource = $scope.selectedResource;
policyState.state.resourceScopes = $scope.resourceScopes;
policyViewState.state.selectedScopes = $scope.selectedScopes;
policyViewState.state.selectedResource = $scope.selectedResource;
policyViewState.state.resourceScopes = $scope.resourceScopes;
},
onRestoreState : function(policy) {
$scope.selectedScopes = policyState.state.selectedScopes;
$scope.selectedResource = policyState.state.selectedResource;
$scope.resourceScopes = policyState.state.resourceScopes;
$scope.selectedScopes = policyViewState.state.selectedScopes;
$scope.selectedResource = policyViewState.state.selectedResource;
$scope.resourceScopes = policyViewState.state.resourceScopes;
}
}, realm, client, $scope);
});
@ -2006,7 +2010,7 @@ module.controller('ResourceServerPolicyTimeDetailCtrl', function($scope, $route,
}
});
module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $route, $location, realm, PolicyController, ResourceServerPolicy, client, PolicyProvider, policyState) {
module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $route, $location, realm, PolicyController, ResourceServerPolicy, client, PolicyProvider, policyViewState) {
PolicyController.onInit({
getPolicyType : function() {
return "aggregate";
@ -2075,7 +2079,7 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r
},
onInitCreate : function(newPolicy) {
policyState.state.previousPage.name = 'authz-add-aggregated-policy';
policyViewState.state.previousPage.name = 'authz-add-aggregated-policy';
},
onCreate : function() {
@ -2091,7 +2095,7 @@ module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $r
}, realm, client, $scope);
});
module.service("PolicyController", function($http, $route, $location, ResourceServer, ResourceServerPolicy, ResourceServerPermission, AuthzDialog, Notifications, policyState, PolicyProvider) {
module.service("PolicyController", function($http, $route, $location, ResourceServer, ResourceServerPolicy, ResourceServerPermission, AuthzDialog, Notifications, policyViewState, PolicyProvider, viewState) {
var PolicyController = {};
@ -2117,49 +2121,49 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
}
});
if ((!policyState.state || !PolicyController.isBackNewAssociatedPolicy()) && !PolicyController.isNewAssociatedPolicy()) {
policyState.state = {};
if ((!policyViewState.state || !PolicyController.isBackNewAssociatedPolicy()) && !PolicyController.isNewAssociatedPolicy()) {
policyViewState.state = {};
}
if (!policyState.state.previousPage) {
policyState.state.previousPage = {};
if (!policyViewState.state.previousPage) {
policyViewState.state.previousPage = {};
}
$scope.policyState = policyState;
$scope.policyViewState = policyViewState;
$scope.addPolicy = function(policyType) {
policyState.state.policy = $scope.policy;
policyViewState.state.policy = $scope.policy;
if (delegate.onSaveState) {
delegate.onSaveState($scope.policy);
}
if ($scope.selectedPolicies) {
policyState.state.selectedPolicies = $scope.selectedPolicies;
policyViewState.state.selectedPolicies = $scope.selectedPolicies;
}
var previousUrl = window.location.href.substring(window.location.href.indexOf('/realms'));
if (previousUrl.indexOf('back=true') == -1) {
previousUrl = previousUrl + '?back=true';
previousUrl = previousUrl + (previousUrl.indexOf('?') == -1 ? '?' : '&') + 'back=true';
}
policyState.state.previousUrl = previousUrl;
policyViewState.state.previousUrl = previousUrl;
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policyType.type + "/create?new_policy=true");
}
$scope.detailPolicy = function(policy) {
policyState.state.policy = $scope.policy;
policyViewState.state.policy = $scope.policy;
if (delegate.onSaveState) {
delegate.onSaveState($scope.policy);
}
if ($scope.selectedPolicies) {
policyState.state.selectedPolicies = $scope.selectedPolicies;
policyViewState.state.selectedPolicies = $scope.selectedPolicies;
}
var previousUrl = window.location.href.substring(window.location.href.indexOf('/realms'));
if (previousUrl.indexOf('back=true') == -1) {
previousUrl = previousUrl + '?back=true';
previousUrl = previousUrl + (previousUrl.indexOf('?') == -1 ? '?' : '&') + 'back=true';
}
policyState.state.previousUrl = previousUrl;
policyViewState.state.previousUrl = previousUrl;
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policy.type + "/" + policy.id + "?new_policy=true");
}
@ -2243,6 +2247,12 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
$scope.changed = $scope.historyBackOnSaveOrCancel || PolicyController.isBackNewAssociatedPolicy();
if (viewState.state != null && viewState.state.previousUrl != null) {
$scope.previousUrl = viewState.state.previousUrl;
policyViewState.state.rootUrl = $scope.previousUrl;
viewState.state = {};
}
$scope.policy = angular.copy(policy);
$scope.$watch('policy', function() {
@ -2267,17 +2277,21 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
}
service.save({realm : realm.realm, client : client.id, type: $scope.policy.type}, $scope.policy, function(data) {
if (delegate.isPermission()) {
if ($scope.historyBackOnSaveOrCancel) {
policyState.state.newPolicyName = $scope.policy.name;
$location.url(policyState.state.previousUrl);
if ($scope.historyBackOnSaveOrCancel || policyViewState.state.rootUrl != null) {
if (policyViewState.state.rootUrl != null) {
$location.url(policyViewState.state.rootUrl);
} else {
policyViewState.state.newPolicyName = $scope.policy.name;
$location.url(policyViewState.state.previousUrl);
}
} else {
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + $scope.policy.type + "/" + data.id);
}
Notifications.success("The permission has been created.");
} else {
if ($scope.historyBackOnSaveOrCancel) {
policyState.state.newPolicyName = $scope.policy.name;
$location.url(policyState.state.previousUrl);
policyViewState.state.newPolicyName = $scope.policy.name;
$location.url(policyViewState.state.previousUrl);
} else {
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + $scope.policy.type + "/" + data.id);
}
@ -2289,14 +2303,18 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
$scope.reset = function() {
if (delegate.isPermission()) {
if ($scope.historyBackOnSaveOrCancel) {
$location.url(policyState.state.previousUrl);
if ($scope.historyBackOnSaveOrCancel || policyViewState.state.rootUrl != null) {
if (policyViewState.state.rootUrl != null) {
$location.url(policyViewState.state.rootUrl);
} else {
$location.url(policyViewState.state.previousUrl);
}
} else {
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/");
}
} else {
if ($scope.historyBackOnSaveOrCancel) {
$location.url(policyState.state.previousUrl);
$location.url(policyViewState.state.previousUrl);
} else {
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/");
}
@ -2339,7 +2357,7 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
service.update({realm : realm.realm, client : client.id, type: $scope.policy.type, id : $scope.policy.id}, $scope.policy, function() {
if (delegate.isPermission()) {
if ($scope.historyBackOnSaveOrCancel) {
$location.url(policyState.state.previousUrl);
$location.url(policyViewState.state.previousUrl);
} else {
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + $scope.policy.type + "/" + $scope.policy.id);
}
@ -2347,7 +2365,7 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
Notifications.success("The permission has been updated.");
} else {
if ($scope.historyBackOnSaveOrCancel) {
$location.url(policyState.state.previousUrl);
$location.url(policyViewState.state.previousUrl);
} else {
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + $scope.policy.type + "/" + $scope.policy.id);
}
@ -2360,7 +2378,7 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
$scope.reset = function() {
if ($scope.historyBackOnSaveOrCancel) {
$location.url(policyState.state.previousUrl);
$location.url(policyViewState.state.previousUrl);
} else {
var freshPolicy = angular.copy(data);
@ -2402,40 +2420,45 @@ module.service("PolicyController", function($http, $route, $location, ResourceSe
}
this.restoreState = function($scope) {
$scope.policy.name = policyState.state.policy.name;
$scope.policy.description = policyState.state.policy.description;
$scope.policy.decisionStrategy = policyState.state.policy.decisionStrategy;
$scope.policy.logic = policyState.state.policy.logic;
$scope.selectedPolicies = policyState.state.selectedPolicies;
$scope.policy.name = policyViewState.state.policy.name;
$scope.policy.description = policyViewState.state.policy.description;
$scope.policy.decisionStrategy = policyViewState.state.policy.decisionStrategy;
$scope.policy.logic = policyViewState.state.policy.logic;
$scope.selectedPolicies = policyViewState.state.selectedPolicies;
if (!$scope.selectedPolicies) {
$scope.selectedPolicies = [];
}
$scope.changed = true;
var previousPage = policyState.state.previousPage;
var previousPage = policyViewState.state.previousPage;
if (policyState.state.newPolicyName) {
if (policyViewState.state.newPolicyName) {
ResourceServerPolicy.query({
realm: realm.realm,
client : client.id,
permission: false,
name: policyState.state.newPolicyName,
name: policyViewState.state.newPolicyName,
max : 20,
first : 0
}, function(response) {
for (i = 0; i < response.length; i++) {
if (response[i].name == policyState.state.newPolicyName) {
if (response[i].name == policyViewState.state.newPolicyName) {
response[i].text = response[i].name;
$scope.selectedPolicies.push(response[i]);
}
}
policyState.state = {};
policyState.state.previousPage = previousPage;
var rootUrl = policyViewState.state.rootUrl;
policyViewState.state = {};
policyViewState.state.previousPage = previousPage;
policyViewState.state.rootUrl = rootUrl;
});
} else {
policyState.state = {};
policyState.state.previousPage = previousPage;
var rootUrl = policyViewState.state.rootUrl;
policyViewState.state = {};
policyViewState.state.previousPage = previousPage;
policyViewState.state.rootUrl = rootUrl;
}
}
}

View file

@ -200,7 +200,15 @@ module.factory('GroupManagementPermissions', function($resource) {
});
});
module.factory('policyState', [function () {
module.factory('policyViewState', [function () {
return {
model: {
state: {}
}
};
}]);
module.factory('viewState', [function () {
return {
model: {
state: {}

View file

@ -41,12 +41,6 @@
</select>
</div>
</div>
<div class="input-group">
<select class="form-control search" data-ng-model="detailsFilter" data-ng-change="searchQuery();">
<option value="" selected>Hide Details</option>
<option value="true">Show Details</option>
</select>
</div>
<div class="pull-right">
<select class="form-control" ng-model="policyType"
ng-options="p.name for p in policyProviders track by p.type"
@ -59,15 +53,16 @@
</th>
</tr>
<tr data-ng-hide="policies.length == 0">
<th width="1%"></th>
<th>{{:: 'name' | translate}}</th>
<th>{{:: 'description' | translate}}</th>
<th>{{:: 'type' | translate}}</th>
<th colspan="3">{{:: 'actions' | translate}}</th>
<th width="7%">{{:: 'type' | translate}}</th>
<th width="6%" style="text-align: center;">{{:: 'actions' | translate}}</th>
</tr>
</thead>
<tfoot data-ng-show="policies && (policies.length >= query.max || query.first > 0)">
<tr>
<td colspan="8">
<td colspan="5">
<div class="table-nav">
<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>
@ -77,42 +72,38 @@
</tr>
</tfoot>
<tbody>
<tr ng-repeat-start="policy in policies | filter: {name: search.name, type: search.type} | orderBy:'name'">
<tr ng-repeat-start="policy in policies | filter: {name: search.name, type: search.type} | orderBy:'name'" data-ng-click="showDetails(policy);" style="cursor: pointer">
<td>
<span ng-if="!policy.details || !policy.details.loaded" class="fa fa-angle-right"></span>
<span ng-if="policy.details && policy.details.loaded" class="fa fa-angle-right fa-angle-down"></span>
</td>
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a></td>
<td>{{policy.description}}</td>
<td>{{policy.type}}</td>
<td ng-if="!policy.details.loaded" class="kc-action-cell" data-ng-click="showDetails(policy);">
{{:: 'authz-show-details' | translate}}
</td>
<td ng-if="policy.details.loaded" class="kc-action-cell" data-ng-click="showDetails(policy);">
{{:: 'authz-hide-details' | translate}}
</td>
<td class="kc-action-cell" ng-click="delete(policy);">
{{:: 'delete' | translate}}
<td align="center">
<div class="dropdown dropdown-kebab-pf">
<button class="btn btn-default" ng-click="delete(policy);">{{:: 'delete' | translate}}
</button>
</div>
</td>
</tr>
<tr ng-if="policy.details && policy.details.loaded" ng-repeat-end="">
<td colspan="5">
<div id="details">
<table class="table kc-authz-table-expanded table-striped">
<thead>
<tr>
<th>Associated Policies</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span data-ng-show="policy.associatedPolicies && !policy.associatedPolicies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
<ul ng-repeat="dep in policy.associatedPolicies" data-ng-show="policy.associatedPolicies.length > 0">
<li>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy/{{dep.type}}/{{dep.id}}">{{dep.name}}</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<td colspan="5" style="background-color: #ffffff">
<div class="list-group-item-container container-fluid">
<div class="close" data-ng-click="showDetails(policy);" style="padding-top: 10px">
<span class="pficon pficon-close"></span>
</div>
<div class="row">
<div class="col-md-12">
<dl class="dl-horizontal">
<dt>{{:: 'authz-associated-policies' | translate}}</dt>
<dd>
<span data-ng-show="policy.associatedPolicies && !policy.associatedPolicies.length">{{:: 'authz-no-policies-available' | translate}}</span>
<span ng-repeat="dep in policy.associatedPolicies" data-ng-show="policy.associatedPolicies.length > 0"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/{{dep.type == 'scope' || dep.type == 'resource' ? 'permission' : 'policy'}}/{{dep.type}}/{{dep.id}}">{{dep.name}}</a>{{$last ? '' : ', '}}</span>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>

View file

@ -40,16 +40,8 @@
<option value="" selected ng-click="query.type = ''">{{:: 'authz-all-types' | translate}}</option>
</select>
</div>
<div class="input-group">
<select class="form-control search" data-ng-model="detailsFilter" data-ng-change="searchQuery();">
<option value="" selected>Hide Details</option>
<option value="true">Show Details</option>
</select>
</div>
</div>
<div class="pull-right">
<a id="hideDetails" data-ng-show="showDetailsFlag" class="btn btn-default" data-ng-click="showDetailsFlag = !showDetailsFlag;showDetails();" href="">{{:: 'authz-hide-details' | translate}}</a>
<a id="showDetails" data-ng-hide="showDetailsFlag" class="btn btn-default" data-ng-click="showDetailsFlag = !showDetailsFlag;showDetails();" href="">{{:: 'authz-show-details' | translate}}</a>
<select id="create-policy" class="form-control" ng-model="policyType"
ng-options="p.name for p in policyProviders track by p.type"
data-ng-change="addPolicy(policyType);">
@ -60,15 +52,16 @@
</th>
</tr>
<tr data-ng-hide="policies.length == 0">
<th width="1%"></th>
<th>{{:: 'name' | translate}}</th>
<th>{{:: 'description' | translate}}</th>
<th>{{:: 'type' | translate}}</th>
<th colspan="3">{{:: 'actions' | translate}}</th>
<th width="7%">{{:: 'type' | translate}}</th>
<th width="6%" style="text-align: center;">{{:: 'actions' | translate}}</th>
</tr>
</thead>
<tfoot data-ng-show="policies && (policies.length >= query.max || query.first > 0)">
<tr>
<td colspan="8">
<td colspan="5">
<div class="table-nav">
<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>
@ -78,42 +71,38 @@
</tr>
</tfoot>
<tbody>
<tr ng-repeat-start="policy in policies | filter: {name: search.name, type: search.type} | orderBy:'name'">
<tr ng-repeat-start="policy in policies | filter: {name: search.name, type: search.type} | orderBy:'name'" data-ng-click="showDetails(policy);" style="cursor: pointer">
<td>
<span ng-if="!policy.details || !policy.details.loaded" class="fa fa-angle-right"></span>
<span ng-if="policy.details && policy.details.loaded" class="fa fa-angle-right fa-angle-down"></span>
</td>
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy/{{policy.type}}/{{policy.id}}">{{policy.name}}</a></td>
<td>{{policy.description}}</td>
<td>{{policy.type}}</td>
<td ng-if="!policy.details.loaded" class="kc-action-cell" data-ng-click="showDetails(policy);">
{{:: 'authz-show-details' | translate}}
</td>
<td ng-if="policy.details.loaded" class="kc-action-cell" data-ng-click="showDetails(policy);">
{{:: 'authz-hide-details' | translate}}
</td>
<td class="kc-action-cell" ng-click="delete(policy);">
{{:: 'delete' | translate}}
<td align="center">
<div class="dropdown dropdown-kebab-pf">
<button class="btn btn-default" ng-click="delete(policy);">{{:: 'delete' | translate}}
</button>
</div>
</td>
</tr>
<tr ng-if="policy.details && policy.details.loaded" ng-repeat-end="">
<td colspan="5">
<div id="details">
<table class="table kc-authz-table-expanded table-striped">
<thead>
<tr>
<th>Dependent Permissions and Policies</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span data-ng-show="policy.dependentPolicies && !policy.dependentPolicies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
<ul ng-repeat="dep in policy.dependentPolicies" data-ng-show="policy.dependentPolicies.length > 0">
<li>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/{{dep.type == 'scope' || dep.type == 'resource' ? 'permission' : 'policy'}}/{{dep.type}}/{{dep.id}}">{{dep.name}}</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<td colspan="5" style="background-color: #ffffff">
<div class="list-group-item-container container-fluid">
<div class="close" data-ng-click="showDetails(policy);" style="padding-top: 10px">
<span class="pficon pficon-close"></span>
</div>
<div class="row">
<div class="col-md-12">
<dl class="dl-horizontal">
<dt>Dependent Policies</dt>
<dd>
<span data-ng-show="policy.dependentPolicies && !policy.dependentPolicies.length">{{:: 'authz-no-policies-available' | translate}}</span>
<span ng-repeat="dep in policy.dependentPolicies" data-ng-show="policy.dependentPolicies.length > 0"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/{{dep.type == 'scope' || dep.type == 'resource' ? 'permission' : 'policy'}}/{{dep.type}}/{{dep.id}}">{{dep.name}}</a>{{$last ? '' : ', '}}</span>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>

View file

@ -3,144 +3,159 @@
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource">{{:: 'authz-resources' | translate}}</a></li>
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' |
translate}}</a></li>
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource">{{::
'authz-resources' | translate}}</a></li>
</ol>
<kc-tabs-resource-server></kc-tabs-resource-server>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th class="kc-table-actions" colspan="7">
<div class="form-inline">
{{:: 'filter' | translate}}:&nbsp;&nbsp;
<div class="form-group">
<div class="input-group">
<input type="text" placeholder="{{:: 'name' | translate}}" data-ng-model="query.name" class="form-control search" onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" id="resourceSearch" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'type' | translate}}" data-ng-model="query.type" class="form-control search" onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'authz-uri' | translate}}" data-ng-model="query.uri" class="form-control search" onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'authz-owner' | translate}}" data-ng-model="query.owner" class="form-control search" onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'authz-scope' | translate}}" data-ng-model="query.scope" class="form-control search" onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<select class="form-control search" data-ng-model="detailsFilter" data-ng-change="searchQuery();">
<option value="" selected>Hide Details</option>
<option value="true">Show Details</option>
</select>
<tr>
<th class="kc-table-actions" colspan="6">
<div class="form-inline">
{{:: 'filter' | translate}}:&nbsp;&nbsp;
<div class="form-group">
<div class="input-group">
<input type="text" placeholder="{{:: 'name' | translate}}" data-ng-model="query.name"
class="form-control search"
onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" id="resourceSearch" type="submit"
data-ng-click="firstPage()"></i>
</div>
</div>
<div class="pull-right">
<a id="createResource" class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/create">{{:: 'create' | translate}}</a>
<div class="input-group">
<input type="text" placeholder="{{:: 'type' | translate}}" data-ng-model="query.type"
class="form-control search"
onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'authz-uri' | translate}}" data-ng-model="query.uri"
class="form-control search"
onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'authz-owner' | translate}}"
data-ng-model="query.owner" class="form-control search"
onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<input type="text" placeholder="{{:: 'authz-scope' | translate}}"
data-ng-model="query.scope" class="form-control search"
onkeydown="if (event.keyCode == 13) document.getElementById('resourceSearch').click()">
<div class="input-group-addon">
<i class="fa fa-search" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
</div>
</th>
</tr>
<tr data-ng-hide="resources.length == 0">
<th>{{:: 'name' | translate}}</th>
<th>{{:: 'type' | translate}}</th>
<th>{{:: 'authz-uri' | translate}}</th>
<th>{{:: 'authz-owner' | translate}}</th>
<th colspan="3">{{:: 'actions' | translate}}</th>
</tr>
<div class="pull-right">
<a id="createResource" class="btn btn-default"
href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/create">{{::
'create' | translate}}</a>
</div>
</div>
</th>
</tr>
<tr data-ng-hide="resources.length == 0">
<th width="1%"></th>
<th>{{:: 'name' | translate}}</th>
<th>{{:: 'type' | translate}}</th>
<th>{{:: 'authz-uri' | translate}}</th>
<th>{{:: 'authz-owner' | translate}}</th>
<th width="11%" style="text-align: center">{{:: 'actions' | translate}}</th>
</tr>
</thead>
<tfoot data-ng-show="resources && (resources.length >= query.max || query.first > 0)">
<tr>
<td colspan="7">
<td colspan="6">
<div class="table-nav">
<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>
<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>
</div>
</td>
</tr>
</tfoot>
<tbody>
<tr ng-repeat-start="resource in resources | filter:search | orderBy:'name'">
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/{{resource._id}}">{{resource.name}}</a></td>
<td>
<span data-ng-show="resource.type">{{resource.type}}</span>
<span data-ng-show="!resource.type">{{:: 'authz-no-type-defined' | translate}}</span>
</td>
<td>
<span data-ng-show="resource.uri">{{resource.uri}}</span>
<span data-ng-show="!resource.uri">{{:: 'authz-no-uri-defined' | translate}}</span>
</td>
<td>{{resource.owner.name}}</td>
<td ng-if="!resource.details.loaded" class="kc-action-cell" data-ng-click="showDetails(resource);">
{{:: 'authz-show-details' | translate}}
</td>
<td ng-if="resource.details.loaded" class="kc-action-cell" data-ng-click="showDetails(resource);">
{{:: 'authz-hide-details' | translate}}
</td>
<td class="kc-action-cell" ng-click="createPolicy(resource);">
{{:: 'authz-create-permission' | translate}}
</td>
<td class="kc-action-cell" ng-click="delete(resource);">
{{:: 'delete' | translate}}
</td>
</tr>
<tr ng-if="resource.details && resource.details.loaded" ng-repeat-end="">
<td colspan="7">
<div id="details">
<table class="table kc-authz-table-expanded table-striped">
<thead>
<tr>
<th>Scopes</th>
<th>Associated Permissions</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span data-ng-show="resource.scopes && !resource.scopes.length">{{:: 'authz-no-scopes-assigned' | translate}}</span>
<ul ng-repeat="scope in resource.scopes" data-ng-show="resource.scopes.length > 0">
<li>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/{{scope.id}}">{{scope.name}}</a>
</li>
</ul>
</td>
<td>
<span data-ng-show="resource.policies && !resource.policies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
<ul ng-repeat="policy in resource.policies" data-ng-show="resource.policies.length > 0">
<li>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<tr ng-repeat-start="resource in resources | filter:search | orderBy:'name'" data-ng-click="showDetails(resource);" style="cursor: pointer;">
<td>
<span ng-if="!resource.details || !resource.details.loaded" class="fa fa-angle-right"></span>
<span ng-if="resource.details && resource.details.loaded" class="fa fa-angle-right fa-angle-down"></span>
</td>
<td>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/{{resource._id}}">{{resource.name}}</a>
</td>
<td>
<span data-ng-show="resource.type">{{resource.type}}</span>
<span data-ng-show="!resource.type">{{:: 'authz-no-type-defined' | translate}}</span>
</td>
<td>
<span data-ng-show="resource.uri">{{resource.uri}}</span>
<span data-ng-show="!resource.uri">{{:: 'authz-no-uri-defined' | translate}}</span>
</td>
<td>{{resource.owner.name}}</td>
<td align="center">
<div class="dropdown dropdown-kebab-pf">
<button class="btn btn-default" ng-click="createPolicy(resource);">{{:: 'authz-create-permission' | translate}}
</button>
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<span class="fa fa-ellipsis-v"></span></button>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownKebabRight">
<li><a href="" ng-click="delete(resource);">{{:: 'delete' | translate}}</a></li>
</ul>
</div>
</td>
</tr>
<tr ng-if="resource.details && resource.details.loaded" ng-repeat-end="">
<td colspan="6" style="background-color: #ffffff">
<div class="list-group-item-container container-fluid">
<div class="close" data-ng-click="showDetails(resource);" style="padding-top: 10px">
<span class="pficon pficon-close"></span>
</div>
</td>
</tr>
<tr data-ng-show="(resources | filter:search).length == 0">
<td class="text-muted" colspan="6" data-ng-show="search.name">{{:: 'no-results' | translate}}</td>
<td class="text-muted" colspan="6" data-ng-hide="search.name">{{:: 'authz-no-resources-available' | translate}}</td>
</tr>
<div class="row">
<div class="col-md-12">
<dl class="dl-horizontal">
<dt>{{:: 'authz-scopes' | translate}}</dt>
<dd>
<span data-ng-show="resource.scopes && !resource.scopes.length">{{:: 'authz-no-scopes-assigned' | translate}}</span>
<span ng-repeat="scope in resource.scopes" data-ng-show="resource.scopes.length > 0"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/{{scope.id}}">{{scope.name}}</a>{{$last ? '' : ', '}} </span>
</dd>
<dt>{{:: 'authz-associated-permissions' | translate}}</dt>
<dd>
<span data-ng-show="resource.policies && !resource.policies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
<span ng-repeat="policy in resource.policies" data-ng-show="resource.policies.length > 0"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>{{$last ? '' : ', '}}</span>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-ng-show="(resources | filter:search).length == 0">
<td class="text-muted" colspan="6" data-ng-show="search.name">{{:: 'no-results' | translate}}</td>
<td class="text-muted" colspan="6" data-ng-hide="search.name">{{:: 'authz-no-resources-available' |
translate}}
</td>
</tr>
</tbody>
</table>
</div>

View file

@ -12,7 +12,7 @@
<table class="table table-striped table-bordered">
<thead>
<tr>
<th class="kc-table-actions" colspan="5">
<th class="kc-table-actions" colspan="3">
<div class="form-inline">
<div class="form-group">
<div class="input-group">
@ -21,12 +21,6 @@
<i class="fa fa-search" id="scopeSearch" type="submit" data-ng-click="firstPage()"></i>
</div>
</div>
<div class="input-group">
<select class="form-control search" data-ng-model="detailsFilter" data-ng-change="showDetails();">
<option value="" selected>Hide Details</option>
<option value="true">Show Details</option>
</select>
</div>
</div>
<div class="pull-right">
<a id="createScope" class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/create">{{:: 'create' | translate}}</a>
@ -35,13 +29,14 @@
</th>
</tr>
<tr data-ng-hide="scopes.length == 0">
<th width="1%"></th>
<th>{{:: 'name' | translate}}</th>
<th colspan="3">{{:: 'actions' | translate}}</th>
<th width="11%" style="text-align: center">{{:: 'actions' | translate}}</th>
</tr>
</thead>
<tfoot data-ng-show="scopes && (scopes.length >= query.max || query.first > 0)">
<tr>
<td colspan="8">
<td colspan="3">
<div class="table-nav">
<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>
@ -51,52 +46,48 @@
</tr>
</tfoot>
<tbody>
<tr ng-repeat-start="scope in scopes | filter:search | orderBy:'name'">
<td width="70%"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/{{scope.id}}">{{scope.name}}</a></td>
<td ng-if="!scope.details.loaded" class="kc-action-cell" data-ng-click="showDetails(scope);">
{{:: 'authz-show-details' | translate}}
<tr ng-repeat-start="scope in scopes | filter:search | orderBy:'name'" data-ng-click="showDetails(scope);" style="cursor: pointer">
<td>
<span ng-if="!scope.details || !scope.details.loaded" class="fa fa-angle-right"></span>
<span ng-if="scope.details && scope.details.loaded" class="fa fa-angle-right fa-angle-down"></span>
</td>
<td ng-if="scope.details.loaded" class="kc-action-cell" data-ng-click="showDetails(scope);">
{{:: 'authz-hide-details' | translate}}
</td>
<td class="kc-action-cell" ng-click="createPolicy(scope);">
{{:: 'authz-create-permission' | translate}}
</td>
<td class="kc-action-cell" ng-click="delete(scope);">
{{:: 'delete' | translate}}
<td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/{{scope.id}}">{{scope.name}}</a></td>
<td align="center">
<div class="dropdown dropdown-kebab-pf">
<button class="btn btn-default" ng-click="createPolicy(scope);">{{:: 'authz-create-permission' |
translate}}
</button>
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<span class="fa fa-ellipsis-v"></span></button>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownKebabRight">
<li><a href="" ng-click="delete(scope);">{{:: 'delete' | translate}}</a></li>
</ul>
</div>
</td>
</tr>
<tr ng-if="scope.details && scope.details.loaded" ng-repeat-end="">
<td colspan="4">
<div id="details">
<table class="table kc-authz-table-expanded table-striped">
<thead>
<tr>
<th>Resources</th>
<th>Associated Permissions</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span data-ng-show="scope.resources && !scope.resources.length">{{:: 'authz-no-resources-assigned' | translate}}</span>
<ul ng-repeat="resource in scope.resources" data-ng-show="scope.resources.length > 0">
<li>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/{{resource._id}}">{{resource.name}}</a>
</li>
</ul>
</td>
<td>
<span data-ng-show="scope.policies && !scope.policies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
<ul ng-repeat="policy in scope.policies" data-ng-show="scope.policies.length > 0">
<li>
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<td colspan="3" style="background-color: #ffffff">
<div class="list-group-item-container container-fluid">
<div class="close" data-ng-click="showDetails(scope);" style="padding-top: 10px">
<span class="pficon pficon-close"></span>
</div>
<div class="row">
<div class="col-md-12">
<dl class="dl-horizontal">
<dt>{{:: 'authz-resources' | translate}}</dt>
<dd>
<span data-ng-show="scope.resources && !scope.resources.length">{{:: 'authz-no-resources-assigned' | translate}}</span>
<span ng-repeat="resource in scope.resources" data-ng-show="scope.resources.length > 0"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/{{resource._id}}">{{resource.name}}</a>{{$last ? '' : ', '}}</span>
</dd>
<dt>{{:: 'authz-associated-permissions' | translate}}</dt>
<dd>
<span data-ng-show="scope.policies && !scope.policies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
<span ng-repeat="policy in scope.policies" data-ng-show="scope.policies.length > 0"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>{{$last ? '' : ', '}}</span>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>