RIFT-15245: Vnfd-id edit in VNF composer behaves strangely
[osm/UI.git] / skyquake / plugins / composer / src / src / components / EditDescriptorModelProperties.js
index 59d2f95..d04dddf 100644 (file)
@@ -39,6 +39,7 @@ import SelectionManager from '../libraries/SelectionManager'
 import DeletionManager from '../libraries/DeletionManager'
 import DescriptorModelIconFactory from '../libraries/model/IconFactory'
 import getEventPath from '../libraries/getEventPath'
+import CatalogDataStore from '../stores/CatalogDataStore'
 
 import imgAdd from '../../../node_modules/open-iconic/svg/plus.svg'
 import imgRemove from '../../../node_modules/open-iconic/svg/trash.svg'
@@ -46,12 +47,12 @@ import imgRemove from '../../../node_modules/open-iconic/svg/trash.svg'
 import '../styles/EditDescriptorModelProperties.scss'
 
 function getDescriptorMetaBasicForType(type) {
-       const basicPropertiesFilter = d => _.contains(DESCRIPTOR_MODEL_FIELDS[type], d.name);
+       const basicPropertiesFilter = d => _.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name);
        return DescriptorModelMetaFactory.getModelMetaForType(type, basicPropertiesFilter) || {properties: []};
 }
 
 function getDescriptorMetaAdvancedForType(type) {
-       const advPropertiesFilter = d => !_.contains(DESCRIPTOR_MODEL_FIELDS[type], d.name);
+       const advPropertiesFilter = d => !_.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name);
        return DescriptorModelMetaFactory.getModelMetaForType(type, advPropertiesFilter) || {properties: []};
 }
 
