RANGER-3804: Update policy UI to support multiple resource-sets
diff --git a/security-admin/src/main/webapp/scripts/modules/XAOverrides.js b/security-admin/src/main/webapp/scripts/modules/XAOverrides.js
index 9237abd..2bc552b 100644
--- a/security-admin/src/main/webapp/scripts/modules/XAOverrides.js
+++ b/security-admin/src/main/webapp/scripts/modules/XAOverrides.js
@@ -487,6 +487,9 @@
events: {
'click': function(event) {
},
+ 'change': function(event) {
+ this.trigger('change', this);
+ },
},
initialize: function(options) {
Form.editors.Base.prototype.initialize.call(this, options);
@@ -691,7 +694,8 @@
that.renderResource(def);
}
//trigger resource event for showing respective access permissions
- Vent.trigger('resourceType:change', changeType = 'resourceType', e.currentTarget.value, e.currentTarget.value, e);
+ var resourceItemIndex = that.form.model && that.form.model.collection.indexOf(that.form.model);
+ Vent.trigger('resourceType:change', { changeType : 'resourceType', value : e.currentTarget.value, resourceName: e.currentTarget.value, event:e, resourceItemIndex : resourceItemIndex });
});
}
},
diff --git a/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js b/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js
index 28f05ae..7cd3194 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js
@@ -105,8 +105,7 @@
// if(XAUtil.isMaskingPolicy(this.rangerPolicyType)) this.renderMaskingTypesForTagBasedPolicies();
} else {
// To handle scenario : Access permission doesnt changes if we change resource before adding new policy item.
- this.renderPerms(this.storeResourceRef.changeType, this.storeResourceRef.value,
- this.storeResourceRef.resourceName, this.storeResourceRef.e );
+ this.renderPerms({ action : "permissionItemAdd" });
if(XAUtil.isMaskingPolicy(this.rangerPolicyType)){
this.renderMaskingType();
}
@@ -279,16 +278,35 @@
}
}).on('select2-focus', XAUtil.select2Focus);
},
- renderPerms :function(changeType, value, resourceName, e){
+ renderPerms :function({changeType, value, resourceName, event, resourceItemIndex, action}){
var that = this , accessTypeByResource = this.accessTypes;
- this.storeResourceRef.changeType = changeType;
- this.storeResourceRef.value = value;
- this.storeResourceRef.resourceName = resourceName;
- this.storeResourceRef.e = e;
+ if(action === 'removed'){
+ var removedItemIndex = _.findIndex(this.storeResourceRef, function(a){ return a.resourceItemIndex == resourceItemIndex;});
+ if(removedItemIndex >= 0){
+ this.storeResourceRef.splice(this.storeResourceRef.findIndex(item => item.resourceItemIndex === resourceItemIndex), 1);
+ _.each(this.storeResourceRef, (obj, index) => {
+ if(index >= removedItemIndex){
+ obj.resourceItemIndex = obj.resourceItemIndex - 1;
+ }
+ });
+ }
+ } else if (changeType || action== 'added') {
+ var resourceChangeObj = { resourceItemIndex, changeType, value, resourceName, event };
+ var found = _.findWhere(this.storeResourceRef, { resourceItemIndex: resourceItemIndex });
+ if(found && changeType){
+ _.extend(_.findWhere(this.storeResourceRef, { resourceItemIndex: resourceItemIndex }), resourceChangeObj );
+ } else {
+ this.storeResourceRef.push(resourceChangeObj)
+ }
+ }
//get permissions by resource only for access policy
- accessTypeByResource = this.getAccessPermissionForSelectedResource(changeType, value, resourceName, e);
+ accessTypeByResource = (this.storeResourceRef.length && (changeType || action === 'removed' || action === 'permissionItemAdd'))
+ ? [] : accessTypeByResource;
+ _.each(this.storeResourceRef, (obj) => {
+ accessTypeByResource = _.union(accessTypeByResource, this.getAccessPermissionForSelectedResource(obj.changeType, obj.value, obj.resourceName, obj.event));
+ });
//reset permissions on resource change
- if(this.permsIds.length > 0 && !_.isUndefined(changeType) && !_.isUndefined(resourceName)){
+ if(this.permsIds.length > 0 && ( !_.isUndefined(changeType) && !_.isUndefined(resourceName) || action === 'removed') ){
this.permsIds = [];
}
this.perms = _.map(accessTypeByResource , function(m){return {text : m.label, value : m.name};});
@@ -297,9 +315,9 @@
}
//if policy items not present. its skip that items and move forward
if(_.isObject(this.ui.addPerms)){
- if(changeType){
- this.ui.addPerms.editable("destroy");
- }
+ if(changeType || action === 'removed' || action== 'added'){
+ this.ui.addPerms.editable("destroy");
+ }
//create x-editable for permissions
this.ui.addPerms.editable({
emptytext : 'Add Permissions',
@@ -1009,7 +1027,31 @@
if(this.collection.length == 0){
this.collection.add(new Backbone.Model())
}
- this.storeResourceRef = {};
+ this.storeResourceRef = [];
+ var resourceDefByPolicyType = this.getResourceDefByPolicyType();
+ if(!this.model.isNew()){
+ _.each(_.union([this.model.get('resources')], this.model.get('additionalResources')), function(obj, index){
+ var resourceNames = Object.keys(obj);
+ var resourceName = resourceNames[0];
+ if(resourceName.length > 1){
+ var resourceByDef = resourceDefByPolicyType.filter((resource) => resourceNames.includes(resource.name) );
+ var maxLevel = Math.max(...resourceByDef.map(function(o) { return o.level; }));
+ var resource = resourceByDef.find(function(o) { return o.level == maxLevel; });
+ resourceName = resource.name;
+ }
+ this.storeResourceRef.push({'changeType': 'resourceType','resourceName': resourceName, value: resourceName, resourceItemIndex: index });
+ }, this);
+ } else {
+ let getChildResource = (resource) => {
+ var childResource = _.findWhere(resourceDefByPolicyType, {parent : resource.name });
+ if(childResource){
+ return getChildResource(childResource);
+ }
+ return resource.name;
+ }
+ var resourceName = getChildResource(resourceDefByPolicyType[0])
+ this.storeResourceRef.push({'changeType': 'resourceType','resourceName': resourceName, value: resourceName, resourceItemIndex: 0 });
+ }
},
onRender : function(){
this.makePolicyItemSortable();
@@ -1075,6 +1117,20 @@
that.$el.find(ui.item[0]).addClass("dirtyField");
},
});
+ },
+ getResourceDefByPolicyType : function () {
+ var resourceDefList = this.rangerServiceDefModel.get('resources');
+ if(XAUtil.isMaskingPolicy(this.model.get('policyType'))){
+ if(!_.isEmpty(this.rangerServiceDefModel.get('dataMaskDef').resources)){
+ resourceDefList = this.rangerServiceDefModel.get('dataMaskDef').resources;
+ }
+ }
+ if(XAUtil.isRowFilterPolicy(this.model.get('policyType'))){
+ if(!_.isEmpty(this.rangerServiceDefModel.get('rowFilterDef').resources)){
+ resourceDefList = this.rangerServiceDefModel.get('rowFilterDef').resources;
+ }
+ }
+ return resourceDefList
}
});
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js
index 65c4f66..b1e7a11 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js
@@ -178,8 +178,9 @@
if(! _.isEmpty(errors)){
return;
}
-
-
+ if(this.form.validatePolicyResource()){
+ return;
+ }
//validate policyItems in the policy
var validateObj1 = this.form.formValidation(this.form.formInputList);
if(!this.validatePolicyItem(validateObj1)) return;
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js
index a672648..c26eaed 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js
@@ -26,18 +26,12 @@
var localization = require('utils/XALangSupport');
var XAUtil = require('utils/XAUtils');
- var VXAuditMap = require('models/VXAuditMap');
- var VXPermMap = require('models/VXPermMap');
- var VXPermMapList = require('collections/VXPermMapList');
- var VXGroupList = require('collections/VXGroupList');
- var VXAuditMapList = require('collections/VXAuditMapList');
- var VXUserList = require('collections/VXUserList');
var PermissionList = require('views/policies/PermissionList');
var vPolicyTimeList = require('views/policies/PolicyTimeList');
- var RangerPolicyResource = require('models/RangerPolicyResource');
var BackboneFormDataType = require('models/BackboneFormDataType');
var App = require('App');
var vPolicyCondition = require('views/policies/RangerPolicyConditions');
+ var ResourceList = require('views/policies/ResourceList');
require('backbone-forms.list');
require('backbone-forms.templates');
@@ -79,10 +73,10 @@
initialize: function(options) {
console.log("initialized a RangerPolicyForm Form View");
_.extend(this, _.pick(options, 'rangerServiceDefModel', 'rangerService'));
- this.setupForm();
Backbone.Form.prototype.initialize.call(this, options);
this.initializeCollection();
+ this.setupForm();
this.bindEvents();
this.defaultValidator={}
},
@@ -97,6 +91,7 @@
this.formInputAllowExceptionList= XAUtil.makeCollForGroupPermission(this.model, 'allowExceptions');
this.formInputDenyList = XAUtil.makeCollForGroupPermission(this.model, 'denyPolicyItems');
this.formInputDenyExceptionList = XAUtil.makeCollForGroupPermission(this.model, 'denyExceptions');
+ this.formInputResourceList = new Backbone.Collection();
},
/** all events binding here */
bindEvents : function(){
@@ -106,7 +101,6 @@
this.on('isEnabled:change', function(form, fieldEditor){
this.evIsEnabledChange(form, fieldEditor);
});
- this.on('policyForm:parentChildHideShow',this.renderParentChildHideShow);
},
ui : {
'denyConditionItems' : '[data-js="denyConditionItems"]',
@@ -123,35 +117,26 @@
return this.getSchema();
},
getSchema : function(){
- var attrs = {},that = this;
- var basicSchema = ['name','isEnabled','policyPriority','policyLabels'];
+ var basicSchema = ['name','isEnabled','policyPriority','policyLabels'];
var schemaNames = this.getPolicyBaseFieldNames();
-
- var formDataType = new BackboneFormDataType();
- attrs = formDataType.getFormElements(this.rangerServiceDefModel.get('resources'),this.rangerServiceDefModel.get('enums'), attrs, this, true);
- if(this.model.schemaBase){
- var attr1 = _.pick(_.result(this.model,'schemaBase'),basicSchema);
- var attr2 = _.pick(_.result(this.model,'schemaBase'),schemaNames);
- return _.extend(attr1,_.extend(attrs,attr2));
- }
+ if(this.model.schemaBase){
+ var attr1 = _.pick(_.result(this.model,'schemaBase'),basicSchema);
+ var attr2 = _.pick(_.result(this.model,'schemaBase'),schemaNames);
+ return _.extend(attr1,attr2);
+ }
},
/** on render callback */
render: function(options) {
var that = this;
Backbone.Form.prototype.render.call(this, options);
- //initialize path plugin for hdfs component : resourcePath
- if(!_.isUndefined(this.initilializePathPlugin) && this.initilializePathPlugin){
- this.initializePathPlugins(this.pathPluginOpts);
- }
if(XAUtil.isAccessPolicy(this.model.get('policyType'))){
this.evdenyAccessChange();
}
if(!this.model.isNew()){
this.setUpSwitches();
}
+ this.renderPolicyResource();
this.renderCustomFields();
- //checkParent
- this.renderParentChildHideShow();
//to show error msg on below the field(only for policy name)
if(this.fields.isEnabled){
@@ -343,60 +328,16 @@
},
setupForm : function() {
+ var that = this;
if(!this.model.isNew()){
- this.selectedResourceTypes = {};
- var resourceDefList = this.rangerServiceDefModel.get('resources');
- if(XAUtil.isMaskingPolicy(this.model.get('policyType')) && XAUtil.isRenderMasking(this.rangerServiceDefModel.get('dataMaskDef'))){
- if(!_.isEmpty(this.rangerServiceDefModel.get('dataMaskDef').resources)){
- resourceDefList = this.rangerServiceDefModel.get('dataMaskDef').resources;
- }
- }
- if(XAUtil.isRowFilterPolicy(this.model.get('policyType')) && XAUtil.isRenderRowFilter(this.rangerServiceDefModel.get('rowFilterDef'))){
- if(!_.isEmpty(this.rangerServiceDefModel.get('rowFilterDef').resources)){
- resourceDefList = this.rangerServiceDefModel.get('rowFilterDef').resources;
- }
- }
- _.each(this.model.get('resources'),function(obj,key){
- var resourceDef = _.findWhere(resourceDefList,{'name':key}),
- sameLevelResourceDef = [], parentResource ;
- sameLevelResourceDef = _.filter(resourceDefList, function(objRsc){
- if (objRsc.level === resourceDef.level && objRsc.parent === resourceDef.parent) {
- return objRsc
- }
- });
- //for parent leftnode status
- if(resourceDef.parent){
- parentResource = _.findWhere(resourceDefList ,{'name':resourceDef.parent});
- }
- if(sameLevelResourceDef.length == 1 && !_.isUndefined(sameLevelResourceDef[0].parent)
- && !_.isEmpty(sameLevelResourceDef[0].parent)
- && parentResource.isValidLeaf){
-// optionsAttrs.unshift({'level':v.level, name:'none',label:'none'});
- sameLevelResourceDef.push({'level':sameLevelResourceDef[0].level, name:'none',label:'none'});
- }
- if(sameLevelResourceDef.length > 1){
- obj['resourceType'] = key;
- if(_.isUndefined(resourceDef.parent)){
- this.model.set('sameLevel'+resourceDef.level, obj);
- //parentShowHide
- this.selectedResourceTypes['sameLevel'+resourceDef.level] = key;
- }else{
- this.model.set('sameLevel'+resourceDef.level+resourceDef.parent, obj);
- this.selectedResourceTypes['sameLevel'+resourceDef.level+resourceDef.parent] = key;
- }
+ var additionalResources = [this.model.get('resources')];
+ additionalResources = _.union(additionalResources, this.model.get('additionalResources'));
- }else{
- //single value support
- /*if(! XAUtil.isSinglevValueInput(resourceDef) ){
- this.model.set(resourceDef.name, obj)
- }else{
- //single value resource
- this.model.set(resourceDef.name, obj.values)
- }*/
- this.model.set(resourceDef.name, obj)
- }
- },this);
+ _.each(additionalResources, function(resources, index) {
+ that.formInputResourceList.add({resources: resources, id : "resource"+index, policyType: that.model.get('policyType'), ...resources});
+ });
}
+
},
setUpSwitches :function(){
var that = this;
@@ -461,96 +402,34 @@
}
},
- renderParentChildHideShow : function(onChangeOfSameLevelType, val, e) {
- var formDiv = this.$el.find('.policy-form');
- if(!this.model.isNew() && !onChangeOfSameLevelType){
- _.each(this.selectedResourceTypes, function(val, sameLevelName) {
- if(formDiv.find('.field-'+sameLevelName).length > 0){
- formDiv.find('.field-'+sameLevelName).attr('data-name','field-'+val)
- }
- });
- }
- //hide form fields if it's parent is hidden
- var resources = formDiv.find('.form-group');
- _.each(resources, function(rsrc , key ){
- var parent = $(rsrc).attr('parent');
- var label = $(rsrc).find('label').html();
- $(rsrc).removeClass('error');
-// remove validation and Required msg
- $(rsrc).find('.help-inline').empty();
- $(rsrc).find('.help-block').empty();
- if( !_.isUndefined(parent) && ! _.isEmpty(parent)){
- var selector = "div[data-name='field-"+parent+"']";
- var kclass = formDiv.find(selector).attr('class');
- var label = $(rsrc).find('label').html();
- if(_.isUndefined(kclass) || (kclass.indexOf("field-sameLevel") >= 0
- && formDiv.find(selector).find('select').val() != parent)
- || formDiv.find(selector).hasClass('hideResource')){
- $(rsrc).addClass('hideResource');
- $(rsrc).removeClass('error');
-// reset input field to "none" if it is hide
- var resorceFieldName = _.pick(this.schema ,this.selectedFields[key]);
- if(resorceFieldName[this.selectedFields[key]].sameLevelOpts && _.contains(resorceFieldName[this.selectedFields[key]].sameLevelOpts , 'none')
- && formDiv.find(selector).find('select').val() != 'none' && onChangeOfSameLevelType){
- //change trigger and set value to selected node
- $(rsrc).find('select').val($(rsrc).find('select option:nth-child(1)').text()).trigger('change',"onChangeResources");
- }
- }else{
- if($(rsrc).find('select').val() == 'none'){
- $(rsrc).find('input[data-js="resource"]').select2('disable');
- $(rsrc).removeClass('error');
- $(rsrc).find('label').html(label.split('*').join(''));
- }else{
- $(rsrc).find('input[data-js="resource"]').select2('enable');
- $(rsrc).find('label').html(label.slice(-1) == '*' ? label : label +"*");
- }
- $(rsrc).removeClass('hideResource');
- }
- }
- },this);
- //remove validation of fields if it's hidden
- //remove validation if fields is not empty
- _.each(this.fields, function(field, key){
- if((key.substring(0,key.length-2) === "sameLevel") && field.$el.find('[data-js="resource"]').val()!="" && field.$el.hasClass('error')){
- field.$el.removeClass('error');
- field.$el.find('.help-inline').empty();
- }
- if(field.$el.hasClass('hideResource')){
- if($.inArray('required',field.editor.validators) >= 0){
- this.defaultValidator[key] = field.editor.validators;
- field.editor.validators=[];
- var label = field.$el.find('label').html();
- field.$el.find('label').html(label.replace('*', ''));
- field.$el.removeClass('error');
- field.$el.find('.help-inline').empty();
- }
- }else{
- if(field.$el.find('select').val() == 'none'){
- field.editor.validators=[];
- this.defaultValidator[key] = field.editor.validators;
- field.$el.removeClass('error');
- field.$el.find('.help-inline').empty();
- }else{
- if(!_.isUndefined(this.defaultValidator[key])){
- field.editor.validators.push('required');
- if($.inArray('required',field.editor.validators) >= 0){
- var label = field.$el.find('label').html();
- field.$el.find('label').html(label.slice(-1) == '*' ? label : label +"*");
- }
+ beforeSave : function(){
+ var additionResources = [];
+ //set sameLevel fieldAttr value with resource name
+ this.formInputResourceList.each(function(model) {
+ let resource = {}
+ _.each(model.attributes, function(val, key) {
+ var isSameLevelResource = key.indexOf("sameLevel") >= 0, isResource = !['policyType', 'resourceForm', 'none', 'resources','id'].includes(key);
+ if ((isSameLevelResource || isResource) && !_.isNull(val)) {
+ var resourceName = isSameLevelResource ? val.resourceType : key;
+ if(resourceName && resourceName != 'none'){
+ model.set(resourceName, val);
+ resource[resourceName] = {
+ values: _.isObject(val.resource[0]) ? _.pluck(val.resource, 'text') : val.resource
+ };
+ if(!_.isUndefined(val.isRecursive)){
+ resource[resourceName]['isRecursive'] = val.isRecursive;
+ }
+ if(!_.isUndefined(val.isExcludes)){
+ resource[resourceName]['isExcludes'] = val.isExcludes;
+ }
+ }
+ if(isSameLevelResource) {
+ model.unset(key);
}
}
- }
- }, this);
- },
- beforeSave : function(){
- var that = this, resources = {};
- //set sameLevel fieldAttr value with resource name
- _.each(this.model.attributes, function(val, key) {
- if(key.indexOf("sameLevel") >= 0 && !_.isNull(val)){
- this.model.set(val.resourceType,val);
- that.model.unset(key);
- }
- },this);
+ }, this);
+ additionResources.push(resource);
+ });
//To set resource values
//Check for masking policies
var resourceDef = this.rangerServiceDefModel.get('resources');
@@ -564,37 +443,7 @@
if(XAUtil.isRowFilterPolicy(this.model.get('policyType')) && XAUtil.isRenderRowFilter(this.rangerServiceDefModel.get('rowFilterDef'))){
resourceDef = this.rangerServiceDefModel.get('rowFilterDef').resources;
}
- _.each(resourceDef,function(obj){
- if(!_.isNull(obj)){
- var tmpObj = that.model.get(obj.name);
- var rPolicyResource = new RangerPolicyResource();
- //single value support
-// if(! XAUtil.isSinglevValueInput(obj) ){
- if(!_.isUndefined(tmpObj) && _.isObject(tmpObj) && !_.isEmpty(tmpObj.resource)){
- rPolicyResource.set('values',_.map(tmpObj.resource, function(m) {
- if(obj.type == "path") {
- return m
- } else {
- return m.text
- }
- }));
- if(!_.isUndefined(tmpObj.isRecursive)){
- rPolicyResource.set('isRecursive', tmpObj.isRecursive)
- }
- if(!_.isUndefined(tmpObj.isExcludes)){
- rPolicyResource.set('isExcludes', tmpObj.isExcludes)
- }
- resources[obj.name] = rPolicyResource;
- that.model.unset(obj.name);
- }
-// }else{
-// //For single value resource
-// rPolicyResource.set('values',tmpObj.split(','));
-// resources[obj.name] = rPolicyResource;
-// that.model.unset(obj.name);
-// }
- }
- });
+
if(this.model.has('policyLabels')){
var policyLabel = _.isEmpty(this.model.get('policyLabels')) ? [] : this.model.get('policyLabels').split(',');
this.model.set('policyLabels', policyLabel);
@@ -602,7 +451,9 @@
if(!_.isUndefined(App.vZone) && App.vZone.vZoneName){
this.model.set('zoneName', App.vZone.vZoneName);
}
- this.model.set('resources',resources);
+ this.model.set('resources',additionResources[0]);
+ additionResources.shift();
+ this.model.set('additionalResources',additionResources);
if(this.model.get('none')) {
this.model.unset('none');
}
@@ -681,227 +532,6 @@
}, this);
return policyItemList;
},
- /** all post render plugin initialization */
- initializePathPlugins: function(options){
- var that= this,defaultValue = [];
- if(!this.model.isNew() && !_.isUndefined(this.model.get('path'))){
- defaultValue = this.model.get('path').values;
- }
- var tagitOpts = {}
- if(!_.isUndefined(options.lookupURL) && options.lookupURL){
- tagitOpts["autocomplete"] = {
- cache: false,
- source: function( request, response ) {
- var url = "service/plugins/services/lookupResource/"+that.rangerService.get('name');
- var context ={
- 'userInput' : request.term,
- 'resourceName' : that.pathFieldName,
- 'resources' : {}
- };
- var val = that.fields[that.pathFieldName].editor.getValue('pathField');
- context.resources[that.pathFieldName] = _.isNull(val) || _.isEmpty(val) ? [] : val.resource;
- var p = $.ajax({
- url : url,
- type : "POST",
- data : JSON.stringify(context),
- dataType : 'json',
- contentType: "application/json; charset=utf-8",
- }).done(function(data){
- if(data){
- response(data);
- } else {
- response();
- }
- }).fail(function(responses){
- if (responses && responses.responseJSON && responses.responseJSON.msgDesc) {
- XAUtil.notifyError('Error', responses.responseJSON.msgDesc);
- } else {
- XAUtil.notifyError('Error', localization.tt('msg.resourcesLookup'));
- }
- response();
- });
- setTimeout(function(){
- p.abort();
- console.log('connection timeout for resource path request...!!');
- }, 10000);
- },
- open : function(){
- $(this).removeClass('working');
- },
- search: function() {
- if(!_.isUndefined(this.value) && this.value.includes('||')) {
- var values = this.value.trim().split('||');
- if (values.length > 1) {
- for (var i = 0; i < values.length; i++) {
- that.fields[that.pathFieldName].editor.$el.find('[data-js="resource"]').tagit("createTag", values[i]);
- }
- return ''
- } else {
- return val
- }
- }
- }
- }
- }
- tagitOpts['beforeTagAdded'] = function(event, ui) {
- // do something special
- that.fields[that.pathFieldName].$el.removeClass('error');
- that.fields[that.pathFieldName].$el.find('.help-inline').html('');
- var tags = [];
- if(!_.isUndefined(options.regExpValidation) && !options.regExpValidation.regexp.test(ui.tagLabel)){
- that.fields[that.pathFieldName].$el.addClass('error');
- that.fields[that.pathFieldName].$el.find('.help-inline').html(options.regExpValidation.message);
- return false;
- }
- }
- tagitOpts['singleFieldDelimiter'] = '||';
- tagitOpts['singleField'] = false;
- this.fields[that.pathFieldName].editor.$el.find('input[data-js="resource"]').tagit(tagitOpts).on('change', function(e){
- //check dirty field for tagit input type : `path`
- XAUtil.checkDirtyField($(e.currentTarget).val(), defaultValue.toString(), $(e.currentTarget));
- });
- },
- getPlugginAttr :function(autocomplete, options){
- var that =this, type = options.containerCssClass, validRegExpString = true, select2Opts=[];
- if(!autocomplete)
- return{tags : true,width :'220px',multiple: true,minimumInputLength: 1, 'containerCssClass' : type};
- else {
- select2Opts = {
- containerCssClass : options.type,
- closeOnSelect : true,
- tags:true,
- multiple: true,
- width :'220px',
- tokenSeparators: [' '],
- initSelection : function (element, callback) {
- var data = [];
- //to set single select value
- if(_.isArray(JSON.parse(element.val()))) {
- $(JSON.parse(element.val())).each(function () {
- data.push({id: this, text: this});
- })
- }
- callback(data);
- },
- createSearchChoice: function(term, data) {
- term = _.escape(term);
- if ($(data).filter(function() {
- return this.text.localeCompare(term) === 0;
- }).length === 0) {
- if(!_.isUndefined(options.regExpValidation) && !options.regExpValidation.regexp.test(term)){
- validRegExpString = false;
- }else if($.inArray(term, this.val()) >= 0){
- return null;
- }else{
- return {
- id : "<b><i class='text-muted-select2'>Create</i></b> " + term,
- text: term,
- };
- }
- }
- },
- ajax: {
- url: options.lookupURL,
- type : 'POST',
- params : {
- timeout: 10000,
- contentType: "application/json; charset=utf-8",
- },
- cache: false,
- data: function (term, page) {
- return that.getDataParams(term, options);
- },
- results: function (data, page) {
- var results = [];
- if(!_.isUndefined(data)){
- if(_.isArray(data) && data.length > 0){
- results = data.map(function(m, i){ return {id : m, text: m}; });
- }
- if(!_.isUndefined(data.resultSize) && data.resultSize != "0"){
- results = data.vXStrings.map(function(m, i){ return {id : m.value, text: m.value}; });
- }
- }
- return {
- results : results
- };
- },
- transport: function (options) {
- $.ajax(options).fail(function(response) {
- if (response && response.responseJSON && response.responseJSON.msgDesc) {
- XAUtil.notifyError('Error', response.responseJSON.msgDesc);
- } else {
- XAUtil.notifyError('Error', localization.tt('msg.resourcesLookup'));
- }
- this.success({
- resultSize : 0
- });
- });
- }
-
- },
- formatResult : function(result){
- return result.id;
- },
- formatSelection : function(result){
- return result.text;
- },
- formatNoMatches : function(term){
- if(!validRegExpString && !_.isUndefined(options.regExpValidation)){
- return options.regExpValidation.message;
- }
- return "No Matches found";
- }
- };
- //To support single value input
- if(!_.isUndefined(options.singleValueInput) && options.singleValueInput){
- select2Opts['maximumSelectionSize'] = 1;
- }
- return select2Opts;
- }
- },
- getDataParams : function(term, options) {
- var resources = {},resourceName = options.type, dataResources = {};
- var isParent = true, name = options.type, val = null,isCurrentSameLevelField = true;
- while(isParent){
- var currentResource = _.findWhere(this.getResources(), {'name': name });
- //same level type
- if(_.isUndefined(this.fields[currentResource.name])){
- if(!_.isUndefined(currentResource.parent)){
- var sameLevelName = 'sameLevel'+currentResource.level + currentResource.parent;
- }else{
- var sameLevelName = 'sameLevel'+currentResource.level;
- }
-
- name = this.fields[sameLevelName].editor.$resourceType.val()
- val = this.fields[sameLevelName].getValue();
- if(isCurrentSameLevelField){
- resourceName = name;
- }
- }else{
- val = this.fields[name].getValue();
- }
- resources[name] = _.isNull(val) ? [] : val.resource;
- if(!_.isEmpty(currentResource.parent)){
- name = currentResource.parent;
- }else{
- isParent = false;
- }
- isCurrentSameLevelField = false;
- }
- if(resources && !_.isEmpty(resources)) {
- _.each(resources, function(val, key) {
- dataResources[key] = _.map(val, function(obj){
- return obj.text
- })
- })
- }
- var context ={
- 'userInput' : term,
- 'resourceName' : resourceName,
- 'resources' : dataResources
- };
- return JSON.stringify(context);
- },
formValidation : function(coll){
var groupSet = false , permSet = false , groupPermSet = false , delegateAdmin = false ,
userSet=false, userPerm = false, userPermSet =false,breakFlag =false, condSet = false,customMaskSet = true,
@@ -987,6 +617,23 @@
}
return this.rangerServiceDefModel.get('resources');
},
+ renderPolicyResource : function (){
+ this.policyResourceForm = new ResourceList({
+ collection : this.formInputResourceList,
+ rangerPolicyModel: this.model,
+ rangerServiceDefModel : this.rangerServiceDefModel,
+ rangerService: this.rangerService,
+ }).render();
+ this.$('[data-customfields="policyResources"]').html(this.policyResourceForm.el);
+ },
+ validatePolicyResource : function (){
+ var errors = null;
+ _.some(this.formInputResourceList.models, function(model) {
+ errors = model.get('resourceForm').commit({validate : false});
+ return ! _.isEmpty(errors);
+ });
+ return errors;
+ }
});
return RangerPolicyForm;
});
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js
index ba94e6f..89d35fd 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js
@@ -134,21 +134,29 @@
resourceDef = this.serviceDef.get('rowFilterDef').resources;
}
}
- _.each(resourceDef, function(def, i){
- if(!_.isUndefined(this.policy.get('resources')[def.name])){
- var resource = {},
- policyResources = this.policy.get('resources')[def.name];
- resource.label = def.label;
- resource.values = policyResources.values;
- if(def.recursiveSupported){
- resource.Rec_Recursive = policyResources.isRecursive ? XAEnums.RecursiveStatus.STATUS_RECURSIVE.label : XAEnums.RecursiveStatus.STATUS_NONRECURSIVE.label;
+ var resources = this.policy.get('resources');
+ if(this.policy.has('additionalResources')){
+ resources = _.union([resources], this.policy.get('additionalResources'));
+ }
+ _.each(resources, function (resourceObj) {
+ var detailResource = [];
+ _.each(resourceDef, function(def, i){
+ if(!_.isUndefined(resourceObj[def.name])){
+ var resource = {}, policyResources = resourceObj[def.name];
+ resource.label = def.label;
+ resource.values = policyResources.values;
+ if(def.recursiveSupported){
+ resource.Rec_Recursive = policyResources.isRecursive ? XAEnums.RecursiveStatus.STATUS_RECURSIVE.label : XAEnums.RecursiveStatus.STATUS_NONRECURSIVE.label;
+ }
+ if(def.excludesSupported){
+ resource.Rec_Exc = policyResources.isExcludes ? XAEnums.ExcludeStatus.STATUS_EXCLUDE.label : XAEnums.ExcludeStatus.STATUS_INCLUDE.label;
+ }
+ detailResource.push(resource);
}
- if(def.excludesSupported){
- resource.Rec_Exc = policyResources.isExcludes ? XAEnums.ExcludeStatus.STATUS_EXCLUDE.label : XAEnums.ExcludeStatus.STATUS_INCLUDE.label;
- }
- details.resources.push(resource);
- }
- }, this);
+ }, this);
+ details.resources.push(detailResource);
+ })
+
details.policyLabels = this.policy.get('policyLabels');
details.zoneName = this.policy.get('zoneName');
var perm = details.permissions = this.getPermHeaders();
diff --git a/security-admin/src/main/webapp/scripts/views/policies/ResourceList.js b/security-admin/src/main/webapp/scripts/views/policies/ResourceList.js
new file mode 100644
index 0000000..aa604a7
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/views/policies/ResourceList.js
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+ /*
+ *
+ */
+define(function(require) {
+ 'use strict';
+
+ var Backbone = require('backbone');
+ var Vent = require('modules/Vent');
+ var XAUtils = require('utils/XAUtils');
+
+ var ZoneResourceForm = require('views/security_zone/ZoneResourceForm');
+
+ var ResourceItem = Backbone.Marionette.ItemView.extend({
+ _msvName : 'ResourceItem',
+ template : require('hbs!tmpl/policies/ResourceItem_tmpl'),
+ ui : {
+ 'deleteBtn' : '[data-action="delete"]'
+ },
+ events : {
+ 'click [data-action="delete"]' : 'evDelete',
+
+ },
+
+ initialize : function(options) {
+ _.extend(this, _.pick(options,'rangerPolicyModel', 'rangerServiceDefModel','rangerService','storeResourceRef'));
+ },
+
+ onRender : function() {
+ this.renderPolicyResource();
+ if(this.model.collection.length === 1){
+ this.ui.deleteBtn.hide();
+ }else{
+ this.ui.deleteBtn.show();
+ }
+
+
+ },
+ renderPolicyResource : function (){
+ this.resourceForm = new ZoneResourceForm({
+ model: this.model,
+ rangerServiceDefModel: this.rangerServiceDefModel,
+ rangerService: this.rangerService,
+ isPolicyResource: true
+ });
+ this.resourceForm.render();
+ this.$('[data-customfields="resource-item"]').html(this.resourceForm.el);
+ this.model.attributes.resourceForm = this.resourceForm;
+ var resourceItemIndex = this.model && this.model.collection.indexOf(this.model);
+ var resourceName = this.getLastResourceName()
+ Vent.trigger('resourceType:change', { changeType : 'resourceType', value : resourceName, resourceName : resourceName, resourceItemIndex : resourceItemIndex, action : 'added' });
+
+ },
+ evDelete : function(){
+ var resourceItemIndex = this.model && this.model.collection.indexOf(this.model);
+ Vent.trigger('resourceType:change', { resourceItemIndex : resourceItemIndex, action : 'removed' });
+ this.collection.remove(this.model);
+ },
+ getResourceName : function (resource, resourceDef){
+ var found = _.findWhere(resourceDef,{'parent': resource.name });
+ if(found){
+ return this.getResourceName(found, resourceDef);
+ }else {
+ return resource.name;
+ }
+ },
+ getLastResourceName : function (){
+ var resourceDef = XAUtils.policyTypeResources(this.rangerServiceDefModel, this.model.get('policyType'));
+ return this.getResourceName(resourceDef[0], resourceDef);
+ }
+
+ });
+
+ return Backbone.Marionette.CompositeView.extend({
+ _msvName : 'PermissionItemList',
+ template : require('hbs!tmpl/policies/ResourceList_tmpl'),
+ templateHelpers: function() {
+ return { resourceCnt : this.collection.length };
+ },
+ getItemView : function(item){
+ if(!item){
+ return;
+ }
+ return ResourceItem;
+ },
+ itemViewContainer : ".js-formInput",
+ itemViewOptions : function() {
+ return {
+ 'collection' : this.collection,
+ 'rangerPolicyModel' : this.rangerPolicyModel,
+ 'rangerServiceDefModel' : this.rangerServiceDefModel,
+ 'rangerService' : this.rangerService,
+ };
+ },
+ ui : {
+ 'showAllResourceChbox' : '[data-js="showAllResourceChbox"]',
+ },
+ events : {
+ 'click [data-action="addGroup"]' : 'addNew',
+ 'click [data-js="showAllResourceChbox"]' : 'onShowAllResource'
+ },
+ collectionEvents: {
+ 'add': 'onAdd',
+ 'remove': 'onRemove'
+ },
+ initialize : function(options) {
+ _.extend(this, _.pick(options, 'rangerPolicyModel', 'rangerServiceDefModel','rangerService'));
+ if(this.collection.length == 0){
+ this.collection.add(new Backbone.Model({ policyType: this.rangerPolicyModel.get('policyType') }))
+ }
+ this.storeResourceRef = {};
+ this.hideFirstResource = false;
+ },
+ onRender : function(){
+ if(this.hideFirstResource){
+ this.$el.find('.additional-resource:not(:first)').hide();
+ this.hideFirstResource = false;
+ }
+
+ },
+
+ addNew : function(){
+ if (!this.ui.showAllResourceChbox.prop("checked")) {
+ this.ui.showAllResourceChbox.trigger('click');
+ }
+ this.collection.add(new Backbone.Model({ policyType: this.rangerPolicyModel.get('policyType') }));
+ },
+ onShowAllResource : function(){
+
+ if (this.ui.showAllResourceChbox.prop("checked")) {
+ this.$el.find('.additional-resource').show();
+ }else {
+ this.$el.find('.additional-resource:not(:first)').hide()
+ }
+ },
+ onAdd : function (){
+ this.$el.find('[data-js="resource-count"]').html(this.collection.length);
+ this.toggleDeleteBtn();
+ },
+ onRemove : function (){
+ this.onAdd();
+ this.toggleDeleteBtn();
+ },
+ toggleDeleteBtn : function (){
+ if(this.collection.length === 1){
+ this.$el.find('.additional-resource .btn-danger').hide();
+ }else {
+ this.$el.find('.additional-resource .btn-danger').show();
+ }
+ }
+ });
+
+});
diff --git a/security-admin/src/main/webapp/scripts/views/security_zone/ZoneResourceForm.js b/security-admin/src/main/webapp/scripts/views/security_zone/ZoneResourceForm.js
index 900d9da..33b01df 100644
--- a/security-admin/src/main/webapp/scripts/views/security_zone/ZoneResourceForm.js
+++ b/security-admin/src/main/webapp/scripts/views/security_zone/ZoneResourceForm.js
@@ -42,18 +42,17 @@
* @constructs
*/
- templateData: function() {
- var policyType = XAUtil.enumElementByValue(XAEnums.RangerPolicyType, this.model.get('policyType'));
+ template: require('hbs!tmpl/security_zone/ZoneResourcesForm_tmpl'),
+ templateData : function(){
return {
- 'id': this.model.id,
- 'policyType': policyType.label,
- 'policyTimeBtnLabel': (this.model.has('validitySchedules') && this.model.get('validitySchedules').length > 0) ? localization.tt('lbl.editValidityPeriod') : localization.tt('lbl.addValidityPeriod')
- };
+ isPolicyResource : this.isPolicyResource
+ }
},
initialize: function(options) {
console.log("initialized a RangerZoneResourceForm Form View");
- _.extend(this, _.pick(options, 'rangerServiceDefModel', 'rangerService'));
+ _.extend(this, _.pick(options, 'rangerServiceDefModel', 'rangerService', 'isPolicyResource'));
+ this.isPolicyResource = this.isPolicyResource ? this.isPolicyResource : false;
this.setupForm();
Backbone.Form.prototype.initialize.call(this, options);
this.bindEvents();
@@ -79,11 +78,14 @@
var attrs = {},
that = this;
var formDataType = new BackboneFormDataType();
- _.each(this.rangerServiceDefModel.get('resources'), function(m) {
- if (_.has(m, 'parent')) {
- m.mandatory = false;
- }
- })
+ if(!this.isPolicyResource){
+ _.each(this.rangerServiceDefModel.get('resources'), function(m) {
+ if (_.has(m, 'parent')) {
+ m.mandatory = false;
+ }
+ })
+ }
+
attrs = formDataType.getFormElements(this.rangerServiceDefModel.get('resources'), this.rangerServiceDefModel.get('enums'), attrs, this, true);
return attrs;
},
@@ -150,7 +152,7 @@
/** all custom field rendering */
renderParentChildHideShow: function(onChangeOfSameLevelType, val, e) {
- var formDiv = this.$el.find('.zoneResources-form');
+ var formDiv = this.$el.find('.form-resources');
if (!this.model.isNew() && !onChangeOfSameLevelType) {
_.each(this.selectedResourceTypes, function(val, sameLevelName) {
if (formDiv.find('.field-' + sameLevelName).length > 0) {
@@ -342,8 +344,8 @@
//to set single select value
if (!_.isUndefined(options.singleValueInput) && options.singleValueInput) {
callback({
- id: element.val(),
- text: element.val()
+ id: JSON.parse(element.val())[0],
+ text: JSON.parse(element.val())[0]
});
return;
}
diff --git a/security-admin/src/main/webapp/scripts/views/service/ServiceAuditFilterResources.js b/security-admin/src/main/webapp/scripts/views/service/ServiceAuditFilterResources.js
index 683fa4b..7340236 100644
--- a/security-admin/src/main/webapp/scripts/views/service/ServiceAuditFilterResources.js
+++ b/security-admin/src/main/webapp/scripts/views/service/ServiceAuditFilterResources.js
@@ -144,7 +144,7 @@
/** all custom field rendering */
renderParentChildHideShow: function(onChangeOfSameLevelType, val, e) {
- var formDiv = this.$el.find('.zoneResources-form');
+ var formDiv = this.$el.find('.form-resources');
if (!this.model.isNew() && !onChangeOfSameLevelType) {
_.each(this.selectedResourceTypes, function(val, sameLevelName) {
if (formDiv.find('.field-' + sameLevelName).length > 0) {
diff --git a/security-admin/src/main/webapp/styles/xa.css b/security-admin/src/main/webapp/styles/xa.css
index 2da2f29..52f9128 100644
--- a/security-admin/src/main/webapp/styles/xa.css
+++ b/security-admin/src/main/webapp/styles/xa.css
@@ -1782,7 +1782,7 @@
}
.include-toggle{
margin-left: 360px;
- margin-top: -29px;
+ margin-top: -35px;
width:80px;
position: relative;
top: 7px;
@@ -2248,7 +2248,7 @@
}
.include-toggle-1{
margin-left: 23vw;
- margin-top: -29px;
+ margin-top: -4px;
}
.expanded-contant .include-toggle-1{
margin-left: 18.4vw;
@@ -4093,7 +4093,7 @@
*/
.ranger-policy .form-group.field-isEnabled .policy-enable-disable{
margin-left: 38vw;
- margin-top: -75px;
+ margin-top: -69px;
width: 100px
}
@@ -4103,7 +4103,7 @@
.ranger-policy .form-group.field-policyPriority .policy-priority{
margin-left: 45vw;
- margin-top: -80px;
+ margin-top: -73px;
width: 100px
}
.expanded-contant .form-group.field-policyPriority .policy-priority {
@@ -4428,10 +4428,6 @@
top: -30px;
}
-.form-group.field-policyLabels {
- margin-bottom: 40px;
-}
-
.ranger-policy .form-group.field-isEnabled > label,
.ranger-policy .form-group.field-policyPriority > label {
display: none;
@@ -4717,4 +4713,24 @@
background: #eeeeee;
width: 100%;
display: inline-block;
+}
+
+.js-formInput .policy-resources .select2-container {
+ width: 274px !important;
+}
+.form-resources.policy-resources .form-control.rosource-boder {
+ padding: 0px !important;
+}
+.form-resources.policy-resources .sameLevelDropdown {
+ margin-right: 31px !important;
+ margin-left: -150px !important;
+}
+.show-all-resource {
+ margin-top: -50px;
+}
+.policy-resources .form-group[fieldclass="resorces-css"] {
+ margin-bottom: 0px !important;
+}
+.wrap.position-relative.additional-resource{
+ padding: 20px 20px 0px 20px !important;
}
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/helpers/XAHelpers.js b/security-admin/src/main/webapp/templates/helpers/XAHelpers.js
index e466f62..accef88 100644
--- a/security-admin/src/main/webapp/templates/helpers/XAHelpers.js
+++ b/security-admin/src/main/webapp/templates/helpers/XAHelpers.js
@@ -619,6 +619,9 @@
}
return '<div class="margin-bottom-5 display-block"><label><span>'+obj.label+' : </span></label><input type="input" data-id="inputField" name="'+obj.name+'" ></div>'
});
+ Handlebars.registerHelper("inc", function(value, options) {
+ return parseInt(value) + 1;
+ });
return HHelpers;
});
diff --git a/security-admin/src/main/webapp/templates/policies/RangerPolicyForm_tmpl.html b/security-admin/src/main/webapp/templates/policies/RangerPolicyForm_tmpl.html
index e314e83..864a399 100644
--- a/security-admin/src/main/webapp/templates/policies/RangerPolicyForm_tmpl.html
+++ b/security-admin/src/main/webapp/templates/policies/RangerPolicyForm_tmpl.html
@@ -64,6 +64,15 @@
</div>
</fieldset>
<fieldset>
+ <p class="wrap-header bold formHeader">
+ Resources : <span class="badge badge-yellow pull-right"></span>
+ </p>
+
+ <div>
+ <div data-customfields="policyResources" />
+ </div>
+ </fieldset>
+ <fieldset>
<p class="wrap-header bold formHeader">
{{conditionType}} Conditions: <span class="badge badge-yellow pull-right"></span>
</p>
diff --git a/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html b/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html
index 1edfe24..d4bcdbe 100644
--- a/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html
+++ b/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html
@@ -83,20 +83,6 @@
{{/ifCond}}
</td>
</tr>
- {{#each PolicyDetails.resources}}
- <tr>
- <td>
- {{this.label}}
- </td>
- <td>
- {{#each this.values}}
- <span class="badge badge-info">{{this}}</span>
- {{/each}}
- <span class="badge badge-dark pull-right m-l-sm">{{this.Rec_Recursive}}</span>
- <span class="badge badge-dark pull-right">{{this.Rec_Exc}}</span>
- </td>
- </tr>
- {{/each}}
<tr>
<td>
{{tt 'lbl.description'}}
@@ -135,6 +121,34 @@
</table>
</div>
</div>
+<div class="">
+ <p class="formHeader">Policy Resource :</p>
+ {{#each PolicyDetails.resources}}
+ <div class="table-responsive">
+ <table class="table table-bordered table-condensed backgrid">
+ <thead><th colspan="2" class="text-left">#{{inc @index}}</th></thead>
+ <tbody>
+ {{#each this}}
+ <tr>
+ <td>
+ {{this.label}}
+ </td>
+ <td>
+ {{#each this.values}}
+ <span class="badge badge-info">{{this}}</span>
+ {{/each}}
+ <span class="badge badge-dark pull-right m-l-sm">{{this.Rec_Recursive}}</span>
+ <span class="badge badge-dark pull-right">{{this.Rec_Exc}}</span>
+ </td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+ </div>
+ <br/>
+ {{/each}}
+
+</div>
{{#if PolicyDetails.validitySchedules}}
<div id="policyItems" class="">
<p class="formHeader">Validity Period :<i class="fa-fw fa fa-time fa-fw fa fa-large pull-right"></i></p>
diff --git a/security-admin/src/main/webapp/templates/policies/ResourceItem_tmpl.html b/security-admin/src/main/webapp/templates/policies/ResourceItem_tmpl.html
new file mode 100644
index 0000000..1c270e6
--- /dev/null
+++ b/security-admin/src/main/webapp/templates/policies/ResourceItem_tmpl.html
@@ -0,0 +1,26 @@
+{{!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--}}
+<div class="wrap position-relative additional-resource">
+
+ <div class="pull-right">
+ <button type="button" class="btn btn-sm btn-danger " data-action="delete">
+ <i class="fa-fw fa fa-remove"></i>
+ </button>
+ </div>
+
+ <div data-customfields="resource-item"></div>
+</div>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/policies/ResourceList_tmpl.html b/security-admin/src/main/webapp/templates/policies/ResourceList_tmpl.html
new file mode 100644
index 0000000..931c450
--- /dev/null
+++ b/security-admin/src/main/webapp/templates/policies/ResourceList_tmpl.html
@@ -0,0 +1,37 @@
+{{!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--}}
+<!--div class="col-md-12">
+ <div class="pull-right show-all-resource">
+ <input id="one" type="checkbox" data-js="showAllResourceChbox" style="vertical-align: middle;"/>
+ <label for="one">
+ <i class="icon" aria-hidden="true"></i> <b>Show All (<span data-js="resource-count">{{resourceCnt}}</span>)</b>
+ </label>
+ </div>
+</div-->
+<div class="form-group">
+ <div class="col-md-8 m-t-sm">
+ <div class="js-formInput">
+ </div>
+ </div>
+</div>
+<div class="form-group">
+ <div class="col-md-8 m-t-sm">
+ <button type="button" class="btn btn-primary btn-sm" data-action="addGroup" title="Add">
+ <i class="fa-fw fa fa-plus"></i> Add Resource
+ </button>
+ </div>
+</div>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/security_zone/ZoneResourcesForm_tmpl.html b/security-admin/src/main/webapp/templates/security_zone/ZoneResourcesForm_tmpl.html
index d3ed5ab..9212e2e 100644
--- a/security-admin/src/main/webapp/templates/security_zone/ZoneResourcesForm_tmpl.html
+++ b/security-admin/src/main/webapp/templates/security_zone/ZoneResourcesForm_tmpl.html
@@ -12,6 +12,10 @@
language governing permissions and limitations under the License. --}}
<form class="form-horizontal">
<fieldset>
- <b data-fieldsets class="zoneResources-form"></b>
+ {{#if isPolicyResource}}
+ <div data-fieldsets class="form-resources policy-resources"></div>
+ {{else}}
+ <div data-fieldsets class="form-resources zoneResources-form"></div>
+ {{/if}}
</fieldset>
</form>
\ No newline at end of file