[SDC-29] Amdocs OnBoard 1707 initial commit.

Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370
Signed-off-by: AviZi <avi.ziv@amdocs.com>
diff --git a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx
index f2ec158..0759f2c 100644
--- a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx
+++ b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx
@@ -1,9 +1,24 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React, {Component} from 'react';
 import ListGroupItem from 'react-bootstrap/lib/ListGroupItem.js';
-import ListGroup from 'react-bootstrap/lib/ListGroup.js';
-import Panel from 'react-bootstrap/lib/Panel.js';
 import i18n from 'nfvo-utils/i18n/i18n.js';
-
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import Icon from 'nfvo-components/icon/Icon.jsx';
+import {Collapse} from 'react-bootstrap';
 /**
  * parsing and showing the following Java Response object
  *
@@ -31,103 +46,117 @@
 
 
 	render() {
-		let {validationResponse} = this.props;
+		let {validationResponse : {vspErrors, licensingDataErrors, questionnaireValidationResult, uploadDataErrors}} = this.props;
 		return (
 			<div className='submit-error-response-view'>
-				{validationResponse.vspErrors && this.renderVspErrors(validationResponse.vspErrors)}
-				{validationResponse.licensingDataErrors && this.renderVspErrors(validationResponse.licensingDataErrors)}
-				{validationResponse.compilationErrors && this.renderCompilationErrors(validationResponse.compilationErrors)}
-				{validationResponse.uploadDataErrors && this.renderUploadDataErrors(validationResponse.uploadDataErrors)}
-				{validationResponse.questionnaireValidationResult && this.renderQuestionnaireValidationResult(validationResponse.questionnaireValidationResult)}
+				{vspErrors && this.renderVspErrors(vspErrors)}
+				{licensingDataErrors && this.renderVspErrors(licensingDataErrors)}
+				{questionnaireValidationResult && this.renderComponentsErrors(questionnaireValidationResult)}
+				{uploadDataErrors && this.renderUploadDataErrors(uploadDataErrors)}
 			</div>
 		);
 	}
 
-	renderVspErrors(vspErrors) {
+	renderVspErrors(errors) {
 		return (
-			<Panel header={i18n('VSP Errors')} collapsible>{this.parseErrorCodeCollection(vspErrors)}</Panel>
+			<ErrorBlock errorType={i18n('VSP Errors')}>
+				<div>
+					{errors.length && errors.map(error=>{return (<ErrorMessage error={error.message}/>);})}
+				</div>
+			</ErrorBlock>
 		);
 	}
 
-	renderLicensingDataErrors(licensingDataErrors) {
+
+	renderComponentsErrors(errors) {
 		return (
-			<Panel
-				header={i18n('Licensing Data Errors')}
-				collapsible>{this.parseErrorCodeCollection(licensingDataErrors)}
-			</Panel>
+			<ErrorBlock errorType={i18n('Components Errors')}>
+				<div>
+					{errors.validationData.length && errors.validationData.map(item =>{ return (<ComponentError item={item}/>);})}
+				</div>
+			</ErrorBlock>
 		);
 	}
 
 	renderUploadDataErrors(uploadDataErrors) {
 		return (
-			<Panel
-				header={i18n('Upload Data Errors')}
-				collapsible>{this.parseMapOfErrorMessagesList(uploadDataErrors)}
-			</Panel>
+			<ErrorBlock errorType={i18n('Upload Data Errors')}>
+				<div>
+					<UploadErrorList items={uploadDataErrors}/>
+				</div>
+			</ErrorBlock>
 		);
 	}
-
-	renderCompilationErrors(compilationErrors) {
-		return (
-			<Panel
-				header={i18n('Compilation Errors')}
-				collapsible>{this.parseMapOfErrorMessagesList(compilationErrors)}
-			</Panel>
-		);
-	}
-
-	parseErrorCodeCollection(errors) {
-		return (
-			<ListGroup>{errors.map(error =>
-				<ListGroupItem className='error-code-list-item'>
-					<div><span>{i18n('Category: ')}</span>{error.category}</div>
-					<div><span>{i18n('Message: ')}</span>{error.message}</div>
-				</ListGroupItem>
-			)}</ListGroup>
-		);
-	}
-
-	parseMapOfErrorMessagesList(errorMap) {
-		return (
-			<ListGroup>
-				{Object.keys(errorMap).map(errorStringKey =>
-					<Panel header={errorStringKey} collapsible>
-						<ListGroup>{errorMap[errorStringKey].map(error =>
-							<ListGroupItem className='error-code-list-item'>
-								<div><span>{i18n('Level: ')}</span>{error.level}</div>
-								<div><span>{i18n('Message: ')}</span>{error.message}</div>
-							</ListGroupItem>
-						)}</ListGroup>
-					</Panel>
-				)}
-			</ListGroup>
-		);
-	}
-
-
-	renderQuestionnaireValidationResult(questionnaireValidationResult) {
-		if (!questionnaireValidationResult.valid) {
-			return this.parseAndRenderCompositionEntityValidationData(questionnaireValidationResult.validationData);
-		}
-	}
-
-	parseAndRenderCompositionEntityValidationData(validationData) {
-		let {entityType, entityId, errors = [], subEntitiesValidationData = []} = validationData;
-		return (
-			<ListGroup>
-				<Panel header={`${entityType}: ${entityId}`} collapsible>
-					<ListGroup>{errors.map(error =>
-						<ListGroupItem className='error-code-list-item'>
-							<div>{error}</div>
-						</ListGroupItem>
-					)}</ListGroup>
-					{subEntitiesValidationData.map(subValidationData => this.parseAndRenderCompositionEntityValidationData(subValidationData))}
-				</Panel>
-			</ListGroup>
-		);
-	}
-
-
 }
 
+
+const ComponentError = ({item}) => {
+	let i = 0;
+	return (
+		<div>
+			<div className='component-name-header'>{item.entityName}</div>
+			{item.errors.map(error => {return(<ErrorMessage key={i++} error={error}/>);})}
+		</div>
+	);
+};
+
+function* entries(obj) {
+	for (let key of Object.keys(obj)) {
+		yield {header: key, list: obj[key]};
+	}
+}
+
+const UploadErrorList = ({items}) => {
+	let generator = entries(items);
+
+	let errors = [];
+	let i = 0;
+	for (let item of generator) {errors.push(
+		<div>
+			<div className='component-name-header'>{item.header}</div>
+			{item.list.map(error => <ErrorMessage key={i++} warning={error.level === 'WARNING'} error={error.message}/> )}
+		</div>
+	);}
+	return (
+		<div>
+			{errors}
+		</div>
+	);
+};
+
+class ErrorBlock extends React.Component {
+	state = {
+		collapsed: false
+	};
+
+	render() {
+		let {errorType, children} = this.props;
+		return (
+			<div className='error-block'>
+				<ErrorHeader collapsed={this.state.collapsed} onClick={()=>{this.setState({collapsed: !this.state.collapsed});}} errorType={errorType}/>
+				<Collapse in={this.state.collapsed}>
+					{children}
+				</Collapse>
+			</div>
+		);
+	}
+}
+
+const ErrorHeader = ({errorType, collapsed, onClick}) => {
+	return(
+		<div onClick={onClick} className='error-block-header'>
+			<SVGIcon iconClassName={collapsed ? '' : 'right' } name='chevron-down'/>
+			{errorType}
+		</div>
+	);
+};
+
+const ErrorMessage = ({error, warning}) => {
+	return (
+		<ListGroupItem className='error-code-list-item'>
+			<Icon image={warning ? 'warning' : 'error'} label={error}/>
+		</ListGroupItem>
+	);
+};
+
 export default SubmitErrorResponse;
diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLog.js b/openecomp-ui/src/nfvo-components/activity-log/ActivityLog.js
new file mode 100644
index 0000000..f7354f9
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/activity-log/ActivityLog.js
@@ -0,0 +1,27 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 {connect} from 'react-redux';
+import ActivityLogView from './ActivityLogView.jsx';
+
+export const mapStateToProps = ({licenseModel: {activityLog}}) => {
+
+	let activities = activityLog;
+	return {
+		activities
+	};
+};
+
+export default connect(mapStateToProps, undefined, null, {withRef: true})(ActivityLogView);
diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogActionHelper.js b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogActionHelper.js
new file mode 100644
index 0000000..01a27ab
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogActionHelper.js
@@ -0,0 +1,31 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
+import Configuration from 'sdc-app/config/Configuration.js';
+import ActivityLogConstants from './ActivityLogConstants.js';
+
+
+function baseUrl(itemId, versionId) {
+	const restPrefix = Configuration.get('restPrefix');
+	return `${restPrefix}/v1.0/activity-logs/${itemId}/versions/${versionId}`;
+}
+
+export default {
+
+	fetchActivityLog(dispatch, {itemId, versionId}){
+		return RestAPIUtil.fetch(baseUrl(itemId, versionId)).then(response => dispatch({type: ActivityLogConstants.ACTIVITY_LOG_UPDATED, response}));
+	}
+};
diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogConstants.js b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogConstants.js
new file mode 100644
index 0000000..69faf7c
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogConstants.js
@@ -0,0 +1,23 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export default keyMirror({
+
+	ACTIVITY_LOG_UPDATED: null
+
+});
+
diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogReducer.js b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogReducer.js
new file mode 100644
index 0000000..fc3dfa1
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogReducer.js
@@ -0,0 +1,25 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 ActivityLogConstants from './ActivityLogConstants.js';
+
+export default (state = [], action) => {
+	switch (action.type) {
+		case ActivityLogConstants.ACTIVITY_LOG_UPDATED:
+			return [...action.response.results];
+	}
+
+	return state;
+};
diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogView.jsx b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogView.jsx
new file mode 100644
index 0000000..6ff3c80
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/activity-log/ActivityLogView.jsx
@@ -0,0 +1,124 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React, {Component} from 'react';
+import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+function ActivityLogSortableCellHeader({isHeader, data, isDes, onSort}) {
+	if (isHeader) {
+		return (
+			<span className='date-header' onClick={onSort}>
+				<span>{data}</span>
+				<span className={`header-sort-arrow ${isDes ? 'up' : 'down'}`}></span>
+			</span>
+		);
+	}
+	return (
+		<span className='date-cell'>
+			<span>{i18n.dateNormal(data, {
+				year: 'numeric', month: 'numeric', day: 'numeric'
+			})}</span>
+			<span>{i18n.dateNormal(data, {
+				hour: 'numeric', minute: 'numeric',
+				hour12: true
+			})}</span>
+		</span>
+	);
+}
+
+function ActivityLogStatus({status, isHeader}) {
+	if (isHeader) {
+		return <span>{status}</span>;
+	}
+	let {message, success} = status;
+	return (
+		<span>
+			<span className={`status-icon ${success}`}>{`${success ? i18n('Success') : i18n('Failure')}`}</span>
+			{success && <SVGIcon name='check-circle'/>}
+			{!success && <OverlayTrigger placement='bottom' overlay={<Tooltip className='activity-log-message-tooltip' id={'activity-log-message-tooltip'}>
+				<div className='message-block'>{message}</div>
+			</Tooltip>}>
+				<span className='message-further-info-icon'>{'?'}</span>
+			</OverlayTrigger>}
+		</span>
+	);
+}
+
+export function ActivityListItem({activity, isHeader, isDes, onSort}) {
+	let {type, timestamp, comment, user, status} = activity;
+	return (
+		<li className={`activity-list-item ${isHeader ? 'header' : ''}`} data-test-id='activity-list-item'>
+			<div className='table-cell activity-date' data-test-id='activity-date'><ActivityLogSortableCellHeader isHeader={isHeader} data={timestamp} isDes={isDes} onSort={onSort}/></div>
+			<div className='table-cell activity-action' data-test-id='activity-action'>{type}</div>
+			<div className='table-cell activity-comment' title={comment} data-test-id='activity-comment'><span>{comment}</span></div>
+			<div className='table-cell activity-username' data-test-id='activity-username'>{user}</div>
+			<div className='table-cell activity-status' data-test-id='activity-status'><ActivityLogStatus isHeader={isHeader} status={status}/></div>
+		</li>
+	);
+}
+
+class ActivityLogView extends Component {
+
+	state = {
+		localFilter: '',
+		sortDescending: true
+	};
+
+	render() {
+		return (
+			<div className='activity-log-view'>
+				<ListEditorView
+					title={i18n('Activity Log')}
+					filterValue={this.state.localFilter}
+					onFilter={filter => this.setState({localFilter: filter})}>
+					<ActivityListItem
+						isHeader={true}
+						activity={{timestamp: 'Date', type: 'Action', comment: 'Comment', user: 'Username', status: 'Status'}}
+						isDes={this.state.sortDescending}
+						onSort={() => this.setState({sortDescending: !this.state.sortDescending})}/>
+					{this.sortActivities(this.filterActivities(), this.state.sortDescending).map(activity => <ActivityListItem key={activity.id} activity={activity}/>)}
+				</ListEditorView>
+			</div>
+		);
+	}
+
+	filterActivities() {
+		let {activities} = this.props;
+		let {localFilter} = this.state;
+		if (localFilter.trim()) {
+			const filter = new RegExp(escape(localFilter), 'i');
+			return activities.filter(({user = '', comment = '', type = ''}) => escape(user).match(filter) || escape(comment).match(filter) || escape(type).match(filter));
+		}
+		else {
+			return activities;
+		}
+	}
+
+	sortActivities(activities) {
+		if (this.state.sortDescending) {
+			return activities.sort((a, b) => a.timestamp - b.timestamp);
+		}
+		else {
+			return activities.reverse();
+		}
+	}
+
+}
+
+export default ActivityLogView;
diff --git a/openecomp-ui/src/nfvo-components/confirmations/ConfirmationModalView.jsx b/openecomp-ui/src/nfvo-components/confirmations/ConfirmationModalView.jsx
deleted file mode 100644
index cc971c6..0000000
--- a/openecomp-ui/src/nfvo-components/confirmations/ConfirmationModalView.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import Button from 'react-bootstrap/lib/Button.js';
-
-import i18n from 'nfvo-utils/i18n/i18n.js';
-import Modal from 'nfvo-components/modal/Modal.jsx';
-
-let typeClass = {
-	'default': 'primary',
-	error: 'danger',
-	warning: 'warning',
-	success: 'success'
-};
-
-
-class ConfirmationModalView extends React.Component {
-
-	static propTypes = {
-		show: React.PropTypes.bool,
-		type: React.PropTypes.oneOf(['default', 'error', 'warning', 'success']),
-		msg: React.PropTypes.node,
-		title: React.PropTypes.string,
-		confirmationDetails: React.PropTypes.object,
-		confirmationButtonText: React.PropTypes.string,
-
-	};
-
-	static defaultProps = {
-		show: false,
-		type: 'warning',
-		title: 'Warning',
-		msg: '',
-		confirmationButtonText: i18n('Delete')
-	};
-
-	render() {
-		let {title, type, msg, show, confirmationButtonText} = this.props;
-
-		return(
-			<Modal show={show} className={`notification-modal ${typeClass[type]}`}>
-				<Modal.Header>
-					<Modal.Title>{title}</Modal.Title>
-				</Modal.Header>
-				<Modal.Body>{msg}</Modal.Body>
-				<Modal.Footer>
-					<Button bsStyle={typeClass[type]} onClick={() => this.props.onDeclined(this.props.confirmationDetails)}>{i18n('Cancel')}</Button>
-					<Button bsStyle={typeClass[type]} onClick={() => this.props.onConfirmed(this.props.confirmationDetails)}>{confirmationButtonText}</Button>
-				</Modal.Footer>
-			</Modal>
-		);
-	};
-}
-
-export default ConfirmationModalView;
diff --git a/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx b/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx
index 4a106b5..2a0b7d4 100644
--- a/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx
+++ b/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 import classnames from 'classnames';
 
@@ -7,10 +22,17 @@
 export default class TabulatedEditor extends React.Component {
 
 	render() {
-		const {versionControllerProps, navigationBarProps, onToggle, onVersionSwitching, onCreate, onSave, onClose, onVersionControllerAction, onNavigate, children} = this.props;
+		const {navigationBarProps, onToggle, onVersionSwitching, onCreate, onSave, onClose, onVersionControllerAction, onNavigate, children, meta} = this.props;
+		let {versionControllerProps} = this.props;
 		const {className = ''} = React.Children.only(children).props;
 		const child = this.prepareChild();
 
+		if(onClose) {
+			versionControllerProps = {
+				...versionControllerProps,
+				onClose: () => onClose(versionControllerProps)
+			};
+		}
 		return (
 			<div className='software-product-view'>
 				<div className='software-product-navigation-side-bar'>
@@ -19,11 +41,10 @@
 				<div className='software-product-landing-view-right-side flex-column'>
 					<VersionController
 						{...versionControllerProps}
-						onVersionSwitching={version => onVersionSwitching(version)}
-						callVCAction={onVersionControllerAction}
+						onVersionSwitching={version => onVersionSwitching(version, meta)}
+						callVCAction={(action, version) => onVersionControllerAction(action, version, meta)}
 						onCreate={onCreate && this.handleCreate}
-						onSave={onSave && this.handleSave}
-						onClose={() => onClose(versionControllerProps)}/>
+						onSave={onSave && this.handleSave}/>
 					<div className={classnames('content-area', `${className}`)}>
 					{
 						child
diff --git a/openecomp-ui/src/nfvo-components/grid/GridItem.jsx b/openecomp-ui/src/nfvo-components/grid/GridItem.jsx
new file mode 100644
index 0000000..8819ab7
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/grid/GridItem.jsx
@@ -0,0 +1,26 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+
+const GridItem = ({colSpan = 1, children, stretch = false}) => (
+	<div className={`grid-col-${colSpan}`}>
+		<div className={`grid-item${stretch ? '-stretch' : ''}`}>
+			{children}
+		</div>
+	</div>
+);
+
+export default GridItem;
diff --git a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx
new file mode 100644
index 0000000..175b3ee
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx
@@ -0,0 +1,33 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+
+const GridSection = ({title, children, titleClassName}) => {
+	return (
+		<div className='grid-section'>
+			{title && <div className={`section-title ${titleClassName || ''}`}>{title}</div>}
+			<div className='grid-items'>
+				{children}
+			</div>
+		</div>
+	);
+};
+
+GridSection.propTypes = {
+	title: React.PropTypes.string,
+};
+
+export default GridSection;
diff --git a/openecomp-ui/src/nfvo-components/icon/Icon.jsx b/openecomp-ui/src/nfvo-components/icon/Icon.jsx
new file mode 100644
index 0000000..1255776
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/icon/Icon.jsx
@@ -0,0 +1,45 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React, { Component, PropTypes } from 'react';
+
+
+export default class Icon extends Component {
+
+	static propTypes = {
+		image: PropTypes.string.isRequired,
+		onClick: PropTypes.func,
+		label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+		className: PropTypes.string,
+		iconClassName: PropTypes.string
+	};
+
+	static defaultProps = {
+		label: '',
+		className: '',
+		iconClassName: ''
+	};
+
+	render() {
+		let {image, onClick, label, className, iconClassName, ...other} = this.props;
+		let classes = `icon-component ${className} ${onClick ? 'clickable' : ''}`;
+		return (
+			<div {...other} onClick={onClick} className={classes}>
+				<span className={`icon ${image} ${iconClassName}`}></span>
+				<span className='icon-label'>{label}</span>
+			</div>
+		);
+	}
+}
diff --git a/openecomp-ui/src/nfvo-components/icon/SVGIcon.jsx b/openecomp-ui/src/nfvo-components/icon/SVGIcon.jsx
new file mode 100644
index 0000000..dd165fb
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/icon/SVGIcon.jsx
@@ -0,0 +1,54 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React, {PropTypes} from 'react';
+import Configuration from 'sdc-app/config/Configuration.js';
+
+export default class SVGIcon extends React.Component {
+
+	static propTypes = {
+		name: PropTypes.string.isRequired,
+		onClick: PropTypes.func,
+		label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+		labelPosition: PropTypes.string,
+		className: PropTypes.string,
+		iconClassName: PropTypes.string,
+		labelClassName: PropTypes.string
+	};
+
+	static defaultProps = {
+		name: '',
+		label: '',
+		className: '',
+		iconClassName: '',
+		labelClassName: '',
+		labelPosition: 'bottom'
+	};
+
+	render() {
+		let {name, onClick, label, className, iconClassName, labelClassName, labelPosition, ...other} = this.props;
+		let classes = `svg-icon-wrapper ${className} ${onClick ? 'clickable' : ''} ${labelPosition}`;
+
+		return (
+			<div {...other} onClick={onClick} className={classes}>
+				<svg className={`svg-icon ${name} ${iconClassName}`}  >
+					<use href={Configuration.get('appContextPath') + '/resources/images/svg/' + this.props.name + '.svg#' + this.props.name + '_icon' }
+						 xlinkHref={Configuration.get('appContextPath') + '/resources/images/svg/' + this.props.name + '.svg#' + this.props.name + '_icon' } />
+				</svg>
+				{label && <span className={`svg-icon-label ${labelClassName}`}>{label}</span>}
+			</div>
+		);
+	}
+}
diff --git a/openecomp-ui/src/nfvo-components/icon/SVGIcon.stories.js b/openecomp-ui/src/nfvo-components/icon/SVGIcon.stories.js
new file mode 100644
index 0000000..6675670
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/icon/SVGIcon.stories.js
@@ -0,0 +1,50 @@
+import React from 'react';
+import {storiesOf, action} from '@kadira/storybook';
+import {select, text, withKnobs} from '@kadira/storybook-addon-knobs';
+import SVGIcon from './SVGIcon.jsx';
+
+const stories = storiesOf('SVGIcon', module);
+
+const iconNames = ['locked',
+    'pencil',
+    'plus-circle',
+    'plus',
+    'search',
+    'sliders',
+    'trash-o',
+    'unlocked',
+    'vendor',
+    'version-controller-lock-closed',
+    'version-controller-lock-open',
+    'version-controller-revert',
+    'version-controller-save',
+    'version-controller-submit',
+    'vlm',
+    'vsp' ];
+
+function colorChanger() {
+    return {fill: text('Color', '')};
+}
+
+function iconName() {
+    return select('Icon name' , iconNames, iconNames[0]);
+}
+
+stories.addDecorator(withKnobs);
+
+stories
+    .add('icon', () => {
+        return (
+            <SVGIcon name={iconName()} style={colorChanger()}/>
+        );
+    })
+    .add('icon with label', () => {
+        return (
+            <SVGIcon name={iconName()} label={iconName()} style={colorChanger()}/>
+        );
+    })
+    .add('locked clickable', () => {
+        return (
+            <SVGIcon name={iconName()} onClick={action('clicked')} style={colorChanger()}/>
+        );
+    });
\ No newline at end of file
diff --git a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx
index 3ac3fca..e2ee40f 100644
--- a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx
+++ b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx
@@ -1,77 +1,115 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
-import FontAwesome from 'react-fontawesome';
-import classnames from 'classnames';
-import Input from 'react-bootstrap/lib/Input';
+import ReactDOM from 'react-dom';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import Input from 'nfvo-components/input/validation/InputWrapper.jsx';
 
+const ExpandableInputClosed = ({iconType, onClick}) => (
+	<SVGIcon className='expandable-input-wrapper closed' name={iconType} onClick={onClick} />
+);
 
-class ExpandableInput extends React.Component {
-	constructor(props){
-		super(props);
-		this.state = {showInput: false, value: ''};
-		this.toggleInput = this.toggleInput.bind(this);
-		this.handleFocus = this.handleFocus.bind(this);
-		this.handleInput = this.handleInput.bind(this);
-		this.handleClose = this.handleClose.bind(this);
+class ExpandableInputOpened extends React.Component {
+	componentDidMount(){
+		this.rawDomNode = ReactDOM.findDOMNode(this.searchInputNode.inputWrapper);
+		this.rawDomNode.focus();
 	}
 
-	toggleInput(){
-		if (!this.state.showInput){
-			this.searchInputNode.refs.input.focus();
-		} else {
+	componentWillReceiveProps(newProps){
+		if (!newProps.value){
+			if (!(document.activeElement === this.rawDomNode)){
+				this.props.handleBlur();
+			}
+		}
+	}
+
+	handleClose(){
+		this.props.onChange('');
+		this.rawDomNode.focus();
+	}
+
+	handleKeyDown(e){
+		if (e.key === 'Escape'){
+			e.preventDefault();
+			if (this.props.value) {
+				this.handleClose();
+			} else {
+				this.rawDomNode.blur();
+			}
+		};
+	}
+
+	render() {
+		let {iconType, value, onChange, handleBlur} = this.props;
+		return (
+				<div className='expandable-input-wrapper opened' key='expandable'>
+					<Input
+						type='text'
+						value={value}
+						ref={(input) => this.searchInputNode = input}
+						className='expandable-active'
+						groupClassName='expandable-input-control'
+						onChange={e => onChange(e)}
+						onKeyDown={e => this.handleKeyDown(e)}
+						onBlur={handleBlur}/>
+					{value && <SVGIcon onClick={() => this.handleClose()} name='close' />}
+					{!value && <SVGIcon name={iconType} onClick={handleBlur}/>}
+				</div>
+		);
+	}
+}
+
+class ExpandableInput extends React.Component {
+
+	static propTypes = {
+		iconType: React.PropTypes.string,
+		onChange: React.PropTypes.func,
+		value: React.PropTypes.string
+	};
+
+	state = {showInput: false};
+
+	closeInput(){
+		if (!this.props.value) {
 			this.setState({showInput: false});
 		}
 	}
 
-	handleInput(e){
-		let {onChange} = this.props;
-
-		this.setState({value: e.target.value});
-		onChange(e);
-	}
-
-	handleClose(){
-		this.handleInput({target: {value: ''}});
-		this.searchInputNode.refs.input.focus();
-	}
-
-	handleFocus(){
-		if (!this.state.showInput){
-			this.setState({showInput: true});
-		}
-	}
-
 	getValue(){
-		return this.state.value;
+		return this.props.value;
 	}
 
 	render(){
-		let {iconType} = this.props;
-
-		let inputClasses = classnames({
-			'expandable-active': this.state.showInput,
-			'expandable-not-active': !this.state.showInput
-		});
-
-		let iconClasses = classnames(
-			'expandable-icon',
-			{'expandable-icon-active': this.state.showInput}
-		);
-
+		let {iconType, value, onChange = false} = this.props;
 		return (
-			<div className='expandable-input-wrapper'>
-				<Input
-					type='text'
-					value={this.state.value}
-					ref={(input) => this.searchInputNode = input}
-					className={inputClasses}
-					groupClassName='expandable-input-control'
-					onChange={e => this.handleInput(e)}
-					onFocus={this.handleFocus}/>
-				{this.state.showInput && this.state.value && <FontAwesome onClick={this.handleClose} name='close' className='expandable-close-button'/>}
-				{!this.state.value && <FontAwesome onClick={this.toggleInput} name={iconType} className={iconClasses}/>}
+			<div className='expandable-input-top'>
+				{this.state.showInput &&
+					<ExpandableInputOpened
+						key='open'
+						iconType={iconType}
+						onChange={onChange}
+						value={value}
+						handleKeyDown={(e) => this.handleKeyDown(e)}
+						handleBlur={() => this.closeInput()}/>
+				}
+				{!this.state.showInput && <ExpandableInputClosed key='closed' iconType={iconType} onClick={() => this.setState({showInput: true})} />}
 			</div>
-		);
+				);
 	}
 }
 
+
 export default ExpandableInput;
diff --git a/openecomp-ui/src/nfvo-components/input/SelectInput.jsx b/openecomp-ui/src/nfvo-components/input/SelectInput.jsx
index 1036ac4..03c7273 100644
--- a/openecomp-ui/src/nfvo-components/input/SelectInput.jsx
+++ b/openecomp-ui/src/nfvo-components/input/SelectInput.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ */
 /**
  * The HTML structure here is aligned with bootstrap HTML structure for form elements.
  * In this way we have proper styling and it is aligned with other form elements on screen.
@@ -20,8 +35,9 @@
 
 	render() {
 		let {label, value, ...other} = this.props;
+		const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {};
 		return (
-			<div className='validation-input-wrapper dropdown-multi-select'>
+			<div  {...dataTestId} className='validation-input-wrapper dropdown-multi-select'>
 				<div className='form-group'>
 					{label && <label className='control-label'>{label}</label>}
 					<Select ref='_myInput' onChange={value => this.onSelectChanged(value)} {...other} value={value} />
diff --git a/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx b/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx
index 873d3de..7bbafa3 100644
--- a/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx
+++ b/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 
 export default
diff --git a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx
index 171bead..c60d6f7 100644
--- a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx
+++ b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx
@@ -1,6 +1,21 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
-import FontAwesome from 'react-fontawesome';
-import Input from 'react-bootstrap/lib/Input.js';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import Input from 'nfvo-components/input/validation/InputWrapper.jsx';
 
 class DualListboxView extends React.Component {
 
@@ -30,37 +45,32 @@
 
 	state = {
 		availableListFilter: '',
-		selectedValuesListFilter: ''
-	};
-
-	static contextTypes = {
-		isReadOnlyMode: React.PropTypes.bool
+		selectedValuesListFilter: '',
+		selectedValues: []
 	};
 
 	render() {
-		let {availableList, selectedValuesList, filterTitle} = this.props;
+		let {availableList, selectedValuesList, filterTitle, isReadOnlyMode} = this.props;
 		let {availableListFilter, selectedValuesListFilter} = this.state;
-		let isReadOnlyMode = this.context.isReadOnlyMode;
 
 		let unselectedList = availableList.filter(availableItem => !selectedValuesList.find(value => value === availableItem.id));
 		let selectedList = availableList.filter(availableItem => selectedValuesList.find(value => value === availableItem.id));
 		selectedList = selectedList.sort((a, b) => selectedValuesList.indexOf(a.id) - selectedValuesList.indexOf(b.id));
-
 		return (
 			<div className='dual-list-box'>
 				{this.renderListbox(filterTitle.left, unselectedList, {
 					value: availableListFilter,
 					ref: 'availableListFilter',
 					disabled: isReadOnlyMode,
-					onChange: () => this.setState({availableListFilter: this.refs.availableListFilter.getValue()})
-				}, {ref: 'availableValues', disabled: isReadOnlyMode})}
+					onChange: (value) => this.setState({availableListFilter: value})
+				}, {ref: 'availableValues', disabled: isReadOnlyMode, testId: 'available',})}
 				{this.renderOperationsBar(isReadOnlyMode)}
 				{this.renderListbox(filterTitle.right, selectedList, {
 					value: selectedValuesListFilter,
 					ref: 'selectedValuesListFilter',
 					disabled: isReadOnlyMode,
-					onChange: () => this.setState({selectedValuesListFilter: this.refs.selectedValuesListFilter.getValue()})
-				}, {ref: 'selectedValues', disabled: isReadOnlyMode})}
+					onChange: (value) => this.setState({selectedValuesListFilter: value})
+				}, {ref: 'selectedValues', disabled: isReadOnlyMode, testId: 'selected'})}
 			</div>
 		);
 	}
@@ -69,21 +79,25 @@
 		let regExFilter = new RegExp(escape(filterProps.value), 'i');
 		let matchedItems = list.filter(item => item.name.match(regExFilter));
 		let unMatchedItems = list.filter(item => !item.name.match(regExFilter));
-
-
 		return (
 			<div className='dual-search-multi-select-section'>
 				<p>{filterTitle}</p>
 				<div className='dual-text-box-search search-wrapper'>
-					<Input name='search-input-control' type='text' groupClassName='search-input-control' {...filterProps}/>
-					<FontAwesome name='search' className='search-icon'/>
+					<Input data-test-id={`${props.testId}-search-input`}
+						   name='search-input-control' type='text'
+						   groupClassName='search-input-control'
+						   {...filterProps}/>
+					<SVGIcon name='search' className='search-icon'/>
 				</div>
 				<Input
 					multiple
+					onChange={(event) => this.onSelectItems(event.target.selectedOptions)}
 					groupClassName='dual-list-box-multi-select'
 					type='select'
 					name='dual-list-box-multi-select'
-					{...props}>
+					data-test-id={`${props.testId}-select-input`}
+					disabled={props.disabled}
+					ref={props.ref}>
 					{matchedItems.map(item => this.renderOption(item.id, item.name))}
 					{matchedItems.length && unMatchedItems.length && <option style={{pointerEvents: 'none'}}>--------------------</option>}
 					{unMatchedItems.map(item => this.renderOption(item.id, item.name))}
@@ -92,6 +106,11 @@
 		);
 	}
 
+	onSelectItems(selectedOptions) {
+		let selectedValues = Object.keys(selectedOptions).map((k) => selectedOptions[k].value);
+		this.setState({selectedValues});
+	}
+
 	renderOption(value, name) {
 		return (<option className='dual-list-box-multi-select-text' key={value} value={value}>{name}</option>);
 	}
@@ -107,17 +126,19 @@
 		);
 	}
 
-	renderOperationBarButton(onClick, fontAwesomeIconName){
-		return (<div className='dual-list-option' onClick={onClick}><FontAwesome name={fontAwesomeIconName}/></div>);
+	renderOperationBarButton(onClick, iconName){
+		return (<div className='dual-list-option' data-test-id={`operation-icon-${iconName}`} onClick={onClick}><SVGIcon name={iconName}/></div>);
 	}
 
 	addToSelectedList() {
-		this.props.onChange(this.props.selectedValuesList.concat(this.refs.availableValues.getValue()));
+		this.props.onChange(this.props.selectedValuesList.concat(this.state.selectedValues));
+		this.setState({selectedValues: []});
 	}
 
 	removeFromSelectedList() {
-		const selectedValues = this.refs.selectedValues.getValue();
+		const selectedValues = this.state.selectedValues;
 		this.props.onChange(this.props.selectedValuesList.filter(value => !selectedValues.find(selectedValue => selectedValue === value)));
+		this.setState({selectedValues: []});
 	}
 
 	addAllToSelectedList() {
diff --git a/openecomp-ui/src/nfvo-components/input/inputOptions/InputOptions.jsx b/openecomp-ui/src/nfvo-components/input/inputOptions/InputOptions.jsx
index 5daaffe..e8aadc4 100644
--- a/openecomp-ui/src/nfvo-components/input/inputOptions/InputOptions.jsx
+++ b/openecomp-ui/src/nfvo-components/input/inputOptions/InputOptions.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 import i18n from 'nfvo-utils/i18n/i18n.js';
 import classNames from 'classnames';
@@ -13,15 +28,21 @@
 			title: React.PropTypes.string
 		})),
 		isEnabledOther: React.PropTypes.bool,
-		title: React.PropTypes.string,
+		label: React.PropTypes.string,
 		selectedValue: React.PropTypes.string,
-		multiSelectedEnum: React.PropTypes.array,
+		multiSelectedEnum: React.PropTypes.oneOfType([
+			React.PropTypes.string,
+			React.PropTypes.array
+		]),
 		selectedEnum: React.PropTypes.string,
 		otherValue: React.PropTypes.string,
 		onEnumChange: React.PropTypes.func,
 		onOtherChange: React.PropTypes.func,
+		onBlur: React.PropTypes.func,
 		isRequired: React.PropTypes.bool,
-		isMultiSelect: React.PropTypes.bool
+		isMultiSelect: React.PropTypes.bool,
+		hasError: React.PropTypes.bool,
+		disabled: React.PropTypes.bool
 	};
 
 
@@ -41,7 +62,7 @@
 
 	render() {
 		let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, hasError, validations, children} = this.props;
-
+		const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {};
 		let currentMultiSelectedEnum = [];
 		let currentSelectedEnum = '';
 		let {otherInputDisabled} = this.state;
@@ -54,14 +75,18 @@
 		else if(selectedEnum){
 			currentSelectedEnum = selectedEnum;
 		}
+		if (!onBlur) {
+			onBlur = () => {};
+		}
 
 		let isReadOnlyMode = this.context.isReadOnlyMode;
 
 		return(
-			<div className={classNames('form-group', {'required' : validations.required , 'has-error' : hasError})}>
+			<div className={classNames('form-group', {'required' : (validations && validations.required) || isRequired, 'has-error' : hasError})}>
 				{label && <label className='control-label'>{label}</label>}
 				{isMultiSelect && otherInputDisabled ?
 					<Select
+						{...dataTestId}
 						ref='_myInput'
 						value={currentMultiSelectedEnum}
 						className='options-input'
@@ -74,18 +99,18 @@
 						multi/> :
 					<div className={classNames('input-options',{'has-error' : hasError})}>
 						<select
+							{...dataTestId}
 							ref={'_myInput'}
 							label={label}
 							className='form-control input-options-select'
 							value={currentSelectedEnum}
-							style={{'width' : otherInputDisabled ? '100%' : '95px'}}
+							style={{'width' : otherInputDisabled ? '100%' : '100px'}}
 							onBlur={() => onBlur()}
 							disabled={isReadOnlyMode || Boolean(this.props.disabled)}
 							onChange={ value => this.enumChanged(value)}
 							type='select'>
-							{values && values.length && values.map(val => this.renderOptions(val))}
+							{children || (values && values.length && values.map((val, index) => this.renderOptions(val, index)))}
 							{onOtherChange && <option key='other' value={other.OTHER}>{i18n(other.OTHER)}</option>}
-							{children}
 						</select>
 
 						{!otherInputDisabled && <div className='input-options-separator'/>}
@@ -104,9 +129,9 @@
 		);
 	}
 
-	renderOptions(val){
-		return(
-			<option key={val.enum} value={val.enum}>{val.title}</option>
+	renderOptions(val, index){
+		return (
+			<option key={index} value={val.enum}>{val.title}</option>
 		);
 	}
 
@@ -154,9 +179,9 @@
 
 	enumChanged() {
 		let enumValue = this.refs._myInput.value;
-		let {onEnumChange, isMultiSelect, onChange} = this.props;
+		let {onEnumChange, onOtherChange, isMultiSelect, onChange} = this.props;
 		this.setState({
-			otherInputDisabled: enumValue !== other.OTHER
+			otherInputDisabled: !Boolean(onOtherChange) || enumValue !== other.OTHER
 		});
 
 		let value = isMultiSelect ? [enumValue] : enumValue;
@@ -169,7 +194,7 @@
 	}
 
 	multiSelectEnumChanged(enumValue) {
-		let {onEnumChange} = this.props;
+		let {onEnumChange, onOtherChange} = this.props;
 		let selectedValues = enumValue.map(enumVal => {
 			return enumVal.value;
 		});
@@ -182,7 +207,7 @@
 		}
 
 		this.setState({
-			otherInputDisabled: !selectedValues.includes(i18n(other.OTHER))
+			otherInputDisabled: !Boolean(onOtherChange) || !selectedValues.includes(i18n(other.OTHER))
 		});
 		onEnumChange(selectedValues);
 	}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
new file mode 100644
index 0000000..47922f86
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
@@ -0,0 +1,114 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+import ValidationButtons from './ValidationButtons.jsx';
+
+class Form extends React.Component {
+
+	static defaultProps = {
+		hasButtons : true,
+		onSubmit : null,
+		onReset :  null,
+		labledButtons: true,
+		onValidChange :  null,
+		isValid: true
+	};
+
+	static propTypes = {
+		isValid : React.PropTypes.bool,
+		formReady : React.PropTypes.bool,
+		isReadOnlyMode : React.PropTypes.bool,
+		hasButtons : React.PropTypes.bool,
+		onSubmit : React.PropTypes.func,
+		onReset : React.PropTypes.func,
+		labledButtons: React.PropTypes.bool,
+		onValidChange : React.PropTypes.func,
+		onValidityChanged: React.PropTypes.func,
+		onValidateForm: React.PropTypes.func
+	};
+
+	constructor(props) {
+		super(props);
+	}
+
+
+	render() {
+		// eslint-disable-next-line no-unused-vars
+		let {isValid, formReady, onValidateForm, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, onDataChanged, children, ...formProps} = this.props;
+		return (
+			<form {...formProps} ref={(form) => this.form = form} onSubmit={event => this.handleFormValidation(event)}>
+				<div className='validation-form-content'>
+					<fieldset disabled={isReadOnlyMode}>
+						{children}
+					</fieldset>
+				</div>
+				{hasButtons && <ValidationButtons labledButtons={labledButtons} ref={(buttons) => this.buttons = buttons} isReadOnlyMode={isReadOnlyMode}/>}
+			</form>
+		);
+	}
+
+	handleFormValidation(event) {
+		event.preventDefault();
+		if (this.props.onValidateForm && !this.props.formReady){
+			return this.props.onValidateForm();
+		} else {
+			return this.handleFormSubmit(event);
+		}
+	}
+	handleFormSubmit(event) {
+		if (event) {
+			event.preventDefault();
+		}
+		if(this.props.onSubmit) {
+			return this.props.onSubmit(event);
+		}
+	}
+
+	componentDidMount() {
+		if (this.props.hasButtons) {
+			this.buttons.setState({isValid: this.props.isValid});
+		}
+	}
+
+
+
+	componentDidUpdate(prevProps) {
+		// only handling this programatically if the validation of the form is done outside of the view
+		// (example with a form that is dependent on the state of other forms)
+		if (prevProps.isValid !== this.props.isValid) {
+			if (this.props.hasButtons) {
+				this.buttons.setState({isValid: this.props.isValid});
+			}
+			// callback in case form is part of bigger picture in view
+			if (this.props.onValidChange) {
+				this.props.onValidChange(this.props.isValid);
+			}
+
+			// TODO - maybe this has to be part of componentWillUpdate
+			if(this.props.onValidityChanged) {
+				this.props.onValidityChanged(this.props.isValid);
+			}
+		}
+		if (this.props.formReady) { // if form validation succeeded -> continue with submit
+			this.handleFormSubmit();
+		}
+	}
+
+}
+
+
+export default Form;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
new file mode 100644
index 0000000..59c35d7
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
@@ -0,0 +1,180 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+import ReactDOM from 'react-dom';
+import classNames from 'classnames';
+import Checkbox from 'react-bootstrap/lib/Checkbox.js';
+import Radio from 'react-bootstrap/lib/Radio.js';
+import FormGroup from 'react-bootstrap/lib/FormGroup.js';
+import FormControl from 'react-bootstrap/lib/FormControl.js';
+import Overlay from 'react-bootstrap/lib/Overlay.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+class Input extends React.Component {
+
+	state = {
+		value: this.props.value,
+		checked: this.props.checked,
+		selectedValues: []
+	}
+
+	render() {
+		const {label, isReadOnlyMode, value, onBlur, onKeyDown, type, disabled, checked, name} = this.props;
+		// eslint-disable-next-line no-unused-vars
+		const {groupClassName, isValid = true, errorText, isRequired,  ...inputProps} = this.props;
+		let wrapperClassName = (type !== 'radio') ? 'validation-input-wrapper' : 'form-group';
+		if (disabled) {
+			wrapperClassName += ' disabled';
+		}
+		return(
+			<div className={wrapperClassName}>
+				<FormGroup className={classNames('form-group', [groupClassName], {'required' : isRequired , 'has-error' : !isValid})} >
+					{(label && (type !== 'checkbox' && type !== 'radio')) && <label className='control-label'>{label}</label>}
+					{(type === 'text' || type === 'number') &&
+					<FormControl
+						bsClass={'form-control input-options-other'}
+						onChange={(e) => this.onChange(e)}
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						onBlur={onBlur}
+						onKeyDown={onKeyDown}
+						value={value || ''}
+						inputRef={(input) => this.input = input}
+						type={type}
+						data-test-id={this.props['data-test-id']}/>}
+
+					{type === 'textarea' &&
+					<FormControl
+						className='form-control input-options-other'
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						value={value || ''}
+						onBlur={onBlur}
+						onKeyDown={onKeyDown}
+						componentClass={type}
+						onChange={(e) => this.onChange(e)}
+						inputRef={(input) => this.input = input}
+						data-test-id={this.props['data-test-id']}/>}
+
+					{type === 'checkbox' &&
+					<Checkbox
+						className={classNames({'required' : isRequired , 'has-error' : !isValid})}
+						onChange={(e)=>this.onChangeCheckBox(e)}
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						checked={value}
+						data-test-id={this.props['data-test-id']}>{label}</Checkbox>}
+
+					{type === 'radio' &&
+					<Radio name={name}
+						   checked={checked}
+						   disabled={isReadOnlyMode || Boolean(disabled)}
+						   value={value}
+						   onChange={(e)=>this.onChangeRadio(e)}
+						   data-test-id={this.props['data-test-id']}>{label}</Radio>}
+					{type === 'select' &&
+					<FormControl onClick={ (e) => this.optionSelect(e) }
+						 componentClass={type}
+						 inputRef={(input) => this.input = input}
+						 name={name} {...inputProps}
+						 data-test-id={this.props['data-test-id']}/>}
+				</FormGroup>
+				{ this.renderErrorOverlay() }
+			</div>
+		);
+	}
+
+	getValue() {
+		return this.props.type !== 'select' ? this.state.value : this.state.selectedValues;
+	}
+
+	getChecked() {
+		return this.state.checked;
+	}
+
+	optionSelect(e) {
+		let selectedValues = [];
+		if (e.target.value) {
+			selectedValues.push(e.target.value);
+		}
+		this.setState({
+			selectedValues
+		});
+	}
+
+	onChange(e) {
+		const {onChange, type} = this.props;
+		let value = e.target.value;
+		if (type === 'number') {
+			value = Number(value);
+		}
+		this.setState({
+			value
+		});
+		onChange(value);
+	}
+
+	onChangeCheckBox(e) {
+		let {onChange} = this.props;
+		this.setState({
+			checked: e.target.checked
+		});
+		onChange(e.target.checked);
+	}
+
+	onChangeRadio(e) {
+		let {onChange} = this.props;
+		this.setState({
+			checked: e.target.checked
+		});
+		onChange(this.state.value);
+	}
+
+	focus() {
+		ReactDOM.findDOMNode(this.input).focus();
+	}
+
+	renderErrorOverlay() {
+		let position = 'right';
+		const {errorText = '', isValid = true, type, overlayPos} = this.props;
+
+		if (overlayPos) {
+			position = overlayPos;
+		}
+		else if (type === 'text'
+			|| type === 'email'
+			|| type === 'number'
+			|| type === 'password') {
+			position = 'bottom';
+		}
+
+		return (
+			<Overlay
+				show={!isValid}
+				placement={position}
+				target={() => {
+					let target = ReactDOM.findDOMNode(this.input);
+					return target.offsetParent ? target : undefined;
+				}}
+				container={this}>
+				<Tooltip
+					id={`error-${errorText.replace(' ', '-')}`}
+					className='validation-error-message'>
+					{errorText}
+				</Tooltip>
+			</Overlay>
+		);
+	}
+
+}
+export default  Input;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
new file mode 100644
index 0000000..6e54254
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
@@ -0,0 +1,279 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+import ReactDOM from 'react-dom';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import classNames from 'classnames';
+import Select from 'nfvo-components/input/SelectInput.jsx';
+import Overlay from 'react-bootstrap/lib/Overlay.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+export const other = {OTHER: 'Other'};
+
+class InputOptions extends React.Component {
+
+	static propTypes = {
+		values: React.PropTypes.arrayOf(React.PropTypes.shape({
+			enum: React.PropTypes.string,
+			title: React.PropTypes.string
+		})),
+		isEnabledOther: React.PropTypes.bool,
+		label: React.PropTypes.string,
+		selectedValue: React.PropTypes.string,
+		multiSelectedEnum: React.PropTypes.oneOfType([
+			React.PropTypes.string,
+			React.PropTypes.array
+		]),
+		selectedEnum: React.PropTypes.string,
+		otherValue: React.PropTypes.string,
+		overlayPos: React.PropTypes.string,
+		onEnumChange: React.PropTypes.func,
+		onOtherChange: React.PropTypes.func,
+		onBlur: React.PropTypes.func,
+		isRequired: React.PropTypes.bool,
+		isMultiSelect: React.PropTypes.bool,
+		isValid: React.PropTypes.bool,
+		disabled: React.PropTypes.bool
+	};
+
+	state = {
+		otherInputDisabled: !this.props.otherValue
+	};
+
+	oldProps = {
+		selectedEnum: '',
+		otherValue: '',
+		multiSelectedEnum: []
+	};
+
+	render() {
+		let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, isValid, children, isReadOnlyMode} = this.props;
+		const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {};
+		let currentMultiSelectedEnum = [];
+		let currentSelectedEnum = '';
+		let {otherInputDisabled} = this.state;
+		if (isMultiSelect) {
+			currentMultiSelectedEnum = multiSelectedEnum;
+			if(!otherInputDisabled) {
+				currentSelectedEnum = multiSelectedEnum ? multiSelectedEnum.toString() : undefined;
+			}
+		}
+		else if(selectedEnum){
+			currentSelectedEnum = selectedEnum;
+		}
+		if (!onBlur) {
+			onBlur = () => {};
+		}
+
+		return(
+			<div className='validation-input-wrapper' >
+				<div className={classNames('form-group', {'required' : isRequired, 'has-error' : !isValid})} >
+					{label && <label className='control-label'>{label}</label>}
+					{isMultiSelect && otherInputDisabled ?
+						<Select
+							{...dataTestId}
+							ref={(input) => this.input = input}
+							value={currentMultiSelectedEnum}
+							className='options-input'
+							clearable={false}
+							required={isRequired}
+							disabled={isReadOnlyMode || Boolean(this.props.disabled)}
+							onBlur={() => onBlur()}
+							onMultiSelectChanged={value => this.multiSelectEnumChanged(value)}
+							options={this.renderMultiSelectOptions(values)}
+							multi/> :
+						<div className={classNames('input-options',{'has-error' : !isValid})} >
+							<select
+								{...dataTestId}
+								ref={(input) => this.input = input}
+								label={label}
+								className='form-control input-options-select'
+								value={currentSelectedEnum}
+								style={{'width' : otherInputDisabled ? '100%' : '100px'}}
+								onBlur={() => onBlur()}
+								disabled={isReadOnlyMode || Boolean(this.props.disabled)}
+								onChange={ value => this.enumChanged(value)}
+								type='select'>
+								{children || (values && values.length && values.map((val, index) => this.renderOptions(val, index)))}
+								{onOtherChange && <option key='other' value={other.OTHER}>{i18n(other.OTHER)}</option>}
+							</select>
+
+							{!otherInputDisabled && <div className='input-options-separator'/>}
+							<input
+								className='form-control input-options-other'
+								placeholder={i18n('other')}
+								ref={(otherValue) => this.otherValue = otherValue}
+								style={{'display' : otherInputDisabled ? 'none' : 'block'}}
+								disabled={isReadOnlyMode || Boolean(this.props.disabled)}
+								value={otherValue || ''}
+								onBlur={() => onBlur()}
+								onChange={() => this.changedOtherInput()}/>
+						</div>
+					}
+					</div>
+				{ this.renderErrorOverlay() }
+			</div>
+		);
+	}
+
+	renderOptions(val, index){
+		return (
+			<option key={index} value={val.enum}>{val.title}</option>
+		);
+	}
+
+
+	renderMultiSelectOptions(values) {
+		let {onOtherChange} = this.props;
+		let optionsList = [];
+		if (onOtherChange) {
+			optionsList = values.map(option => {
+				return {
+					label: option.title,
+					value: option.enum,
+				};
+			}).concat([{
+				label: i18n(other.OTHER),
+				value: i18n(other.OTHER),
+			}]);
+		}
+		else {
+			optionsList = values.map(option => {
+				return {
+					label: option.title,
+					value: option.enum,
+				};
+			});
+		}
+		if (optionsList.length > 0 && optionsList[0].value === '') {
+			optionsList.shift();
+		}
+		return optionsList;
+	}
+
+	renderErrorOverlay() {
+		let position = 'right';
+		const {errorText = '', isValid = true, type, overlayPos} = this.props;
+
+		if (overlayPos) {
+			position = overlayPos;
+		}
+		else if (type === 'text'
+			|| type === 'email'
+			|| type === 'number'
+			|| type === 'password') {
+			position = 'bottom';
+		}
+
+		return (
+			<Overlay
+				show={!isValid}
+				placement={position}
+				target={() => {
+					let {otherInputDisabled} = this.state;
+					let target = otherInputDisabled ? ReactDOM.findDOMNode(this.input) :  ReactDOM.findDOMNode(this.otherValue);
+					return target.offsetParent ? target : undefined;
+				}}
+				container={this}>
+				<Tooltip
+					id={`error-${errorText.replace(' ', '-')}`}
+					className='validation-error-message'>
+					{errorText}
+				</Tooltip>
+			</Overlay>
+		);
+	}
+
+	getValue() {
+		let res = '';
+		let {isMultiSelect} = this.props;
+		let {otherInputDisabled} = this.state;
+
+		if (otherInputDisabled) {
+			res = isMultiSelect ? this.input.getValue() : this.input.value;
+		} else {
+			res = this.otherValue.value;
+		}
+		return res;
+	}
+
+	enumChanged() {
+		let enumValue = this.input.value;
+		let {onEnumChange, onOtherChange, isMultiSelect, onChange} = this.props;
+		this.setState({
+			otherInputDisabled: !Boolean(onOtherChange) || enumValue !== other.OTHER
+		});
+
+		let value = isMultiSelect ? [enumValue] : enumValue;
+		if (onEnumChange) {
+			onEnumChange(value);
+		}
+		if (onChange) {
+			onChange(value);
+		}
+	}
+
+	multiSelectEnumChanged(enumValue) {
+		let {onEnumChange, onOtherChange} = this.props;
+		let selectedValues = enumValue.map(enumVal => {
+			return enumVal.value;
+		});
+
+		if (this.state.otherInputDisabled === false) {
+			selectedValues.shift();
+		}
+		else if (selectedValues.includes(i18n(other.OTHER))) {
+			selectedValues = [i18n(other.OTHER)];
+		}
+
+		this.setState({
+			otherInputDisabled: !Boolean(onOtherChange) || !selectedValues.includes(i18n(other.OTHER))
+		});
+		onEnumChange(selectedValues);
+	}
+
+	changedOtherInput() {
+		let {onOtherChange} = this.props;
+		onOtherChange(this.otherValue.value);
+	}
+
+	componentDidUpdate() {
+		let {otherValue, selectedEnum, onInputChange, multiSelectedEnum} = this.props;
+		if (this.oldProps.otherValue !== otherValue
+			|| this.oldProps.selectedEnum !== selectedEnum
+			|| this.oldProps.multiSelectedEnum !== multiSelectedEnum) {
+			this.oldProps = {
+				otherValue,
+				selectedEnum,
+				multiSelectedEnum
+			};
+			onInputChange();
+		}
+	}
+
+	static getTitleByName(values, name) {
+		for (let key of Object.keys(values)) {
+			let option = values[key].find(option => option.enum === name);
+			if (option) {
+				return option.title;
+			}
+		}
+		return name;
+	}
+
+}
+
+export default InputOptions;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
new file mode 100644
index 0000000..5ca716c
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
@@ -0,0 +1,134 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+import ReactDOM from 'react-dom';
+import classNames from 'classnames';
+import Checkbox from 'react-bootstrap/lib/Checkbox.js';
+import Radio from 'react-bootstrap/lib/Radio.js';
+import FormGroup from 'react-bootstrap/lib/FormGroup.js';
+import FormControl from 'react-bootstrap/lib/FormControl.js';
+
+class InputWrapper extends React.Component {
+
+	state = {
+		value: this.props.value,
+		checked: this.props.checked,
+		selectedValues: []
+	}
+
+	render() {
+		const {label, hasError, validations = {}, isReadOnlyMode, value, onBlur, onKeyDown, type, disabled, checked, name} = this.props;
+		const {groupClassName, ...inputProps} = this.props;
+		return(
+			<FormGroup className={classNames('form-group', [groupClassName], {'required' : validations.required , 'has-error' : hasError})} >
+				{(label && (type !== 'checkbox' && type !== 'radio')) && <label className='control-label'>{label}</label>}
+				{(type === 'text' || type === 'number') &&
+					<FormControl
+						bsClass={'form-control input-options-other'}
+						onChange={(e) => this.onChange(e)}
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						onBlur={onBlur}
+						onKeyDown={onKeyDown}
+						value={value || ''}
+						ref={(input) => this.inputWrapper = input}
+						type={type}
+						data-test-id={this.props['data-test-id']}/>}
+
+				{type === 'textarea' &&
+					<FormControl
+						className='form-control input-options-other'
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						value={value || ''}
+						onBlur={onBlur}
+						onKeyDown={onKeyDown}
+						componentClass={type}
+						onChange={(e) => this.onChange(e)}
+						data-test-id={this.props['data-test-id']}/>}
+
+				{type === 'checkbox' &&
+					<Checkbox
+						className={classNames({'required' : validations.required , 'has-error' : hasError})}
+						onChange={(e)=>this.onChangeCheckBox(e)}
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						checked={value}
+						data-test-id={this.props['data-test-id']}>{label}</Checkbox>}
+
+				{type === 'radio' &&
+					<Radio name={name}
+						checked={checked}
+						disabled={isReadOnlyMode || Boolean(disabled)}
+						value={value}
+						onChange={(e)=>this.onChangeRadio(e)}
+						data-test-id={this.props['data-test-id']}>{label}</Radio>}
+				{type === 'select' &&
+					<FormControl onClick={ (e) => this.optionSelect(e) }
+						componentClass={type}
+						name={name} {...inputProps}
+						data-test-id={this.props['data-test-id']}/>}
+
+			</FormGroup>
+
+		);
+	}
+
+	getValue() {
+		return this.props.type !== 'select' ? this.state.value : this.state.selectedValues;
+	}
+
+	getChecked() {
+		return this.state.checked;
+	}
+
+	optionSelect(e) {
+		let selectedValues = [];
+		if (e.target.value) {
+			selectedValues.push(e.target.value);
+		}
+		this.setState({
+			selectedValues
+		});
+	}
+
+	onChange(e) {
+		let {onChange} = this.props;
+		this.setState({
+			value: e.target.value
+		});
+		onChange(e.target.value);
+	}
+
+	onChangeCheckBox(e) {
+		let {onChange} = this.props;
+		this.setState({
+			checked: e.target.checked
+		});
+		onChange(e.target.checked);
+	}
+
+	onChangeRadio(e) {
+		let {onChange} = this.props;
+		this.setState({
+			checked: e.target.checked
+		});
+		onChange(this.state.value);
+	}
+
+	focus() {
+		ReactDOM.findDOMNode(this.inputWrapper).focus();
+	}
+
+}
+export default  InputWrapper;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
new file mode 100644
index 0000000..95144b1
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
@@ -0,0 +1,79 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+import ReactDOM from 'react-dom';
+import {default as BTabs} from 'react-bootstrap/lib/Tabs.js';
+import Overlay from 'react-bootstrap/lib/Overlay.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+export default
+class Tabs extends React.Component {
+
+	static propTypes = {
+		children: React.PropTypes.node
+	};
+
+	cloneTab(element) {
+		const {invalidTabs} = this.props;
+		return React.cloneElement(
+			element,
+			{
+				key: element.props.eventKey,
+				tabClassName: invalidTabs.indexOf(element.props.eventKey) > -1 ? 'invalid-tab' : 'valid-tab'
+			}
+		);
+	}
+
+	showTabsError() {
+		const {invalidTabs} = this.props;
+		const showError = ((invalidTabs.length === 1 && invalidTabs[0] !== this.props.activeKey) || (invalidTabs.length > 1));
+		return showError;
+	}
+
+	render() {
+		// eslint-disable-next-line no-unused-vars
+		let {invalidTabs, ...tabProps} = this.props;
+		return (
+			<div>
+				<BTabs {...tabProps} ref='tabsList' id='tabsList' >
+					{this.props.children.map(element => this.cloneTab(element))}
+				</BTabs>
+				<Overlay
+					animation={false}
+					show={this.showTabsError()}
+					placement='bottom'
+					containerPadding={50}
+					target={() => {
+						let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.active):nth-of-type(n)');
+						return target && target.offsetParent ? target : undefined;
+					}
+					}
+					container={() => {
+						let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.active):nth-of-type(n)');
+						return target && target.offsetParent ? target.offsetParent : this;
+					}}>
+					<Tooltip
+						id='error-some-tabs-contain-errors'
+						className='validation-error-message'>
+						{i18n('One or more tabs are invalid')}
+					</Tooltip>
+				</Overlay>
+			</div>
+		);
+	}
+}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
index a87c8d6..ebb1473 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ */
 /**
  * Holds the buttons for save/reset for forms.
  * Used by the ValidationForm that changes the state of the buttons according to its own state.
@@ -8,7 +23,7 @@
 import React from 'react';
 import i18n from 'nfvo-utils/i18n/i18n.js';
 import Button from 'react-bootstrap/lib/Button.js';
-import FontAwesome from 'react-fontawesome';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
 
 class ValidationButtons extends React.Component {
 
@@ -22,8 +37,8 @@
 	};
 
 	render() {
-		var submitBtn = this.props.labledButtons ? i18n('Save') : <FontAwesome className='check' name='check'/>;
-		var closeBtn = this.props.labledButtons ? i18n('Cancel') : <FontAwesome className='close' name='close'/>;
+		var submitBtn = this.props.labledButtons ? i18n('Save') : <SVGIcon className='check' name='check'/>;
+		var closeBtn = this.props.labledButtons ? i18n('Cancel') : <SVGIcon className='close' name='close'/>;
 		return (
 			<div className='validation-buttons'>
 				{!this.props.isReadOnlyMode ?
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx
deleted file mode 100644
index 098ccf1..0000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * ValidationForm should be used in order to have a form that handles it's internal validation state.
- * All ValidationInputs inside the form are checked for validity and the styling and submit buttons
- * are updated accordingly.
- *
- * The properties that ahould be given to the form:
- * labledButtons - whether or not use icons only as the form default buttons or use buttons with labels
- * onSubmit - function for click on the submit button
- * onReset - function for click on the reset button
- */
-import React from 'react';
-import JSONSchema from 'nfvo-utils/json/JSONSchema.js';
-import JSONPointer from 'nfvo-utils/json/JSONPointer.js';
-import ValidationButtons from './ValidationButtons.jsx';
-
-class ValidationForm extends React.Component {
-
-	static childContextTypes = {
-		validationParent: React.PropTypes.any,
-		isReadOnlyMode: React.PropTypes.bool,
-		validationSchema: React.PropTypes.instanceOf(JSONSchema),
-		validationData: React.PropTypes.object
-	};
-
-	static defaultProps = {
-		hasButtons : true,
-		onSubmit : null,
-		onReset :  null,
-		labledButtons: true,
-		onValidChange :  null,
-		isValid: true
-	};
-
-	static propTypes = {
-		isValid : React.PropTypes.bool,
-		isReadOnlyMode : React.PropTypes.bool,
-		hasButtons : React.PropTypes.bool,
-		onSubmit : React.PropTypes.func,
-		onReset : React.PropTypes.func,
-		labledButtons: React.PropTypes.bool,
-		onValidChange : React.PropTypes.func,
-		onValidityChanged: React.PropTypes.func,
-		schema: React.PropTypes.object,
-		data: React.PropTypes.object
-	};
-
-	state = {
-		isValid: this.props.isValid
-	};
-
-	constructor(props) {
-		super(props);
-		this.validationComponents = [];
-	}
-
-	componentWillMount() {
-		let {schema, data} = this.props;
-		if (schema) {
-			this.processSchema(schema, data);
-		}
-	}
-
-	componentWillReceiveProps(nextProps) {
-		let {schema, data} = this.props;
-		let {schema: nextSchema, data: nextData} = nextProps;
-
-		if (schema !== nextSchema || data !== nextData) {
-			if (!schema || !nextSchema) {
-				throw new Error('ValidationForm: dynamically adding/removing schema is not supported');
-			}
-
-			if (schema !== nextSchema) {
-				this.processSchema(nextSchema, nextData);
-			} else {
-				this.setState({data: nextData});
-			}
-		}
-	}
-
-	processSchema(rawSchema, rawData) {
-		let schema = new JSONSchema();
-		schema.setSchema(rawSchema);
-		let data = schema.processData(rawData);
-		this.setState({
-			schema,
-			data
-		});
-	}
-
-	render() {
-		// eslint-disable-next-line no-unused-vars
-		let {isValid, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, schema, data, children, ...formProps} = this.props;
-		return (
-			<form {...formProps} onSubmit={event => this.handleFormSubmit(event)}>
-				<div className='validation-form-content'>{children}</div>
-				{hasButtons && <ValidationButtons labledButtons={labledButtons} ref='buttons' isReadOnlyMode={isReadOnlyMode}/>}
-			</form>
-		);
-	}
-
-	handleFormSubmit(event) {
-		event.preventDefault();
-		let isFormValid = true;
-		this.validationComponents.forEach(validationComponent => {
-			const isInputValid = validationComponent.validate().isValid;
-			isFormValid = isInputValid && isFormValid;
-		});
-		if(isFormValid && this.props.onSubmit) {
-			return this.props.onSubmit(event);
-		} else if(!isFormValid) {
-			this.setState({isValid: false});
-		}
-	}
-
-	componentWillUpdate(nextProps, nextState) {
-		if(this.state.isValid !== nextState.isValid && this.props.onValidityChanged) {
-			this.props.onValidityChanged(nextState.isValid);
-		}
-	}
-
-	componentDidUpdate(prevProps, prevState) {
-		// only handling this programatically if the validation of the form is done outside of the view
-		// (example with a form that is dependent on the state of other forms)
-		if (prevProps.isValid !== this.props.isValid) {
-			if (this.props.hasButtons) {
-				this.refs.buttons.setState({isValid: this.state.isValid});
-			}
-		} else if(this.state.isValid !== prevState.isValid) {
-			if (this.props.hasButtons) {
-				this.refs.buttons.setState({isValid: this.state.isValid});
-			}
-			// callback in case form is part of bigger picture in view
-			if (this.props.onValidChange) {
-				this.props.onValidChange(this.state.isValid);
-			}
-		}
-	}
-
-	componentDidMount() {
-		if (this.props.hasButtons) {
-			this.refs.buttons.setState({isValid: this.state.isValid});
-		}
-	}
-
-
-	getChildContext() {
-		return {
-			validationParent: this,
-			isReadOnlyMode: this.props.isReadOnlyMode,
-			validationSchema: this.state.schema,
-			validationData: this.state.data
-		};
-	}
-
-
-	/***
-	 * Used by ValidationInput in order to let the (parent) form know
-	 * the valid state. If there is a change in the state of the form,
-	 * the buttons will be updated.
-	 *
-	 * @param validationComponent
-	 * @param isValid
-	 */
-	childValidStateChanged(validationComponent, isValid) {
-		if (isValid !== this.state.isValid) {
-			let oldState = this.state.isValid;
-			let newState = isValid && this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent).every(otherValidationComponent => {
-				return otherValidationComponent.isValid();
-			});
-
-			if (oldState !== newState) {
-				this.setState({isValid: newState});
-			}
-		}
-	}
-
-	register(validationComponent) {
-		if (this.state.schema) {
-			// TODO: register
-		} else {
-			this.validationComponents.push(validationComponent);
-		}
-	}
-
-	unregister(validationComponent) {
-		this.childValidStateChanged(validationComponent, true);
-		this.validationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent);
-	}
-
-	onValueChanged(pointer, value, isValid, error) {
-		this.props.onDataChanged({
-			data: JSONPointer.setValue(this.props.data, pointer, value),
-			isValid,
-			error
-		});
-	}
-}
-
-
-export default ValidationForm;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx
deleted file mode 100644
index 0f14307..0000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx
+++ /dev/null
@@ -1,509 +0,0 @@
-/**
- * Used for inputs on a validation form.
- * All properties will be passed on to the input element.
- *
- * The following properties can be set for OOB validations and callbacks:
- - required: Boolean:  Should be set to true if the input must have a value
- - numeric: Boolean : Should be set to true id the input should be an integer
- - onChange : Function :  Will be called to validate the value if the default validations are not sufficient, should return a boolean value
- indicating whether the value is valid
- - didUpdateCallback :Function: Will be called after the state has been updated and the component has rerendered. This can be used if
- there are dependencies between inputs in a form.
- *
- * The following properties of the state can be set to determine
- * the state of the input from outside components:
- - isValid : Boolean - whether the value is valid
- - value : value for the input field,
- - disabled : Boolean,
- - required : Boolean - whether the input value must be filled out.
- */
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Validator from 'validator';
-import FormGroup from 'react-bootstrap/lib/FormGroup.js';
-import Input from 'react-bootstrap/lib/Input.js';
-import Overlay from 'react-bootstrap/lib/Overlay.js';
-import Tooltip from 'react-bootstrap/lib/Tooltip.js';
-import isEqual from 'lodash/isEqual.js';
-import i18n from 'nfvo-utils/i18n/i18n.js';
-import JSONSchema from 'nfvo-utils/json/JSONSchema.js';
-import JSONPointer from 'nfvo-utils/json/JSONPointer.js';
-
-
-import InputOptions  from '../inputOptions/InputOptions.jsx';
-
-const globalValidationFunctions = {
-	required: value => value !== '',
-	maxLength: (value, length) => Validator.isLength(value, {max: length}),
-	minLength: (value, length) => Validator.isLength(value, {min: length}),
-	pattern: (value, pattern) => Validator.matches(value, pattern),
-	numeric: value => {
-		if (value === '') {
-			// to allow empty value which is not zero
-			return true;
-		}
-		return Validator.isNumeric(value);
-	},
-	maxValue: (value, maxValue) => value < maxValue,
-	minValue: (value, minValue) => value >= minValue,
-	alphanumeric: value => Validator.isAlphanumeric(value),
-	alphanumericWithSpaces: value => Validator.isAlphanumeric(value.replace(/ /g, '')),
-	validateName: value => Validator.isAlphanumeric(value.replace(/\s|\.|\_|\-/g, ''), 'en-US'),
-	validateVendorName: value => Validator.isAlphanumeric(value.replace(/[\x7F-\xFF]|\s/g, ''), 'en-US'),
-	freeEnglishText: value => Validator.isAlphanumeric(value.replace(/\s|\.|\_|\-|\,|\(|\)|\?/g, ''), 'en-US'),
-	email: value => Validator.isEmail(value),
-	ip: value => Validator.isIP(value),
-	url: value => Validator.isURL(value)
-};
-
-const globalValidationMessagingFunctions = {
-	required: () => i18n('Field is required'),
-	maxLength: (value, maxLength) => i18n('Field value has exceeded it\'s limit, {maxLength}. current length: {length}', {
-		length: value.length,
-		maxLength
-	}),
-	minLength: (value, minLength) => i18n('Field value should contain at least {minLength} characters.', {minLength}),
-	pattern: (value, pattern) => i18n('Field value should match the pattern: {pattern}.', {pattern}),
-	numeric: () => i18n('Field value should contain numbers only.'),
-	maxValue: (value, maxValue) => i18n('Field value should be less than: {maxValue}.', {maxValue}),
-	minValue: (value, minValue) => i18n('Field value should be at least: {minValue}.', {minValue}),
-	alphanumeric: () => i18n('Field value should contain letters or digits only.'),
-	alphanumericWithSpaces: () => i18n('Field value should contain letters, digits or spaces only.'),
-	validateName: ()=> i18n('Field value should contain English letters, digits , spaces, underscores, dashes and dots only.'),
-	validateVendorName: ()=> i18n('Field value should contain English letters digits and spaces only.'),
-	freeEnglishText: ()=> i18n('Field value should contain  English letters, digits , spaces, underscores, dashes and dots only.'),
-	email: () => i18n('Field value should be a valid email address.'),
-	ip: () => i18n('Field value should be a valid ip address.'),
-	url: () => i18n('Field value should be a valid url address.'),
-	general: () => i18n('Field value is invalid.')
-};
-
-class ValidationInput extends React.Component {
-
-	static contextTypes = {
-		validationParent: React.PropTypes.any,
-		isReadOnlyMode: React.PropTypes.bool,
-		validationSchema: React.PropTypes.instanceOf(JSONSchema),
-		validationData: React.PropTypes.object
-	};
-
-	static defaultProps = {
-		onChange: null,
-		disabled: null,
-		didUpdateCallback: null,
-		validations: {},
-		value: ''
-	};
-
-	static propTypes = {
-		type: React.PropTypes.string.isRequired,
-		onChange: React.PropTypes.func,
-		disabled: React.PropTypes.bool,
-		didUpdateCallback: React.PropTypes.func,
-		validations: React.PropTypes.object,
-		isMultiSelect: React.PropTypes.bool,
-		onOtherChange: React.PropTypes.func,
-		pointer: React.PropTypes.string
-	};
-
-
-	state = {
-		isValid: true,
-		style: null,
-		value: this.props.value,
-		error: {},
-		previousErrorMessage: '',
-		wasInvalid: false,
-		validations: this.props.validations,
-		isMultiSelect: this.props.isMultiSelect
-	};
-
-	componentWillMount() {
-		if (this.context.validationSchema) {
-			let {validationSchema: schema, validationData: data} = this.context,
-				{pointer} = this.props;
-
-			if (!schema.exists(pointer)) {
-				console.error(`Field doesn't exists in the schema ${pointer}`);
-			}
-
-			let value = JSONPointer.getValue(data, pointer);
-			if (value === undefined) {
-				value = schema.getDefault(pointer);
-				if (value === undefined) {
-					value = '';
-				}
-			}
-			this.setState({value});
-
-			let enums = schema.getEnum(pointer);
-			if (enums) {
-				let values = enums.map(value => ({enum: value, title: value, groupName: pointer})),
-					isMultiSelect = schema.isArray(pointer);
-
-				if (!isMultiSelect && this.props.type !== 'radiogroup') {
-					values = [{enum: '', title: i18n('Select...')}, ...values];
-				}
-				if (isMultiSelect && Array.isArray(value) && value.length === 0) {
-					value = '';
-				}
-
-				this.setState({
-					isMultiSelect,
-					values,
-					onEnumChange: value => this.changedInputOptions(value),
-					value
-				});
-			}
-
-			this.setState({validations: this.extractValidationsFromSchema(schema, pointer, this.props)});
-		}
-	}
-
-	extractValidationsFromSchema(schema, pointer, props) {
-		/* props are here to get precedence over the scheme definitions */
-		let validations = {};
-
-		if (schema.isRequired(pointer)) {
-			validations.required = true;
-		}
-
-		if (schema.isNumber(pointer)) {
-			validations.numeric = true;
-
-			const maxValue = props.validations.maxValue || schema.getMaxValue(pointer);
-			if (maxValue !== undefined) {
-				validations.maxValue = maxValue;
-			}
-
-			const minValue = props.validations.minValue || schema.getMinValue(pointer);
-			if (minValue !== undefined) {
-				validations.minValue = minValue;
-			}
-		}
-
-
-		if (schema.isString(pointer)) {
-
-			const pattern = schema.getPattern(pointer);
-			if (pattern) {
-				validations.pattern = pattern;
-			}
-
-			const maxLength = schema.getMaxLength(pointer);
-			if (maxLength !== undefined) {
-				validations.maxLength = maxLength;
-			}
-
-			const minLength = schema.getMinLength(pointer);
-			if (minLength !== undefined) {
-				validations.minLength = minLength;
-			}
-		}
-
-		return validations;
-	}
-
-	componentWillReceiveProps({value: nextValue, validations: nextValidations, pointer: nextPointer}, nextContext) {
-		const {validations, value} = this.props;
-		const validationsChanged = !isEqual(validations, nextValidations);
-		if (nextContext.validationSchema) {
-			if (this.props.pointer !== nextPointer ||
-				this.context.validationData !== nextContext.validationData) {
-				let currentValue = JSONPointer.getValue(this.context.validationData, this.props.pointer),
-					nextValue = JSONPointer.getValue(nextContext.validationData, nextPointer);
-				if(nextValue === undefined) {
-					nextValue = '';
-				}
-				if (this.state.isMultiSelect && Array.isArray(nextValue) && nextValue.length === 0) {
-					nextValue = '';
-				}
-				if (currentValue !== nextValue) {
-					this.setState({value: nextValue});
-				}
-				if (validationsChanged) {
-					this.setState({
-						validations: this.extractValidationsFromSchema(nextContext.validationSchema, nextPointer, {validations: nextValidations})
-					});
-				}
-			}
-		} else {
-			if (validationsChanged) {
-				this.setState({validations: nextValidations});
-			}
-			if (this.state.wasInvalid && (value !== nextValue || validationsChanged)) {
-				this.validate(nextValue, nextValidations);
-			} else if (value !== nextValue) {
-				this.setState({value: nextValue});
-			}
-		}
-	}
-
-	shouldTypeBeNumberBySchemeDefinition(pointer) {
-		return this.context.validationSchema &&
-			this.context.validationSchema.isNumber(pointer);
-	}
-
-	hasEnum(pointer) {
-		return this.context.validationSchema &&
-			this.context.validationSchema.getEnum(pointer);
-	}
-
-	render() {
-		let {value, isMultiSelect, values, onEnumChange, style, isValid, validations} = this.state;
-		let {onOtherChange, type, pointer} = this.props;
-		if (this.shouldTypeBeNumberBySchemeDefinition(pointer) && !this.hasEnum(pointer)) {
-			type = 'number';
-		}
-		let props = {...this.props};
-
-		let groupClasses = this.props.groupClassName || '';
-		if (validations.required) {
-			groupClasses += ' required';
-		}
-		let isReadOnlyMode = this.context.isReadOnlyMode;
-
-		if (value === true && (type === 'checkbox' || type === 'radio')) {
-			props.checked = true;
-		}
-		return (
-			<div className='validation-input-wrapper'>
-				{
-					!isMultiSelect && !onOtherChange && type !== 'select' && type !== 'radiogroup'
-					&& <Input
-						{...props}
-						type={type}
-						groupClassName={groupClasses}
-						ref={'_myInput'}
-						value={value}
-						disabled={isReadOnlyMode || Boolean(this.props.disabled)}
-						bsStyle={style}
-						onChange={() => this.changedInput()}
-						onBlur={() => this.blurInput()}>
-						{this.props.children}
-					</Input>
-				}
-				{
-					type === 'radiogroup'
-					&& <FormGroup>
-						{
-							values.map(val =>
-								<Input disabled={isReadOnlyMode || Boolean(this.props.disabled)}
-									inline={true}
-									ref={'_myInput' + (typeof val.enum === 'string' ? val.enum.replace(/\W/g, '_') : val.enum)}
-									value={val.enum} checked={value === val.enum}
-									type='radio' label={val.title}
-									name={val.groupName}
-									onChange={() => this.changedInput()}/>
-							)
-						}
-					</FormGroup>
-				}
-				{
-					(isMultiSelect || onOtherChange || type === 'select')
-					&& <InputOptions
-						onInputChange={() => this.changedInput()}
-						onBlur={() => this.blurInput()}
-						hasError={!isValid}
-						ref={'_myInput'}
-						isMultiSelect={isMultiSelect}
-						values={values}
-						onEnumChange={onEnumChange}
-						selectedEnum={value}
-						multiSelectedEnum={value}
-						{...props} />
-				}
-				{this.renderOverlay()}
-			</div>
-		);
-	}
-
-	renderOverlay() {
-		let position = 'right';
-		if (this.props.type === 'text'
-			|| this.props.type === 'email'
-			|| this.props.type === 'number'
-			|| this.props.type === 'password'
-
-		) {
-			position = 'bottom';
-		}
-
-		let validationMessage = this.state.error.message || this.state.previousErrorMessage;
-		return (
-			<Overlay
-				show={!this.state.isValid}
-				placement={position}
-				target={() => {
-					let target = ReactDOM.findDOMNode(this.refs._myInput);
-					return target.offsetParent ? target : undefined;
-				}}
-				container={this}>
-				<Tooltip
-					id={`error-${validationMessage.replace(' ', '-')}`}
-					className='validation-error-message'>
-					{validationMessage}
-				</Tooltip>
-			</Overlay>
-		);
-	}
-
-	componentDidMount() {
-		if (this.context.validationParent) {
-			this.context.validationParent.register(this);
-		}
-	}
-
-	componentDidUpdate(prevProps, prevState) {
-		if (this.context.validationParent) {
-			if (prevState.isValid !== this.state.isValid) {
-				this.context.validationParent.childValidStateChanged(this, this.state.isValid);
-			}
-		}
-		if (this.props.didUpdateCallback) {
-			this.props.didUpdateCallback();
-		}
-
-	}
-
-	componentWillUnmount() {
-		if (this.context.validationParent) {
-			this.context.validationParent.unregister(this);
-		}
-	}
-
-	isNumberInputElement() {
-		return this.props.type === 'number' || this.refs._myInput.props.type === 'number';
-	}
-
-	/***
-	 * Adding same method as the actual input component
-	 * @returns {*}
-	 */
-	getValue() {
-		if (this.props.type === 'checkbox') {
-			return this.refs._myInput.getChecked();
-		}
-		if (this.props.type === 'radiogroup') {
-			for (let key in this.refs) { // finding the value of the radio button that was checked
-				if (this.refs[key].getChecked()) {
-					return this.refs[key].getValue();
-				}
-			}
-		}
-		if (this.isNumberInputElement()) {
-			return Number(this.refs._myInput.getValue());
-		}
-
-		return this.refs._myInput.getValue();
-	}
-
-	resetValue() {
-		this.setState({value: this.props.value});
-	}
-
-
-	/***
-	 * internal method that validated the value. includes callback to the onChange method
-	 * @param value
-	 * @param validations - map containing validation id and the limitation describing the validation.
-	 * @returns {object}
-	 */
-	validateValue = (value, validations) => {
-		let {customValidationFunction} = validations;
-		let error = {};
-		let isValid = true;
-		for (let validation in validations) {
-			if ('customValidationFunction' !== validation) {
-				if (validations[validation]) {
-					if (!globalValidationFunctions[validation](value, validations[validation])) {
-						error.id = validation;
-						error.message = globalValidationMessagingFunctions[validation](value, validations[validation]);
-						isValid = false;
-						break;
-					}
-				}
-			} else {
-				let customValidationResult = customValidationFunction(value);
-
-				if (customValidationResult !== true) {
-					error.id = 'custom';
-					isValid = false;
-					if (typeof customValidationResult === 'string') {//custom validation error message supplied.
-						error.message = customValidationResult;
-					} else {
-						error.message = globalValidationMessagingFunctions.general();
-					}
-					break;
-				}
-
-
-			}
-		}
-
-		return {
-			isValid,
-			error
-		};
-	};
-
-	/***
-	 * Internal method that handles the change event of the input. validates and updates the state.
-	 */
-	changedInput() {
-
-		let {isValid, error} = this.state.wasInvalid ? this.validate() : this.state;
-		let onChange = this.props.onChange;
-		if (onChange) {
-			onChange(this.getValue(), isValid, error);
-		}
-		if (this.context.validationSchema) {
-			let value = this.getValue();
-			if (this.state.isMultiSelect && value === '') {
-				value = [];
-			}
-			if (this.shouldTypeBeNumberBySchemeDefinition(this.props.pointer)) {
-				value = Number(value);
-			}
-			this.context.validationParent.onValueChanged(this.props.pointer, value, isValid, error);
-		}
-	}
-
-	changedInputOptions(value) {
-		this.context.validationParent.onValueChanged(this.props.pointer, value, true);
-	}
-
-	blurInput() {
-		if (!this.state.wasInvalid) {
-			this.setState({wasInvalid: true});
-		}
-
-		let {isValid, error} = !this.state.wasInvalid ? this.validate() : this.state;
-		let onBlur = this.props.onBlur;
-		if (onBlur) {
-			onBlur(this.getValue(), isValid, error);
-		}
-	}
-
-	validate(value = this.getValue(), validations = this.state.validations) {
-		let validationStatus = this.validateValue(value, validations);
-		let {isValid, error} = validationStatus;
-		let _style = isValid ? null : 'error';
-		this.setState({
-			isValid,
-			error,
-			value,
-			previousErrorMessage: this.state.error.message || '',
-			style: _style,
-			wasInvalid: !isValid || this.state.wasInvalid
-		});
-
-		return validationStatus;
-	}
-
-	isValid() {
-		return this.state.isValid;
-	}
-
-}
-export default ValidationInput;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx
deleted file mode 100644
index 6036518..0000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import React from 'react';
-import Tab from 'react-bootstrap/lib/Tab.js';
-
-export default
-class ValidationTab extends React.Component {
-
-	static propTypes = {
-		children: React.PropTypes.node,
-		eventKey: React.PropTypes.any.isRequired,
-		onValidationStateChange: React.PropTypes.func //This property is assigned dynamically via React.cloneElement. lookup ValidationTabs.jsx. therefore it cannot be stated as required!
-	};
-
-	constructor(props) {
-		super(props);
-		this.validationComponents = [];
-	}
-
-	static childContextTypes = {
-		validationParent: React.PropTypes.any
-	};
-
-	static contextTypes = {
-		validationParent: React.PropTypes.any
-	};
-
-	getChildContext() {
-		return {validationParent: this};
-	}
-
-	state = {
-		isValid: true,
-		notifyParent: false
-	};
-
-	componentDidMount() {
-		let validationParent = this.context.validationParent;
-		if (validationParent) {
-			validationParent.register(this);
-		}
-	}
-
-	componentWillUnmount() {
-		let validationParent = this.context.validationParent;
-		if (validationParent) {
-			validationParent.unregister(this);
-		}
-	}
-
-	register(validationComponent) {
-		this.validationComponents.push(validationComponent);
-	}
-
-	unregister(validationComponent) {
-		this.childValidStateChanged(validationComponent, true);
-		this.validationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent);
-	}
-
-	notifyValidStateChangedToParent(isValid) {
-
-		let validationParent = this.context.validationParent;
-		if (validationParent) {
-			validationParent.childValidStateChanged(this, isValid);
-		}
-	}
-
-	childValidStateChanged(validationComponent, isValid) {
-
-		const currentValidState = this.state.isValid;
-		if (isValid !== currentValidState) {
-			let filteredValidationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent);
-			let newValidState = isValid && filteredValidationComponents.every(otherValidationComponent => {
-				return otherValidationComponent.isValid();
-			});
-			this.setState({isValid: newValidState, notifyParent: true});
-		}
-	}
-
-	validate() {
-		let isValid = true;
-		this.validationComponents.forEach(validationComponent => {
-			const isValidationComponentValid = validationComponent.validate().isValid;
-			isValid = isValidationComponentValid && isValid;
-		});
-		this.setState({isValid, notifyParent: false});
-		return {isValid};
-	}
-
-	componentDidUpdate(prevProps, prevState) {
-		if(prevState.isValid !== this.state.isValid) {
-			if(this.state.notifyParent) {
-				this.notifyValidStateChangedToParent(this.state.isValid);
-			}
-			this.props.onValidationStateChange(this.props.eventKey, this.state.isValid);
-		}
-	}
-
-	isValid() {
-		return this.state.isValid;
-	}
-
-	render() {
-		let {children, ...tabProps} = this.props;
-		return (
-			<Tab {...tabProps}>{children}</Tab>
-		);
-	}
-}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx
deleted file mode 100644
index 6eda4b9..0000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Tabs from 'react-bootstrap/lib/Tabs.js';
-import Overlay from 'react-bootstrap/lib/Overlay.js';
-import Tooltip from 'react-bootstrap/lib/Tooltip.js';
-
-import i18n from 'nfvo-utils/i18n/i18n.js';
-
-export default
-class ValidationTab extends React.Component {
-
-	static propTypes = {
-		children: React.PropTypes.node
-	};
-
-	state = {
-		invalidTabs: []
-	};
-
-	cloneTab(element) {
-		const {invalidTabs} = this.state;
-		return React.cloneElement(
-			element,
-			{
-				key: element.props.eventKey,
-				tabClassName: invalidTabs.indexOf(element.props.eventKey) > -1 ? 'invalid-tab' : 'valid-tab',
-				onValidationStateChange: (eventKey, isValid) => this.validTabStateChanged(eventKey, isValid)
-			}
-		);
-	}
-
-	validTabStateChanged(eventKey, isValid) {
-		let {invalidTabs} = this.state;
-		let invalidTabIndex = invalidTabs.indexOf(eventKey);
-		if (isValid && invalidTabIndex > -1) {
-			this.setState({invalidTabs: invalidTabs.filter(otherEventKey => eventKey !== otherEventKey)});
-		} else if (!isValid && invalidTabIndex === -1) {
-			this.setState({invalidTabs: [...invalidTabs, eventKey]});
-		}
-	}
-
-	showTabsError() {
-		const {invalidTabs} = this.state;
-		return invalidTabs.length > 0 && (invalidTabs.length > 1 || invalidTabs[0] !== this.props.activeKey);
-	}
-
-	render() {
-		return (
-			<div>
-				<Tabs {...this.props} ref='tabsList'>
-					{this.props.children.map(element => this.cloneTab(element))}
-				</Tabs>
-				<Overlay
-					animation={false}
-					show={this.showTabsError()}
-					placement='bottom'
-					target={() => {
-						let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.active):nth-of-type(n)');
-						return target && target.offsetParent ? target : undefined;
-					}
-					}
-					container={this}>
-					<Tooltip
-						id='error-some-tabs-contain-errors'
-						className='validation-error-message'>
-						{i18n('One or more tabs are invalid')}
-					</Tooltip>
-				</Overlay>
-			</div>
-		);
-	}
-}
diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx
index e8d0fc2..f6c906b 100644
--- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx
+++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx
@@ -1,7 +1,24 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
-import FontAwesome from 'react-fontawesome';
+import classnames from 'classnames';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
 import store from 'sdc-app/AppStore.js';
