3 * Copyright 2016 RIFT.IO Inc
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * Created by onvelocity on 1/18/16.
21 * This class generates the form fields used to edit the CONFD JSON model.
25 import _
from 'lodash'
26 import utils
from '../libraries/utils'
27 import React
from 'react'
28 import ClassNames
from 'classnames'
29 import changeCase
from 'change-case'
30 import toggle
from '../libraries/ToggleElementHandler'
31 import Button
from './Button'
32 import Property
from '../libraries/model/DescriptorModelMetaProperty'
33 import ComposerAppActions
from '../actions/ComposerAppActions'
34 import CatalogItemsActions
from '../actions/CatalogItemsActions'
35 import DESCRIPTOR_MODEL_FIELDS
from '../libraries/model/DescriptorModelFields'
36 import DescriptorModelFactory
from '../libraries/model/DescriptorModelFactory'
37 import DescriptorModelMetaFactory
from '../libraries/model/DescriptorModelMetaFactory'
38 import SelectionManager
from '../libraries/SelectionManager'
39 import DeletionManager
from '../libraries/DeletionManager'
40 import DescriptorModelIconFactory
from '../libraries/model/IconFactory'
41 import getEventPath
from '../libraries/getEventPath'
42 import CatalogDataStore
from '../stores/CatalogDataStore'
44 import imgAdd
from '../../../node_modules/open-iconic/svg/plus.svg'
45 import imgRemove
from '../../../node_modules/open-iconic/svg/trash.svg'
47 import '../styles/EditDescriptorModelProperties.scss'
51 function getDescriptorMetaBasicForType(type
) {
52 const basicPropertiesFilter
= d
=> _
.includes(DESCRIPTOR_MODEL_FIELDS
[type
], d
.name
);
53 return DescriptorModelMetaFactory
.getModelMetaForType(type
, basicPropertiesFilter
) || {properties
: []};
56 function getDescriptorMetaAdvancedForType(type
) {
57 const advPropertiesFilter
= d
=> !_
.includes(DESCRIPTOR_MODEL_FIELDS
[type
], d
.name
);
58 return DescriptorModelMetaFactory
.getModelMetaForType(type
, advPropertiesFilter
) || {properties
: []};
61 function getTitle(model
= {}) {
62 if (typeof model
['short-name'] === 'string' && model
['short-name']) {
63 return model
['short-name'];
65 if (typeof model
.name
=== 'string' && model
.name
) {
68 if (model
.uiState
&& typeof model
.uiState
.displayName
=== 'string' && model
.uiState
.displayName
) {
69 return model
.uiState
.displayName
71 if (typeof model
.id
=== 'string') {
75 function startEditing() {
76 DeletionManager
.removeEventListeners();
79 function endEditing() {
80 DeletionManager
.addEventListeners();
83 function onClickSelectItem(property
, path
, value
, event
) {
84 event
.preventDefault();
85 const root
= this.getRoot();
86 if (SelectionManager
.select(value
)) {
87 CatalogItemsActions
.catalogItemMetaDataChanged(root
.model
);
91 function onFocusPropertyFormInputElement(property
, path
, value
, event
) {
93 event
.preventDefault();
96 function removeIsFocusedClass(event
) {
97 event
.target
.removeEventListener('blur', removeIsFocusedClass
);
98 Array
.from(document
.querySelectorAll('.-is-focused')).forEach(d
=> d
.classList
.remove('-is-focused'));
101 removeIsFocusedClass(event
);
103 const propertyWrapper
= getEventPath(event
).reduce((parent
, element
) => {
107 if (!element
.classList
) {
110 if (element
.classList
.contains('property')) {
115 if (propertyWrapper
) {
116 propertyWrapper
.classList
.add('-is-focused');
117 event
.target
.addEventListener('blur', removeIsFocusedClass
);
122 function buildAddPropertyAction(container
, property
, path
) {
123 function onClickAddProperty(property
, path
, event
) {
124 event
.preventDefault();
125 //SelectionManager.resume();
126 const create
= Property
.getContainerCreateMethod(property
, this);
129 create(model
, path
, property
);
131 const name
= path
.join('.');
132 const value
= Property
.createModelInstance(property
);
133 utils
.assignPathValue(this.model
, name
, value
);
135 CatalogItemsActions
.catalogItemDescriptorChanged(this.getRoot());
138 <Button className
="inline-hint" onClick
={onClickAddProperty
.bind(container
, property
, path
)} label
="Add" src
={imgAdd
} />
142 function buildRemovePropertyAction(container
, property
, path
) {
143 function onClickRemoveProperty(property
, path
, event
) {
144 event
.preventDefault();
145 const name
= path
.join('.');
146 const removeMethod
= Property
.getContainerMethod(property
, this, 'remove');
148 removeMethod(utils
.resolvePath(this.model
, name
));
150 utils
.removePathValue(this.model
, name
);
152 CatalogItemsActions
.catalogItemDescriptorChanged(this.getRoot());
155 <Button className
="remove-property-action inline-hint" title
="Remove" onClick
={onClickRemoveProperty
.bind(container
, property
, path
)} label
="Remove" src
={imgRemove
}/>
159 function onFormFieldValueChanged(event
) {
160 if (DescriptorModelFactory
.isContainer(this)) {
161 event
.preventDefault();
162 const name
= event
.target
.name
;
163 const value
= event
.target
.value
;
164 utils
.assignPathValue(this.model
, name
, value
);
165 CatalogItemsActions
.catalogItemDescriptorChanged(this.getRoot());
169 function buildField(container
, property
, path
, value
, fieldKey
) {
170 let cds
= CatalogDataStore
;
171 let catalogs
= cds
.getTransientCatalogs();
173 const name
= path
.join('.');
174 const isEditable
= true;
175 const isGuid
= Property
.isGuid(property
);
176 const onChange
= onFormFieldValueChanged
.bind(container
);
177 const isEnumeration
= Property
.isEnumeration(property
);
178 const isLeafRef
= Property
.isLeafRef(property
);
179 const onFocus
= onFocusPropertyFormInputElement
.bind(container
, property
, path
, value
);
180 const placeholder
= changeCase
.title(property
.name
);
181 const className
= ClassNames(property
.name
+ '-input', {'-is-guid': isGuid
});
182 const fieldValue
= value
? (value
.constructor.name
!= "Object") ? value
: '' : undefined;
184 const enumeration
= Property
.getEnumeration(property
, value
);
185 const options
= enumeration
.map((d
, i
) => {
186 // note yangforge generates values for enums but the system does not use them
187 // so we categorically ignore them
188 // https://trello.com/c/uzEwVx6W/230-bug-enum-should-not-use-index-only-name
189 //return <option key={fieldKey + ':' + i} value={d.value}>{d.name}</option>;
190 return <option key
={fieldKey
.toString() + ':' + i
} value
={d
.name
}>{d
.name
}</option
>;
192 const isValueSet
= enumeration
.filter(d
=> d
.isSelected
).length
> 0;
193 if (!isValueSet
|| property
.cardinality
=== '0..1') {
194 const noValueDisplayText
= changeCase
.title(property
.name
);
195 options
.unshift(<option key
={'(value-not-in-enum)' + fieldKey
.toString()} value
="" placeholder
={placeholder
}>{noValueDisplayText
}</option
>);
197 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
>;
201 let fullFieldKey
= _
.isArray(fieldKey
) ? fieldKey
.join(':') : fieldKey
;
202 let containerRef
= container
;
203 while (containerRef
.parent
) {
204 fullFieldKey
= containerRef
.parent
.key
+ ':' + fullFieldKey
;
205 containerRef
= containerRef
.parent
;
207 const leafRefPathValues
= Property
.getLeafRef(property
, path
, value
, fullFieldKey
, catalogs
, container
);
209 const options
= leafRefPathValues
&& leafRefPathValues
.map((d
, i
) => {
210 return <option key
={fieldKey
.toString() + ':' + i
} value
={d
.value
}>{d
.value
}</option
>;
212 const isValueSet
= leafRefPathValues
.filter(d
=> d
.isSelected
).length
> 0;
213 if (!isValueSet
|| property
.cardinality
=== '0..1') {
214 const noValueDisplayText
= changeCase
.title(property
.name
);
215 options
.unshift(<option key
={'(value-not-in-leafref)' + fieldKey
.toString()} value
="" placeholder
={placeholder
}>{noValueDisplayText
}</option
>);
217 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
>;
220 if (property
['preserve-line-breaks']) {
221 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
} />;
224 return <input key
={fieldKey
.toString()}
225 id
={fieldKey
.toString()}
229 className
={className
}
230 placeholder
={placeholder
}
234 onMouseDown
={startEditing
}
235 onMouseOver
={startEditing
}
236 onMouseOut
={endEditing
}
237 onMouseLeave
={endEditing
}
238 readOnly
={!isEditable
}
243 function buildElement(container
, property
, valuePath
, value
) {
244 return property
.properties
.map((property
, index
) => {
246 const childPath
= valuePath
.slice();
247 if (typeof value
=== 'object') {
248 childValue
= value
[property
.name
];
250 if(property
.type
!= 'choice'){
251 childPath
.push(property
.name
);
253 return build(container
, property
, childPath
, childValue
);
258 function buildChoice(container
, property
, path
, value
, key
, props
={}) {
260 function onFormFieldValueChanged(event
) {
261 if (DescriptorModelFactory
.isContainer(this)) {
263 event
.preventDefault();
265 let name
= event
.target
.name
;
266 const value
= event
.target
.value
;
270 Transient State is stored for convenience in the uiState field.
271 The choice yang type uses case elements to describe the "options".
272 A choice can only ever have one option selected which allows
273 the system to determine which type is selected by the name of
274 the element contained within the field.
277 const stateExample = {
292 const statePath
= ['uiState.choice'].concat(name
);
293 const stateObject
= utils
.resolvePath(this.model
, statePath
.join('.')) || {};
294 const selected
= stateObject
.selected
? stateObject
.selected
.split('.')[1] : undefined;
295 // write state back to the model so the new state objects are captured
296 utils
.assignPathValue(this.model
, statePath
.join('.'), stateObject
);
298 // write the current choice value into the state
299 let choiceObject
= utils
.resolvePath(this.model
, [name
, selected
].join('.'));
300 let isTopCase
= false;
303 choiceObject
= utils
.resolvePath(this.model
, [selected
].join('.'));
305 utils
.assignPathValue(stateObject
, [selected
].join('.'), _
.cloneDeep(choiceObject
));
308 if(this.model
.uiState
.choice
.hasOwnProperty(name
)) {
309 delete this.model
[selected
];
310 utils
.removePathValue(this.model
, [name
, selected
].join('.'), isTopCase
);
312 // remove the current choice value from the model
313 utils
.removePathValue(this.model
, [name
, selected
].join('.'), isTopCase
);
317 // get any state for the new selected choice
318 const newChoiceObject
= utils
.resolvePath(stateObject
, [value
].join('.')) || {};
320 // assign new choice value to the model
322 utils
.assignPathValue(this.model
, [name
, value
].join('.'), newChoiceObject
);
324 utils
.assignPathValue(this.model
, [value
].join('.'), newChoiceObject
)
328 // update the selected name
329 utils
.assignPathValue(this.model
, statePath
.concat('selected').join('.'), value
);
331 CatalogItemsActions
.catalogItemDescriptorChanged(this.getRoot());
335 const caseByNameMap
= {};
337 const onChange
= onFormFieldValueChanged
.bind(container
);
339 const cases
= property
.properties
.map(d
=> {
340 if (d
.type
=== 'case') {
341 caseByNameMap
[d
.name
] = d
.properties
[0];
344 optionTitle
: d
.description
,
345 //represents case name and case element name
346 optionValue
: [d
.name
, d
.properties
[0].name
].join('.')
349 caseByNameMap
[d
.name
] = d
;
350 return {optionName
: d
.name
};
353 const options
= [{optionName
: '', optionValue
: false}].concat(cases
).map((d
, i
) => {
355 <option key
={i
} value
={d
.optionValue
} title
={d
.optionTitle
}>
357 {i
? null : changeCase
.title(property
.name
)}
362 const selectName
= path
.join('.');
363 let selectedOptionPath
= ['uiState.choice', selectName
, 'selected'].join('.');
364 //Currently selected choice/case statement on UI model
365 let selectedOptionValue
= utils
.resolvePath(container
.model
, selectedOptionPath
);
366 //If first time loaded, and none is selected, check if there is a value corresponding to a case statement in the container model
367 if(!selectedOptionValue
) {
368 //get field properties for choice on container model
369 let fieldProperties
= utils
.resolvePath(container
.model
, selectName
);
370 if(fieldProperties
) {
371 //Check each case statement in model and see if it is present in container model.
372 cases
.map(function(c
){
373 if(fieldProperties
.hasOwnProperty(c
.optionValue
.split('.')[1])) {
374 utils
.assignPathValue(container
.model
, ['uiState.choice', selectName
, 'selected'].join('.'), c
.optionValue
);
377 selectedOptionValue
= utils
.resolvePath(container
.model
, ['uiState.choice', selectName
, 'selected'].join('.'));
379 property
.properties
.map(function(p
) {
380 let pname
= p
.properties
[0].name
;
381 if(container
.model
.hasOwnProperty(pname
)) {
382 utils
.assignPathValue(container
.model
, ['uiState.choice', selectName
, 'selected'].join('.'), [p
.name
, pname
].join('.'));
385 selectedOptionValue
= utils
.resolvePath(container
.model
, ['uiState.choice', selectName
, 'selected'].join('.'));
388 //If selectedOptionValue is present, take first item in string which represents the case name.
389 const valueProperty
= caseByNameMap
[selectedOptionValue
? selectedOptionValue
.split('.')[0] : undefined] || {properties
: []};
390 const isLeaf
= Property
.isLeaf(valueProperty
);
391 const hasProperties
= _
.isArray(valueProperty
.properties
) && valueProperty
.properties
.length
;
392 const isMissingDescriptorMeta
= !hasProperties
&& !Property
.isLeaf(valueProperty
);
393 //Some magic that prevents errors for arising
394 const valueResponse
= valueProperty
.properties
.length
? valueProperty
.properties
.map((d
, i
) => {
395 const childPath
= path
.concat(valueProperty
.name
, d
.name
);
396 const childValue
= utils
.resolvePath(container
.model
, childPath
.join('.'));
398 <div key
={childPath
.concat('info', i
).join(':')}>
399 {build(container
, d
, childPath
, childValue
, props
)}
402 }) : (!isMissingDescriptorMeta
) ? build(container
, valueProperty
, path
.concat(valueProperty
.name
), utils
.resolvePath(container
.model
, path
.concat(valueProperty
.name
).join('.')) || container
.model
[valueProperty
.name
]) : null
404 const onFocus
= onFocusPropertyFormInputElement
.bind(container
, property
, path
, value
);
407 <div key
={key
} className
="choice">
408 <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
}>
417 function buildSimpleListItem(container
, property
, path
, value
, key
, index
) {
418 // todo need to abstract this better
419 const title
= getTitle(value
);
420 var req
= require
.context("../", true, /\.svg
/);
423 <a href
="#select-list-item" key
={Date
.now()} className
={property
.name
+ '-list-item simple-list-item '} onClick
={onClickSelectItem
.bind(container
, property
, path
, value
)}>
424 <img src
={req('./' + DescriptorModelIconFactory
.getUrlForType(property
.name
))} width
="20px" />
427 {buildRemovePropertyAction(container
, property
, path
)}
432 function buildRemoveListItem(container
, property
, valuePath
, fieldKey
, index
) {
433 const className
= ClassNames(property
.name
+ '-remove actions');
435 <div key
={fieldKey
.concat(index
).join(':')} className
={className
}>
437 <span className
={property
.type
+ '-name name'}>{changeCase
.title(property
.name
)}</span
>
438 <span className
="info">{index
+ 1}</span
>
439 {buildRemovePropertyAction(container
, property
, valuePath
)}
445 function buildLeafListItem(container
, property
, valuePath
, value
, key
, index
) {
446 // look at the type to determine how to parse the value
449 {buildRemoveListItem(container
, property
, valuePath
, key
, index
)}
450 {buildField(container
, property
, valuePath
, value
, key
)}
456 function build(container
, property
, path
, value
, props
= {}) {
459 const isLeaf
= Property
.isLeaf(property
);
460 const isArray
= Property
.isArray(property
);
461 const isObject
= Property
.isObject(property
);
462 const isLeafList
= Property
.isLeafList(property
);
463 const fieldKey
= [container
.id
].concat(path
);
464 const isRequired
= Property
.isRequired(property
);
465 const title
= changeCase
.titleCase(property
.name
);
466 const columnCount
= property
.properties
.length
|| 1;
467 const isColumnar
= isArray
&& (Math
.round(props
.width
/ columnCount
) > 155);
468 const classNames
= {'-is-required': isRequired
, '-is-columnar': isColumnar
};
470 if (!property
.properties
&& isObject
) {
471 const uiState
= DescriptorModelMetaFactory
.getModelMetaForType(property
.name
) || {};
472 property
.properties
= uiState
.properties
;
475 const hasProperties
= _
.isArray(property
.properties
) && property
.properties
.length
;
476 const isMissingDescriptorMeta
= !hasProperties
&& !Property
.isLeaf(property
);
478 // ensure value is not undefined for non-leaf property types
480 if (typeof value
!== 'object') {
481 value
= isArray
? [] : {};
484 const valueAsArray
= _
.isArray(value
) ? value
: isLeafList
&& typeof value
=== 'undefined' ? [] : [value
];
486 const isMetaField
= property
.name
=== 'meta';
487 const isCVNFD
= property
.name
=== 'constituent-vnfd';
488 const isSimpleListView
= Property
.isSimpleList(property
);
490 valueAsArray
.forEach((value
, index
) => {
493 const key
= fieldKey
.slice();
494 const valuePath
= path
.slice();
497 valuePath
.push(index
);
502 if (typeof value
=== 'object') {
503 value
= JSON
.stringify(value
, undefined, 12);
504 } else if (typeof value
!== 'string') {
509 if (isMissingDescriptorMeta
) {
510 field
= <span key
={key
.concat('warning').join(':')} className
="warning">No Descriptor Meta
for {property
.name
}</span
>;
511 } else if (property
.type
=== 'choice') {
512 field
= buildChoice(container
, property
, valuePath
, value
, key
.join(':'), props
);
513 } else if (isSimpleListView
) {
514 field
= buildSimpleListItem(container
, property
, valuePath
, value
, key
, index
, props
);
515 } else if (isLeafList
) {
516 field
= buildLeafListItem(container
, property
, valuePath
, value
, key
, index
, props
);
517 } else if (hasProperties
) {
518 field
= buildElement(container
, property
, valuePath
, value
, key
.join(':'), props
)
520 field
= buildField(container
, property
, valuePath
, value
, key
.join(':'), props
);
523 function onClickLeaf(property
, path
, value
, event
) {
524 if (event
.isDefaultPrevented()) {
527 event
.preventDefault();
528 event
.stopPropagation();
529 this.getRoot().uiState
.focusedPropertyPath
= path
.join('.');
530 console
.log('property selected', path
.join('.'));
531 ComposerAppActions
.propertySelected([path
.join('.')]);
534 const clickHandler
= isLeaf
? onClickLeaf
: () => {};
535 const isContainerList
= isArray
&& !(isSimpleListView
|| isLeafList
);
538 <div key
={fieldKey
.concat(['property-content', index
]).join(':')}
539 className
={ClassNames('property-content', {'simple-list': isSimpleListView
})}
540 onClick
={clickHandler
.bind(container
, property
, valuePath
, value
)}>
541 {isContainerList
? buildRemoveListItem(container
, property
, valuePath
, fieldKey
, index
) : null}
548 classNames
['-is-leaf'] = isLeaf
;
549 classNames
['-is-array'] = isArray
;
550 classNames
['cols-' + columnCount
] = isColumnar
;
552 if (property
.type
=== 'choice') {
553 value
= utils
.resolvePath(container
.model
, ['uiState.choice'].concat(path
, 'selected').join('.'));
555 property
.properties
.map(function(p
) {
556 let pname
= p
.properties
[0].name
;
557 if(container
.model
.hasOwnProperty(pname
)) {
558 value
= container
.model
[pname
];
564 let displayValue
= typeof value
=== 'object' ? '' : value
;
565 const displayValueInfo
= isArray
? valueAsArray
.filter(d
=> typeof d
!== 'undefined').length
+ ' items' : '';
567 const onFocus
= isLeaf
? event
=> event
.target
.classList
.add('-is-focused') : false;
570 <div key
={fieldKey
.join(':')} className
={ClassNames(property
.type
+ '-property property', classNames
)} onFocus
={onFocus
}>
571 <h3 className
="property-label">
572 <label htmlFor
={fieldKey
.join(':')}>
573 <span className
={property
.type
+ '-name name'}>{title
}</span
>
575 <span className
={property
.type
+ '-info info'}>{displayValueInfo
}</span
>
576 <span className
={property
.type
+ '-value value'}>{displayValue
}</span
>
578 {isArray
? buildAddPropertyAction(container
, property
, path
.concat(valueAsArray
.length
)) : null}
581 <span className
={property
.type
+ '-description description'}>{property
.description
}</span
>
582 <val className
="property-value">
583 {isCVNFD
? <span className
={property
.type
+ '-tip tip'}>Drag a VNFD
from the Catalog to add more
.</span
> : null}
590 export default function EditDescriptorModelProperties(props
, type
) {
592 const container
= props
.container
;
594 if (!(DescriptorModelFactory
.isContainer(container
))) {
600 const containerType
= (_
.isEmpty(type
) ? false : type
)|| container
.uiState
['qualified-type'] || container
.uiState
.type
;
601 const basicProperties
= getDescriptorMetaBasicForType(containerType
).properties
;
603 function buildBasicGroup() {
604 if (basicProperties
.length
=== 0) {
608 <div className
="basic-properties-group">
611 {basicProperties
.map(property
=> {
612 const path
= [property
.name
];
613 const value
= container
.model
[property
.name
];
614 return build(container
, property
, path
, value
);
621 function buildAdvancedGroup() {
622 const properties
= getDescriptorMetaAdvancedForType(containerType
).properties
;
623 if (properties
.length
=== 0) {
626 const hasBasicFields
= basicProperties
.length
> 0;
627 const closeGroup
= basicProperties
.length
> 0;
629 <div className
="advanced-properties-group">
630 <h1 data
-toggle
={closeGroup
? 'true' : 'false'} className
={ClassNames({'-is-toggled': closeGroup
})} onClick
={toggle
} style
={{display
: hasBasicFields
? 'block' : 'none'}}>
631 <a className
="toggle-show-more" href
="#show-more-properties">more
&hellip
;</a
>
632 <a className
="toggle-show-less" href
="#show-more-properties">less
&hellip
;</a
>
634 <div className
="toggleable">
635 {properties
.map(property
=> {
636 const path
= [property
.name
];
637 const value
= container
.model
[property
.name
];
638 return build(container
, property
, path
, value
, _
.assign({toggle
: true, width
: props
.width
}, props
));
641 <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>
646 function buildMoreLess(d, i) {
648 <span key={'bread
-crumb
-part
-' + i}>
649 <a href="#select-item" onClick={onClickSelectItem.bind(d, null, null, d)}>{d.title}</a>
656 if (container.parent) {
657 path.push(container.parent);
659 path.push(container);
662 <div className="EditDescriptorModelProperties -is-tree-view">
663 <h1>{path.map(buildMoreLess)}</h1>
665 {buildAdvancedGroup()}
671 // export buildElement;
672 // export buildChoice;