diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-workflow.service.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-workflow.service.spec.js index 68d52a3133..d5334c7abc 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-workflow.service.spec.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-workflow.service.spec.js @@ -29,7 +29,9 @@ }); return spec; }; - $provide.value('horizon.app.core.openstack-service-api.serviceCatalog', {}); + $provide.value('horizon.app.core.openstack-service-api.serviceCatalog', { + ifTypeEnabled: angular.noop + }); $provide.value('horizon.framework.util.workflow.service', workflow); })); diff --git a/openstack_dashboard/static/app/core/workflow/decorator.service.js b/openstack_dashboard/static/app/core/workflow/decorator.service.js index 872ccd09a2..696355c2a3 100644 --- a/openstack_dashboard/static/app/core/workflow/decorator.service.js +++ b/openstack_dashboard/static/app/core/workflow/decorator.service.js @@ -1,5 +1,6 @@ /* * (c) Copyright 2015 Hewlett-Packard Development Company, L.P. + * Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,14 +27,16 @@ * @kind function * @description * - * A workflow decorator function that adds checkReadiness method to step in - * the work flow. checkReadiness function will check if a bunch of certain - * types of OpenStack services is enabled in the cloud for that step to show - * on the user interface. + * A workflow decorator function that looks for the requiredServiceTypes or policy + * properties on each step in the workflow. If either of these properties exist then + * the checkReadiness method is added to the step. The checkReadiness method will + * make sure the necessary OpenStack services are enabled and the policy check passes + * in order for the step to be displayed. * * Injected dependencies: * - $q * - serviceCatalog horizon.app.core.openstack-service-api.serviceCatalog + * - policy horizon.app.core.openstack-service-api.policy * * @param {Object} spec The input workflow specification object. * @returns {Object} The decorated workflow specification object, the same @@ -46,12 +49,13 @@ dashboardWorkflowDecorator.$inject = [ '$q', - 'horizon.app.core.openstack-service-api.serviceCatalog' + 'horizon.app.core.openstack-service-api.serviceCatalog', + 'horizon.app.core.openstack-service-api.policy' ]; ///////////// - function dashboardWorkflowDecorator($q, serviceCatalog) { + function dashboardWorkflowDecorator($q, serviceCatalog, policy) { return decorator; function decorator(spec) { @@ -64,12 +68,19 @@ } function decorateStep(step) { + var promises = []; var types = step.requiredServiceTypes; if (types && types.length > 0) { + promises = promises.concat(types.map(function checkServiceEnabled(type) { + return serviceCatalog.ifTypeEnabled(type); + })); + } + if (step.policy) { + promises.push(policy.ifAllowed(step.policy)); + } + if (promises.length > 0) { step.checkReadiness = function () { - return $q.all(types.map(function (type) { - return serviceCatalog.ifTypeEnabled(type); - })); + return $q.all(promises); }; } } diff --git a/openstack_dashboard/static/app/core/workflow/decorator.service.spec.js b/openstack_dashboard/static/app/core/workflow/decorator.service.spec.js new file mode 100644 index 0000000000..3f54d89f2f --- /dev/null +++ b/openstack_dashboard/static/app/core/workflow/decorator.service.spec.js @@ -0,0 +1,71 @@ +/* + * Copyright 2016 IBM Corp. + * + * Licensed 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. + */ +(function () { + 'use strict'; + + describe('Workflow Decorator', function () { + var decoratorService, catalogService, policyService, $scope, deferred; + var steps = [ + { id: '1' }, + { id: '2', requiredServiceTypes: ['foo-service'] }, + { id: '3', policy: 'foo-policy' } + ]; + var spec = { steps: steps }; + + beforeEach(module('horizon.app.core')); + beforeEach(module('horizon.framework.util')); + beforeEach(module('horizon.framework.conf')); + beforeEach(module('horizon.framework.widgets.toast')); + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + deferred = $injector.get('$q').defer(); + decoratorService = $injector.get('horizon.app.core.workflow.decorator'); + catalogService = $injector.get('horizon.app.core.openstack-service-api.serviceCatalog'); + policyService = $injector.get('horizon.app.core.openstack-service-api.policy'); + spyOn(catalogService, 'ifTypeEnabled').and.returnValue(deferred.promise); + spyOn(policyService, 'ifAllowed').and.returnValue(deferred.promise); + })); + + it('is a function', function() { + expect(angular.isFunction(decoratorService)).toBe(true); + }); + + it('checks each step for required services and policies', function() { + decoratorService(spec); + expect(steps[0].checkReadiness).toBeUndefined(); + expect(steps[1].checkReadiness).toBeDefined(); + expect(steps[2].checkReadiness).toBeDefined(); + expect(catalogService.ifTypeEnabled.calls.count()).toBe(1); + expect(catalogService.ifTypeEnabled).toHaveBeenCalledWith('foo-service'); + expect(policyService.ifAllowed.calls.count()).toBe(1); + expect(policyService.ifAllowed).toHaveBeenCalledWith('foo-policy'); + }); + + it('step checkReadiness function returns correct results', function() { + decoratorService(spec); + var readinessResult; + deferred.resolve('foo'); + steps[1].checkReadiness().then(function(result) { + readinessResult = result; + }); + $scope.$apply(); + expect(readinessResult).toEqual(['foo']); + }); + + }); + +})(); diff --git a/openstack_dashboard/static/app/core/workflow/workflow.service.js b/openstack_dashboard/static/app/core/workflow/workflow.service.js index 4ce3c03d00..6b2ba0e833 100644 --- a/openstack_dashboard/static/app/core/workflow/workflow.service.js +++ b/openstack_dashboard/static/app/core/workflow/workflow.service.js @@ -28,6 +28,35 @@ * - dashboardWorkflowDecorator {@link horizon.app.core.workflow.factory * :horizon.app.core.workflow.decorator `dashboardWorkflowDecorator`} * + * @example + * ``` + * var workflow = workflowService({ + * title: gettext('Create Volume'), + * btnText: { finish: gettext('Create Volume') }, + * steps: [{ + * title: gettext('Step 1'), + * templateUrl: basePath + 'steps/create-volume/step1.html', + * helpUrl: basePath + 'steps/create-volume/step1.help.html', + * formName: 'step1Form' + * },{ + * title: gettext('Step 2'), + * templateUrl: basePath + 'steps/create-volume/step2.html', + * helpUrl: basePath + 'steps/create-volume/step2.help.html', + * formName: 'step2Form', + * requiredServiceTypes: ['network'] + * },{ + * title: gettext('Step 3'), + * templateUrl: basePath + 'steps/create-volume/step3.html', + * helpUrl: basePath + 'steps/create-volume/step3.help.html', + * formName: 'step3Form', + * policy: { rules: [['compute', 'os_compute_api:os-scheduler-hints:discoverable']] } + * }] + * }); + * ``` + * For each step, the requiredServiceTypes property specifies the service types that must + * be available in the service catalog for the step to be displayed. The policy property + * specifies the policy check that must pass in order for the step to be displayed. + * * @param {Object} The input workflow specification object * @returns {Object} The decorated workflow specification object, the same * reference to the input spec object. diff --git a/releasenotes/notes/workflow-step-policy-1ca99b0249294337.yaml b/releasenotes/notes/workflow-step-policy-1ca99b0249294337.yaml new file mode 100644 index 0000000000..8f2225591e --- /dev/null +++ b/releasenotes/notes/workflow-step-policy-1ca99b0249294337.yaml @@ -0,0 +1,5 @@ +--- +features: + - Added policy support to the angular workflow service so each step in a + workflow can specify a policy check that must pass in order for the step + to be displayed. \ No newline at end of file