Merge "Add Angular keystone role deletion action"

This commit is contained in:
Jenkins 2017-02-14 04:09:57 +00:00 committed by Gerrit Code Review
commit a265d8cd64
4 changed files with 238 additions and 1 deletions

View File

@ -18,7 +18,8 @@
angular
.module('horizon.framework.util.i18n', [])
.factory('horizon.framework.util.i18n.gettext', getText);
.factory('horizon.framework.util.i18n.gettext', getText)
.factory('horizon.framework.util.i18n.ngettext', nGetText);
getText.$inject = ['$window'];
@ -52,4 +53,27 @@
return gettextFunc.apply(this, arguments);
};
}
nGetText.$inject = ['$window'];
/**
* @name horizon.framework.util.i18n.ngettext
* @description
* Provides a wrapper for translation, using the global 'ngettext'
* function if it is present. Provides a method that
* simply returns the input if the expected global 'ngettext' is
* not provided.
*/
function nGetText($window) {
// If no global function, revert to just returning given text.
var nGettextFunc = $window.ngettext || function (x) {
return x;
};
// Eventually, could delete the window ngettext references here,
// or provide an appropriate method.
return function () {
return nGettextFunc.apply(this, arguments);
};
}
})();

View File

@ -33,15 +33,38 @@
registerRoleActions.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.identity.roles.actions.create.service',
'horizon.dashboard.identity.roles.actions.delete.service',
'horizon.dashboard.identity.roles.resourceType'
];
function registerRoleActions(
registry,
createService,
deleteService,
roleResourceTypeCode
) {
var roleResourceType = registry.getResourceType(roleResourceTypeCode);
roleResourceType.itemActions
.append({
id: 'deleteAction',
service: deleteService,
template: {
text: gettext('Delete Role'),
type: 'delete'
}
});
roleResourceType.batchActions
.append({
id: 'batchDeleteAction',
service: deleteService,
template: {
type: 'delete-selected',
text: gettext('Delete Roles')
}
});
roleResourceType.globalActions
.append({
id: 'createRoleAction',

View File

@ -0,0 +1,107 @@
/**
* Copyright 2016 99Cloud
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use self 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.
*/
(function() {
'use strict';
angular
.module('horizon.dashboard.identity.roles')
.factory('horizon.dashboard.identity.roles.actions.delete.service', deleteRoleService);
deleteRoleService.$inject = [
'horizon.app.core.openstack-service-api.keystone',
'horizon.app.core.openstack-service-api.policy',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.i18n.ngettext',
'horizon.framework.widgets.modal.deleteModalService',
'horizon.dashboard.identity.roles.resourceType'
];
/*
* @ngdoc factory
* @name horizon.dashboard.identity.roles.actions.delete.service
*
* @Description
* Brings up the delete roles confirmation modal dialog.
* On submit, delete given roles.
* On cancel, do nothing.
*/
function deleteRoleService(
keystone,
policy,
actionResultService,
ngettext,
deleteModal,
roleResourceType
) {
return {
allowed: allowed,
perform: perform,
deleteResult: deleteResult // exposed just for testing
};
//////////////
function allowed() {
return policy.ifAllowed({rules: [[ 'identity', 'identity:delete_role' ]]});
}
function perform(items, scope) {
var roles = angular.isArray(items) ? items : [items];
var context = {
labels: labelize(roles.length),
deleteEntity: function deleteRole(role) {
return keystone.deleteRole(role);
}
};
return deleteModal.open(scope, roles, context).then(deleteResult);
}
function deleteResult(deleteModalResult) {
// To make the result of this action generically useful, reformat the return
// from the deleteModal into a standard form
var actionResult = actionResultService.getActionResult();
deleteModalResult.pass.forEach(function markDeleted(item) {
actionResult.deleted(roleResourceType, item.context.id);
});
deleteModalResult.fail.forEach(function markFailed(item) {
actionResult.failed(roleResourceType, item.context.id);
});
return actionResult.result;
}
function labelize(count) {
return {
title: ngettext(
'Confirm Delete Role',
'Confirm Delete Roles', count),
message: ngettext(
'You have selected "%s". Deleted role is not recoverable.',
'You have selected "%s". Deleted roles are not recoverable.', count),
submit: ngettext(
'Delete Role',
'Delete Roles', count),
success: ngettext(
'Deleted Role: %s.',
'Deleted Roles: %s.', count),
error: ngettext(
'Unable to delete Role: %s.',
'Unable to delete Roles: %s.', count)
};
}
}
})();

View File

@ -0,0 +1,83 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use self 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.
*/
(function() {
'use strict';
describe('horizon.dashboard.identity.roles.actions.delete.service', function() {
beforeEach(module('horizon.app.core'));
beforeEach(module('horizon.dashboard.identity.roles'));
beforeEach(module('horizon.framework'));
var deleteModalService, service, keystoneAPI, policyAPI;
beforeEach(inject(function($injector) {
service = $injector.get('horizon.dashboard.identity.roles.actions.delete.service');
keystoneAPI = $injector.get('horizon.app.core.openstack-service-api.keystone');
deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService');
policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy');
}));
describe('perform method', function() {
beforeEach(function () {
// just need for this to return something that looks like a promise but does nothing
spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop});
});
it('should open the modal with correct label for single entity', function test() {
service.perform({name: 'spam'});
var labels = deleteModalService.open.calls.argsFor(0)[2].labels;
expect(deleteModalService.open).toHaveBeenCalled();
angular.forEach(labels, function eachLabel(label) {
expect(label.toLowerCase()).toContain('role');
});
});
it('should open the modal with correct label for multiple entities', function test() {
service.perform([{name: 'one'}, {name: 'two'}]);
var labels = deleteModalService.open.calls.argsFor(0)[2].labels;
expect(deleteModalService.open).toHaveBeenCalled();
angular.forEach(labels, function eachLabel(label) {
expect(label.toLowerCase()).toContain('roles');
});
});
it('should open the delete modal with correct entities', function test() {
service.perform([{name: 'one'}, {name: 'two'}]);
var entities = deleteModalService.open.calls.argsFor(0)[1];
expect(deleteModalService.open).toHaveBeenCalled();
expect(entities.length).toEqual(2);
});
it('should pass in a function that deletes an role', function test() {
spyOn(keystoneAPI, 'deleteRole').and.callFake(angular.noop);
service.perform({id: 1, name: 'one'});
var contextArg = deleteModalService.open.calls.argsFor(0)[2];
var deleteFunction = contextArg.deleteEntity;
deleteFunction(1);
expect(keystoneAPI.deleteRole).toHaveBeenCalledWith(1);
});
});
describe('allow method', function() {
it('should use default policy if batch action', function test() {
spyOn(policyAPI, 'ifAllowed');
service.allowed();
expect(policyAPI.ifAllowed).toHaveBeenCalled();
});
}); // end of allowed
}); // end of delete
})();