--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO 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.
+ *
+ */
+/**
+ * Created by onvelocity on 1/18/16.
+ *
+ * This class generates the form fields used to edit the CONFD JSON model.
+ */
+'use strict';
+
+import _ from 'lodash'
+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 ComposerAppActions from '../actions/ComposerAppActions'
+import CatalogItemsActions from '../actions/CatalogItemsActions'
+import DESCRIPTOR_MODEL_FIELDS from '../libraries/model/DescriptorModelFields'
+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 '../styles/EditDescriptorModelProperties.scss'
+
+
+
+function getDescriptorMetaBasicForType(type) {
+ const basicPropertiesFilter = d => _.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name);
+ return DescriptorModelMetaFactory.getModelMetaForType(type, basicPropertiesFilter) || {properties: []};
+}
+
+function getDescriptorMetaAdvancedForType(type) {
+ const advPropertiesFilter = d => !_.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name);
+ return DescriptorModelMetaFactory.getModelMetaForType(type, advPropertiesFilter) || {properties: []};
+}
+
+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 startEditing() {
+ DeletionManager.removeEventListeners();
+ }
+
+ function endEditing() {
+ DeletionManager.addEventListeners();
+ }
+
+ function onClickSelectItem(property, path, value, event) {
+ event.preventDefault();
+ const root = this.getRoot();
+ if (SelectionManager.select(value)) {
+ CatalogItemsActions.catalogItemMetaDataChanged(root.model);
+ }
+ }
+
+ 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'));
+ }
+
+ removeIsFocusedClass(event);
+
+ const propertyWrapper = getEventPath(event).reduce((parent, element) => {
+ if (parent) {
+ return parent;
+ }
+ if (!element.classList) {
+ return false;
+ }
+ 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());
+ }
+ return (
+ <Button className="inline-hint" onClick={onClickAddProperty.bind(container, property, path)} label="Add" src={imgAdd} />
+ );
+ }
+
+ 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());
+ }
+ return (
+ <Button className="remove-property-action inline-hint" title="Remove" onClick={onClickRemoveProperty.bind(container, property, path)} label="Remove" src={imgRemove}/>
+ );
+ }
+
+ 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 <option key={fieldKey + ':' + i} value={d.value}>{d.name}</option>;
+ return <option key={fieldKey.toString() + ':' + i} value={d.name}>{d.name}</option>;
+ });
+ const isValueSet = enumeration.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-enum)' + 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 (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} />;
+ }
+
+ return <input key={fieldKey.toString()}
+ id={fieldKey.toString()}
+ type="text"
+ name={name}
+ value={fieldValue}
+ className={className}
+ placeholder={placeholder}
+ onChange={onChange}
+ onFocus={onFocus}
+ onBlur={endEditing}
+ onMouseDown={startEditing}
+ onMouseOver={startEditing}
+ onMouseOut={endEditing}
+ onMouseLeave={endEditing}
+ readOnly={!isEditable}
+ />;
+
+ }
+
+ 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(container, property, path, value, key, props={}) {
+
+ 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('.'));
+ }
+ 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);
+ }
+ }
+
+ // 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());
+ }
+ }
+
+ const caseByNameMap = {};
+
+ const onChange = onFormFieldValueChanged.bind(container);
+
+ 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};
+ });
+
+ const options = [{optionName: '', optionValue: false}].concat(cases).map((d, i) => {
+ return (
+ <option key={i} value={d.optionValue} title={d.optionTitle}>
+ {d.optionName}
+ {i ? null : changeCase.title(property.name)}
+ </option>
+ );
+ });
+
+ 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('.'));
+ }
+ }
+ //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('.'));
+ return (
+ <div key={childPath.concat('info', i).join(':')}>
+ {build(container, d, childPath, childValue, props)}
+ </div>
+ );
+ }) : (!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);
+
+ return (
+ <div key={key} className="choice">
+ <select key={Date.now()} className={ClassNames({'-value-not-set': !selectedOptionValue})} name={selectName} value={selectedOptionValue} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} onMouseOut={endEditing} onMouseLeave={endEditing}>
+ {options}
+ </select>
+ {valueResponse}
+ </div>
+ );
+
+ }
+
+ function buildSimpleListItem(container, property, path, value, key, index) {
+ // todo need to abstract this better
+ const title = getTitle(value);
+ var req = require.context("../", true, /\.svg/);
+ return (
+ <div>
+ <a href="#select-list-item" key={Date.now()} className={property.name + '-list-item simple-list-item '} onClick={onClickSelectItem.bind(container, property, path, value)}>
+ <img src={req('./' + DescriptorModelIconFactory.getUrlForType(property.name))} width="20px" />
+ <span>{title}</span>
+ </a>
+ {buildRemovePropertyAction(container, property, path)}
+ </div>
+ );
+ }
+
+ function buildRemoveListItem(container, property, valuePath, fieldKey, index) {
+ const className = ClassNames(property.name + '-remove actions');
+ return (
+ <div key={fieldKey.concat(index).join(':')} className={className}>
+ <h3>
+ <span className={property.type + '-name name'}>{changeCase.title(property.name)}</span>
+ <span className="info">{index + 1}</span>
+ {buildRemovePropertyAction(container, property, valuePath)}
+ </h3>
+ </div>
+ );
+ }
+
+ function buildLeafListItem(container, property, valuePath, value, key, index) {
+ // look at the type to determine how to parse the value
+ return (
+ <div>
+ {buildRemoveListItem(container, property, valuePath, key, index)}
+ {buildField(container, property, valuePath, value, key)}
+ </div>
+
+ );
+ }
+
+ function build(container, property, path, value, props = {}) {
+
+ 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};
+
+ if (!property.properties && isObject) {
+ 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 = <span key={key.concat('warning').join(':')} className="warning">No Descriptor Meta for {property.name}</span>;
+ } else if (property.type === 'choice') {
+ field = buildChoice(container, property, valuePath, value, key.join(':'), props);
+ } else if (isSimpleListView) {
+ field = buildSimpleListItem(container, property, valuePath, value, key, index, props);
+ } else if (isLeafList) {
+ field = buildLeafListItem(container, property, valuePath, value, key, index, props);
+ } else if (hasProperties) {
+ field = buildElement(container, property, valuePath, value, key.join(':'), props)
+ } else {
+ field = buildField(container, property, valuePath, value, key.join(':'), props);
+ }
+
+ 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(
+ <div key={fieldKey.concat(['property-content', index]).join(':')}
+ className={ClassNames('property-content', {'simple-list': isSimpleListView})}
+ onClick={clickHandler.bind(container, property, valuePath, value)}>
+ {isContainerList ? buildRemoveListItem(container, property, valuePath, fieldKey, index) : null}
+ {field}
+ </div>
+ );
+
+ });
+
+ 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 (
+ <div key={fieldKey.join(':')} className={ClassNames(property.type + '-property property', classNames)} onFocus={onFocus}>
+ <h3 className="property-label">
+ <label htmlFor={fieldKey.join(':')}>
+ <span className={property.type + '-name name'}>{title}</span>
+ <small>
+ <span className={property.type + '-info info'}>{displayValueInfo}</span>
+ <span className={property.type + '-value value'}>{displayValue}</span>
+ </small>
+ {isArray ? buildAddPropertyAction(container, property, path.concat(valueAsArray.length)) : null}
+ </label>
+ </h3>
+ <span className={property.type + '-description description'}>{property.description}</span>
+ <val className="property-value">
+ {isCVNFD ? <span className={property.type + '-tip tip'}>Drag a VNFD from the Catalog to add more.</span> : null}
+ {fields}
+ </val>
+ </div>
+ );
+
+ }
+export default function EditDescriptorModelProperties(props, type) {
+
+ const container = props.container;
+
+ if (!(DescriptorModelFactory.isContainer(container))) {
+ return
+ }
+
+
+
+ const containerType = (_.isEmpty(type) ? false : type)|| container.uiState['qualified-type'] || container.uiState.type;
+ const basicProperties = getDescriptorMetaBasicForType(containerType).properties;
+
+
+ function buildAdvancedGroup() {
+ const properties = getDescriptorMetaAdvancedForType(containerType).properties;
+ if (properties.length === 0) {
+ return null;
+ }
+ const hasBasicFields = basicProperties.length > 0;
+ const closeGroup = basicProperties.length > 0;
+ return (
+ <div className="advanced-properties-group">
+
+ <div className="toggleable">
+ {properties.map((property,i) => {
+ const path = [property.name];
+ const value = container.model[property.name];
+ if(path == 'id') {
+ return null
+ }
+ if(path == 'config-parameter-request') {
+ return (
+ <div className="container-property property" key={path + '-' + i}>
+ <h3 className="property-label">
+ <span className="container-name name">{`VNF Index: ${value['member-vnf-index-ref']}`}</span>
+ </h3>
+ <val className="property-value">
+ <div className="property-content">
+ <val className="property-value" style={{width: '100%'}}>
+ <div className="property-content">
+ <div className="leaf-property property -is-leaf">
+ <h3 className="property-label">
+ <label for={path + '-' + i}>
+ <span className="leaf-name name">
+ Parameter Request
+ </span>
+ </label>
+ </h3>
+ <input value={value['config-parameter-request-ref']} readonly placeholder="Parameter Request" name={path + '-' + i}>
+
+ </input>
+ </div>
+ </div>
+ </val>
+ </div>
+ </val>
+
+ </div>
+ )
+ } else {
+ return build(container, property, path, value, _.assign({toggle: true, width: props.width}, props));
+ }
+
+ })}
+ </div>
+ <div className="toggle-bottom-spacer" style={{visibility: 'hidden', 'height': '50%', position: 'absolute'}}>We need this so when the user closes the panel it won't shift away and scare the bj out of them!</div>
+ </div>
+ );
+ }
+
+ function buildMoreLess(d, i) {
+ return (
+ <span key={'bread-crumb-part-' + i}>
+ <a href="#select-item" onClick={onClickSelectItem.bind(d, null, null, d)}>{d.title}</a>
+ <i> / </i>
+ </span>
+ );
+ }
+
+ const path = [];
+ if (container.parent) {
+ path.push(container.parent);
+ }
+ path.push(container);
+
+ return (
+ <div className="EditDescriptorModelProperties -is-tree-view">
+ {buildAdvancedGroup()}
+ </div>
+ );
+
+}
+export {build}
+// export buildElement;
+// export buildChoice;