diff --git a/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.controller.js b/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.controller.js index d62aca1b..6944332c 100644 --- a/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.controller.js +++ b/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.controller.js @@ -29,9 +29,9 @@ 'horizon.dashboard.admin.ironic.validDatapathIdPattern', 'horizon.dashboard.admin.ironic.form-field.service', 'horizon.app.core.openstack-service-api.ironic', + 'horizon.dashboard.admin.ironic.property-collection.service', 'ctrl', - 'node' - ]; + 'node']; /** * @description Utility class used to manage local-link-connection @@ -141,13 +141,9 @@ validDatapathIdPattern, formFieldService, ironic, + propertyCollectionService, ctrl, node) { - ctrl.port = { - extra: {}, - node_uuid: node.uuid - }; - ctrl.address = new formFieldService.FormField({ id: "macAddress", title: gettext("MAC address"), @@ -186,7 +182,8 @@ var field = ctrl.portgroup_uuid; if (portgroups.length > 0) { - field.portgroups.push({uuid: null, name: gettext("Select a portgroup")}); + field.portgroups.push({uuid: null, + name: gettext("Select a portgroup")}); } field.portgroups = field.portgroups.concat(portgroups); @@ -195,6 +192,13 @@ } }); + ctrl.extra = new propertyCollectionService.PropertyCollection({ + id: 'extra', + title: gettext('Extras'), + addPropertyLabel: gettext('Add Extra'), + placeholder: gettext('Property Name') + }); + /** * Cancel the modal * @@ -203,26 +207,5 @@ ctrl.cancel = function() { $uibModalInstance.dismiss('cancel'); }; - - /** - * Delete a port metadata property - * - * @param {string} propertyName - Name of the property - * @return {void} - */ - ctrl.deleteExtra = function(propertyName) { - delete ctrl.port.extra[propertyName]; - }; - - /** - * Check whether the specified port metadata property already exists - * - * @param {string} propertyName - Name of the metadata property - * @return {boolean} True if the property already exists, - * otherwise false - */ - ctrl.checkExtraUnique = function(propertyName) { - return !(propertyName in ctrl.port.extra); - }; } })(); diff --git a/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.html b/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.html index 7958e680..ff2ee476 100644 --- a/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.html +++ b/ironic_ui/static/dashboard/admin/ironic/base-port/base-port.html @@ -26,49 +26,7 @@ -
- -
- - Add Extra: - - - - -
-
- -
-
- - {$ propertyName $} - - -
- - - -
-
-
+ + + +
+
+ + {$ propertyName $} + + +
+ + + +
+
+
+ diff --git a/ironic_ui/static/dashboard/admin/ironic/property-collection.service.js b/ironic_ui/static/dashboard/admin/ironic/property-collection.service.js new file mode 100644 index 00000000..c0678c4a --- /dev/null +++ b/ironic_ui/static/dashboard/admin/ironic/property-collection.service.js @@ -0,0 +1,105 @@ +/* + * 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'; + + angular + .module('horizon.dashboard.admin.ironic') + .factory('horizon.dashboard.admin.ironic.property-collection.service', + propertyCollectionService); + + function propertyCollectionService() { + var service = { + PropertyCollection: PropertyCollection + }; + + /** + * @description Utility class for managing property collections. + * Used is association with the property-collection-editor directive. + * + * @param {object} args - Base properties are: + * id [string] - Unique id used to create DOM element ids, and + * internal variable names + * title [string] - Label used to identify the collection to the user + * addPropertyLabel [string] - Label used to prompt the user to add a new + * property + * placeholder [string] - Placeholder for text input field + * properties [object] - Dictionary of property values indexed by + * property name + * + * @return {void} + */ + function PropertyCollection(args) { + var collection = this; + collection.id = undefined; + collection.title = undefined; + collection.addPropertyLabel = undefined; + collection.placeholder = undefined; + collection.properties = {}; + + angular.forEach(args, function(value, arg) { + collection[arg] = value; + }); + + /** + * @description Test whether this collection contains a property. + * + * @param {string} propertyName - Property name. + * @return {boolean} True if the property already exists, false otherwise. + */ + this.checkPropertyUnique = function(propertyName) { + return !(propertyName in collection.properties); + }; + + /** + * @description Add a property to the collection. + * + * @param {string} propertyName - Property name. + * @return {void} + */ + this.addProperty = function(propertyName) { + this.properties[propertyName] = null; + }; + + /** + * @description Delete a specified property. + * + * @param {string} propertyName - Property name. + * @return {void} + */ + this.deleteProperty = function(propertyName) { + delete collection.properties[propertyName]; + }; + + /** + * @description Test whether this collection is in a complete state. + * Complete is defined as all properties having a non-null value. + * + * @return {boolean} True if the collection is complete, false otherwise. + */ + this.complete = function() { + for (var propertyName in this.properties) { + if (this.properties.hasOwnProperty(propertyName) && + this.properties[propertyName] === null) { + return false; + } + } + return true; + }; + } + return service; + } +})(); diff --git a/ironic_ui/static/dashboard/admin/ironic/property-collection.service.spec.js b/ironic_ui/static/dashboard/admin/ironic/property-collection.service.spec.js new file mode 100644 index 00000000..93a3ff6d --- /dev/null +++ b/ironic_ui/static/dashboard/admin/ironic/property-collection.service.spec.js @@ -0,0 +1,100 @@ +/** + * 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"; + + /** + * @description Unit tests for the form-field service + */ + + describe( + 'horizon.dashboard.admin.ironic.property-collection.service', + + function() { + var propertyCollectionService; + + beforeEach(module('horizon.dashboard.admin.ironic')); + + beforeEach(inject(function($injector) { + propertyCollectionService = + $injector.get('horizon.dashboard.admin.ironic.property-collection.service'); + })); + + it('defines the form-field service', function() { + expect(propertyCollectionService).toBeDefined(); + }); + + it('PropertyCollection - default construction', function() { + var collection = new propertyCollectionService.PropertyCollection({}); + + expect(collection.id).toBeUndefined(); + expect(collection.title).toBeUndefined(); + expect(collection.addPropertyLabel).toBeUndefined(); + expect(collection.placeholder).toBeUndefined(); + expect(collection.properties).toEqual({}); + expect(collection.checkPropertyUnique).toBeDefined(); + expect(collection.addProperty).toBeDefined(); + expect(collection.deleteProperty).toBeDefined(); + expect(collection.complete).toBeDefined(); + }); + + it('PropertyCollection - local parameters', function() { + var args = {id: 'id', + title: 'title', + placeholder: 'placeholder', + properties: {'prop-1': 'prop1-val', + 'prop-2': 'prop2-val'} + }; + var collection = new propertyCollectionService.PropertyCollection(args); + for (var arg in args) { + if (args.hasOwnProperty(arg)) { + expect(collection[arg]).toBeDefined(); + expect(collection[arg]).toEqual(args[arg]); + } + } + }); + + it('checkPropertyUnique', function() { + var collection = new propertyCollectionService.PropertyCollection({}); + expect(collection.checkPropertyUnique('foo')).toBe(true); + collection.addProperty('foo'); + expect(collection.checkPropertyUnique('foo')).toBe(false); + }); + + it('addProperty', function() { + var collection = new propertyCollectionService.PropertyCollection({}); + collection.addProperty('foo'); + expect(collection.properties.foo).toBeDefined(); + expect(collection.properties.foo).toBe(null); + }); + + it('deleteProperty', function() { + var collection = new propertyCollectionService.PropertyCollection({}); + var original = angular.copy(collection); + collection.addProperty('foo'); + collection.deleteProperty('foo'); + expect(collection).toEqual(original); + }); + + it('complete', function() { + var collection = new propertyCollectionService.PropertyCollection({}); + expect(collection.complete()).toBe(true); + collection.addProperty('foo'); + expect(collection.complete()).toBe(false); + }); + }); +})();