-import NotificationConstants from 'nfvo-components/notifications/NotificationConstants.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
 
 class ListEditorItem extends React.Component {
 	static propTypes = {
@@ -16,14 +33,14 @@
 		let {onDelete, onSelect, onEdit, children, isReadOnlyMode} = this.props;
 		let isAbilityToDelete = isReadOnlyMode === undefined ? true : !isReadOnlyMode;
 		return (
-			<div className='list-editor-item-view'>
+			<div className={classnames('list-editor-item-view', {'selectable': Boolean(onSelect)})} data-test-id='list-editor-item'>
 				<div className='list-editor-item-view-content' onClick={onSelect}>
 					{children}
 				</div>
-				<div className='list-editor-item-view-controller'>
-					{onEdit && <FontAwesome name='sliders' onClick={() => this.onClickedItem(onEdit)}/>}
-					{onDelete && isAbilityToDelete && <FontAwesome name='trash-o' onClick={() => this.onClickedItem(onDelete)}/>}
-				</div>
+				{(onEdit || onDelete) && <div className='list-editor-item-view-controller'>
+					{onEdit && <SVGIcon name='sliders' onClick={() => this.onClickedItem(onEdit)}/>}
+					{onDelete && isAbilityToDelete && <SVGIcon name='trash-o' onClick={() => this.onClickedItem(onDelete)}/>}
+				</div>}
 			</div>
 		);
 	}
@@ -33,8 +50,11 @@
 			let {isCheckedOut} = this.props;
 			if (isCheckedOut === false) {
 				store.dispatch({
-					type: NotificationConstants.NOTIFY_ERROR,
-					data: {title: 'Error', msg: 'This item is checkedin/submitted, Click Check Out to continue'}
+					type: modalActionTypes.GLOBAL_MODAL_WARNING,
+					data: {
+						title: i18n('Error'), 
+						msg: i18n('This item is checkedin/submitted, Click Check Out to continue')						
+					}
 				});
 			}
 			else {
diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx
new file mode 100644
index 0000000..839f9a5
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx
@@ -0,0 +1,24 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+
+export const ListEditorItemViewField = ({children}) => (
+	<div className='list-editor-item-view-field'>
+		{children}
+	</div>
+);
+
+export default ListEditorItemViewField;
diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx
index 1ee91f3..cc805e9 100644
--- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx
+++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx
@@ -1,12 +1,63 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
-import FontAwesome from 'react-fontawesome';
-import Input from 'react-bootstrap/lib/Input.js';
+import classnames from 'classnames';
+import ExpandableInput from 'nfvo-components/input/ExpandableInput.jsx';
 
+const ListEditorHeader = ({onAdd, isReadOnlyMode, title, plusButtonTitle}) => {
+	 return (
+		 <div className='list-editor-view-header'>
+			 {title && <div className='list-editor-view-title'>{title}</div>}
+			 <div className={`list-editor-view-add-controller${isReadOnlyMode ? ' disabled' : ''}`}>
+				 { onAdd &&
+					 <div className='list-editor-view-add-title' data-test-id='add-button' onClick={onAdd}>
+						 <span>{`+ ${plusButtonTitle}`}</span>
+					 </div>
+				 }
+			 </div>
+		 </div>
+	 );
+};
+
+const ListEditorScroller = ({children, twoColumns}) => {
+	return (
+		<div className='list-editor-view-list-scroller'>
+			<div className={classnames('list-editor-view-list', {'two-columns': twoColumns})}>
+				{children}
+			</div>
+		</div>
+	);
+};
+
+const FilterWrapper = ({onFilter, filterValue}) => {
+	return (
+		<div className='expandble-search-wrapper'>
+			<ExpandableInput
+				onChange={onFilter}
+				iconType='search'
+				value={filterValue}/>
+		</div>
+	);
+};
 
 class ListEditorView extends React.Component {
 
 	static defaultProps = {
-		className: ''
+		className: '',
+		twoColumns: false
 	};
 
 	static propTypes = {
@@ -17,45 +68,17 @@
 		onFilter: React.PropTypes.func,
 		className: React.PropTypes.string,
 		isReadOnlyMode: React.PropTypes.bool,
-		placeholder: React.PropTypes.string
+		placeholder: React.PropTypes.string,
+		twoColumns: React.PropTypes.bool
 	};
 
 	render() {
-		let {title, plusButtonTitle, onAdd, children, filterValue, onFilter, className, placeholder, isReadOnlyMode} = this.props;
+		let {title, plusButtonTitle, onAdd, children, onFilter, className, isReadOnlyMode, twoColumns, filterValue} = this.props;
 		return (
-			<div className={`list-editor-view ${className}`}>
-				{title && onAdd && <div className='list-editor-view-title'>{title}</div>}
-				<div className='list-editor-view-actions'>
-					{title && !onAdd && <div className='list-editor-view-title-inline'>{title}</div>}
-					<div className={`list-editor-view-add-controller${isReadOnlyMode ? ' disabled' : ''}`} >
-						{ onAdd &&
-							<div onClick={onAdd}>
-								<span className='plus-icon-button pull-left'/>
-								<span>{plusButtonTitle}</span>
-							</div>
-						}
-					</div>
-
-					{
-						onFilter &&
-							<div className='list-editor-view-search search-wrapper'>
-								<Input
-									ref='filter'
-									type='text'
-									value={filterValue}
-									name='list-editor-view-search'
-									placeholder={placeholder}
-									groupClassName='search-input-control'
-									onChange={() => onFilter(this.refs.filter.getValue())}/>
-								<FontAwesome name='filter' className='filter-icon'/>
-							</div>
-					}
-				</div>
-				<div className='list-editor-view-list-scroller'>
-					<div className='list-editor-view-list'>
-						{children}
-					</div>
-				</div>
+			<div className={classnames('list-editor-view', className)}>
+				<ListEditorHeader onAdd={onAdd} isReadOnlyMode={isReadOnlyMode} plusButtonTitle={plusButtonTitle} title={title}/>
+				{onFilter && (children.length || filterValue) && <FilterWrapper onFilter={onFilter} filterValue={filterValue}/>}
+				<ListEditorScroller children={children} twoColumns={twoColumns}/>
 			</div>
 		);
 	}
diff --git a/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js b/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js
new file mode 100644
index 0000000..276b05e
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import {storiesOf, action} from '@kadira/storybook';
+import ListEditorView from './ListEditorView.jsx';
+import ListEditorItemView from './ListEditorItemView.jsx';
+import ListEditorItemViewField from './ListEditorItemViewField.jsx';
+import {text, number} from '@kadira/storybook-addon-knobs';
+import {withKnobs} from '@kadira/storybook-addon-knobs';
+
+function makeChildren({onEdit = false, onDelete = false} = {}) {
+    return (
+        [...Array(number('Items', 2)).keys()].map(index => (
+            <ListEditorItemView 
+                key={index} 
+                onEdit={onEdit ? onEdit : undefined}
+                onDelete={onDelete ? onDelete : undefined}>
+                <ListEditorItemViewField>
+                    <div>{text('field 1', 'Lorum Ipsum')}</div>
+                </ListEditorItemViewField>
+                <ListEditorItemViewField>
+                    <div>{text('field 2', 'Lorum Ipsum')}</div>
+                </ListEditorItemViewField>
+            </ListEditorItemView>)
+        )
+    );
+}
+
+const stories = storiesOf('ListEditor', module);
+stories.addDecorator(withKnobs);
+
+stories
+    .add('regular', () => (
+        <ListEditorView title='List Editor'>
+        {makeChildren()}
+        </ListEditorView>
+    ))
+    .add('two columns', () => (
+        <ListEditorView title='List Editor' twoColumns>
+            {makeChildren()}
+        </ListEditorView>
+    ))
+    .add('with add', () => (
+        <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns>
+        {makeChildren()}
+        </ListEditorView>
+    ))
+    .add('with delete', () => (
+        <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns>
+        {makeChildren({onDelete: action('onDelete')})}
+        </ListEditorView>
+    ))
+    .add('with edit', () => (
+        <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns>
+        {makeChildren({onEdit: action('onEdit')})}
+        </ListEditorView>
+    ))
+    .add('with edit and delete', () => (
+        <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns>
+        {makeChildren({onDelete: action('onDelete'), onEdit: action('onEdit')})}
+        </ListEditorView>
+    ));
diff --git a/openecomp-ui/src/nfvo-components/loader/Loader.jsx b/openecomp-ui/src/nfvo-components/loader/Loader.jsx
index cc1ffdb..675b04c 100644
--- a/openecomp-ui/src/nfvo-components/loader/Loader.jsx
+++ b/openecomp-ui/src/nfvo-components/loader/Loader.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 import {connect} from 'react-redux';
 
diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js b/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js
index e8e4953..7c0c0e2 100644
--- a/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js
+++ b/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js
@@ -1,23 +1,18 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
+/*!
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
+ *
  * 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
- * 
+ *
+ * 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.
- * ============LICENSE_END=========================================================
+ * 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 keyMirror from 'nfvo-utils/KeyMirror.js';
 
 export const actionTypes = keyMirror({
diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js
index 582eff3..2eff70a 100644
--- a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js
+++ b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js
@@ -1,23 +1,18 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
+/*!
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
+ *
  * 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
- * 
+ *
+ * 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.
- * ============LICENSE_END=========================================================
+ * 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 {actionTypes} from './LoaderConstants.js';
 
 export default (state = {}, action) => {
diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js
new file mode 100644
index 0000000..65a1ad6
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js
@@ -0,0 +1,120 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
+import {connect} from 'react-redux';
+
+import Modal from 'nfvo-components/modal/Modal.jsx';
+import Button from 'react-bootstrap/lib/Button.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import {modalContentComponents} from 'sdc-app/common/modal/ModalContentMapper.js';
+import {actionTypes, typeEnum} from './GlobalModalConstants.js';
+
+
+const typeClass = {
+	'default': 'primary',
+	error: 'danger',
+	warning: 'warning',
+	success: 'success'
+};
+
+
+const ModalFooter = ({type, onConfirmed, onDeclined, onClose, confirmationButtonText, cancelButtonText}) => 
+		<Modal.Footer>
+			<Button bsStyle={typeClass[type]} onClick={onDeclined ? () => {
+				onDeclined(); 
+				onClose();} : () => onClose()}>
+				{cancelButtonText}
+				</Button>
+			{onConfirmed && <Button bsStyle={typeClass[type]} onClick={() => {
+				onConfirmed();
+				onClose();
+			}}>{confirmationButtonText}</Button>}
+		</Modal.Footer>;
+
+ModalFooter.defaultProps = {
+	type: 'default',
+	confirmationButtonText: i18n('OK'),
+	cancelButtonText: i18n('Cancel')
+};
+
+export const mapStateToProps = ({modal}) => {
+	const show = !!modal;
+	return {
+		show,
+		...modal
+	};
+};
+
+export const mapActionToProps = (dispatch) => {
+	return {
+		onClose:  () => dispatch({type: actionTypes.GLOBAL_MODAL_CLOSE})
+	};
+};
+
+
+export class  GlobalModalView extends React.Component {
+
+	static propTypes = {
+		show: React.PropTypes.bool,
+		type: React.PropTypes.oneOf(['default', 'error', 'warning', 'success']),
+		title: React.PropTypes.string,
+		modalComponentProps: React.PropTypes.object,
+		modalComponentName: React.PropTypes.string,
+		onConfirmed: React.PropTypes.func,
+		onDeclined: React.PropTypes.func,
+		confirmationButtonText: React.PropTypes.string,
+		cancelButtonText: React.PropTypes.string
+	};
+
+	static defaultProps = {
+		show: false,
+		type: 'default',
+		title: ''
+	};
+
+	render() {
+		let {title, type, show, modalComponentName, modalComponentProps, 
+		modalClassName, msg, onConfirmed, onDeclined, confirmationButtonText, cancelButtonText, onClose} = this.props;
+		const  ComponentToRender = modalContentComponents[modalComponentName];
+		return (
+			<Modal show={show} bsSize={modalComponentProps && modalComponentProps.size} className={`onborading-modal ${modalClassName || ''} ${typeClass[type]}`}>
+				<Modal.Header>
+					<Modal.Title>{title}</Modal.Title>
+				</Modal.Header>
+				<Modal.Body>
+					{ComponentToRender ? <ComponentToRender {...modalComponentProps}/> :  msg}				
+				</Modal.Body>
+				{(onConfirmed || onDeclined || type !== typeEnum.DEFAULT) &&
+						<ModalFooter
+							type={type}
+							onConfirmed={onConfirmed}
+							onDeclined={onDeclined}
+							onClose={onClose}
+							confirmationButtonText={confirmationButtonText}
+							cancelButtonText={cancelButtonText}/>}
+			</Modal>
+		);
+	}
+
+	componentDidUpdate() {
+		if (this.props.timeout) {
+			setTimeout(this.props.onClose, this.props.timeout);
+		}
+	}	
+};
+
+export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(GlobalModalView);
diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js b/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js
new file mode 100644
index 0000000..0a0ed1f
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js
@@ -0,0 +1,33 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const actionTypes = keyMirror({
+	GLOBAL_MODAL_SHOW: null,
+	GLOBAL_MODAL_CLOSE: null,
+	GLOBAL_MODAL_ERROR: null,
+	GLOBAL_MODAL_WARNING: null,
+	GLOBAL_MODAL_SUCCESS: null,
+
+});
+
+
+export const typeEnum = {
+	DEFAULT: 'default',
+	ERROR: 'error',
+	WARNING: 'warning',
+	SUCCESS: 'success'
+};
diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js b/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js
new file mode 100644
index 0000000..28674ea
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js
@@ -0,0 +1,50 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 {actionTypes, typeEnum} from './GlobalModalConstants.js';
+
+export default (state = null, action) => {
+	switch (action.type) {
+		case actionTypes.GLOBAL_MODAL_SHOW:			
+			return {
+				...action.data
+			};
+		case actionTypes.GLOBAL_MODAL_ERROR:
+			return {
+				type: typeEnum.ERROR,
+				modalClassName: 'notification-modal',
+				...action.data
+			};
+		case actionTypes.GLOBAL_MODAL_WARNING:
+			return {
+				type: typeEnum.WARNING,
+				modalClassName: 'notification-modal',
+				...action.data
+			};
+
+		case actionTypes.GLOBAL_MODAL_SUCCESS:
+			return {
+				type: typeEnum.SUCCESS,
+				modalClassName: 'notification-modal',
+				...action.data
+			};	
+
+		case actionTypes.GLOBAL_MODAL_CLOSE:
+			return null;			
+		default:
+			return state;
+	}
+};
diff --git a/openecomp-ui/src/nfvo-components/modal/Modal.jsx b/openecomp-ui/src/nfvo-components/modal/Modal.jsx
index be4963e..b0f704d 100644
--- a/openecomp-ui/src/nfvo-components/modal/Modal.jsx
+++ b/openecomp-ui/src/nfvo-components/modal/Modal.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 import ReactDOM from 'react-dom';
 import BootstrapModal from 'react-bootstrap/lib/Modal.js';
diff --git a/openecomp-ui/src/nfvo-components/notifications/NotificationConstants.js b/openecomp-ui/src/nfvo-components/notifications/NotificationConstants.js
deleted file mode 100644
index 1a53f4c..0000000
--- a/openecomp-ui/src/nfvo-components/notifications/NotificationConstants.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-import keyMirror from 'nfvo-utils/KeyMirror.js';
-
-export default keyMirror({
-	NOTIFY_ERROR: null,
-	NOTIFY_SUCCESS: null,
-	NOTIFY_WARNING: null,
-	NOTIFY_INFO: null,
-	NOTIFY_CLOSE: null
-});
diff --git a/openecomp-ui/src/nfvo-components/notifications/NotificationModal.jsx b/openecomp-ui/src/nfvo-components/notifications/NotificationModal.jsx
deleted file mode 100644
index 7179309..0000000
--- a/openecomp-ui/src/nfvo-components/notifications/NotificationModal.jsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * NotificationModal options:
- *
- * show: whether to show notification or not,
- * type: the type of the notification. valid values are: 'default', 'error', 'warning', 'success'
- * msg: the notification content. could be a string or node (React component)
- * title: the notification title
- * timeout: timeout for the notification to fade out. if timeout == 0 then the notification is rendered until the user closes it
- *
- */
-import React, {Component, PropTypes} from 'react';
-import {connect} from 'react-redux';
-import Button from 'react-bootstrap/lib/Button.js';
-
-import i18n from 'nfvo-utils/i18n/i18n.js';
-import Modal from 'nfvo-components/modal/Modal.jsx';
-import SubmitErrorResponse from 'nfvo-components/SubmitErrorResponse.jsx';
-import NotificationConstants from './NotificationConstants.js';
-
-let typeClass = {
-	'default': 'primary',
-	error: 'danger',
-	warning: 'warning',
-	success: 'success'
-};
-
-const mapActionsToProps = (dispatch) => {
-	return {onCloseClick: () => dispatch({type: NotificationConstants.NOTIFY_CLOSE})};
-};
-
-const mapStateToProps = ({notification}) => {
-
-	let show = notification !== null && notification.title !== 'Conflict';
-	let mapResult = {show};
-	if (show) {
-		mapResult = {show, ...notification};
-	}
-
-	return mapResult;
-};
-
-export class NotificationModal extends Component {
-
-	static propTypes = {
-		show: PropTypes.bool,
-		type: PropTypes.oneOf(['default', 'error', 'warning', 'success']),
-		title: PropTypes.string,
-		msg: PropTypes.node,
-		validationResponse: PropTypes.object,
-		timeout: PropTypes.number
-	};
-
-	static defaultProps = {
-		show: false,
-		type: 'default',
-		title: '',
-		msg: '',
-		timeout: 0
-	};
-
-	state = {type: undefined};
-
-	componentWillReceiveProps(nextProps) {
-		if (this.props.show !== nextProps.show && nextProps.show === false) {
-			this.setState({type: this.props.type});
-		}
-		else {
-			this.setState({type: undefined});
-		}
-	}
-
-	componentDidUpdate() {
-		if (this.props.timeout) {
-			setTimeout(this.props.onCloseClick, this.props.timeout);
-		}
-	}
-
-	render() {
-		let {title, type, msg, show, validationResponse, onCloseClick} = this.props;
-		if (!show) {
-			type = this.state.type;
-		}
-		if (validationResponse) {
-			msg = (<SubmitErrorResponse validationResponse={validationResponse}/>);
-		}
-		return (
-			<Modal show={show} className={`notification-modal ${typeClass[type]}`}>
-				<Modal.Header>
-					<Modal.Title>{title}</Modal.Title>
-				</Modal.Header>
-				<Modal.Body>{msg}</Modal.Body>
-				<Modal.Footer>
-					<Button bsStyle={typeClass[type]} onClick={onCloseClick}>{i18n('OK')}</Button>
-				</Modal.Footer>
-			</Modal>
-		);
-	}
-}
-
-export default connect(mapStateToProps, mapActionsToProps)(NotificationModal);
diff --git a/openecomp-ui/src/nfvo-components/notifications/NotificationReducer.js b/openecomp-ui/src/nfvo-components/notifications/NotificationReducer.js
deleted file mode 100644
index c8b30d6..0000000
--- a/openecomp-ui/src/nfvo-components/notifications/NotificationReducer.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-import NotificationConstants from './NotificationConstants.js';
-
-export default (state = null, action) => {
-	switch (action.type) {
-		case NotificationConstants.NOTIFY_INFO:
-			return {type: 'default', title: action.data.title, msg: action.data.msg, timeout: action.data.timeout};
-
-		case NotificationConstants.NOTIFY_ERROR:
-			return {
-				type: 'error',
-				title: action.data.title,
-				msg: action.data.msg,
-				validationResponse: action.data.validationResponse,
-				timeout: action.data.timeout
-			};
-
-		case NotificationConstants.NOTIFY_WARNING:
-			return {type: 'warning', title: action.data.title, msg: action.data.msg, timeout: action.data.timeout};
-
-		case NotificationConstants.NOTIFY_SUCCESS:
-			return {
-				type: 'success', title: action.data.title, msg: action.data.msg, timeout: action.data.timeout
-			};
-		case NotificationConstants.NOTIFY_CLOSE:
-			return null;
-
-		default:
-			return state;
-	}
-
-};
diff --git a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx
index feb0f81..3b89137 100644
--- a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx
+++ b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx
@@ -1,9 +1,23 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 import classnames from 'classnames';
 import Collapse from 'react-bootstrap/lib/Collapse.js';
 
 class NavigationSideBar extends React.Component {
-
 	static PropTypes = {
 		activeItemId: React.PropTypes.string.isRequired,
 		onSelect: React.PropTypes.func,
@@ -11,51 +25,26 @@
 		groups: React.PropTypes.array
 	};
 
+	constructor(props) {
+		super(props);
+		this.state = {
+			activeItemId: null
+		};
+		this.handleItemClicked = this.handleItemClicked.bind(this);
+	}
+
 	render() {
 		let {groups, activeItemId} = this.props;
 
 		return (
 			<div className='navigation-side-content'>
 				{groups.map(group => (
-					<div className='navigation-group'  key={group.id}>
-						<div className='group-name'>{group.name}</div>
-						<div className='navigation-group-items'>
-							{
-								group.items && group.items.map(item => this.renderGroupItem(item, activeItemId))
-							}
-						</div>
-					</div>
+					<NavigationMenu menu={group} activeItemId={activeItemId} onNavigationItemClick={this.handleItemClicked} key={'menu_' + group.id} />
 				))}
 			</div>
 		);
 	}
 
-	renderGroupItem(item, activeItemId) {
-		let isGroup = item.items && item.items.length > 0;
-		return (
-			<div className={classnames('navigation-group-item', {'selected-item': item.id === activeItemId})}>
-				<div
-					key={item.id}
-					className={classnames('navigation-group-item-name', {
-						'selected': item.id === activeItemId,
-						'disabled': item.disabled,
-						'bold-name': item.expanded,
-						'hidden': item.hidden
-					})}
-					onClick={(event) => this.handleItemClicked(event, item)}>
-					{item.name}
-				</div>
-				{isGroup &&
-					<Collapse in={item.expanded}>
-						<div>
-							{item.items.map(item => this.renderGroupItem(item, activeItemId))}
-						</div>
-					</Collapse>
-				}
-			</div>
-		);
-	}
-
 	handleItemClicked(event, item) {
 		event.stopPropagation();
 		if(this.props.onToggle) {
@@ -70,4 +59,70 @@
 	}
 }
 
+class NavigationMenu extends React.Component {
+	static PropTypes = {
+		activeItemId: React.PropTypes.string.isRequired,
+		onNavigationItemClick: React.PropTypes.func,
+		menu: React.PropTypes.array
+	};
+
+	render() {
+		const {menu, activeItemId, onNavigationItemClick} = this.props;
+		return (
+			<div className='navigation-group'  key={menu.id}>
+				<NavigationMenuHeader title={menu.name} />
+				<NavigationMenuItems items={menu.items} activeItemId={activeItemId} onNavigationItemClick={onNavigationItemClick} />
+			</div>);
+	}
+}
+
+function NavigationMenuHeader(props) {
+	return <div className='group-name' data-test-id='navbar-group-name'>{props.title}</div>;
+}
+
+function NavigationMenuItems(props) {
+	const {items, activeItemId, onNavigationItemClick} = props;
+	return (
+		<div className='navigation-group-items'>
+			{
+				items && items.map(item => (<NavigationMenuItem key={'menuItem_' + item.id} item={item} activeItemId={activeItemId} onNavigationItemClick={onNavigationItemClick} />))
+			}
+		</div>
+	);
+}
+
+function NavigationMenuItem(props) {
+	const {onNavigationItemClick, item, activeItemId} = props;
+	const isGroup = item.items && item.items.length > 0;
+	return (
+		<div className={classnames('navigation-group-item', {'selected-item': item.id === activeItemId})} key={'item_' + item.id}>
+			<NavigationLink item={item} activeItemId={activeItemId} onClick={onNavigationItemClick} />
+			{isGroup && <Collapse in={item.expanded} data-test-id={'navigation-group-' + item.id}>
+				<div>
+						{item.items.map(subItem => (<NavigationMenuItem key={'menuItem_' + subItem.id} item={subItem} onNavigationItemClick={onNavigationItemClick} activeItemId={activeItemId}  />)) }
+				</div>
+			</Collapse>
+			}
+		</div>
+	);
+}
+
+function NavigationLink(props) {
+	const {item, activeItemId, onClick} = props;
+	return (
+		<div
+			key={'navAction_' + item.id}
+			className={classnames('navigation-group-item-name', {
+				'selected': item.id === activeItemId,
+				'disabled': item.disabled,
+				'bold-name': item.expanded,
+				'hidden': item.hidden
+			})}
+			onClick={(event) => onClick(event, item)}
+			data-test-id={'navbar-group-item-' + item.id}>
+			{item.name}
+		</div>
+	);
+}
+
 export default NavigationSideBar;
diff --git a/openecomp-ui/src/nfvo-components/panel/SlidePanel.jsx b/openecomp-ui/src/nfvo-components/panel/SlidePanel.jsx
deleted file mode 100644
index 10c5326..0000000
--- a/openecomp-ui/src/nfvo-components/panel/SlidePanel.jsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import React from 'react';
-import FontAwesome from 'react-fontawesome';
-import ReactDOM from 'react-dom';
-
-class SlidePanel extends React.Component {
-
-	static PropTypes = {
-		direction: React.PropTypes.string.isRequired,
-		className: React.PropTypes.string,
-		title: React.PropTypes.string,
-		isOpen: React.PropTypes.bool
-	};
-
-	static defaultProps = {
-		title: '',
-		className: '',
-		isOpen: true
-	};
-
-	state = {
-		isOpen: this.props.isOpen,
-		direction: this.props.direction,
-		width: 0,
-		arrowWidth: 0
-	};
-
-	componentDidMount() {
-		this.setSliderPosition();
-	}
-
-	componentDidUpdate() {
-		this.setSliderPosition();
-	}
-
-	render() {
-
-		let {children, className} = this.props;
-		let {isOpen} = this.state;
-
-		return (
-			<div className={ `slide-panel ${className}`}>
-				{this.renderHeader(isOpen)}
-				<div className={'slide-panel-content ' + (isOpen ? 'opened' : 'closed')}>{children}</div>
-			</div>
-		);
-	}
-
-	renderHeader(isOpen) {
-		let {direction: initialDirection, title} = this.props;
-		let {direction: currentDirection} = this.state;
-
-		let iconName = currentDirection === 'right' ? 'angle-double-right collapse-double-icon' : 'angle-double-left collapse-double-icon';
-
-		let awestyle = {padding: '5px'};
-
-		if (!isOpen && initialDirection === 'right') {
-			awestyle.marginLeft = '-1px';
-		}
-		return (
-			<div className='slide-panel-header'>
-				{ initialDirection === 'left' && <span className='slide-panel-header-title'>{title}</span>}
-				<FontAwesome
-					ref='arrowIcon'
-					style={awestyle}
-					onClick={this.handleClick}
-					className='pull-right'
-					name={iconName}
-					size='2x'/>
-				{ initialDirection === 'right' && <span className='slide-panel-header-title'>{title}</span>}
-			</div>
-		);
-	}
-
-	handleClick = () => {
-		this.setState({
-			isOpen: !this.state.isOpen,
-			direction: this.state.direction === 'left' ? 'right' : 'left'
-		});
-	}
-
-	setSliderPosition = () => {
-
-		let el = ReactDOM.findDOMNode(this);
-		let {style} = el;
-
-		let {direction: initialDirection} = this.props;
-		let arrowIconSize = Math.floor(ReactDOM.findDOMNode(this.refs.arrowIcon).getBoundingClientRect().width) * 2;
-		if (!this.state.isOpen) {
-			if (this.props.direction === 'left') {
-				style.left = arrowIconSize - el.getBoundingClientRect().width + 'px';
-			}
-			if (initialDirection === 'right') {
-				style.right = arrowIconSize - el.getBoundingClientRect().width + 'px';
-			}
-		}
-		else {
-			if (initialDirection === 'left') {
-				style.left = '0px';
-			}
-
-			if (this.props.direction === 'right') {
-				style.right = '0px';
-			}
-		}
-	}
-
-}
-
-export default SlidePanel;
\ No newline at end of file
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx
index 78525f8..6d900dd 100644
--- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx
@@ -1,17 +1,31 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
-import classnames from 'classnames';
 import i18n from 'nfvo-utils/i18n/i18n.js';
 
-import Navbar from 'react-bootstrap/lib/Navbar.js';
-import Nav from 'react-bootstrap/lib/Nav.js';
-import ValidationInput from 'nfvo-components/input/validation/ValidationInput.jsx';
-import {actionsEnum, statusEnum} from './VersionControllerConstants.js';
+import {actionsEnum, statusEnum, statusBarTextMap } from './VersionControllerConstants.js';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
 
 
 class VersionController extends React.Component {
 
 	static propTypes = {
-		version: React.PropTypes.string,
+		version: React.PropTypes.object,
 		viewableVersions: React.PropTypes.array,
 		onVersionSwitching: React.PropTypes.func,
 		isCheckedOut: React.PropTypes.bool.isRequired,
@@ -23,143 +37,146 @@
 	};
 
 	render() {
-		let {status, isCheckedOut, version = '', viewableVersions = [], onVersionSwitching, callVCAction, onSave, isFormDataValid, onClose} = this.props;
+		let {status, isCheckedOut, version = {},  viewableVersions = [], onVersionSwitching, callVCAction, onSave, isFormDataValid, onClose} = this.props;
 		let isCheckedIn = Boolean(status === statusEnum.CHECK_IN_STATUS);
-		let isLatestVersion = Boolean(version === viewableVersions[viewableVersions.length - 1]);
+		let isLatestVersion = Boolean(version.id === viewableVersions[viewableVersions.length - 1].id);
 		if (!isLatestVersion) {
 			status = statusEnum.PREVIOUS_VERSION;
 		}
-
 		return (
 			<div className='version-controller-bar'>
-				<Navbar inverse className='navbar'>
-					<Navbar.Collapse>
-						<Nav className='items-in-left'>
-							<div className='version-section'>
-								<ValidationInput
-									type='select'
-									selectedEnum={version}
-									onEnumChange={value => onVersionSwitching && onVersionSwitching(value)}>
-									{viewableVersions && viewableVersions.map(viewVersion => {
-										return (
-											<option key={viewVersion} value={viewVersion}>{`V ${viewVersion}`}</option>
-										);
-									})
-									}
-									{!viewableVersions.includes(version) &&
-									<option key={version} value={version}>{`V ${version}`}</option>}
-								</ValidationInput>
-							</div>
-							<div className='vc-status'>
-								<div className='onboarding-status-icon'></div>
-								<div className='status-text'> {i18n('ONBOARDING')}
-									<div className='status-text-dash'> -</div>
-								</div>
-								{this.renderStatus(status)}
-							</div>
-						</Nav>
-						<Nav pullRight>
-							<div className='items-in-right'>
-								<div className='action-buttons'>
-									{callVCAction &&
-									<div className='version-control-buttons'>
-										<div
-											className={classnames('vc-nav-item-button button-submit', {'disabled': !isCheckedIn || !isLatestVersion})}
-											onClick={() => this.submit(callVCAction)}>
-											{i18n('Submit')}
-										</div>
-										<div
-											className={classnames('vc-nav-item-button button-checkin-checkout', {'disabled': status === statusEnum.LOCK_STATUS || !isLatestVersion})}
-											onClick={() => this.checkinCheckoutVersion(callVCAction)}>
-											{`${isCheckedOut ? i18n('Check In') : i18n('Check Out')}`}
-										</div>
-										<div
-											className={classnames('sprite-new revert-btn ng-scope ng-isolate-scope', {'disabled': !isCheckedOut || version === '0.1' || !isLatestVersion})}
-											onClick={() => this.revertCheckout(callVCAction)}>
-										</div>
-									</div>
-									}
-									{onSave &&
-									<div
-										className={classnames('sprite-new save-btn ng-scope ng-isolate-scope', {'disabled': !isCheckedOut || !isFormDataValid || !isLatestVersion})}
-										onClick={() => onSave()}>
-									</div>
-									}
-								</div>
-								<div className='vc-nav-item-close' onClick={() => onClose && onClose()}> X</div>
-							</div>
-						</Nav>
-					</Navbar.Collapse>
-				</Navbar>
+				<div className='vc-container'>
+					<div className='version-status-container'>
+						<VersionSelector viewableVersions={viewableVersions} version={version} onVersionSwitching={onVersionSwitching} />
+						<StatusBarUpdates status={status}/>
+					</div>
+					<div className='save-submit-cancel-container'>
+						<ActionButtons onSubmit={callVCAction ? () => this.submit(callVCAction, version) : undefined}
+							onRevert={callVCAction ? () => this.revertCheckout(callVCAction, version) : undefined}
+							status={status}
+							onCheckinCheckout={callVCAction ? () => this.checkinCheckoutVersion(callVCAction, version) : undefined}
+							onSave={onSave ? () => onSave() : undefined}
+							isLatestVersion={isLatestVersion}
+							isCheckedOut={isCheckedOut}
+							isCheckedIn={isCheckedIn} isFormDataValid={isFormDataValid} version={version}/>
+						{onClose && <div className='vc-nav-item-close' onClick={() => onClose()} data-test-id='vc-cancel-btn'> X</div>}
+					</div>
+				</div>
 			</div>
 		);
 	}
 
-	renderStatus(status) {
-		switch (status) {
-			case statusEnum.CHECK_OUT_STATUS:
-				return (
-					<div className='checkout-status-icon'>
-						<div className='catalog-tile-check-in-status sprite-new checkout-editable-status-icon'></div>
-						<div className='status-text'> {i18n('CHECKED OUT')} </div>
-					</div>
-				);
-			case statusEnum.LOCK_STATUS:
-				return (
-					<div className='status-text'> {i18n('LOCKED')} </div>
-				);
-			case statusEnum.CHECK_IN_STATUS:
-				return (
-					<div className='status-text'> {i18n('CHECKED IN')} </div>
-				);
-			case statusEnum.SUBMIT_STATUS:
-				return (
-					<div className='status-text'> {i18n('SUBMITTED')} </div>
-				);
-			default:
-				return (
-					<div className='status-text'> {i18n(status)} </div>
-				);
-		}
+	submit(callVCAction, version) {
+		const action = actionsEnum.SUBMIT;
+		callVCAction(action, version);
 	}
 
-	checkinCheckoutVersion(callVCAction) {
+	revertCheckout(callVCAction, version) {
+		const action = actionsEnum.UNDO_CHECK_OUT;
+		callVCAction(action, version);
+	}
+
+	checkinCheckoutVersion(callVCAction, version) {
 		if (this.props.isCheckedOut) {
-			this.checkin(callVCAction);
+			this.checkin(callVCAction, version);
 		}
 		else {
-			this.checkout(callVCAction);
+			this.checkout(callVCAction, version);
 		}
 	}
-
-	checkin(callVCAction) {
-
+	checkin(callVCAction, version) {
 		const action = actionsEnum.CHECK_IN;
-
 		if (this.props.onSave) {
 			this.props.onSave().then(()=>{
-				 callVCAction(action);
-			 });
+				callVCAction(action, version);
+			});
 		}else{
-			callVCAction(action);
+			callVCAction(action, version);
 		}
 
 	}
-
-	checkout(callVCAction) {
+	checkout(callVCAction, version) {
 		const action = actionsEnum.CHECK_OUT;
-		callVCAction(action);
+		callVCAction(action, version);
 	}
+}
 
-	submit(callVCAction) {
-		const action = actionsEnum.SUBMIT;
-		callVCAction(action);
+class ActionButtons extends React.Component {
+	static propTypes = {
+		version: React.PropTypes.object,
+		onSubmit: React.PropTypes.func,
+		onRevert: React.PropTypes.func,
+		onSave: React.PropTypes.func,
+		isLatestVersion: React.PropTypes.bool,
+		isCheckedIn: React.PropTypes.bool,
+		isCheckedOut: React.PropTypes.bool,
+		isFormDataValid: React.PropTypes.bool
+	};
+	render() {
+		const {onSubmit, onRevert, onSave, isLatestVersion, isCheckedIn, isCheckedOut, isFormDataValid, version, status, onCheckinCheckout} = this.props;
+		const [checkinBtnIconSvg, checkinCheckoutBtnTitle] = status === statusEnum.CHECK_OUT_STATUS ?
+			['version-controller-lock-open', i18n('Check In')] :
+			['version-controller-lock-closed', i18n('Check Out')];
+		const disabled = (isLatestVersion && onCheckinCheckout && status !== statusEnum.LOCK_STATUS) ? false : true;
+		return (
+			<div className='action-buttons'>
+				<VCButton dataTestId='vc-checkout-btn' onClick={onCheckinCheckout} isDisabled={disabled}
+					name={checkinBtnIconSvg} tooltipText={checkinCheckoutBtnTitle}/>
+				{onSubmit && onRevert &&
+					<div className='version-control-buttons'>
+						<VCButton dataTestId='vc-submit-btn' onClick={onSubmit}  isDisabled={!isCheckedIn || !isLatestVersion}
+							name='version-controller-submit' tooltipText={i18n('Submit')}/>
+						<VCButton dataTestId='vc-revert-btn' onClick={onRevert} isDisabled={!isCheckedOut || version.label === '0.1' || !isLatestVersion}
+							name='version-controller-revert' tooltipText={i18n('Revert')}/>
+					</div>
+				}
+				{onSave &&
+					<VCButton dataTestId='vc-save-btn' onClick={() => onSave()} isDisabled={!isCheckedOut || !isFormDataValid || !isLatestVersion}
+						name='version-controller-save'  tooltipText={i18n('Save')}/>
+				}
+			</div>
+		);
 	}
+}
 
-	revertCheckout(callVCAction) {
-		const action = actionsEnum.UNDO_CHECK_OUT;
-		callVCAction(action);
-	}
+function StatusBarUpdates({status}) {
+	return (
+		<div className='vc-status'>
+			<span className='status-text'>{i18n(statusBarTextMap[status])}</span>
+		</div>
+	);
+}
+
+function VCButton({name, tooltipText, isDisabled, onClick, dataTestId}) {
+	let onClickAction = isDisabled ? ()=>{} : onClick;
+	let disabled = isDisabled ? 'disabled' : '';
+
+	return (
+		<OverlayTrigger placement='top' overlay={<Tooltip id='vc-tooltip'>{tooltipText}</Tooltip>}>
+			<div disabled={disabled} className='action-buttons-svg'>
+				<SVGIcon data-test-id={dataTestId} iconClassName={disabled} onClick={onClickAction ? onClickAction : undefined} name={name}/>
+			</div>
+		</OverlayTrigger>
+	);
+}
+
+function VersionSelector(props) {
+	let {version = {}, viewableVersions = [], onVersionSwitching} = props;
+	const includedVersions = viewableVersions.filter(ver => {return ver.id === version.id;});
+	return (<div className='version-section-wrapper'>
+		<select className='version-selector'
+			onChange={ev => onVersionSwitching && onVersionSwitching({id: ev.target.value, label: ev.target.value})}
+			value={version.label}>
+				{viewableVersions && viewableVersions.map(viewVersion => {
+					return (
+						<option key={viewVersion.id} value={viewVersion.id} data-test-id='vc-version-option'>{`V ${viewVersion.label}`}</option>
+					);
+				})
+				}
+				{!includedVersions.length &&
+				<option key={version.id} value={version.id}>{`V ${version.label}`}</option>}
+		</select>
+	</div>);
 }
 
 export default VersionController;
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js
index 9251fd1..9af1424 100644
--- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js
@@ -1,23 +1,18 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
+/*!
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
+ *
  * 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
- * 
+ *
+ * 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.
- * ============LICENSE_END=========================================================
+ * 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 keyMirror from 'nfvo-utils/KeyMirror.js';
 
 export const actionsEnum = keyMirror({
@@ -36,3 +31,11 @@
 	PREVIOUS_VERSION: 'READ ONLY'
 });
 
+export const statusBarTextMap = keyMirror({
+	'Locked': 'Checked Out',
+	'LockedByUser': '',
+	'Available': 'Checked In',
+	'Final': 'Submitted',
+	'READ ONLY': 'Locked'
+});
+
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerUtils.js b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerUtils.js
index de99144..e8c12ab 100644
--- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerUtils.js
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerUtils.js
@@ -1,23 +1,18 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
+/*!
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
+ *
  * 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
- * 
+ *
+ * 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.
- * ============LICENSE_END=========================================================
+ * 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 Configuration from 'sdc-app/config/Configuration.js';
 import {statusEnum} from './VersionControllerConstants.js';
 
@@ -25,24 +20,32 @@
 const VersionControllerUtils = {
 
 	getCheckOutStatusKindByUserID(status, lockingUser) {
-		let currentLoginUserID = Configuration.get('ATTUserID');
-		let isCheckedOut = currentLoginUserID === lockingUser;
+		let returnStatus;
+		let isCheckedOut;
+		let currentLoginUserID = Configuration.get('UserID');
+		if (lockingUser) {
+			isCheckedOut = currentLoginUserID === lockingUser;
+			returnStatus = isCheckedOut ? status : statusEnum.LOCK_STATUS;
+		} else {
+			isCheckedOut = false;
+			returnStatus = status;
+		}
 
 		return {
-			status: isCheckedOut ? status : statusEnum.LOCK_STATUS,
+			status: returnStatus,
 			isCheckedOut
 		};
 	},
 
 	isCheckedOutByCurrentUser(resource) {
-		let currentLoginUserID = Configuration.get('ATTUserID');
+		let currentLoginUserID = Configuration.get('UserID');
 		return resource.lockingUser !== undefined && resource.lockingUser === currentLoginUserID;
 	},
 
 	isReadOnly(resource) {
 		const {version, viewableVersions = []} = resource;
 		const latestVersion = viewableVersions[viewableVersions.length - 1];
-		return version !== latestVersion || !VersionControllerUtils.isCheckedOutByCurrentUser(resource);
+		return version.id !== latestVersion.id || !VersionControllerUtils.isCheckedOutByCurrentUser(resource);
 	}
 };
 
diff --git a/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx b/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx
index d786aee..40720c3 100644
--- a/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx
+++ b/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx
@@ -1,3 +1,18 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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 React from 'react';
 
 class ProgressBar extends React.Component {
diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx
new file mode 100644
index 0000000..06cb98b
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import uuid from 'uuid-js';
+
+export default class SelectActionTable extends React.Component {
+
+	render() {
+		let {columns, onAdd, isReadOnlyMode, children, onAddItem} = this.props;
+		return (
+			<div className={`select-action-table-view ${isReadOnlyMode ? 'disabled' : ''}`}>
+				<div className='select-action-table-controllers'>
+					{onAdd && onAddItem && <div data-test-id='select-action-table-add' onClick={onAdd}>{onAddItem}</div>}
+					<SVGIcon name='trash-o' className='dummy-icon' />
+				</div>
+				<div className='select-action-table'>
+					<div className='select-action-table-headers'>
+						{columns.map(column => <div key={uuid.create()} className='select-action-table-header'>{i18n(column)}</div>)}
+						<SVGIcon name='trash-o' className='dummy-icon' />
+						<SVGIcon name='trash-o' className='dummy-icon' />
+					</div>
+					<div className='select-action-table-body'>
+						{children}
+					</div>
+				</div>
+			</div>
+		);
+	}
+}
diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx
new file mode 100644
index 0000000..2664c8e
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import SelectInput from 'nfvo-components/input/SelectInput.jsx';
+
+const SelectActionTableCell = ({options, selected, disabled, onChange, clearable = true, placeholder}) => {
+	return (
+		<div className='select-action-table-cell'>
+			<SelectInput
+				placeholder={placeholder}
+				type='select'
+				value={selected}
+				data-test-id='select-action-table-dropdown'
+				disabled={disabled}
+				onChange={option => onChange(option ? option.value : null)}
+				clearable={clearable}
+				options={options} />
+		</div>
+	);
+};
+
+export default SelectActionTableCell;
diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx
new file mode 100644
index 0000000..17d8a17
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import SVGIcon from '../icon/SVGIcon.jsx';
+import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+function tooltip (msg)  {
+	return (
+  		<Tooltip className='select-action-table-error-tooltip' id='error-tooltip'>{msg}</Tooltip>
+	);
+};
+
+const IconWithOverlay = ({overlayMsg}) => (
+	<OverlayTrigger placement='bottom' overlay={tooltip(overlayMsg)}>
+		<SVGIcon name='error-circle'/>
+	</OverlayTrigger>
+);
+
+const SelectActionTableRow = ({children, onDelete, hasError, overlayMsg}) => (
+	<div className='select-action-table-row-wrapper'>
+		<div className={`select-action-table-row ${hasError ? 'has-error' : ''}`}>
+			{children}
+		</div>
+		{onDelete ? <SVGIcon name='trash-o' data-test-id='select-action-table-delete' onClick={onDelete} /> : <SVGIcon name='angle-left' className='dummy-icon' />}		
+		{hasError ? overlayMsg ? <IconWithOverlay overlayMsg={overlayMsg}/> :  <SVGIcon name='error-circle'/>
+					: hasError === undefined ? <SVGIcon name='angle-left' className='dummy-icon'/> : <SVGIcon name='check-circle'/>}		
+		
+	</div>
+);
+
+export default SelectActionTableRow;