Merging master to master_vca_intg

Signed-off-by: Kiran Kashalkar <kiran.kashalkar@riftio.com>
diff --git a/skyquake/plugins/composer/api/composer.js b/skyquake/plugins/composer/api/composer.js
index ebe5636..eaf5059 100644
--- a/skyquake/plugins/composer/api/composer.js
+++ b/skyquake/plugins/composer/api/composer.js
@@ -636,7 +636,7 @@
             forever: constants.FOREVER_ON,
             rejectUnauthorized: false,
         }, function(error, response, body) {
-            if (utils.validateResponse('restconfAPI.streams', error, response, body, resolve, reject)) {
+            if (utils.validateResponse('FileManager.job', error, response, body, resolve, reject)) {
                 var data = JSON.parse(response.body)['rw-pkg-mgmt:download-jobs'];
                 var returnData = [];
                 data && data.job.map(function(d) {
diff --git a/skyquake/plugins/composer/src/src/components/CanvasPanel.js b/skyquake/plugins/composer/src/src/components/CanvasPanel.js
index 9eece49..86afd56 100644
--- a/skyquake/plugins/composer/src/src/components/CanvasPanel.js
+++ b/skyquake/plugins/composer/src/src/components/CanvasPanel.js
@@ -34,9 +34,9 @@
 import EditForwardingGraphPaths from './EditorForwardingGraph/EditForwardingGraphPaths'
 import SelectionManager from '../libraries/SelectionManager'
 import DescriptorModelIconFactory from '../libraries/model/IconFactory'
-
 import FileManager from './filemanager/FileManager.jsx';
 
+import ConfigPrimitiveParameters from './ConfigPrimitiveParameters/ConfigPrimitiveParameters'
 import '../styles/CanvasPanel.scss'
 
 const CanvasPanel = React.createClass({
@@ -91,6 +91,13 @@
 					</div>
 				</div>
        		)
+        //CanvasPanelTray panel to display
+        let displayedPanel = null;
+        switch (this.props.displayedPanel) {
+            case 'forwarding' : displayedPanel = (<EditForwardingGraphPaths containers={this.props.containers} />); break;
+            case 'parameter' : displayedPanel = (<ConfigPrimitiveParameters  containers={this.props.containers} />); break;
+            default: displayedPanel = (<div><p className="welcome-message">Please select a tab</p></div>); break;
+        }
 		return (
 			<div id="canvasPanelDiv" className="CanvasPanel" style={style} onDragOver={this.onDragOver} onDrop={this.onDrop}>
 				<div onDoubleClick={this.onDblClickOpenFullScreen}  className="CanvasPanelHeader panel-header" data-resizable="limit_bottom">
@@ -108,8 +115,8 @@
 						<CanvasZoom zoom={this.props.zoom} style={{bottom: this.props.layout.bottom + 20}}/>
 						: null
 				}
-				<CanvasPanelTray layout={this.props.layout} show={isEditingNSD && isDescriptorView}>
-					<EditForwardingGraphPaths containers={this.props.containers} />
+				<CanvasPanelTray layout={this.props.layout} displayedPanel={this.props.displayedPanel} show={isEditingNSD && isDescriptorView}>
+					{displayedPanel}
 				</CanvasPanelTray>
 			</div>
 		);
diff --git a/skyquake/plugins/composer/src/src/components/CanvasPanelTray.js b/skyquake/plugins/composer/src/src/components/CanvasPanelTray.js
index 57f29a0..5fde578 100644
--- a/skyquake/plugins/composer/src/src/components/CanvasPanelTray.js
+++ b/skyquake/plugins/composer/src/src/components/CanvasPanelTray.js
@@ -16,13 +16,17 @@
 		right: props.layout.right,
 		display: props.show ? false : 'none'
 	};
+    const PANEL = {
+        FORWARD: 'forwarding',
+        PARAMETER: 'parameter'
+    }
 	const classNames = ClassNames('CanvasPanelTray', {'-with-transitions': !document.body.classList.contains('resizing')});
 	function onClickToggleOpenClose(event) {
 		if (event.defaultPrevented) return;
 		event.preventDefault();
 		// don't toggle if the user was resizing
 		if (!uiTransient.isResizing) {
-			CanvasPanelTrayActions.toggleOpenClose();
+			CanvasPanelTrayActions.toggleOpenClose(event);
 		}
 		event.target.removeEventListener('mousemove', onMouseMove, true);
 	}
@@ -37,10 +41,29 @@
 	const isOpen = style.height > 25;
 	return (
 		<div className={classNames} data-resizable="top" data-resizable-handle-offset="4" style={style}>
-			<h1 data-open-close-icon={isOpen ? 'open' : 'closed'} onMouseDownCapture={onMouseDown} onClick={onClickToggleOpenClose}>Forwarding Graphs</h1>
+            <div  className="CanvasPanelTray-buttons" onClick={onClickToggleOpenClose}>
+                <button
+                    style={{flex: '1 1 auto'}}
+                    className={ClassNames({'-selected': props.displayedPanel === PANEL.FORWARD})}
+                    onMouseDownCapture={onMouseDown}
+                    data-event={PANEL.FORWARD}>
+                    Forwarding Graphs
+                </button>
+
+                <button
+                    style={{flex: '1 1 auto', borderLeft: '1px solid white'}}
+                    className={ClassNames({'-selected': props.displayedPanel === PANEL.PARAMETER})}
+                    onMouseDownCapture={onMouseDown}
+                    data-event={PANEL.PARAMETER}>
+                        Config Parameter Map
+                </button>
+                <div  data-open-close-icon={isOpen ? 'open' : 'closed'}  style={{flex: '0 1', width: '40px', height: '25px', cursor: 'pointer'}} data-event='arrow'>
+
+                </div>
+            </div>
 			<div className="tray-body">
 				{props.children}
 			</div>
 		</div>
 	);
-}
\ No newline at end of file
+}
diff --git a/skyquake/plugins/composer/src/src/components/ConfigPrimitiveParameters/ConfigPrimitiveParameters.js b/skyquake/plugins/composer/src/src/components/ConfigPrimitiveParameters/ConfigPrimitiveParameters.js
new file mode 100644
index 0000000..4c7bbdd
--- /dev/null
+++ b/skyquake/plugins/composer/src/src/components/ConfigPrimitiveParameters/ConfigPrimitiveParameters.js
@@ -0,0 +1,354 @@
+
+/*
+ *
+ *   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.
+ *
+ */
+
+
+'use strict';
+
+import _ from 'lodash'
+import d3 from 'd3'
+import React from 'react'
+import Range from '../Range'
+import Button from '../Button'
+import ClassNames from 'classnames'
+import changeCase from 'change-case'
+import LayoutRow from '../LayoutRow'
+import SelectionManager from '../../libraries/SelectionManager'
+import PureRenderMixin from 'react-addons-pure-render-mixin'
+import CatalogItemsActions from '../../actions/CatalogItemsActions'
+import CanvasEditorActions from '../../actions/CanvasEditorActions'
+import DescriptorModelFactory from '../../libraries/model/DescriptorModelFactory'
+import ComposerAppActions from '../../actions/ComposerAppActions'
+import DescriptorModelMetaFactory from '../../libraries/model/DescriptorModelMetaFactory'
+import ComposerAppStore from '../../stores/ComposerAppStore'
+import DeletionManager from '../../libraries/DeletionManager'
+import ContentEditableDiv from '../ContentEditableDiv'
+import TooltipManager from '../../libraries/TooltipManager'
+import HighlightRecordServicePaths from '../../libraries/graph/HighlightRecordServicePaths'
+
+import '../../styles/EditForwardingGraphPaths.scss'
+
+import imgNSD from '../../images/default-catalog-icon.svg'
+import imgFG from '../../../../node_modules/open-iconic/svg/infinity.svg'
+import imgRemove from '../../../../node_modules/open-iconic/svg/trash.svg'
+import imgAdd from '../../../../node_modules/open-iconic/svg/plus.svg'
+import imgConnection from '../../../../node_modules/open-iconic/svg/random.svg'
+import imgClassifier from '../../../../node_modules/open-iconic/svg/spreadsheet.svg'
+import imgReorder from '../../../../node_modules/open-iconic/svg/menu.svg'
+import CatalogDataStore from '../../stores/CatalogDataStore'
+import utils from '../../libraries/utils'
+import getEventPath from '../../libraries/getEventPath'
+import guid from '../../libraries/guid'
+
+import '../../styles/EditDescriptorModelProperties.scss'
+import '../../styles/EditConfigParameterMap.scss';
+
+function configParameterMapMap(ap, i) {
+
+    const context = this;
+    context.vnfapMap = ap;
+    return (
+        <div key={i}>
+        <div>{ap.id}</div>
+        <div>{ap.capability['member-vnf-index']}</div>
+        <div>{ap.capability['capability-ref']}</div>
+
+        </div>
+    )
+
+}
+
+function mapNSD(nsd, i) {
+
+    const context = this;
+    context.nsd = nsd;
+
+    function onClickAddConfigParameterMap(nsd, event) {
+        event.preventDefault();
+        nsd.createConfigParameterMap();
+        CatalogItemsActions.catalogItemDescriptorChanged(nsd.getRoot());
+    }
+
+    const forwardingGraphs = nsd.configParameterMap.map(configParameterMap.bind(context));
+    if (forwardingGraphs.length === 0) {
+        forwardingGraphs.push(
+            <div key="1" className="welcome-message">
+                No Forwarding Graphs to model.
+            </div>
+        );
+    }
+
+    return (
+        <div key={i} className={nsd.className}>
+            {forwardingGraphs}
+            <div className="footer-actions">
+                <div className="row-action-column">
+                    <Button className="create-new-forwarding-graph" src={imgAdd} width="20px" onClick={onClickAddConfigParameterMap.bind(null, nsd)} label="Add new Access Point" />
+                </div>
+            </div>
+        </div>
+    );
+
+}
+
+
+function startEditing() {
+        event.stopPropagation();
+        DeletionManager.removeEventListeners();
+    }
+
+function endEditing() {
+    DeletionManager.addEventListeners();
+}
+
+
+const ConfigPrimitiveParameters = React.createClass({
+    mixins: [PureRenderMixin],
+    getInitialState: function () {
+        return ComposerAppStore.getState();
+    },
+    getDefaultProps: function () {
+        return {
+            containers: []
+        };
+    },
+    componentWillMount: function () {
+    },
+    componentDidMount: function () {
+    },
+    componentDidUpdate: function () {
+    },
+    componentWillUnmount: function () {
+    },
+    render() {
+        const self = this;
+        const containers = this.props.containers;
+        let NSContainer = containers.filter(function(c) {
+           return c.className == "NetworkService"
+        })[0]
+        const context = {
+            component: this,
+            containers: containers
+        };
+
+        const networkService = containers.filter(d => d.type === 'nsd');
+        if (networkService.length === 0) {
+            return <p className="welcome-message">No <img src={imgNSD} width="20px" /> NSD open in the canvas. Try opening an NSD.</p>;
+        }
+        let MapData = constructRequestSourceData(containers);
+        let mapCounter = 1;
+
+
+
+        return (
+                <div className="ConfigParameterMap">
+
+                        <div className="config-parameter-map">
+                            <div className="config-parameter-titles">
+                                <div className="config-parameter">
+                                    Primitive Parameter Request
+                                </div>
+                                <div className="config-parameter">
+                                    Data Source
+                                </div>
+                            </div>
+                            {
+                                MapData.Requests.map(function(r, i) {
+                                    let currentValue = {};
+                                    let SourceOptions = [<option value={JSON.stringify({
+                                            requestValue: r.name,
+                                            requestIndex: r.vnfdIndex
+                                        })} key="reset">No Source Selected</option>]
+                                    MapData.Sources.map(function(s, j) {
+                                        let value = {
+                                            value: s.name,
+                                            index: s.vnfdIndex,
+                                            requestValue: r.name,
+                                            requestIndex: r.vnfdIndex
+                                        }
+                                        if (r.vnfdIndex !== s.vnfdIndex) {
+                                            SourceOptions.push(<option value={JSON.stringify(value)} key={`${j}-${i}`} >{`${s.vnfdName} (${s.vnfdIndex}): ${s.name}`}</option>)
+                                        }
+                                    })
+                                    //Finds current value
+                                    NSContainer.model['config-parameter-map'] && NSContainer.model['config-parameter-map'].map((c)=>{
+                                        if(
+                                            c['config-parameter-request'] &&
+                                            (c['config-parameter-request']['config-parameter-request-ref'] == r.name)
+                                            && (c['config-parameter-request']['member-vnf-index-ref'] == r.vnfdIndex)
+                                           ) {
+                                            currentValue = {
+                                                value: c['config-parameter-source']['config-parameter-source-ref'],
+                                                index: c['config-parameter-source']['member-vnf-index-ref'],
+                                                requestValue: r.name,
+                                                requestIndex: r.vnfdIndex
+                                            };
+                                        }
+                                    })
+                                    currentValue.hasOwnProperty('value') ? mapCounter++ : mapCounter--;
+                                    let currentMapIndex = (mapCounter > 0) ? (mapCounter) - 1: 0;
+                                    return (
+                                            <div key={i} className="EditDescriptorModelProperties -is-tree-view config-parameter config-parameter-group">
+                                                <div  className="config-parameter-request" >{`${r.vnfdName} (${r.vnfdIndex}): ${r.name}`}</div>
+                                                <div className="config-parameter-source">
+                                                    <select
+                                                        onChange={onFormFieldValueChanged.bind(NSContainer, i)}
+                                                        onBlur={endEditing}
+                                                        onMouseDown={startEditing}
+                                                        onMouseOver={startEditing}
+                                                        value={JSON.stringify(currentValue)}
+                                                         >
+                                                        }
+                                                        {SourceOptions}
+                                                    </select>
+                                                </div>
+                                            </div>
+                                    )
+                                })
+                            }
+                        </div>
+                </div>
+        )
+    }
+});
+
+    function onFormFieldValueChanged(index, event) {
+        if (DescriptorModelFactory.isContainer(this)) {
+            event.preventDefault();
+            const name = event.target.name;
+            const value = JSON.parse(event.target.value);
+
+            let ConfigMap = utils.resolvePath(this.model, 'config-parameter-map');
+            let ConfigMapIndex = false;
+            let id = guid().substring(0, 8);
+            //Check current map, if request is present, assign map index.
+            ConfigMap.map(function(c, i) {
+                let req = c['config-parameter-request'];
+                if((req['config-parameter-request-ref'] == value.requestValue) &&
+                   (req['member-vnf-index-ref'] == value.requestIndex)) {
+                    ConfigMapIndex = i;
+                    id = c.id;
+                }
+            });
+            if(!ConfigMapIndex && _.isBoolean(ConfigMapIndex)) {
+                ConfigMapIndex = ConfigMap.length;
+            }
+            if(value.value) {
+                utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-source.config-parameter-source-ref', value.value);
+                utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-source.member-vnf-index-ref', value.index);
+                utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-request.config-parameter-request-ref', value.requestValue);
+                utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.config-parameter-request.member-vnf-index-ref', value.requestIndex);
+                utils.assignPathValue(this.model, 'config-parameter-map.' + ConfigMapIndex + '.id', id);
+                CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot());
+            } else {
+                utils.removePathValue(this.model, 'config-parameter-map.' + ConfigMapIndex)
+                CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot());
+
+            }
+        }
+    }
+
+
+//Values from
+//
+
+//To update
+//Container:NSD
+//path
+//["config-parameter", "config-parameter-source"]
+//{config-parameter-source-ref: "service_port", member-vnf-index-ref: 2}
+
+function constructRequestSourceData(containers) {
+    let cds = CatalogDataStore;
+    let catalogs = cds.getTransientCatalogs();
+    let Requests = [];
+    let Sources = [];
+    let vnfdData = {
+        index:[],
+        vnfdIDs:[],
+        indexRefs: {},
+        vnfdRefs:{}
+    };
+
+    //Init VNFD map
+    //{
+    //
+    //  index:[1], //member-vnfd-index-ref
+    //  vnfdIDs:[],
+    //  indexRefs: {
+    //      1: vnfdID
+    //  },
+    //  vnfdRefs: {
+    //      {1.id} : {...}
+    //  }
+    //}
+
+    containers.map(function(c, i) {
+        if(c.className == 'ConstituentVnfd') {
+            vnfdData.index.push(c.vnfdIndex);
+            vnfdData.vnfdIDs.push(c.vnfdId);
+            vnfdData.indexRefs[c.vnfdIndex] = c.vnfdId;
+            vnfdData.vnfdRefs[c.vnfdId] = {
+                id: c.vnfdId,
+                name: c.name,
+                'short-name': c['short-name']
+            };
+        }
+    });
+
+    //Decorate VNFDMap with descriptor data;
+    catalogs[1].descriptors
+        .filter((v) => vnfdData.vnfdIDs.indexOf(v.id) > -1)
+        .map(constructVnfdMap.bind(this, vnfdData));
+
+
+    vnfdData.index.map(function(vnfdIndex) {
+        let vnfdId = vnfdData.indexRefs[vnfdIndex];
+        let vnfd = vnfdData.vnfdRefs[vnfdId];
+        let vnfdShortName = vnfd['short-name'];
+        vnfd.requests && vnfd.requests.map(function(request) {
+            Requests.push(_.merge({
+                            id: vnfdId,
+                            vnfdIndex: vnfdIndex,
+                            vnfdName: vnfdShortName,
+                        }, request))
+        });
+        vnfd.sources && vnfd.sources.map(function(source) {
+            Sources.push(_.merge({
+                            id: vnfdId,
+                            vnfdIndex: vnfdIndex,
+                            vnfdName: vnfdShortName,
+                        }, source));
+        });
+    })
+
+    return {Requests, Sources};
+
+    function constructVnfdMap(vnfdData, vnfd) {
+        let data = {
+            requests: vnfd['config-parameter']['config-parameter-request'],
+            sources: vnfd['config-parameter']['config-parameter-source']
+        };
+        vnfdData.vnfdRefs[vnfd.id] =  _.merge(vnfdData.vnfdRefs[vnfd.id], data);
+    }
+
+}
+
+
+
+export default ConfigPrimitiveParameters;
diff --git a/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js b/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js
index a69f3bb..19af539 100644
--- a/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js
+++ b/skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js
@@ -46,6 +46,8 @@
 
 import '../styles/EditDescriptorModelProperties.scss'
 