@@ -173,16 +174,19 @@ export default function EditDescriptorModelProperties(props) {
        }
 
        function buildField(container, property, path, value, fieldKey) {
+               let cds = CatalogDataStore;
+               let catalogs = cds.getTransientCatalogs();
 
                const name = path.join('.');
-               const isEditable = true;
                const isGuid = Property.isGuid(property);
+               const isEditable = isGuid;
                const onChange = onFormFieldValueChanged.bind(container);
                const isEnumeration = Property.isEnumeration(property);
+               const isLeafRef = Property.isLeafRef(property);
                const onFocus = onFocusPropertyFormInputElement.bind(container, property, path, value);
                const placeholder = changeCase.title(property.name);
                const className = ClassNames(property.name + '-input', {'-is-guid': isGuid});
-               const fieldValue = value ? value.constructor.name == "String" ? value : '' : undefined;
+               const fieldValue = value ? (value.constructor.name != "Object") ? value : '' : undefined;
                if (isEnumeration) {
                        const enumeration = Property.getEnumeration(property, value);
                        const options = enumeration.map((d, i) => {
@@ -200,6 +204,26 @@ export default function EditDescriptorModelProperties(props) {
                        return <select key={fieldKey.toString()} id={fieldKey.toString()} className={ClassNames({'-value-not-set': !isValueSet})} name={name} value={value} title={name} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} readOnly={!isEditable}>{options}</select>;
                }
 
+               if (isLeafRef) {
+                       let fullFieldKey = _.isArray(fieldKey) ? fieldKey.join(':') : fieldKey;
+                       let containerRef = container;
+                       while (containerRef.parent) {
+                               fullFieldKey = containerRef.parent.key + ':' + fullFieldKey;
+                               containerRef = containerRef.parent;
+                       }
+                       const leafRefPathValues = Property.getLeafRef(property, path, value, fullFieldKey, catalogs, container);
+
+                       const options = leafRefPathValues && leafRefPathValues.map((d, i) => {
+                               return <option key={fieldKey.toString() + ':' + i} value={d.value}>{d.value}</option>;
+                       });
+                       const isValueSet = leafRefPathValues.filter(d => d.isSelected).length > 0;
+                       if (!isValueSet || property.cardinality === '0..1') {
+                               const noValueDisplayText = changeCase.title(property.name);
+                               options.unshift(<option key={'(value-not-in-leafref)' + fieldKey.toString()} value="" placeholder={placeholder}>{noValueDisplayText}</option>);
+                       }
+                       return <select key={fieldKey.toString()} id={fieldKey.toString()} className={ClassNames({'-value-not-set': !isValueSet})} name={name} value={value} title={name} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} readOnly={!isEditable}>{options}</select>;
+               }
+
                if (property['preserve-line-breaks']) {
                        return <textarea key={fieldKey.toString()} cols="5" id={fieldKey.toString()} name={name} value={value} placeholder={placeholder} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} onMouseOut={endEditing} onMouseLeave={endEditing} readOnly={!isEditable} />;
                }
@@ -245,9 +269,10 @@ export default function EditDescriptorModelProperties(props) {
 
                                event.preventDefault();
 
-                               const name = event.target.name;
+                               let name = event.target.name;
                                const value = event.target.value;
 
+
                                /*
                                        Transient State is stored for convenience in the uiState field.
                                        The choice yang type uses case elements to describe the "options".
@@ -255,22 +280,22 @@ export default function EditDescriptorModelProperties(props) {
                                        the system to determine which type is selected by the name of
                                        the element contained within the field.
                                 */
-
-                               //const stateExample = {
-                               //      uiState: {
-                               //              choice: {
-                               //                      'conf-config': {
-                               //                              selected: 'rest',
-                               //                              'case': {
-                               //                                      rest: {},
-                               //                                      netconf: {},
-                               //                                      script: {}
-                               //                              }
-                               //                      }
-                               //              }
-                               //      }
-                               //};
-
+                               /*
+                                       const stateExample = {
+                                               uiState: {
+                                                       choice: {
+                                                               'conf-config': {
+                                                                       selected: 'rest',
+                                                                       'case': {
+                                                                               rest: {},
+                                                                               netconf: {},
+                                                                               script: {}
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       };
+                               */
                                const statePath = ['uiState.choice'].concat(name);
                                const stateObject = utils.resolvePath(this.model, statePath.join('.')) || {};
                                const selected = stateObject.selected ? stateObject.selected.split('.')[1] : undefined;
@@ -278,19 +303,34 @@ export default function EditDescriptorModelProperties(props) {
                                utils.assignPathValue(this.model, statePath.join('.'), stateObject);
 
                                // write the current choice value into the state
-                               const choiceObject = utils.resolvePath(this.model, [name, selected].join('.'));
-                               if (choiceObject) {
-                                       utils.assignPathValue(stateObject, ['case', selected].join('.'), _.cloneDeep(choiceObject));
+                               let choiceObject = utils.resolvePath(this.model, [name, selected].join('.'));
+                               let isTopCase = false;
+                               if (!choiceObject) {
+                                       isTopCase = true;
+                                       choiceObject = utils.resolvePath(this.model, [selected].join('.'));
+                               }
+                               utils.assignPathValue(stateObject, [selected].join('.'), _.cloneDeep(choiceObject));
+
+                               if(selected) {
+                                       if(this.model.uiState.choice.hasOwnProperty(name)) {
+                                               delete this.model[selected];
+                                               utils.removePathValue(this.model, [name, selected].join('.'), isTopCase);
+                                       } else {
+                                               // remove the current choice value from the model
+                                               utils.removePathValue(this.model, [name, selected].join('.'), isTopCase);
+                                       }
                                }
-
-                               // remove the current choice value from the model
-                               utils.removePathValue(this.model, [name, selected].join('.'));
 
                                // get any state for the new selected choice
-                               const newChoiceObject = utils.resolvePath(stateObject, ['case', value].join('.')) || {};
+                               const newChoiceObject = utils.resolvePath(stateObject, [value].join('.')) || {};
 
                                // assign new choice value to the model
-                               utils.assignPathValue(this.model, [name, value].join('.'), newChoiceObject);
+                               if (isTopCase) {
+                                       utils.assignPathValue(this.model, [name, value].join('.'), newChoiceObject);
+                               } else {
+                                       utils.assignPathValue(this.model, [value].join('.'), newChoiceObject)
+                               }
+
 
                                // update the selected name
                                utils.assignPathValue(this.model, statePath.concat('selected').join('.'), value);
@@ -317,7 +357,7 @@ export default function EditDescriptorModelProperties(props) {
                        return {optionName: d.name};
                });
 
-               const options = [{optionName: ''}].concat(cases).map((d, i) => {
+               const options = [{optionName: '', optionValue: false}].concat(cases).map((d, i) => {
                        return (
                                <option key={i} value={d.optionValue} title={d.optionTitle}>
                                        {d.optionName}
@@ -337,11 +377,19 @@ export default function EditDescriptorModelProperties(props) {
                        if(fieldProperties) {
                                //Check each case statement in model and see if it is present in container model.
                                cases.map(function(c){
-                                       if(fieldProperties.hasOwnProperty(c.optionName)) {
+                                       if(fieldProperties.hasOwnProperty(c.optionValue.split('.')[1])) {
                                                utils.assignPathValue(container.model, ['uiState.choice', selectName, 'selected'].join('.'), c.optionValue);
                                        }
                                });
                                selectedOptionValue = utils.resolvePath(container.model, ['uiState.choice', selectName, 'selected'].join('.'));
+                       } else {
+                               property.properties.map(function(p) {
+                                       let pname = p.properties[0].name;
+                                       if(container.model.hasOwnProperty(pname)) {
+                                               utils.assignPathValue(container.model, ['uiState.choice', selectName, 'selected'].join('.'), [p.name, pname].join('.'));
+                                       }
+                               })
+                               selectedOptionValue = utils.resolvePath(container.model, ['uiState.choice', selectName, 'selected'].join('.'));
                        }
                }
                //If selectedOptionValue is present, take first item in string which represents the case name.
@@ -358,7 +406,7 @@ export default function EditDescriptorModelProperties(props) {
                                        {build(container, d, childPath, childValue, props)}
                                </div>
                        );
-               }) : (!isMissingDescriptorMeta) ? build(container, valueProperty, path.concat(valueProperty.name), utils.resolvePath(container.model, path.concat(valueProperty.name).join('.'))) : null
+               }) : (!isMissingDescriptorMeta) ? build(container, valueProperty, path.concat(valueProperty.name), utils.resolvePath(container.model, path.concat(valueProperty.name).join('.')) || container.model[valueProperty.name]) : null
                // end magic
                const onFocus = onFocusPropertyFormInputElement.bind(container, property, path, value);
 
@@ -510,6 +558,14 @@ export default function EditDescriptorModelProperties(props) {
 
                if (property.type === 'choice') {
                        value = utils.resolvePath(container.model, ['uiState.choice'].concat(path, 'selected').join('.'));
+                       if(!value) {
+                               property.properties.map(function(p) {
+                                       let pname = p.properties[0].name;
+                                       if(container.model.hasOwnProperty(pname)) {
+                                               value = container.model[pname];
+                                       }
+                               })
+                       }
                }
 
                let displayValue = typeof value === 'object' ? '' : value;