KEYCLOAK-18875 UI for managing group of attributes
This commit is contained in:
parent
ac92e600fc
commit
acb2ac1c8d
3 changed files with 280 additions and 28 deletions
|
@ -1919,6 +1919,7 @@ dialogs.delete.message=Are you sure you want to permanently delete the {{type}}
|
|||
dialogs.delete.confirm=Delete
|
||||
dialogs.cancel=Cancel
|
||||
dialogs.ok=Ok
|
||||
use=Use
|
||||
|
||||
user.profile.attribute=Attribute
|
||||
user.profile.attribute.name=Name
|
||||
|
@ -1947,4 +1948,10 @@ user.profile.attribute.validation.add.validator=Add Validator
|
|||
user.profile.attribute.validation.add.validator.tooltip=Select a validator to enforce specific constraints to the attribute value.
|
||||
user.profile.attribute.validation.no.validators=No validators.
|
||||
user.profile.attribute.annotation=Annotation
|
||||
use=Use
|
||||
user.profile.attribute.group=Attribute Group
|
||||
attribute-groups=Attribute Groups
|
||||
user.profile.attributegroup.displayHeader=Display header
|
||||
user.profile.attributegroup.displayDescription=Display description
|
||||
user.profile.attributegroup=Attribute Group
|
||||
user.profile.attributegroup.name=Name
|
||||
user.profile.attributegroup.annotation=Annotation
|
||||
|
|
|
@ -1415,6 +1415,8 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
$scope.validatorProviders = serverInfo.componentTypes['org.keycloak.validate.Validator'];
|
||||
|
||||
$scope.isShowAttributes = true;
|
||||
$scope.isShowAttributeGroups = false;
|
||||
$scope.isShowJsonEditor = false;
|
||||
|
||||
UserProfile.get({realm: realm.realm}, function(config) {
|
||||
$scope.config = config;
|
||||
|
@ -1422,14 +1424,27 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
});
|
||||
|
||||
$scope.isShowAttributes = true;
|
||||
$scope.isShowAttributeGroups = false;
|
||||
$scope.isShowJsonEditor = false;
|
||||
|
||||
$scope.showAttributes = function() {
|
||||
$route.reload();
|
||||
delete $scope.currentAttributeGroup;
|
||||
}
|
||||
|
||||
$scope.showAttributeGroups = function() {
|
||||
$scope.isShowAttributes = false;
|
||||
$scope.isShowAttributeGroups = true;
|
||||
$scope.isShowJsonEditor = false;
|
||||
delete $scope.currentAttribute;
|
||||
}
|
||||
|
||||
$scope.showJsonEditor = function() {
|
||||
$scope.isShowAttributes = false;
|
||||
$scope.isShowAttributeGroups = false;
|
||||
$scope.isShowJsonEditor = true;
|
||||
delete $scope.currentAttribute;
|
||||
delete $scope.currentAttributeGroup;
|
||||
}
|
||||
|
||||
$scope.isRequiredRoles = {
|
||||
|
@ -1517,12 +1532,16 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
|
||||
$scope.attributeSelected = false;
|
||||
|
||||
$scope.showListing = function() {
|
||||
$scope.showAttributeListing = function() {
|
||||
return !$scope.attributeSelected && $scope.currentAttribute == null && $scope.isShowAttributes;
|
||||
}
|
||||
|
||||
$scope.create = function() {
|
||||
$scope.isCreate = true;
|
||||
$scope.showAttributeGroupListing = function() {
|
||||
return !$scope.attributeGroupSelected && $scope.currentAttributeGroup == null && $scope.isShowAttributeGroups;
|
||||
}
|
||||
|
||||
$scope.createAttribute = function() {
|
||||
$scope.isCreateAttribute = true;
|
||||
$scope.currentAttribute = {
|
||||
selector: {
|
||||
scopes: []
|
||||
|
@ -1538,6 +1557,11 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
};
|
||||
};
|
||||
|
||||
$scope.createAttributeGroup = function() {
|
||||
$scope.isCreateAttributeGroup = true;
|
||||
$scope.currentAttributeGroup = {};
|
||||
};
|
||||
|
||||
$scope.isNotUsernameOrEmail = function(attributeName) {
|
||||
return attributeName != "username" && attributeName != "email";
|
||||
};
|
||||
|
@ -1555,6 +1579,19 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
$scope.save();
|
||||
}
|
||||
|
||||
$scope.groupOrderUp = function(index) {
|
||||
$scope.moveAttributeGroup(index, index - 1);
|
||||
};
|
||||
|
||||
$scope.groupOrderDown = function(index) {
|
||||
$scope.moveAttributeGroup(index, index + 1);
|
||||
};
|
||||
|
||||
$scope.moveAttributeGroup = function(old_index, new_index){
|
||||
$scope.config.groups.splice(new_index, 0, $scope.config.groups.splice(old_index, 1)[0]);
|
||||
$scope.save(false);
|
||||
}
|
||||
|
||||
$scope.removeAttribute = function(attribute) {
|
||||
Dialog.confirmDelete(attribute.name, 'attribute', function() {
|
||||
let newAttributes = [];
|
||||
|
@ -1570,7 +1607,22 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
});
|
||||
};
|
||||
|
||||
$scope.addAnnotation = function() {
|
||||
$scope.removeAttributeGroup = function(attributeGroup) {
|
||||
Dialog.confirmDelete(attributeGroup.name, 'group', function() {
|
||||
let newGroups = [];
|
||||
|
||||
for (var v of $scope.config.groups) {
|
||||
if (v != attributeGroup) {
|
||||
newGroups.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.config.groups = newGroups;
|
||||
$scope.save();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addAttributeAnnotation = function() {
|
||||
if (!$scope.currentAttribute.annotations) {
|
||||
$scope.currentAttribute.annotations = {};
|
||||
}
|
||||
|
@ -1578,11 +1630,23 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
delete $scope.newAnnotation;
|
||||
}
|
||||
|
||||
$scope.removeAnnotation = function(key) {
|
||||
$scope.removeAttributeAnnotation = function(key) {
|
||||
delete $scope.currentAttribute.annotations[key];
|
||||
}
|
||||
|
||||
$scope.edit = function(attribute) {
|
||||
$scope.addAttributeGroupAnnotation = function() {
|
||||
if (!$scope.currentAttributeGroup.annotations) {
|
||||
$scope.currentAttributeGroup.annotations = {};
|
||||
}
|
||||
$scope.currentAttributeGroup.annotations[$scope.newAttributeGroupAnnotation.key] = $scope.newAttributeGroupAnnotation.value;
|
||||
delete $scope.newGroupAnnotation;
|
||||
}
|
||||
|
||||
$scope.removeAttributeGroupAnnotation = function(key) {
|
||||
delete $scope.currentAttributeGroup.annotations[key];
|
||||
}
|
||||
|
||||
$scope.editAttribute = function(attribute) {
|
||||
if (attribute.permissions == null) {
|
||||
attribute.permissions = {
|
||||
view: [],
|
||||
|
@ -1628,6 +1692,20 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
$scope.attributeSelected = true;
|
||||
};
|
||||
|
||||
$scope.editAttributeGroup = function(attributeGroup) {
|
||||
$scope.currentAttributeGroup = attributeGroup;
|
||||
$scope.attributeGroupSelected = true;
|
||||
};
|
||||
|
||||
$scope.groupIsReferencedInAnyAttribute = function(group) {
|
||||
for (var currentAttribute of $scope.config.attributes) {
|
||||
if (currentAttribute.group === group.name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.$watch('isRequired', function() {
|
||||
if ($scope.isRequired) {
|
||||
$scope.currentAttribute.required = {
|
||||
|
@ -1720,8 +1798,19 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
$scope.currentAttribute.validations = newValidators;
|
||||
};
|
||||
|
||||
$scope.reloadConfigurationFromUserProfile = function () {
|
||||
UserProfile.get({realm: realm.realm}, function(config) {
|
||||
$scope.config = config;
|
||||
$scope.rawConfig = angular.toJson(config, true);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.save = function() {
|
||||
if (!$scope.isShowAttributes) {
|
||||
$scope.save(true)
|
||||
}
|
||||
|
||||
$scope.save = function(reload) {
|
||||
if ($scope.isShowJsonEditor) {
|
||||
$scope.config = JSON.parse($scope.rawConfig);
|
||||
}
|
||||
|
||||
|
@ -1740,26 +1829,52 @@ module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientS
|
|||
$scope.currentAttribute.selector.scopes.push($scope.selectorByScope[i].name);
|
||||
}
|
||||
|
||||
if ($scope.isCreate) {
|
||||
if ($scope.isCreateAttribute) {
|
||||
$scope.config['attributes'].push($scope.currentAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.currentAttributeGroup) {
|
||||
if ($scope.config['groups'] == null) {
|
||||
$scope.config['groups'] = []
|
||||
}
|
||||
if ($scope.isCreateAttributeGroup) {
|
||||
$scope.config['groups'].push($scope.currentAttributeGroup);
|
||||
}
|
||||
}
|
||||
|
||||
UserProfile.update({realm: realm.realm},
|
||||
|
||||
$scope.config, function () {
|
||||
$scope.attributeSelected = false;
|
||||
delete $scope.currentAttribute;
|
||||
delete $scope.isCreate;
|
||||
delete $scope.isCreateAttribute
|
||||
delete $scope.attributeSelected;
|
||||
delete $scope.currentAttributeGroup;
|
||||
delete $scope.isCreateAttributeGroup;
|
||||
delete $scope.attributeGroupSelected;
|
||||
delete $scope.isRequired;
|
||||
delete $scope.canUserView;
|
||||
delete $scope.canAdminView;
|
||||
delete $scope.canUserEdit;
|
||||
delete $scope.canAdminEdit;
|
||||
$route.reload();
|
||||
|
||||
if (reload) {
|
||||
$route.reload();
|
||||
} else {
|
||||
$scope.reloadConfigurationFromUserProfile();
|
||||
}
|
||||
Notifications.success("User Profile configuration has been saved.");
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancelEditAttributeGroup = function() {
|
||||
delete $scope.currentAttributeGroup;
|
||||
delete $scope.isCreateAttributeGroup;
|
||||
delete $scope.attributeGroupSelected;
|
||||
$scope.reloadConfigurationFromUserProfile();
|
||||
}
|
||||
|
||||
$scope.reset = function() {
|
||||
$route.reload();
|
||||
};
|
||||
|
|
|
@ -3,19 +3,22 @@
|
|||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li ng-class="{active: isShowAttributes}"><a href="" data-ng-click="showAttributes()">{{:: 'attributes' | translate}}</a></li>
|
||||
<li ng-class="{active: !isShowAttributes}"><a href=""
|
||||
<li ng-class="{active: isShowAttributeGroups}"><a href=""
|
||||
data-ng-click="showAttributeGroups()">{{:: 'attribute-groups' | translate}}</a>
|
||||
|
||||
<li ng-class="{active: isShowJsonEditor}"><a href=""
|
||||
data-ng-click="showJsonEditor()">{{:: 'client-profiles-json-editor' | translate}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div data-ng-show="showListing()">
|
||||
<div data-ng-show="showAttributeListing()">
|
||||
<table class="datatable table table-striped table-bordered dataTable no-footer">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="4">
|
||||
<th class="kc-table-actions" colspan="5">
|
||||
<div class="form-inline">
|
||||
<div class="pull-right" data-ng-show="access.manageClients">
|
||||
<button class="btn btn-default" data-ng-click="create()">
|
||||
<button class="btn btn-default" data-ng-click="createAttribute()">
|
||||
{{:: 'create' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -24,7 +27,8 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th width="25%">{{:: 'name' | translate}}</th>
|
||||
<th width="65%">{{:: 'user.profile.attribute.displayName' | translate}}</th>
|
||||
<th width="40%">{{:: 'user.profile.attribute.displayName' | translate}}</th>
|
||||
<th width="25%">{{:: 'user.profile.attribute.group' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -33,18 +37,58 @@
|
|||
<td class="kc-sorter">
|
||||
<button data-ng-hide="flow.builtIn" data-ng-disabled="$first" class="btn btn-default btn-sm" data-ng-click="guiOrderUp($index)"><i class="fa fa-angle-up"></i></button>
|
||||
<button data-ng-hide="flow.builtIn" data-ng-disabled="$last" class="btn btn-default btn-sm" data-ng-click="guiOrderDown($index)"><i class="fa fa-angle-down"></i></button>
|
||||
<span><a href="" data-ng-click="edit(attribute)">{{attribute.name}}</a></span>
|
||||
<span><a href="" data-ng-click="editAttribute(attribute)">{{attribute.name}}</a></span>
|
||||
</td>
|
||||
<td>{{attribute.displayName}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="edit(attribute)">{{:: 'edit' | translate}}</td>
|
||||
<td>{{attribute.group}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="editAttribute(attribute)">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="removeAttribute(attribute)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div data-ng-show="showAttributeGroupListing()">
|
||||
<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="pull-right" data-ng-show="access.manageClients">
|
||||
<button class="btn btn-default" data-ng-click="createAttributeGroup()">
|
||||
{{:: 'create' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th width="25%">{{:: 'name' | translate}}</th>
|
||||
<th width="25%">{{:: 'user.profile.attributegroup.displayHeader' | translate}}</th>
|
||||
<th width="40%">{{:: 'user.profile.attributegroup.displayDescription' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="group in config.groups">
|
||||
<td class="kc-sorter">
|
||||
<button data-ng-hide="flow.builtIn" data-ng-disabled="$first" class="btn btn-default btn-sm" data-ng-click="groupOrderUp($index)"><i class="fa fa-angle-up"></i></button>
|
||||
<button data-ng-hide="flow.builtIn" data-ng-disabled="$last" class="btn btn-default btn-sm" data-ng-click="groupOrderDown($index)"><i class="fa fa-angle-down"></i></button>
|
||||
<span><a href="" data-ng-click="editAttributeGroup(group)">{{group.name}}</a></span>
|
||||
</td>
|
||||
<td>{{group.displayHeader}}</td>
|
||||
<td>{{group.displayDescription}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="editAttributeGroup(group)">{{:: 'edit' | translate}}</td>
|
||||
<!-- show delete button enabled/disabled depending whether it is referenced in any attribute -->
|
||||
<td class="kc-action-cell" ng-if="!(groupIsReferencedInAnyAttribute(group))" data-ng-click="removeAttributeGroup(group)">{{:: 'delete' | translate}}</td>
|
||||
<td class="kc-action-cell-disabled" ng-if="(groupIsReferencedInAnyAttribute(group))" align="center" >{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm"
|
||||
data-ng-show="!isShowAttributes">
|
||||
data-ng-show="isShowJsonEditor">
|
||||
<filedset>
|
||||
<div class="form-group">
|
||||
<div class="col-md-10">
|
||||
|
@ -69,7 +113,7 @@
|
|||
data-ng-show="currentAttribute != null">
|
||||
<p/>
|
||||
<legend expanded><span class="text">{{:: 'user.profile.attribute' | translate}} <b
|
||||
data-ng-show="!isCreate">{{currentAttribute.name}}</b> {{:: 'configuration' | translate}}</span>
|
||||
data-ng-show="!isCreateAttribute">{{currentAttribute.name}}</b> {{:: 'configuration' | translate}}</span>
|
||||
</legend>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="currentAttribute.name">{{:: 'user.profile.attribute.name' | translate}}</label>
|
||||
|
@ -77,8 +121,8 @@
|
|||
<div class="col-md-4">
|
||||
<input name="currentAttribute.name" data-ng-model="currentAttribute.name" id="currentAttribute.name"
|
||||
type="text" class="form-control"
|
||||
data-ng-readonly="!isCreate"
|
||||
required/>
|
||||
data-ng-readonly="!isCreateAttribute"
|
||||
data-ng-required="currentAttribute != null"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -89,6 +133,20 @@
|
|||
type="text" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="currentAttribute.group">{{:: 'user.profile.attribute.group' | translate}}</label>
|
||||
<div class="col-md-2">
|
||||
<div>
|
||||
<select id="select-attributeGroup" data-ng-model="currentAttribute.group" class="form-control"
|
||||
data-ng-options="group.name as group.name for group in config.groups" >
|
||||
<option value="" /> <!-- add the "no group" option -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'user.profile.attribute.group.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group" data-ng-show="isNotUsernameOrEmail(currentAttribute.name)">
|
||||
<label class="col-md-2 control-label" for="selectorByScopeSelect">{{:: 'user.profile.attribute.selector.scopes' | translate}}</label>
|
||||
<kc-tooltip>{{:: 'user.profile.attribute.selector.scopes.tooltip' | translate}}</kc-tooltip>
|
||||
|
@ -222,7 +280,7 @@
|
|||
<tr>
|
||||
<td><input ng-model="newAnnotation.key" class="form-control" type="text" id="newAnnotationKey"/></td>
|
||||
<td><input ng-model="newAnnotation.value" class="form-control" type="text" id="newAnnotationValue"/></td>
|
||||
<td class="kc-action-cell" data-ng-click="addAnnotation()"
|
||||
<td class="kc-action-cell" data-ng-click="addAttributeAnnotation()"
|
||||
data-ng-disabled="!newAnnotation.key.length || !newAnnotation.value.length">{{:: 'add' | translate}}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -239,6 +297,78 @@
|
|||
</div>
|
||||
</form>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm"
|
||||
data-ng-show="currentAttributeGroup != null">
|
||||
<p/>
|
||||
<legend expanded><span class="text">{{:: 'user.profile.attributegroup' | translate}} <b
|
||||
data-ng-show="!isCreateAttributeGroup">{{currentAttributeGroup.name}}</b> {{:: 'configuration' | translate}}</span>
|
||||
</legend>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="currentAttributeGroup.name">{{:: 'user.profile.attributegroup.name' | translate}}</label>
|
||||
<kc-tooltip>{{:: 'user.profile.attributegroup.name.tooltip' | translate}}</kc-tooltip>
|
||||
<div class="col-md-4">
|
||||
<input name="currentAttributeGroup.name" data-ng-model="currentAttributeGroup.name" id="currentAttributeGroup.name"
|
||||
type="text" class="form-control"
|
||||
data-ng-readonly="!isCreateAttributeGroup"
|
||||
data-ng-required="currentAttributeGroup != null"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="currentAttributeGroup.displayHeader">{{:: 'user.profile.attributegroup.displayHeader' | translate}}</label>
|
||||
<kc-tooltip>{{:: 'user.profile.attributegroup.displayHeader.tooltip' | translate}}</kc-tooltip>
|
||||
<div class="col-md-4">
|
||||
<input name="currentAttributeGroup.displayHeader" data-ng-model="currentAttributeGroup.displayHeader" id="currentAttributeGroup.displayHeader"
|
||||
type="text" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="currentAttributeGroup.displayDescription">{{:: 'user.profile.attributegroup.displayDescription' | translate}}</label>
|
||||
<kc-tooltip>{{:: 'user.profile.attributegroup.displayDescription.tooltip' | translate}}</kc-tooltip>
|
||||
<div class="col-md-4">
|
||||
<input name="currentAttributeGroup.displayDescription" data-ng-model="currentAttributeGroup.displayDescription" id="currentAttributeGroup.displayDescription"
|
||||
type="text" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset>
|
||||
<legend collapsed><span class="text">{{:: 'user.profile.attributegroup.annotation' | translate}}</span></legend>
|
||||
<div class="form-group col-sm-10">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{:: 'key' | translate}}</th>
|
||||
<th>{{:: 'value' | translate}}</th>
|
||||
<th>{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(key, value) in currentAttributeGroup.annotations | toOrderedMapSortedByKey">
|
||||
<td>{{key}}</td>
|
||||
<td><input ng-model="currentAttributeGroup.annotations[key]" class="form-control" type="text" name="{{key}}"
|
||||
id="attributegroup-{{key}}"/></td>
|
||||
<td class="kc-action-cell" data-ng-click="removeAttributeGroupAnnotation(key)">{{:: 'delete' | translate}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input ng-model="newAttributeGroupAnnotation.key" class="form-control" type="text" id="newAttributeGroupAnnotationKey"/></td>
|
||||
<td><input ng-model="newAttributeGroupAnnotation.value" class="form-control" type="text" id="newAttributeGroupAnnotationValue"/></td>
|
||||
<td class="kc-action-cell" data-ng-click="addAttributeGroupAnnotation()"
|
||||
data-ng-disabled="!newAttributeGroupAnnotation.key.length || !newAttributeGroupAnnotation.value.length">{{:: 'add' | translate}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-group">
|
||||
<p/>
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
|
||||
<button kc-save>{{:: 'save' | translate}}</button>
|
||||
<button class="btn btn-default" data-ng-click="cancelEditAttributeGroup()">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<kc-menu></kc-menu>
|
Loading…
Reference in a new issue