+
+
 function getDescriptorMetaBasicForType(type) {
 	const basicPropertiesFilter = d => _.includes(DESCRIPTOR_MODEL_FIELDS[type], d.name);
 	return DescriptorModelMetaFactory.getModelMetaForType(type, basicPropertiesFilter) || {properties: []};
@@ -70,16 +72,7 @@
 		return model.id;
 	}
 }
-
-export default function EditDescriptorModelProperties(props) {
-
-	const container = props.container;
-
-	if (!(DescriptorModelFactory.isContainer(container))) {
-		return
-	}
-
-	function startEditing() {
+function startEditing() {
 		DeletionManager.removeEventListeners();
 	}
 
@@ -288,7 +281,7 @@
 		});
 	}
 
-	function buildChoice(container, property, path, value, key) {
+    function buildChoice(container, property, path, value, key, props={}) {
 
 		function onFormFieldValueChanged(event) {
 			if (DescriptorModelFactory.isContainer(this)) {
@@ -542,15 +535,15 @@
 			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(':'));
+                field = buildChoice(container, property, valuePath, value, key.join(':'), props);
 			} else if (isSimpleListView) {
-				field = buildSimpleListItem(container, property, valuePath, value, key, index);
+                field = buildSimpleListItem(container, property, valuePath, value, key, index, props);
 			} else if (isLeafList) {
-				field = buildLeafListItem(container, property, valuePath, value, key, index);
+                field = buildLeafListItem(container, property, valuePath, value, key, index, props);
 			} else if (hasProperties) {
-				field = buildElement(container, property, valuePath, value, key.join(':'))
+                field = buildElement(container, property, valuePath, value, key.join(':'), props)
 			} else {
-				field = buildField(container, property, valuePath, value, key.join(':'));
+                field = buildField(container, property, valuePath, value, key.join(':'), props);
 			}
 
 			function onClickLeaf(property, path, value, event) {
@@ -620,8 +613,17 @@
 		);
 
 	}
+export default function EditDescriptorModelProperties(props, type) {
 
-	const containerType = container.uiState['qualified-type'] || container.uiState.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 buildBasicGroup() {
@@ -659,7 +661,7 @@
 					{properties.map(property => {
 						const path = [property.name];
 						const value = container.model[property.name];
-						return build(container, property, path, value, {toggle: true, width: props.width});
+                        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>
@@ -691,3 +693,6 @@
 	);
 
 }
+export {build}
+// export buildElement;
+// export buildChoice;
diff --git a/skyquake/plugins/composer/src/src/components/EditDescriptorModelPropertiesBkUp.js b/skyquake/plugins/composer/src/src/components/EditDescriptorModelPropertiesBkUp.js
new file mode 100644
index 0000000..c8e664a
--- /dev/null
+++ b/skyquake/plugins/composer/src/src/components/EditDescriptorModelPropertiesBkUp.js
@@ -0,0 +1,671 @@
+/*
+ *
+ *   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 => _.contains(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);
+    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;
+    }
+}
+
+export default function EditDescriptorModelProperties(props) {
+
+    const container = props.container;
+
+    if (!(DescriptorModelFactory.isContainer(container))) {
+        return
+    }
+
+    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 = 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) {
+
+        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(':'));
+            } 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(
+                <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>
+        );
+
+    }
+
+    const containerType = container.uiState['qualified-type'] || container.uiState.type;
+    const basicProperties = getDescriptorMetaBasicForType(containerType).properties;
+
+    function buildBasicGroup() {
+        if (basicProperties.length === 0) {
+            return null;
+        }
+        return (
+            <div className="basic-properties-group">
+                <h2>Basic</h2>
+                <div>
+                    {basicProperties.map(property => {
+                        const path = [property.name];
+                        const value = container.model[property.name];
+                        return build(container, property, path, value);
+                    })}
+                </div>
+            </div>
+        );
+    }
+
+    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">
+                <h1 data-toggle={closeGroup ? 'true' : 'false'} className={ClassNames({'-is-toggled': closeGroup})} onClick={toggle} style={{display: hasBasicFields ? 'block' : 'none'}}>
+                    <a className="toggle-show-more" href="#show-more-properties">more&hellip;</a>
+                    <a className="toggle-show-less" href="#show-more-properties">less&hellip;</a>
+                </h1>
+                <div className="toggleable">
+                    {properties.map(property => {
+                        const path = [property.name];
+                        const value = container.model[property.name];
+                        return build(container, property, path, value, {toggle: true, width: props.width});
+                    })}
+                </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">
+            <h1>{path.map(buildMoreLess)}</h1>
+            {buildBasicGroup()}
+            {buildAdvancedGroup()}
+        </div>
+    );
+
+}
+// export buildElement;
+// export buildChoice;
diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModel.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModel.js
index 1a2ba4f..b0acc08 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModel.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModel.js
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFactory.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFactory.js
index ac59872..d5b6a28 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFactory.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFactory.js
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,7 +51,7 @@
 import InternalConnectionPointRef from './descriptors/InternalConnectionPointRef'
 import VirtualNetworkFunctionConnectionPoint from './descriptors/VirtualNetworkFunctionConnectionPoint'
 import VirtualDeploymentUnitInternalConnectionPoint from './descriptors/VirtualDeploymentUnitInternalConnectionPoint'
-
+import VirtualNetworkFunctionAccessPointMap from './descriptors/VirtualNetworkFunctionAccessPointMap'
 function findChildDescriptorModelAndUpdateModel(model, parent) {
 	if (parent instanceof DescriptorModel) {
 		const child = parent.findChildByUid(model);
@@ -120,6 +120,9 @@
 			fg.rsp.forEach(rsp => mapRSP(rsp, containerList));
 			fg.classifier.forEach(classifier => mapClassifier(classifier, containerList));
 		}
+        function mapConfigParameterMap(ap, containerList) {
+            containerList.push(ap);
+        }
 
 		function mapVDU(vdu, containerList) {
 			containerList.push(vdu);
@@ -143,6 +146,7 @@
 			nsd.constituentVnfd.forEach(cvnfd => mapCVNFD(cvnfd, containerList));
 			nsd.vld.forEach(vld => mapVLD(vld, containerList));
 			nsd.vnffgd.forEach(fg => mapFG(fg, containerList));
+            nsd.configParameterMap.forEach(ap => mapConfigParameterMap(ap, containerList));
 		}
 
 		function mapVNFD(vnfd, containerList) {
@@ -226,6 +230,9 @@
 		return findChildDescriptorModelAndUpdateModel(model, parent) || new VnfdConnectionPointRef(model, parent);
 	}
 
+    static newVirtualNetworkFunctionAccessPointMap(model, parent) {
+        return findChildDescriptorModelAndUpdateModel(model, parent) || new VirtualNetworkFunctionAccessPointMap(model, parent);
+    }
 	static newForwardingGraph(model, parent) {
 		return findChildDescriptorModelAndUpdateModel(model, parent) || new ForwardingGraph(model, parent);
 	}
@@ -322,6 +329,9 @@
 		return obj instanceof VirtualNetworkFunction;
 	}
 
+    static isVirtualNetworkFunctionAccessPointMap(obj) {
+        return obj instanceof VirtualNetworkFunctionAccessPointMap;
+    }
 	static isForwardingGraph(obj) {
 		return obj instanceof ForwardingGraph;
 	}
@@ -342,6 +352,9 @@
 		return NetworkService;
 	}
 
+    static get VirtualNetworkFunctionAccessPointMap () {
+        return VirtualNetworkFunctionAccessPointMap;
+    }
 	static get ForwardingGraph () {
 		return ForwardingGraph;
 	}
diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFields.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFields.js
index 8b86b0c..d8d9e58 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFields.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFields.js
@@ -28,6 +28,7 @@
 	vld: common.concat([]),
 	vnfd: common.concat(['vdu', 'internal-vld']),
 	'vnfd.vdu': common.concat(['image', 'image-checksum', 'external-interface', 'vm-flavor', 'cloud-init', 'filename']),
+    'nsd.config-parameter-map': common.concat([]),
 	// white-list valid fields to send in the meta field
 	meta: ['containerPositionMap']
 };
diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js
index d3ef200..b8624ec 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js
@@ -14,6 +14,7 @@
 
 const exportInnerTypesMap = {
 	'constituent-vnfd': 'nsd.constituent-vnfd',
+    'config-parameter-map': 'nsd.config-parameter-map',
 	'vdu': 'vnfd.vdu'
 };
 
diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaProperty.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaProperty.js
index 8fe51d9..6fe1112 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaProperty.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaProperty.js
@@ -139,6 +139,31 @@
 
 		return leafRefObjects;
 	},
+
+	getConfigParamRef(property = {}, path, value, fullFieldKey, transientCatalogs, container, vnfdId) {
+		// const leafRefPath = property['data-type']['leafref']['path'];
+		const leafRefPath = "/vnfd:vnfd-catalog/vnfd:vnfd[vnfd:id = " + vnfdId + "]/vnfd:config-parameter/vnfd:config-parameter-source/vnfd:name"
+		const transientCatalogHash = {};
+
+		transientCatalogs.map((catalog) => {
+			transientCatalogHash[catalog.type + '-catalog'] = {};
+			transientCatalogHash[catalog.type + '-catalog'][catalog.type] = catalog['descriptors'];
+		});
+
+		let leafRefPathValues = utils.resolveLeafRefPath(transientCatalogHash, leafRefPath, fullFieldKey, path, container);
+
+		let leafRefObjects = [];
+
+		leafRefPathValues && leafRefPathValues.map((leafRefPathValue) => {
+			leafRefObjects.push({
+				name: leafRefPathValue,
+				value: leafRefPathValue,
+				isSelected: String(leafRefPathValue) === String(value)
+			});
+		});
+
+		return leafRefObjects;
+	},
 	isGuid(property = {}) {
 		const type = property['data-type'];
 		if (typeof type === 'object' && type.leafref && type.leafref.path) {
diff --git a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js
index 8ce90cf..449f0a3 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js
@@ -29,6 +29,7 @@
 let vldFields = null;
 let vnfdFields = null;
 let cvnfdFields = null;
+let configParameterMapFields = null;
 
 
 
@@ -197,6 +198,13 @@
 			const confd = _.omit(copy, ['uiState']);
 			return cleanEmptyTopKeys(confd);
 		}
+    },
+    'config-parameter-map': {
+        serialize(configParameterMap) {
+            //vnfapMapFields
+            if(!configParameterMapFields) configParameterMapFields = DescriptorModelMetaFactory.getModelFieldNamesForType('nsd.config-parameter-map');
+            return _.pick(configParameterMap, configParameterMapFields);
+        }
 	}
 };
 
diff --git a/skyquake/plugins/composer/src/src/libraries/model/descriptors/NetworkService.js b/skyquake/plugins/composer/src/src/libraries/model/descriptors/NetworkService.js
index 16fb159..494bf38 100644
--- a/skyquake/plugins/composer/src/src/libraries/model/descriptors/NetworkService.js
+++ b/skyquake/plugins/composer/src/src/libraries/model/descriptors/NetworkService.js
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,6 +25,7 @@
 import ColorGroups from '../../ColorGroups'
 import DescriptorModel from '../DescriptorModel'
 import ForwardingGraph from './ForwardingGraph'
+import VirtualNetworkFunctionAccessPointMap from './VirtualNetworkFunctionAccessPointMap'
 import VirtualLink from './VirtualLink'
 import ConstituentVnfd from './ConstituentVnfd'
 import PhysicalNetworkFunction from './PhysicalNetworkFunction'
@@ -128,6 +129,45 @@
 	}
 
 
+// <<<<<<< Updated upstream
+//     get configParameterMap() {
+//         if (!this.model['config-parameter-map']) {
+//             this.model['config-parameter-map'] = [];
+//         }
+//         return this.model['config-parameter-map'].map(d => DescriptorModelFactory.newVirtualNetworkFunctionAccessPointMap(d, this)).map((fg, i) => {
+//             return fg;
+//         });
+//     }
+
+//     set configParameterMap(obj) {
+//         const onVirtualNetworkFunctionAccessPointMap = (fg) => {
+
+//         };
+//         this.updateModelList('config-parameter-map', obj, VirtualNetworkFunctionAccessPointMap, onVirtualNetworkFunctionAccessPointMap);
+//     }
+
+//     createConfigParameterMap(model) {
+//         model = model || DescriptorModelMetaFactory.createModelInstanceForType('nsd.config-parameter-map');
+//         return this.configParameterMap = DescriptorModelFactory.newVirtualNetworkFunctionAccessPointMap(model, this);
+//     }
+// =======
+	get configParameterMap() {
+		if (!this.model['config-parameter-map']) {
+			this.model['config-parameter-map'] = [];
+		}
+		return this.model['config-parameter-map'].map(d => DescriptorModelFactory.newVirtualNetworkFunctionAccessPointMap(d, this))
+	}
+
+	set configParameterMap(obj) {
+		this.updateModelList('config-parameter-map', obj, VirtualNetworkFunctionAccessPointMap);
+	}
+
+	createConfigParameterMap() {
+		const model = DescriptorModelMetaFactory.createModelInstanceForType('nsd.config-parameter-map');
+		return this.configParameterMap = DescriptorModelFactory.newVirtualNetworkFunctionAccessPointMap(model, this);
+	}
+// >>>>>>> Stashed changes
+
 	get vnffgd() {
 		if (!this.model.vnffgd) {
 			this.model.vnffgd = [];
@@ -160,6 +200,7 @@
 	}
 
 
+
 	// NOTE temporarily disable NSD connection points
 	// https://trello.com/c/crVgg2A1/88-do-not-render-nsd-connection-in-the-composer
 	//get connectionPoint() {
diff --git a/skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPoint.js b/skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPoint.js
new file mode 100644
index 0000000..defa317
--- /dev/null
+++ b/skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPoint.js
@@ -0,0 +1,57 @@
+/*
+ *
+ *   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 11/23/15.
+ */
+
+'use strict';
+
+import DescriptorModel from '../DescriptorModel'
+import DescriptorModelFactory from '../DescriptorModelFactory'
+
+export default class VnfapMap extends DescriptorModel {
+
+    static get type() {
+        return 'vnfap-map';
+    }
+
+    static get className() {
+        return 'VnfapMap';
+    }
+
+    constructor(model, parent) {
+        super(model, parent);
+        this.type = 'vnfap-map';
+        this.uiState['qualified-type'] = 'nsd.vnfap-map';
+        this.className = 'VnfapMap';
+        // this.addProp('vnfdRef', DescriptorModelFactory.newVirtualNetworkFunctionReadOnlyWrapper({}, this));
+    }
+
+    get id() {
+        return this.model.id;
+    }
+    get capability() {
+        return []
+    }
+
+    get dependency() {
+
+    }
+
+
+}
diff --git a/skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPointMap.js b/skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPointMap.js
new file mode 100644
index 0000000..16b57dc
--- /dev/null
+++ b/skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPointMap.js
@@ -0,0 +1,99 @@
+/*
+ *
+ *   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 11/23/15.
+ */
+
+'use strict';
+
+import DescriptorModel from '../DescriptorModel'
+import DescriptorModelFactory from '../DescriptorModelFactory'
+
+export default class ConfigParameterMap extends DescriptorModel {
+
+// <<<<<<< Updated upstream
+//     static get type() {
+//         return 'config-parameter-map';
+//     }
+
+//     static get className() {
+//         return 'ConfigParameterMap';
+//     }
+
+//     constructor(model, parent) {
+//         super(model, parent);
+//         this.type = 'config-parameter-map';
+//         this.uiState['qualified-type'] = 'nsd.config-parameter-map';
+//         this.className = 'ConfigParameterMap';
+//         // this.addProp('vnfdRef', DescriptorModelFactory.newVirtualNetworkFunctionReadOnlyWrapper({}, this));
+//     }
+
+//     get id() {
+//         return this.model.id;
+//     }
+//     get capability() {
+//         return {
+//             'member-vnf-index': this.model.capability['member-vnf-index'],
+//             'capability-ref': this.model.capability['capability-ref'],
+//         }
+//     }
+//     get availableCapabilities() {
+
+//     }
+
+//     get dependency() {
+
+//     }
+// =======
+	static get type() {
+		return 'config-parameter-map';
+	}
+
+	static get className() {
+		return 'ConfigParameterMap';
+	}
+	static get qualifiedType() {
+		return 'nsd.' + ConfigParameterMap.type;
+	}
+	constructor(model, parent) {
+		super(model, parent);
+		this.type = 'config-parameter-map';
+		this.uiState['qualified-type'] = 'nsd.config-parameter-map';
+		this.className = 'ConfigParameterMap';
+		// this.addProp('vnfdRef', DescriptorModelFactory.newVirtualNetworkFunctionReadOnlyWrapper({}, this));
+	}
+
+	get id() {
+		return this.model.id;
+	}
+	// get capability() {
+	// 	return {
+	// 		'member-vnf-index': this.model.capability['member-vnf-index'],
+	// 		'capability-ref': this.model.capability['capability-ref'],
+	// 	}
+	// }
+	// get availableCapabilities() {
+
+	// }
+
+	// get dependency() {
+
+	// }
+
+
+}
diff --git a/skyquake/plugins/composer/src/src/libraries/utils.js b/skyquake/plugins/composer/src/src/libraries/utils.js
index ee4163c..be55d23 100644
--- a/skyquake/plugins/composer/src/src/libraries/utils.js
+++ b/skyquake/plugins/composer/src/src/libraries/utils.js
@@ -289,11 +289,11 @@
 
 		// Check if relative path or not
 		// TODO: Below works but
-		// better to convert the pathCopy to absolute/rooted path 
+		// better to convert the pathCopy to absolute/rooted path
 		// and use the absolute module instead
 		if (this.isRelativePath(leafRefPathCopy)) {
 			let i = pathArray.length;
-			while (pathArray[pathArray.length - i] == '..') {
+			while ((pathArray[pathArray.length - i] == '..') && fieldKeyArray.length > 1) {
 				fieldKeyArray.splice(-1, 1);
 				if (!isNaN(Number(fieldKeyArray[fieldKeyArray.length - 1]))) {
 					// found a number, so an index. strip it
@@ -328,7 +328,7 @@
 						}
 					}
 				}
-			} else {
+			}  else {
 				// not supported - too many levels deep ... maybe some day
 				console.log('The relative path is from a node too many levels deep from root. This is not supported at the time');
 			}
diff --git a/skyquake/plugins/composer/src/src/styles/CanvasPanel.scss b/skyquake/plugins/composer/src/src/styles/CanvasPanel.scss
index 9fa1149..2f684d2 100644
--- a/skyquake/plugins/composer/src/src/styles/CanvasPanel.scss
+++ b/skyquake/plugins/composer/src/src/styles/CanvasPanel.scss
@@ -28,6 +28,7 @@
 	min-width: 300px;
 	overflow: hidden;
 	z-index: 1;
+
 	.CanvasPanelHeader {
 		h1 {
 			margin: 0;
diff --git a/skyquake/plugins/composer/src/src/styles/CanvasPanelTray.scss b/skyquake/plugins/composer/src/src/styles/CanvasPanelTray.scss
index 7e9e336..94f2b43 100644
--- a/skyquake/plugins/composer/src/src/styles/CanvasPanelTray.scss
+++ b/skyquake/plugins/composer/src/src/styles/CanvasPanelTray.scss
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,8 @@
 	right: 0;
 	height: 25px;
 	min-width: 300px;
-	background-color: white;
+	/* background-color: white;*/
+	background: $panel-bg-color;
 	&.-with-transitions {
 		transition: height 300ms cubic-bezier(0.230, 1.000, 0.320, 1.000);
 	}
@@ -60,4 +61,43 @@
 		}
 	}
 
+
+	&-buttons {
+		display: -ms-flexbox;
+		display: flex;
+		margin-top: 2px;
+		button {
+			padding: 6px 34px;
+		}
+	}
+	.tray-body {
+		top:31px;
+	}
+	.ConfigParameterMap {
+		padding: 10px 20px;
+		background: $panel-bg-color;
+
+		.toggleable {
+			display:-ms-flexbox;
+			display:flex;
+			-ms-flex-wrap: wrap;
+			    flex-wrap: wrap;
+		    background: $panel-bg-color-contrast;
+		    margin:8px 0;
+		 	& > .leaf-property {
+			    -ms-flex: 1 0 100%;
+		        flex: 1 0 100%;
+		        margin: 8px 0;
+				padding: 0 8px;
+				background: none;
+		        .property-label {
+		        }
+			}
+			& > .container-property {
+				-ms-flex: 1 1;
+				    flex: 1 1;
+			}
+		}
+	}
+
 }
diff --git a/skyquake/plugins/composer/src/src/styles/EditConfigParameterMap.scss b/skyquake/plugins/composer/src/src/styles/EditConfigParameterMap.scss
new file mode 100644
index 0000000..f0407d6
--- /dev/null
+++ b/skyquake/plugins/composer/src/src/styles/EditConfigParameterMap.scss
@@ -0,0 +1,357 @@
+/*
+ *
+ *   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.
+ *
+ */
+
+@import "main";
+@import "variables";
+@import "ColorGroups";
+
+.config-parameter-map {
+
+	$field-border-radius: 3px;
+	$field-background-color: white;
+	$child-indent-left-right-margin: 5px;
+
+	/* font-size: smaller;*/
+	display:-ms-flexbox;
+	display:flex;
+	-ms-flex-wrap: wrap;
+	    flex-wrap: wrap;
+
+
+
+	max-width: 980px;
+	.config-parameter-titles {
+		display: -ms-flexbox;
+		display: flex;
+		-ms-flex: 1 1 100%;
+		    flex: 1 1 100%;
+	    padding-bottom:10px;
+	    color: #AEAEAE;
+	    text-transform:uppercase;
+		    .config-parameter {
+		    	padding-left: 10px;
+		    }
+	}
+	.config-parameter {
+		display:-ms-flexbox;
+		display:flex;
+		-ms-flex: 1 0 50%;
+		    flex: 1 0 50%;
+		    &-source, &-request {
+		    	-ms-flex: 1 1 50%;
+		    	flex: 1 1 50%;
+				border-top:1px solid silver;
+				padding: 10px 10px;
+						    }
+		    &-request{
+		    	line-height: 25px;
+		    }
+		    &-group {
+		    	-ms-flex: 1 1 100%;
+		    	    flex: 1 1 100%;
+		    	display:-ms-flexbox;
+		    	display:flex;
+		    	&:nth-child(even) {
+		    		background: $panel-bg-color-contrast;
+		    	}
+		    }
+	}
+
+
+	h1 {
+		text-align: left;
+		span:last-child {
+			i {
+				display: none;
+			}
+		}
+	}
+
+	h2 {
+		@extend h1;
+
+	}
+
+	.basic-properties-group {
+		> h1 {
+			display: none;
+		}
+	}
+
+	.advanced-properties-group {
+	}
+
+	/* label is used as list item headers */
+	h3 {
+		@extend h2;
+		display: inline-block;
+		.name {
+			color: #586e75;
+		}
+		.value {
+			display: none;
+			color: #002b36;
+		}
+		.info {
+			margin: 4px;
+		}
+	}
+
+	val {
+		display: inline-block;
+		color: #073642;
+	}
+
+	a {
+		&.simple-list-item {
+			display: inline-block;
+			width: 230px;
+			padding: 4px 16px 4px 4px;
+			white-space: nowrap;
+		}
+		&.vld-list-item,
+		&.internal-vld-list-item{
+			border: 1px solid $vld-primary-color;
+			border-radius: 24px;
+			background: white linear-gradient(to right, $vld-primary-color 34px, white 34px);;
+		}
+		&.vnfd-list-item,
+		&.constituent-vnfd-list-item{
+			border: 1px solid $vnfd-primary-color;
+			border-radius: 11px;
+			background: white linear-gradient(to right, $vnfd-primary-color 34px, white 34px);;
+		}
+		&.vdu-list-item {
+			border: 1px solid $vdu-primary-color;
+			border-radius: 11px;
+			background: white linear-gradient(to right, $vdu-primary-color 34px, white 34px);;
+		}
+		&.vnffgd-list-item {
+			border: 1px solid $vnffgd-primary-color;
+			border-radius: 11px;
+			background: white linear-gradient(to right, $vnffgd-primary-color 34px, white 34px);;
+		}
+	}
+
+	&.-is-tree-view {
+		.property {
+
+			position: relative;
+			overflow: hidden;
+
+			margin: 8px 8px;
+
+			background-color: rgba(147, 161, 161, 0.5);
+			border-radius: $field-border-radius;
+
+			> h3 {
+				position: absolute;
+				top: 2px;
+				right: 18px;
+				height: 21px;
+				pointer-events: none;
+				border-radius: $field-border-radius;
+				padding: 3px 0;
+			}
+
+			> val {
+				width: 100%;
+				> .property-content {
+					width: 100%;
+				}
+
+			}
+
+			&.-is-focused {
+				> h3 {
+					/*z-index: -1;*/
+				}
+			}
+
+			&.leaf-property {
+				overflow: hidden;
+				min-height: 25px;
+				> h3 {
+					background: linear-gradient(to right, transparent, $field-background-color 21px);
+					padding-left: 25px;
+				}
+				> val {
+					border-radius: $field-border-radius;
+					> .property-content {
+						border-radius: $field-border-radius;
+					}
+				}
+			}
+
+			&.property:not(.leaf-property) {
+
+				padding: 7px $child-indent-left-right-margin 0 $child-indent-left-right-margin;
+
+				&.list-property {
+					> h3 {
+						padding: 4px 8px;
+					}
+				}
+
+				> h3 {
+					right: auto;
+					top: 0;
+					left: 0;
+					width: 100%;
+					height: 25px;
+					z-index: 1;
+					padding: 8px;
+					/*background: red;*/
+					pointer-events: all;
+				}
+				> val {
+					margin: 28px 0 8px 0;
+					> .property-content {
+						position: relative;
+						border-radius: $field-border-radius;
+						margin-top: 4px;
+						padding: 4px;
+						&:first-of-type {
+							margin-top: 0;
+						}
+						&.simple-list {
+							min-height: 15px;
+							margin: 11px;
+							.simple-list-item {
+								img,
+								span {
+									margin: 0 5px;
+									vertical-align: middle;
+								}
+							}
+						}
+					}
+					> .property-content:not(.simple-list) {
+						&:nth-of-type(odd) {
+							background-color: rgba(238, 232, 213, 0.33);
+						}
+						&:nth-of-type(even) {
+							background-color: rgba(147, 161, 161, 0.33);
+						}
+					}
+					.tip {
+						font-style: italic;
+						font-size: small;
+						color: #93a1a1;
+					}
+				}
+			}
+
+			.actions {
+				span {
+					vertical-align: middle;
+					padding: 0 5px;
+				}
+			}
+
+		}
+
+	}
+
+	.description {
+		display: none;
+	}
+
+	input,
+	select,
+	textarea {
+		height: 25px;
+		line-height: 25px;
+		max-width: 100%;
+		min-width: 100%;
+		margin: 0;
+		padding: 0 0px 4px 8px;
+		border: 1px solid $field-background-color;
+		border-radius: $field-border-radius;
+		color: #002b36;
+		background-color: $field-background-color;
+		vertical-align: top;
+		&:focus {
+			color: #002b36;
+			background-color: white !important;
+		}
+		&::-webkit-input-placeholder {
+			color: #eee8d5 !important;
+		}
+
+		&:-moz-placeholder { /* Firefox 18- */
+			color: #eee8d5 !important;
+		}
+
+		&::-moz-placeholder {  /* Firefox 19+ */
+			color: #eee8d5 !important;
+		}
+
+		&:-ms-input-placeholder {
+			color: #eee8d5 !important;
+		}
+	}
+
+	select {
+		padding-right: 0;
+		margin-right: 0;
+		-webkit-appearance: none;
+		-webkit-border-radius: $field-border-radius;
+		&.-value-not-set {
+			color: #eee8d5;
+		}
+	}
+
+	select {
+		-webkit-appearance: none;
+		   -moz-appearance: none;
+		        appearance: none; /* using -prefix-free http://leaverou.github.io/prefixfree/*/
+        background: $field-background-color url(../../../node_modules/open-iconic/svg/caret-bottom.svg) no-repeat right 8px center;
+		background-size: 10px;
+		border: {
+			color: $field-background-color;
+			radius: $field-border-radius;
+			style: solid;
+			width: 1px;
+		}
+	}
+
+	/* Removes default arrow for IE10+*/
+	/* IE 8/9 get dafault arrow which covers caret image*/
+	/* as long as caret image is small than and positioned*/
+	/* behind default arrow*/
+	select::-ms-expand {
+		display: none;
+	}
+
+	textarea {
+		height: 50px;
+	}
+
+	input {
+		padding: 0 20px 0 8px;
+		line-height: 25px;
+	}
+
+	input[name$="id"],
+	input.-is-guid {
+		font-size: 10px;
+		font-family: monospace;
+	}
+
+}