X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=skyquake%2Fplugins%2Fcomposer%2Fsrc%2Fsrc%2Fcomponents%2FEditDescriptorModelProperties.js;h=19e699d2862dd8570e353765fc42cdc87fea7f7b;hb=03156e335275de1dafbc2a816e98006afdf249bf;hp=4ee4345b7ebc2ba652e15cf4b6e144e2d0dcaf64;hpb=4e7b00465d087292dc6127bc892a5fa3a64365b6;p=osm%2FUI.git diff --git a/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js b/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js index 4ee4345b7..19e699d28 100644 --- a/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js +++ b/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js @@ -20,648 +20,427 @@ * * This class generates the form fields used to edit the CONFD JSON model. */ -'use strict'; -import _ from 'lodash' +import _uniqueId from 'lodash/uniqueId'; +import _set from 'lodash/set'; +import _get from 'lodash/get'; +import _has from 'lodash/has'; +import _keys from 'lodash/keys'; +import _isObject from 'lodash/isObject'; +import _isArray from 'lodash/isArray'; import utils from '../libraries/utils' import React from 'react' -import ClassNames from 'classnames' import changeCase from 'change-case' import toggle from '../libraries/ToggleElementHandler' -import Button from './Button' import Property from '../libraries/model/DescriptorModelMetaProperty' +import SelectionManager from '../libraries/SelectionManager' import ComposerAppActions from '../actions/ComposerAppActions' import CatalogItemsActions from '../actions/CatalogItemsActions' -import DESCRIPTOR_MODEL_FIELDS from '../libraries/model/DescriptorModelFields' +import DescriptorEditorActions from '../actions/DescriptorEditorActions' import DescriptorModelFactory from '../libraries/model/DescriptorModelFactory' import DescriptorModelMetaFactory from '../libraries/model/DescriptorModelMetaFactory' -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' +import ModelBreadcrumb from './model/ModelBreadcrumb' +import ListItemAsLink from './model/ListItemAsLink' +import LeafField from './model/LeafField' +import { List, ListItem } from './model/List' +import ContainerWrapper from './model/Container' +import Choice from './model/Choice' import '../styles/EditDescriptorModelProperties.scss' -function getDescriptorMetaBasicForType(type) { - const basicPropertiesFilter = d => _.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name); - return DescriptorModelMetaFactory.getModelMetaForType(type, basicPropertiesFilter) || {properties: []}; + +function resolveReactKey(value) { + const keyPath = ['uiState', 'fieldKey']; + if (!_has(value, keyPath)) { + _set(value, keyPath, _uniqueId()); + } + return _get(value, keyPath); } -function getDescriptorMetaAdvancedForType(type) { - const advPropertiesFilter = d => !_.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name); - return DescriptorModelMetaFactory.getModelMetaForType(type, advPropertiesFilter) || {properties: []}; +function getTipForProperty(property) { + return property.name === 'constituent-vnfd' ? "Drag a VNFD from the Catalog to add more." : null } -function getTitle(model = {}) { - if (typeof model['short-name'] === 'string' && model['short-name']) { - return model['short-name']; - } - if (typeof model.name === 'string' && model.name) { - return model.name; - } - if (model.uiState && typeof model.uiState.displayName === 'string' && model.uiState.displayName) { - return model.uiState.displayName - } - if (typeof model.id === 'string') { - return model.id; - } +function selectModel(container, model, property) { + ComposerAppActions.selectModel(container.findChildByUid(model)); } -export default function EditDescriptorModelProperties(props) { +function removeListEntry(container, property, path) { + DescriptorEditorActions.removeListItem({ descriptor: container, property, path }); +} - const container = props.container; +function createAndAddItemToPath(container, property, path) { + DescriptorEditorActions.addListItem({ descriptor: container, property, path }); +} - if (!(DescriptorModelFactory.isContainer(container))) { - return - } +function notifyPropertyFocused(container, path) { + container.getRoot().uiState.focusedPropertyPath = path.join('.'); + console.debug('property selected', path.join('.')); + ComposerAppActions.propertySelected([path.join('.')]); +} - function startEditing() { - DeletionManager.removeEventListeners(); - } +function setPropertyOpenState(container, path, property, isOpen) { + DescriptorEditorActions.setOpenState({ descriptor: container, property, path, isOpen }); +} - function endEditing() { - DeletionManager.addEventListeners(); - } +function isDataProperty(property) { + return property.type === 'leaf' || property.type === 'leaf_list' || property.type === 'choice'; +} - function onClickSelectItem(property, path, value, event) { - event.preventDefault(); - const root = this.getRoot(); - if (SelectionManager.select(value)) { - CatalogItemsActions.catalogItemMetaDataChanged(root.model); +function checkIfValueEmpty(value) { + if (value === null || typeof value === 'undefined') { + return true; + } else if (_isArray(value) && !value.length) { + return true; + } else if (_isObject(value)) { + const keys = _keys(value); + if (keys.length < 2) { + return !keys.length || (keys[0] === 'uiState') } } + return false; +} - function onFocusPropertyFormInputElement(property, path, value, event) { - - event.preventDefault(); - startEditing(); - - function removeIsFocusedClass(event) { - event.target.removeEventListener('blur', removeIsFocusedClass); - Array.from(document.querySelectorAll('.-is-focused')).forEach(d => d.classList.remove('-is-focused')); +export default function EditDescriptorModelProperties(props) { + const { container, idMaker, showHelp, collapsePanelsByDefault, openPanelsWithData } = props; + const readOnly = props.readOnly || container.isReadOnly; + const showElementHelp = showHelp.forAll; + const uiState = container.uiState; + + function getPanelOpenedCondition(value, path) { + const showOpened = container.getUiState('opened', path); + if (typeof showOpened === 'undefined') { + return (openPanelsWithData && !checkIfValueEmpty(value)) ? true : !collapsePanelsByDefault; } + return showOpened; + } - removeIsFocusedClass(event); + function buildField(property, path, value, fieldKey) { + const pathToProperty = path.join('.'); + const fieldValue = value ? (value.constructor.name != "Object") ? value : '' : (isNaN(value) ? undefined : value); - const propertyWrapper = getEventPath(event).reduce((parent, element) => { - if (parent) { - return parent; - } - if (!element.classList) { - return false; + // process the named field value change + function processFieldValueChange(name, value) { + console.debug('processed change for -- ' + name + ' -- with value -- ' + value); + if (DescriptorModelFactory.isContainer(container)) { + DescriptorEditorActions.setValue({ descriptor: container, path, value }); } - if (element.classList.contains('property')) { - return element; - } - }, false); - - if (propertyWrapper) { - propertyWrapper.classList.add('-is-focused'); - event.target.addEventListener('blur', removeIsFocusedClass); } - } - - function buildAddPropertyAction(container, property, path) { - function onClickAddProperty(property, path, event) { - event.preventDefault(); - //SelectionManager.resume(); - const create = Property.getContainerCreateMethod(property, this); - if (create) { - const model = null; - create(model, path, property); - } else { - const name = path.join('.'); - const value = Property.createModelInstance(property); - utils.assignPathValue(this.model, name, value); - } - CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot()); + function onErrorHandler(message) { + DescriptorEditorActions.setError({ descriptor: container, path, message }); } - return ( - - ); - } - function buildRemovePropertyAction(container, property, path) { - function onClickRemoveProperty(property, path, event) { - event.preventDefault(); - const name = path.join('.'); - const removeMethod = Property.getContainerMethod(property, this, 'remove'); - if (removeMethod) { - removeMethod(utils.resolvePath(this.model, name)); - } else { - utils.removePathValue(this.model, name); - } - CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot()); - } + // create an onChange event handler for a select field for the specified field path + const onChangeHandler = processFieldValueChange.bind(null, pathToProperty); return ( - + ); } - function onFormFieldValueChanged(event) { - if (DescriptorModelFactory.isContainer(this)) { - event.preventDefault(); - const name = event.target.name; - const value = event.target.value; - utils.assignPathValue(this.model, name, value); - CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot()); - } - } - - 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 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 != "Object") ? value : '' : undefined; - if (isEnumeration) { - const enumeration = Property.getEnumeration(property, value); - const options = enumeration.map((d, i) => { - // note yangforge generates values for enums but the system does not use them - // so we categorically ignore them - // https://trello.com/c/uzEwVx6W/230-bug-enum-should-not-use-index-only-name - //return {d.name}; - return {d.name}; - }); - const isValueSet = enumeration.filter(d => d.isSelected).length > 0; - if (!isValueSet || property.cardinality === '0..1') { - const noValueDisplayText = changeCase.title(property.name); - options.unshift({noValueDisplayText}); + /** + * buiid and return an array of components representing an editor for each property. + * + * @param {any} container the master document being edited + * @param {[property]} properties + * @param {string} pathToProperties path within the container to the properties + * @param {Object} data source for each property + * @returns an array of react components + */ + function buildComponentsForProperties(properties, pathToProperties, data) { + return properties.map((property) => { + let value; + let propertyPath = pathToProperties.slice(); + if (property.type != 'choice') { + propertyPath.push(property.name); } - return {options}; - } - - if (isLeafRef) { - let fullFieldKey = _.isArray(fieldKey) ? fieldKey.join(':') : fieldKey; - let containerRef = container; - while (containerRef.parent) { - fullFieldKey = containerRef.parent.key + ':' + fullFieldKey; - containerRef = containerRef.parent; + if (data && typeof data === 'object') { + value = _get(data, property.name); } - const leafRefPathValues = Property.getLeafRef(property, path, value, fullFieldKey, catalogs, container); - - const options = leafRefPathValues && leafRefPathValues.map((d, i) => { - return {d.value}; - }); - const isValueSet = leafRefPathValues.filter(d => d.isSelected).length > 0; - if (!isValueSet || property.cardinality === '0..1') { - const noValueDisplayText = changeCase.title(property.name); - options.unshift({noValueDisplayText}); + let result = null; + try { + result = buildPropertyComponent(property, propertyPath, value); + } catch (e) { + console.error(e); } - return {options}; - } - - if (property['preserve-line-breaks']) { - return ; - } - - return ; - + return result; + }); } - function buildElement(container, property, valuePath, value) { - return property.properties.map((property, index) => { - let childValue; - const childPath = valuePath.slice(); - if (typeof value === 'object') { - childValue = value[property.name]; - } - if(property.type != 'choice'){ - childPath.push(property.name); - } - return build(container, property, childPath, childValue); + function buildChoice(property, path, value, uniqueId) { + const uiStatePath = path.concat(['uiState']); + const choiceStatePath = ['choice', property.name]; + const fullChoiceStatePath = uiStatePath.concat(choiceStatePath); - }); - } + function determineSelectedChoice(model) { + let choiceState = utils.resolvePath(container.model, fullChoiceStatePath.join('.')); + if (choiceState) { + return property.properties.find(c => c.name === choiceState.selected); + } + const selectedCase = property.properties.find(c => + c.properties && c.properties.find(p => _has(model, path.concat([p.name]))) + ); + // lets remember this + let stateObject = utils.resolvePath(container.model, uiStatePath.join('.')); + stateObject = _set(stateObject || {}, choiceStatePath, { selected: selectedCase ? selectedCase.name : "" }); + utils.assignPathValue(container.model, uiStatePath.join('.'), stateObject); + return selectedCase; + } - function buildChoice(container, property, path, value, key) { - - function onFormFieldValueChanged(event) { - if (DescriptorModelFactory.isContainer(this)) { - - event.preventDefault(); - - 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". - A choice can only ever have one option selected which allows - 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 statePath = ['uiState.choice'].concat(name); - const stateObject = utils.resolvePath(this.model, statePath.join('.')) || {}; - const selected = stateObject.selected ? stateObject.selected.split('.')[1] : undefined; - // write state back to the model so the new state objects are captured - utils.assignPathValue(this.model, statePath.join('.'), stateObject); - - // write the current choice value into the state - let choiceObject = utils.resolvePath(this.model, [name, selected].join('.')); - let isTopCase = false; - if (!choiceObject) { - isTopCase = true; - choiceObject = utils.resolvePath(this.model, [selected].join('.')); + function pullOutCaseModel(caseName) { + const model = container.model; + const properties = property.properties.find(c => c.name === caseName).properties; + return properties.reduce((o, p) => { + const valuePath = path.concat([p.name]).join('.'); + const value = utils.resolvePath(model, valuePath); + if (value) { + o[p.name] = value; } - utils.assignPathValue(stateObject, [selected].join('.'), _.cloneDeep(choiceObject)); + return o; + }, {}); + } - if(selected) { - if(this.model.uiState.choice.hasOwnProperty(name)) { - delete this.model[selected]; - utils.removePathValue(this.model, [name, selected].join('.'), isTopCase); + function processChoiceChange(value) { + if (DescriptorModelFactory.isContainer(container)) { + let uiState = utils.resolvePath(container.model, uiStatePath.join('.')); + // const stateObject = utils.resolvePath(container.model, fullChoiceStatePath.join('.')) || {}; + let choiceState = _get(uiState, choiceStatePath); + const previouslySelectedChoice = choiceState.selected; + if (previouslySelectedChoice === value) { + return; + } + if (previouslySelectedChoice) { + choiceState[previouslySelectedChoice] = pullOutCaseModel(previouslySelectedChoice); + } + const modelUpdate = _keys(choiceState[previouslySelectedChoice]).reduce((o, k) => _set(o, k, null), {}) + choiceState.selected = value; + _set(uiState, choiceStatePath, choiceState); + _set(modelUpdate, 'uiState', uiState); + if (choiceState.selected) { + const previous = choiceState[choiceState.selected]; + if (previous) { + Object.assign(modelUpdate, previous); } else { - // remove the current choice value from the model - utils.removePathValue(this.model, [name, selected].join('.'), isTopCase); + const newChoice = property.properties.find(p => p.name === choiceState.selected); + if (newChoice.properties.length === 1) { + const property = newChoice.properties[0]; + if (property.type === 'leaf' && property['data-type'] === 'empty') { + let obj = {}; + obj[property.name] = [null]; + Object.assign(modelUpdate, obj); + } + } } } - - // get any state for the new selected choice - const newChoiceObject = utils.resolvePath(stateObject, [value].join('.')) || {}; - - // assign new choice value to the model - 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); - - CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot()); + DescriptorEditorActions.assignValue({ descriptor: container, path, source: modelUpdate }); } } - const caseByNameMap = {}; - - const onChange = onFormFieldValueChanged.bind(container); + const selectedCase = determineSelectedChoice(container.model); + const children = selectedCase ? + + {buildComponentsForProperties(selectedCase.properties, path, path.length ? _get(container.model, path) : container.model)} + + : null; - const cases = property.properties.map(d => { - if (d.type === 'case') { - caseByNameMap[d.name] = d.properties[0]; - return { - optionName: d.name, - optionTitle: d.description, - //represents case name and case element name - optionValue: [d.name, d.properties[0].name].join('.') - }; - } - caseByNameMap[d.name] = d; - return {optionName: d.name}; - }); + return ( + + {children} + + ); - const options = [{optionName: '', optionValue: false}].concat(cases).map((d, i) => { - return ( - - {d.optionName} - {i ? null : changeCase.title(property.name)} - - ); - }); + } - const selectName = path.join('.'); - let selectedOptionPath = ['uiState.choice', selectName, 'selected'].join('.'); - //Currently selected choice/case statement on UI model - let selectedOptionValue = utils.resolvePath(container.model, selectedOptionPath); - //If first time loaded, and none is selected, check if there is a value corresponding to a case statement in the container model - if(!selectedOptionValue) { - //get field properties for choice on container model - let fieldProperties = utils.resolvePath(container.model, selectName); - 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.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('.')); - } + function buildLeafList(property, path, value, uniqueId) { + if (!Array.isArray(value)) { + value = [value]; } - //If selectedOptionValue is present, take first item in string which represents the case name. - const valueProperty = caseByNameMap[selectedOptionValue ? selectedOptionValue.split('.')[0] : undefined] || {properties: []}; - const isLeaf = Property.isLeaf(valueProperty); - const hasProperties = _.isArray(valueProperty.properties) && valueProperty.properties.length; - const isMissingDescriptorMeta = !hasProperties && !Property.isLeaf(valueProperty); - //Some magic that prevents errors for arising - const valueResponse = valueProperty.properties.length ? valueProperty.properties.map((d, i) => { - const childPath = path.concat(valueProperty.name, d.name); - const childValue = utils.resolvePath(container.model, childPath.join('.')); + const children = value && value.map((v, i) => { + let itemPath = path.concat([i]); + const field = buildField(property, itemPath, v, uniqueId + i); return ( - - {build(container, d, childPath, childValue, props)} - - ); - }) : (!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); - + + {field} + + ) + }); return ( - - - {options} - - {valueResponse} - + + {children} + ); - } - function buildSimpleListItem(container, property, path, value, key, index) { - // todo need to abstract this better - const title = getTitle(value); - var req = require.context("../", true, /\.svg/); + function buildList(property, path, value, uniqueId) { + if (value && !Array.isArray(value)) { + value = [value]; + } + function getListItemSummary(index, value) { + const keys = property.key.map((key) => value[key]); + const summary = keys.join(' '); + return summary.length > 1 ? summary : '' + (index + 1); + } + const children = value && value.map((itemValue, i) => { + const itemPath = path.concat([i]); + const key = resolveReactKey(itemValue); + const children = buildComponentsForProperties(property.properties, itemPath, itemValue); + const showOpened = getPanelOpenedCondition(value, itemPath); + return ( + + {children} + + ) + }); + const showOpened = getPanelOpenedCondition(value, path); return ( - - - - {title} - - {buildRemovePropertyAction(container, property, path)} - + + {children} + ); } - function buildRemoveListItem(container, property, valuePath, fieldKey, index) { - const className = ClassNames(property.name + '-remove actions'); + function buildSimpleList(property, path, value, uniqueId) { + if (value && !Array.isArray(value)) { + value = [value]; + } + const children = value && value.map((v, i) => { + let itemPath = path.concat([i]); + return ( + + ) + }); + const tip = getTipForProperty(property); + const showOpened = getPanelOpenedCondition(value, path); + const changeOpenState = setPropertyOpenState.bind(null, container, path, property, !showOpened); return ( - - - {changeCase.title(property.name)} - {index + 1} - {buildRemovePropertyAction(container, property, valuePath)} - - + + {children} + ); } - function buildLeafListItem(container, property, valuePath, value, key, index) { - // look at the type to determine how to parse the value + function buildContainer(property, path, value, uniqueId) { + const children = buildComponentsForProperties(property.properties, path, value); + const showOpened = getPanelOpenedCondition(value, path); + const changeOpenState = setPropertyOpenState.bind(null, container, path, property, !showOpened); return ( - - {buildRemoveListItem(container, property, valuePath, key, index)} - {buildField(container, property, valuePath, value, key)} - - + + {children} + ); } - function build(container, property, path, value, props = {}) { + function buildPropertyComponent(property, path, value) { const fields = []; - const isLeaf = Property.isLeaf(property); const isArray = Property.isArray(property); const isObject = Property.isObject(property); - const isLeafList = Property.isLeafList(property); - const fieldKey = [container.id].concat(path); - const isRequired = Property.isRequired(property); const title = changeCase.titleCase(property.name); - const columnCount = property.properties.length || 1; - const isColumnar = isArray && (Math.round(props.width / columnCount) > 155); - const classNames = {'-is-required': isRequired, '-is-columnar': isColumnar}; + + // create a unique Id for use as react component keys and html element ids + // use uid (from ui info) instead of id property (which is not stable) + let uniqueId = idMaker(container, path); if (!property.properties && isObject) { + console.debug('no properties', property); const uiState = DescriptorModelMetaFactory.getModelMetaForType(property.name) || {}; property.properties = uiState.properties; } - const hasProperties = _.isArray(property.properties) && property.properties.length; - const isMissingDescriptorMeta = !hasProperties && !Property.isLeaf(property); - - // ensure value is not undefined for non-leaf property types - if (isObject) { - if (typeof value !== 'object') { - value = isArray ? [] : {}; - } - } - const valueAsArray = _.isArray(value) ? value : isLeafList && typeof value === 'undefined' ? [] : [value]; - - const isMetaField = property.name === 'meta'; - const isCVNFD = property.name === 'constituent-vnfd'; - const isSimpleListView = Property.isSimpleList(property); - - valueAsArray.forEach((value, index) => { - - let field; - const key = fieldKey.slice(); - const valuePath = path.slice(); - - if (isArray) { - valuePath.push(index); - key.push(index); - } - - if (isMetaField) { - if (typeof value === 'object') { - value = JSON.stringify(value, undefined, 12); - } else if (typeof value !== 'string') { - value = '{}'; - } - } - - if (isMissingDescriptorMeta) { - field = No Descriptor Meta for {property.name}; - } else if (property.type === 'choice') { - field = buildChoice(container, property, valuePath, value, key.join(':')); - } else if (isSimpleListView) { - field = buildSimpleListItem(container, property, valuePath, value, key, index); - } else if (isLeafList) { - field = buildLeafListItem(container, property, valuePath, value, key, index); - } else if (hasProperties) { - field = buildElement(container, property, valuePath, value, key.join(':')) - } else { - field = buildField(container, property, valuePath, value, key.join(':')); - } - - function onClickLeaf(property, path, value, event) { - if (event.isDefaultPrevented()) { - return; - } - event.preventDefault(); - event.stopPropagation(); - this.getRoot().uiState.focusedPropertyPath = path.join('.'); - console.log('property selected', path.join('.')); - ComposerAppActions.propertySelected([path.join('.')]); - } - - const clickHandler = isLeaf ? onClickLeaf : () => {}; - const isContainerList = isArray && !(isSimpleListView || isLeafList); - - fields.push( - - {isContainerList ? buildRemoveListItem(container, property, valuePath, fieldKey, index) : null} - {field} - + if (property.type === 'leaf') { + return buildField(property, path, value, uniqueId); + } else if (property.type === 'leaf_list') { + return buildLeafList(property, path, value, uniqueId); + } else if (property.type === 'list') { + return Property.isSimpleList(property) ? + buildSimpleList(property, path, value, uniqueId) + : + buildList(property, path, value, uniqueId); + } else if (property.type === 'container') { + return buildContainer(property, path, value, uniqueId); + } else if (property.type === 'choice') { + return buildChoice(property, path, value, uniqueId); + } else { + return ( + No Descriptor Meta for {property.name} ); - - }); - - classNames['-is-leaf'] = isLeaf; - classNames['-is-array'] = isArray; - classNames['cols-' + columnCount] = isColumnar; - - 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; - const displayValueInfo = isArray ? valueAsArray.filter(d => typeof d !== 'undefined').length + ' items' : ''; - - const onFocus = isLeaf ? event => event.target.classList.add('-is-focused') : false; - - return ( - - - - {title} - - {displayValueInfo} - {displayValue} - - {isArray ? buildAddPropertyAction(container, property, path.concat(valueAsArray.length)) : null} - - - {property.description} - - {isCVNFD ? Drag a VNFD from the Catalog to add more. : null} - {fields} - - - ); + if (!(DescriptorModelFactory.isContainer(container))) { + return } const containerType = container.uiState['qualified-type'] || container.uiState.type; - const basicProperties = getDescriptorMetaBasicForType(containerType).properties; - - function buildBasicGroup() { - if (basicProperties.length === 0) { - return null; - } - return ( - - Basic - - {basicProperties.map(property => { - const path = [property.name]; - const value = container.model[property.name]; - return build(container, property, path, value); - })} - - - ); + let properties = DescriptorModelMetaFactory.getModelMetaForType(containerType).properties; + const breadcrumb = []; + if (container.parent) { + breadcrumb.push(container.parent); } - - function buildAdvancedGroup() { - const properties = getDescriptorMetaAdvancedForType(containerType).properties; - if (properties.length === 0) { - return null; + breadcrumb.push(container); + // bubble all data properties to top of list + let twoLists = properties.reduce((o, property) => { + const value = _get(container.model, [property.name]); + if (isDataProperty(property)) { + o.listOne.push(property); + } else { + o.listTwo.push(property); } - const hasBasicFields = basicProperties.length > 0; - const closeGroup = basicProperties.length > 0; - return ( - - - more… - less… - - - {properties.map(property => { - const path = [property.name]; - const value = container.model[property.name]; - return build(container, property, path, value, {toggle: true, width: props.width}); - })} - - We need this so when the user closes the panel it won't shift away and scare the bj out of them! - - ); - } - - function buildMoreLess(d, i) { - return ( - - {d.title} - / - - ); + return o; + }, { listOne: [], listTwo: [] }); + properties = twoLists.listOne.concat(twoLists.listTwo); + const children = buildComponentsForProperties(properties, [], container.model); + + function onClick(event) { + console.debug(event.target); + if (event.isDefaultPrevented()) { + return; + } + event.preventDefault(); + event.stopPropagation(); + // notifyFocusedHandler(); } - const path = []; - if (container.parent) { - path.push(container.parent); + function onWrapperFocus(event) { + console.debug(event.target); + //notifyFocusedHandler(); } - path.push(container); return ( - - {path.map(buildMoreLess)} - {buildBasicGroup()} - {buildAdvancedGroup()} + + + {children} ); +}; -}