Add new code new version

Change-Id: Ic02a76313503b526f17c3df29eb387a29fe6a42a
Signed-off-by: Michael Lando <ml636r@att.com>
diff --git a/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsView.jsx b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsView.jsx
new file mode 100644
index 0000000..7e2dda8
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/heatvalidation/attachments/AttachmentsView.jsx
@@ -0,0 +1,190 @@
+import React from 'react';
+import FontAwesome from 'react-fontawesome';
+import classNames from 'classnames';
+import Collapse from 'react-bootstrap/lib/Collapse.js';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import {nodeTypes, mouseActions} from './AttachmentsConstants';
+
+const typeToIcon = Object.freeze({
+	heat: 'building-o',
+	volume: 'database',
+	network: 'cloud',
+	artifact: 'gear',
+	env: 'server',
+	other: 'cube'
+});
+
+const leftPanelWidth = 250;
+
+class SoftwareProductAttachmentsView extends React.Component {
+
+	static propTypes = {
+		attachmentsTree: React.PropTypes.object.isRequired
+	};
+	state = {
+		treeWidth: '400',
+	};
+
+	render() {
+		let {attachmentsTree, errorList = []} = this.props;
+
+		let {treeWidth} = this.state;
+		return (
+			<div className='software-product-attachments'>
+				<div className='software-product-view'>
+					<div className='software-product-landing-view-right-side'>
+						<div className='software-product-attachments-main'>
+							<div className='software-product-attachments-tree' style={{'width' : treeWidth + 'px'}}>
+								<div className='tree-wrapper'>
+									{
+										attachmentsTree && attachmentsTree.children && attachmentsTree.children.map((child, ind) => this.renderNode(child, [ind]))
+									}
+								</div>
+							</div>
+							<div className='software-product-attachments-separator' onMouseDown={e => this.onChangeTreeWidth(e)} />
+							<div className='software-product-attachments-error-list'>
+								{errorList.length ? this.renderErrorList(errorList) : <div className='no-errors'>{attachmentsTree.children ?
+									i18n('VALIDATION SUCCESS') : i18n('THERE IS NO HEAT DATA TO PRESENT') }</div>}
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+		);
+	}
+
+
+
+	renderNode(node, path) {
+		let isFolder = node.children && node.children.length > 0;
+		let {onSelectNode} = this.props;
+		return (
+			<div key={node.name} className='tree-block-inside'>
+				{
+					<div onDoubleClick={() => this.props.toggleExpanded(path)} className={this.getTreeRowClassName(node.name)}>
+						{
+							isFolder &&
+							<div onClick={() => this.props.toggleExpanded(path)} className={classNames('tree-node-expander', {'tree-node-expander-collapsed': !node.expanded})}>
+								<FontAwesome name='caret-down'/>
+							</div>
+						}
+						{
+
+							<span className='tree-node-icon'>
+								<FontAwesome name={typeToIcon[node.type]}/>
+							</span>
+						}
+						{
+
+							<span onClick={() => onSelectNode(node.name)} className={this.getTreeTextClassName(node)}>
+							{node.name}
+							</span>
+						}
+					</div>
+				}
+				{
+					isFolder &&
+					<Collapse in={node.expanded}>
+						<div className='tree-node-children'>
+							{
+								node.children.map((child, ind) => this.renderNode(child, [...path, ind]))
+							}
+						</div>
+					</Collapse>
+				}
+			</div>
+		);
+	}
+
+	createErrorList(errorList, node, parent) {
+		if (node.errors) {
+			node.errors.forEach(error => errorList.push({
+				error,
+				name: node.name,
+				parentName: parent.name,
+				type: node.type
+			}));
+		}
+		if (node.children && node.children.length) {
+			node.children.map((child) => this.createErrorList(errorList, child, node));
+		}
+	}
+
+	renderErrorList(errors) {
+		let prevError = {};
+		let {selectedNode} = this.props;
+		return errors.map(error => {
+			let isSameNodeError = error.name === prevError.name && error.parentName === prevError.parentName;
+			prevError = error;
+
+			return (
+				<div
+					key={error.name + error.errorMessage + error.parentName}
+
+					onClick={() => this.selectNode(error.name)}
+					className={classNames('error-item', {'clicked': selectedNode === error.name, 'shifted': !isSameNodeError})}>
+					<span className={classNames('error-item-file-type', {'strong': !isSameNodeError})}>
+					{
+						error.hasParent ?
+							i18n('{type}  {name} in {parentName}: ', {
+								type: nodeTypes[error.type],
+								name: error.name,
+								parentName: error.parentName
+							}) :
+							i18n('{type}  {name}: ', {
+								type: nodeTypes[error.type],
+								name: error.name
+							})
+					}
+					</span>
+					<span className={`error-item-file-type ${error.errorLevel}`}> {error.errorMessage} </span>
+				</div>
+			);
+		});
+	}
+
+	selectNode(currentSelectedNode) {
+		let {onUnselectNode, onSelectNode, selectedNode} = this.props;
+		if (currentSelectedNode !== selectedNode) {
+			onSelectNode(currentSelectedNode);
+		}else{
+			onUnselectNode();
+		}
+
+	}
+
+	getTreeRowClassName(name) {
+		let {hoveredNode, selectedNode} = this.props;
+		return classNames({
+			'tree-node-row': true,
+			'tree-node-selected': name === hoveredNode,
+			'tree-node-clicked': name === selectedNode
+		});
+	}
+
+	getTreeTextClassName(node) {
+		let {selectedNode} = this.props;
+		return classNames({
+			'tree-element-text': true,
+			'error-status': node.errors,
+			'error-status-selected': node.name === selectedNode
+		});
+	}
+
+	onChangeTreeWidth(e) {
+		if (e.button === mouseActions.MOUSE_BUTTON_CLICK) {
+			let onMouseMove = (e) => {
+				this.setState({treeWidth: e.clientX - leftPanelWidth});
+			};
+			let onMouseUp = () => {
+				document.removeEventListener('mousemove', onMouseMove);
+				document.removeEventListener('mouseup', onMouseUp);
+			};
+			document.addEventListener('mousemove', onMouseMove);
+			document.addEventListener('mouseup', onMouseUp);
+		}
+	}
+}
+
+export default SoftwareProductAttachmentsView;