diff --git a/ironic_ui/karma.conf.js b/ironic_ui/karma.conf.js index ffcd4161..2e7dc4af 100644 --- a/ironic_ui/karma.conf.js +++ b/ironic_ui/karma.conf.js @@ -58,6 +58,7 @@ toxPath + 'xstatic/pkg/rickshaw/data/rickshaw.js', toxPath + 'xstatic/pkg/angular_smart_table/data/smart-table.js', toxPath + 'xstatic/pkg/angular_lrdragndrop/data/lrdragndrop.js', + toxPath + 'xstatic/pkg/angular_fileupload/data/ng-file-upload-all.js', toxPath + 'xstatic/pkg/spin/data/spin.js', toxPath + 'xstatic/pkg/spin/data/spin.jquery.js', toxPath + 'xstatic/pkg/tv4/data/tv4.js', diff --git a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.js b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.js index 28a02317..43e16b3f 100644 --- a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.js +++ b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.js @@ -57,14 +57,26 @@ - adding new properties - displaying the list of properties in the set - changing the value of properties + + Collection attributes: + id: Name of the property inside the node object that is used + to store the collection. + formId: Name of the controller variable that can be used to + access the property collection form. + prompt: Label used to prompt the user to add properties + to the collection. + placeholder: Label used to guide the user in providiing property + values. */ ctrl.propertyCollections = [ {id: "properties", + formId: "properties_form", title: gettext("Properties"), addPrompt: gettext("Add Property"), placeholder: gettext("Property Name") }, {id: "extra", + formId: "extra_form", title: gettext("Extras"), addPrompt: gettext("Add Extra"), placeholder: gettext("Extra Property Name") @@ -75,11 +87,13 @@ name: null, driver: null, driver_info: {}, - properties: {}, - extra: {}, network_interface: null }; + angular.forEach(ctrl.propertyCollections, function(collection) { + ctrl.node[collection.id] = {}; + }); + /** * @description Get the list of currently active Ironic drivers * @@ -102,70 +116,6 @@ }); }; - /** - * @description Check whether a group contains required properties - * - * @param {DriverProperty[]} group - Property group - * @return {boolean} Return true if the group contains required - * properties, false otherwise - */ - function driverPropertyGroupHasRequired(group) { - var hasRequired = false; - for (var i = 0; i < group.length; i++) { - if (group[i].required) { - hasRequired = true; - break; - } - } - return hasRequired; - } - - /** - * @description Convert array of driver property groups to a string - * - * @param {array[]} groups - Array for driver property groups - * @return {string} Output string - */ - function driverPropertyGroupsToString(groups) { - var output = []; - angular.forEach(groups, function(group) { - var groupStr = []; - angular.forEach(group, function(property) { - groupStr.push(property.name); - }); - groupStr = groupStr.join(", "); - output.push(['[', groupStr, ']'].join("")); - }); - output = output.join(", "); - return ['[', output, ']'].join(""); - } - - /** - * @description Comaprison function used to sort driver property groups - * - * @param {DriverProperty[]} group1 - First group - * @param {DriverProperty[]} group2 - Second group - * @return {integer} Return: - * < 0 if group1 should precede group2 in an ascending ordering - * > 0 if group2 should precede group1 - * 0 if group1 and group2 are considered equal from ordering perpsective - */ - function compareDriverPropertyGroups(group1, group2) { - var group1HasRequired = driverPropertyGroupHasRequired(group1); - var group2HasRequired = driverPropertyGroupHasRequired(group2); - - if (group1HasRequired === group2HasRequired) { - if (group1.length === group2.length) { - return group1[0].name.localeCompare(group2[0].name); - } else { - return group1.length - group2.length; - } - } else { - return group1HasRequired ? -1 : 1; - } - return 0; - } - /** * @description Order driver properties in the form using the following * rules: @@ -176,7 +126,7 @@ * (2) Required properties with no dependents should be located at the * top of the form * - * @return {void} + * @return {[]} Ordered list of groups of strongly related properties */ ctrl._sortDriverProperties = function() { // Build dependency graph between driver properties @@ -221,10 +171,10 @@ components.push(component); }, groups); - groups.sort(compareDriverPropertyGroups); + groups.sort(baseNodeService.compareDriverPropertyGroups); $log.debug("Found the following property groups: " + - driverPropertyGroupsToString(groups)); + baseNodeService.driverPropertyGroupsToString(groups)); return groups; }; @@ -297,5 +247,28 @@ ctrl.isDriverPropertyActive = function(property) { return property.isActive(); }; + + /** + * @description Check whether the node definition form is ready for + * to be submitted. + * + * @return {boolean} True if the form is ready to be submitted, + * otherwise false. + */ + ctrl.readyToSubmit = function() { + var ready = true; + if (ctrl.driverProperties) { + for (var i = 0; i < ctrl.propertyCollections.length; i++) { + var collection = ctrl.propertyCollections[i]; + if (ctrl[collection.formId].$invalid) { + ready = false; + break; + } + } + } else { + ready = false; + } + return ready; + }; } })(); diff --git a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.spec.js b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.spec.js new file mode 100644 index 00000000..759b41f4 --- /dev/null +++ b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.spec.js @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Cray Inc. + * + * 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('horizon.dashboard.admin.ironic.base-node', function () { + var ironicBackendMockService, uibModalInstance; + var ctrl = {}; + + beforeEach(module('horizon.dashboard.admin.ironic')); + + beforeEach(module('horizon.framework.util')); + + beforeEach(module(function($provide) { + $provide.value('$uibModal', {}); + })); + + beforeEach(module(function($provide) { + uibModalInstance = { + dismiss: jasmine.createSpy() + }; + $provide.value('$uibModalInstance', uibModalInstance); + })); + + beforeEach(module(function($provide) { + $provide.value('horizon.framework.widgets.toast.service', + {}); + })); + + beforeEach(module('horizon.app.core.openstack-service-api')); + + beforeEach(inject(function($injector) { + ironicBackendMockService = + $injector.get('horizon.dashboard.admin.ironic.backend-mock.service'); + ironicBackendMockService.init(); + + var controller = $injector.get('$controller'); + controller('BaseNodeController', {ctrl: ctrl}); + })); + + afterEach(function() { + ironicBackendMockService.postTest(); + }); + + it('controller should be defined', function () { + expect(ctrl).toBeDefined(); + }); + + it('base construction', function () { + expect(ctrl.drivers).toBeNull(); + expect(ctrl.images).toBeNull(); + expect(ctrl.loadingDriverProperties).toBe(false); + expect(ctrl.driverProperties).toBeNull(); + expect(ctrl.driverPropertyGroups).toBeNull(); + expect(ctrl.modalTitle).toBeDefined(); + angular.forEach(ctrl.propertyCollections, function(collection) { + expect(Object.getOwnPropertyNames(collection).sort()).toEqual( + PROPERTY_COLLECTION_PROPERTIES.sort()); + }); + expect(ctrl.propertyCollections) + .toContain(jasmine.objectContaining({id: "properties"})); + expect(ctrl.propertyCollections) + .toContain(jasmine.objectContaining({id: "extra"})); + expect(ctrl.node).toEqual({ + name: null, + driver: null, + driver_info: {}, + properties: {}, + extra: {}, + network_interface: null}); + expect(Object.getOwnPropertyNames(ctrl).sort()).toEqual( + BASE_NODE_CONTROLLER_PROPERTIES.sort()); + }); + + it('_loadDrivers', function () { + ctrl._loadDrivers(); + ironicBackendMockService.flush(); + expect(ctrl.drivers).toEqual(ironicBackendMockService.getDrivers()); + }); + + it('_getImages', function () { + ctrl._getImages(); + ironicBackendMockService.flush(); + expect(ctrl.images).toEqual(ironicBackendMockService.getImages()); + }); + + it('cancel', function () { + ctrl.cancel(); + expect(uibModalInstance.dismiss).toHaveBeenCalledWith('cancel'); + }); + + }); +})(); diff --git a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.html b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.html index a5b04f08..34daabd0 100644 --- a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.html +++ b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.html @@ -125,8 +125,8 @@ -
+
@@ -253,10 +253,7 @@