summaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/nfvo-components/panel
diff options
context:
space:
mode:
authortalig <talig@amdocs.com>2017-12-20 14:30:43 +0200
committerVitaly Emporopulo <Vitaliy.Emporopulo@amdocs.com>2017-12-21 11:12:33 +0000
commit8e9c0653dd6c6862123c9609ae34e1206d86456e (patch)
tree5eeef00ec0677133baa439ca8d7ffd7aca4804b6 /openecomp-ui/src/nfvo-components/panel
parent785ebcc95de3e064e843bec04ba7a209d854fc7c (diff)
Add collaboration feature
Issue-ID: SDC-767 Change-Id: I14fb4c1f54086ed03a56a7ff7fab9ecd40381795 Signed-off-by: talig <talig@amdocs.com>
Diffstat (limited to 'openecomp-ui/src/nfvo-components/panel')
-rw-r--r--openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx22
-rw-r--r--openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx176
-rw-r--r--openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js23
-rw-r--r--openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerUtils.js52
-rw-r--r--openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx109
-rw-r--r--openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx73
-rw-r--r--openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx65
7 files changed, 329 insertions, 191 deletions
diff --git a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx
index fb3b71f0c8..02552fcb7e 100644
--- a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx
+++ b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx
@@ -14,15 +14,16 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
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,
- onToggle: React.PropTypes.func,
- groups: React.PropTypes.array
+ activeItemId: PropTypes.string.isRequired,
+ onSelect: PropTypes.func,
+ onToggle: PropTypes.func,
+ groups: PropTypes.array
};
constructor(props) {
@@ -61,9 +62,9 @@ class NavigationSideBar extends React.Component {
class NavigationMenu extends React.Component {
static PropTypes = {
- activeItemId: React.PropTypes.string.isRequired,
- onNavigationItemClick: React.PropTypes.func,
- menu: React.PropTypes.array
+ activeItemId: PropTypes.string.isRequired,
+ onNavigationItemClick: PropTypes.func,
+ menu: PropTypes.array
};
render() {
@@ -80,6 +81,9 @@ function NavigationMenuHeader(props) {
return <div className='group-name' data-test-id='navbar-group-name'>{props.title}</div>;
}
+function getItemDataTestId(itemId) {
+ return itemId.split('|')[0];
+}
function NavigationMenuItems(props) {
const {items, activeItemId, onNavigationItemClick} = props;
return (
@@ -97,7 +101,7 @@ function NavigationMenuItem(props) {
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}>
+ {isGroup && <Collapse in={item.expanded} data-test-id={'navigation-group-' + getItemDataTestId(item.id)}>
<div>
{item.items.map(subItem => (<NavigationMenuItem key={'menuItem_' + subItem.id} item={subItem} onNavigationItemClick={onNavigationItemClick} activeItemId={activeItemId} />)) }
</div>
@@ -120,7 +124,7 @@ function NavigationLink(props) {
'hidden': item.hidden
})}
onClick={(event) => onClick(event, item)}
- data-test-id={'navbar-group-item-' + item.id}>
+ data-test-id={'navbar-group-item-' + getItemDataTestId(item.id)}>
{item.name}
</div>
);
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx
index 922db05282..5273785f07 100644
--- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx
@@ -14,51 +14,66 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import i18n from 'nfvo-utils/i18n/i18n.js';
-import {actionsEnum, statusEnum, statusBarTextMap } from './VersionControllerConstants.js';
-import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
-import Tooltip from 'react-bootstrap/lib/Tooltip.js';
-import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
+import {actionsEnum} from './VersionControllerConstants.js';
+import ActionButtons from './components/ActionButtons.jsx';
+import NotificationsView from 'sdc-app/onboarding/userNotifications/NotificationsView.jsx';
class VersionController extends React.Component {
static propTypes = {
- version: React.PropTypes.object,
- viewableVersions: React.PropTypes.array,
- onVersionSwitching: React.PropTypes.func,
- isCheckedOut: React.PropTypes.bool.isRequired,
- status: React.PropTypes.string.isRequired,
- callVCAction: React.PropTypes.func,
- onSave: React.PropTypes.func,
- onClose: React.PropTypes.func,
- isFormDataValid: React.PropTypes.bool
+ version: PropTypes.object,
+ viewableVersions: PropTypes.array,
+ onVersionSwitching: PropTypes.func,
+ callVCAction: PropTypes.func,
+ onSave: PropTypes.func,
+ onClose: PropTypes.func,
+ isFormDataValid: PropTypes.bool,
+ onOpenCommentCommitModal: PropTypes.func,
+ isReadOnlyMode: PropTypes.bool
+ };
+
+ state = {
+ showPermissions: false,
+ showRevisions: false
};
render() {
- let {status, isCheckedOut, version = {}, viewableVersions = [], onVersionSwitching, callVCAction, onSave, isFormDataValid, onClose} = this.props;
- let isCheckedIn = Boolean(status === statusEnum.CHECK_IN_STATUS);
- let isLatestVersion = Boolean(version.id === viewableVersions[viewableVersions.length - 1].id);
- if (!isLatestVersion) {
- status = statusEnum.PREVIOUS_VERSION;
- }
+ let {version = {}, viewableVersions = [], onVersionSwitching, onMoreVersionsClick, callVCAction, onSave, isReadOnlyMode, itemPermission,
+ isFormDataValid, onClose, onManagePermissions, permissions = {}, userInfo, usersList, itemName, onOpenCommentCommitModal, onOpenRevisionsModal, isManual} = this.props;
return (
<div className='version-controller-bar'>
<div className='vc-container'>
<div className='version-status-container'>
- <VersionSelector viewableVersions={viewableVersions} version={version} onVersionSwitching={onVersionSwitching} />
- <StatusBarUpdates status={status}/>
+ <VersionSelector
+ viewableVersions={viewableVersions}
+ version={version}
+ onVersionSwitching={onVersionSwitching}
+ onMoreVersionsClick={() => onMoreVersionsClick({itemName, users: usersList})}/>
</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}
+ onRevert={callVCAction ? () => this.revert(callVCAction, version) : undefined}
+ onOpenRevisionsModal={onOpenRevisionsModal}
onSave={onSave ? () => onSave() : undefined}
- isLatestVersion={isLatestVersion}
- isCheckedOut={isCheckedOut}
- isCheckedIn={isCheckedIn} isFormDataValid={isFormDataValid} version={version}/>
+ permissions={permissions}
+ userInfo={userInfo}
+ onManagePermissions={onManagePermissions}
+ showPermissions={this.state.showPermissions}
+ onClosePermissions={()=>this.setState({showPermissions: false})}
+ onClickPermissions={() => this.onClickPermissions()}
+ onSync={callVCAction ? () => this.sync(callVCAction, version) : undefined}
+ onOpenCommentCommitModal={onOpenCommentCommitModal}
+ onCommit={callVCAction ? (comment) => this.commit(callVCAction, version, comment) : undefined}
+ isFormDataValid={isFormDataValid}
+ itemPermissions={itemPermission}
+ isReadOnlyMode={isReadOnlyMode}
+ isManual={isManual} />
+ <div className='vc-separator'></div>
+ <NotificationsView />
{onClose && <div className='vc-nav-item-close' onClick={() => onClose()} data-test-id='vc-cancel-btn'> X</div>}
</div>
</div>
@@ -66,116 +81,57 @@ class VersionController extends React.Component {
);
}
+ onClickPermissions() {
+ let {onOpenPermissions, usersList} = this.props;
+ let {showPermissions} = this.state;
+ let promise = showPermissions ? Promise.resolve() : onOpenPermissions({users: usersList});
+ promise.then(() => this.setState({showPermissions: !showPermissions}));
+ }
+
+
submit(callVCAction, version) {
const action = actionsEnum.SUBMIT;
callVCAction(action, version);
}
- revertCheckout(callVCAction, version) {
- const action = actionsEnum.UNDO_CHECK_OUT;
+ revert(callVCAction, version) {
+ const action = actionsEnum.REVERT;
callVCAction(action, version);
}
- checkinCheckoutVersion(callVCAction, version) {
- if (this.props.isCheckedOut) {
- this.checkin(callVCAction, version);
- }
- else {
- this.checkout(callVCAction, version);
- }
- }
- checkin(callVCAction, version) {
- const action = actionsEnum.CHECK_IN;
- if (this.props.onSave) {
- this.props.onSave().then(()=>{
- callVCAction(action, version);
- });
- }else{
- callVCAction(action, version);
- }
-
- }
- checkout(callVCAction, version) {
- const action = actionsEnum.CHECK_OUT;
+ sync(callVCAction, version) {
+ const action = actionsEnum.SYNC;
callVCAction(action, version);
}
-}
-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 ?
- ['versionControllerLockOpen', i18n('Check In')] :
- ['versionControllerLockClosed', 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='versionControllerSubmit' tooltipText={i18n('Submit')}/>
- <VCButton dataTestId='vc-revert-btn' onClick={onRevert} isDisabled={!isCheckedOut || version.label === '0.1' || !isLatestVersion}
- name='versionControllerRevert' tooltipText={i18n('Revert')}/>
- </div>
- }
- {onSave &&
- <VCButton dataTestId='vc-save-btn' onClick={() => onSave()} isDisabled={!isCheckedOut || !isFormDataValid || !isLatestVersion}
- name='versionControllerSave' tooltipText={i18n('Save')}/>
- }
- </div>
- );
+ commit(callVCAction, version, comment) {
+ const action = actionsEnum.COMMIT;
+ callVCAction(action, version, comment);
}
-}
-
-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' : '';
+ permissions() {
- return (
- <OverlayTrigger placement='top' overlay={<Tooltip id='vc-tooltip'>{tooltipText}</Tooltip>}>
- <div disabled={disabled} className='action-buttons-svg'>
- <SVGIcon data-test-id={dataTestId} disabled={isDisabled} onClick={onClickAction ? onClickAction : undefined} name={name}/>
- </div>
- </OverlayTrigger>
- );
+ }
}
function VersionSelector(props) {
- let {version = {}, viewableVersions = [], onVersionSwitching} = props;
+ let {version = {}, onMoreVersionsClick, 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}>
+ onChange={ev => onVersionSwitching && onVersionSwitching(viewableVersions.find(version => version.id === ev.target.value))}
+ value={version.id}
+ data-test-id='vc-versions-select-box'>
{viewableVersions && viewableVersions.map(viewVersion => {
return (
- <option key={viewVersion.id} value={viewVersion.id} data-test-id='vc-version-option'>{`V ${viewVersion.label}`}</option>
+ <option key={viewVersion.id} value={viewVersion.id} data-test-id='vc-version-option'>{`V ${viewVersion.name} ${viewVersion.status}`}</option>
);
})
}
{!includedVersions.length &&
- <option key={version.id} value={version.id}>{`V ${version.label}`}</option>}
+ <option key={version.id} value={version.id} data-test-id='vc-selected-version-option'>{`V ${version.name} ${version.status}`}</option>}
</select>
+ <span onClick={onMoreVersionsClick} className='version-selector-more-versions' data-test-id='vc-versions-page-link'>{i18n('Versions Page')}</span>
</div>);
}
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js
index c2548e4fb4..ddb428a1e9 100644
--- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js
@@ -16,26 +16,9 @@
import keyMirror from 'nfvo-utils/KeyMirror.js';
export const actionsEnum = keyMirror({
- CHECK_IN: 'Checkin',
- CHECK_OUT: 'Checkout',
- UNDO_CHECK_OUT: 'Undo_Checkout',
+ REVERT: 'Revert',
+ SYNC: 'Sync',
SUBMIT: 'Submit',
+ COMMIT: 'Commit',
CREATE_PACKAGE: 'Create_Package'
});
-
-export const statusEnum = keyMirror({
- CHECK_OUT_STATUS: 'Locked',
- CHECK_IN_STATUS: 'Available',
- SUBMIT_STATUS: 'Final',
- LOCK_STATUS: 'LockedByUser',
- PREVIOUS_VERSION: 'READ ONLY'
-});
-
-export const statusBarTextMap = keyMirror({
- 'Locked': 'Checked Out',
- 'LockedByUser': 'Locked',
- '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
deleted file mode 100644
index e8c12abec3..0000000000
--- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerUtils.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*!
- * 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 Configuration from 'sdc-app/config/Configuration.js';
-import {statusEnum} from './VersionControllerConstants.js';
-
-
-const VersionControllerUtils = {
-
- getCheckOutStatusKindByUserID(status, 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: returnStatus,
- isCheckedOut
- };
- },
-
- isCheckedOutByCurrentUser(resource) {
- 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.id !== latestVersion.id || !VersionControllerUtils.isCheckedOutByCurrentUser(resource);
- }
-};
-
-export default VersionControllerUtils;
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx
new file mode 100644
index 0000000000..4346a0e5dc
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx
@@ -0,0 +1,109 @@
+/*!
+ * 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 PropTypes from 'prop-types';
+import enhanceWithClickOutside from 'react-click-outside';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
+import Overlay from 'nfvo-components/overlay/Overlay.jsx';
+import Permissions from './Permissions.jsx';
+
+class ClickOutsideWrapper extends Component {
+ handleClickOutside() {
+ this.props.onClose();
+ }
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+}
+
+const EnhancedClickOutsideWrapper = enhanceWithClickOutside(ClickOutsideWrapper);
+
+const VCButton = ({name, tooltipText, disabled, onClick, dataTestId}) => {
+ let onClickAction = disabled ? ()=>{} : onClick;
+ return (
+ <div className={`action-button-wrapper ${disabled ? 'disabled' : 'clickable'}`} onClick={onClickAction}>
+ <div className='action-buttons-svg'>
+ <SVGIcon label={tooltipText} labelPosition='bottom' labelClassName='action-button-label'
+ data-test-id={dataTestId} name={name} disabled={disabled}/>
+ </div>
+ </div>
+ );
+};
+
+const Separator = () => (<div className='vc-separator'></div>);
+
+const SubmitButton = ({onClick, disabled}) => (
+ <div onClick={()=>onClick()} data-test-id='vc-submit-btn' className={`vc-submit-button ${disabled ? 'disabled' : ''}`}>
+ <SVGIcon name='check' iconClassName='vc-v-submit' disabled={disabled} />
+ {i18n('Submit')}
+ </div>
+);
+
+
+const ActionButtons = ({isReadOnlyMode, onSubmit, onRevert, onSave, isFormDataValid, onClickPermissions, onSync, onCommit,
+ onOpenCommentCommitModal, showPermissions, onClosePermissions, permissions, onManagePermissions, userInfo, onOpenRevisionsModal, isManual,
+ itemPermissions: {isCertified, isCollaborator, isDirty, isOutOfSync, isUpToDate}}) => (
+ <div className='action-buttons'>
+ <EnhancedClickOutsideWrapper onClose={onClosePermissions}>
+ <VCButton disabled={isManual} dataTestId='vc-permission-btn' onClick={onClickPermissions}
+ name='version-controller-permissions' tooltipText={i18n('Permissons')} />
+ {showPermissions &&
+ <Overlay>
+ <Permissions userInfo={userInfo} onManagePermissions={onManagePermissions} permissions={permissions} onClosePermissions={onClosePermissions}/>
+ </Overlay>
+ }
+ </EnhancedClickOutsideWrapper>
+ {isCollaborator && <div className='collaborator-action-buttons'>
+ <Separator />
+ {onSave && <div className='vc-save-section'>
+ <VCButton dataTestId='vc-save-btn' onClick={() => onSave()}
+ name='version-controller-save' tooltipText={i18n('Save')} disabled={isReadOnlyMode || !isFormDataValid} />
+ <Separator />
+ </div>
+ }
+ <VCButton dataTestId='vc-sync-btn' onClick={onSync}
+ name='version-controller-sync' tooltipText={i18n('Sync')} disabled={!isCollaborator || isUpToDate || isCertified} />
+ <VCButton dataTestId='vc-commit-btn' onClick={() => onOpenCommentCommitModal({onCommit, title: i18n('Commit')})}
+ name='version-controller-commit' tooltipText={i18n('Share')} disabled={isReadOnlyMode || !isDirty || isOutOfSync} />
+ {onRevert &&
+ <VCButton dataTestId='vc-revert-btn' onClick={onOpenRevisionsModal}
+ name='version-controller-revert' tooltipText={i18n('Revert')} disabled={isReadOnlyMode || isOutOfSync} />
+ }
+ {onSubmit && (permissions.owner && permissions.owner.userId === userInfo.userId) &&
+ <div className='vc-submit-section'>
+ <Separator />
+ <SubmitButton onClick={onSubmit}
+ disabled={isReadOnlyMode || isOutOfSync || !isUpToDate || isCertified} />
+ </div>
+ }
+ </div>}
+ </div>
+);
+
+ActionButtons.propTypes = {
+ version: PropTypes.object,
+ onSubmit: PropTypes.func,
+ onRevert: PropTypes.func,
+ onSave: PropTypes.func,
+ isLatestVersion: PropTypes.bool,
+ isCheckedIn: PropTypes.bool,
+ isCheckedOut: PropTypes.bool,
+ isFormDataValid: PropTypes.bool,
+ isReadOnlyMode: PropTypes.bool
+};
+
+export default ActionButtons;
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx
new file mode 100644
index 0000000000..600eaeefaa
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx
@@ -0,0 +1,73 @@
+/*!
+ * 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 i18n from 'nfvo-utils/i18n/i18n.js';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const CommitModalType = keyMirror({
+ COMMIT: null,
+ COMMIT_SUBMIT: null
+
+});
+
+export const mapActionToProps = (dispatch) => {
+ return {
+ onClose: () => dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_CLOSE
+ })
+ };
+};
+
+class CommitCommentModal extends React.Component {
+
+ state = {
+ comment: ''
+ };
+
+ render() {
+ const {onCommit, onClose, type} = this.props;
+ const [commitButtonText, descriptionText] = type === CommitModalType.COMMIT ?
+ [i18n('Commit'), i18n('You are about to commit your version')] :
+ [i18n('Commit & Submit'), i18n('You must commit your changes before the submit')];
+
+ return (
+ <Form
+ ref='validationForm'
+ hasButtons={true}
+ onSubmit={ () => {onCommit(this.state.comment); onClose();} }
+ onReset={onClose}
+ submitButtonText={commitButtonText}
+ labledButtons={true}
+ isValid={true}
+ className='comment-commit-form'>
+ <div className='commit-modal-text'>{descriptionText}</div>
+ <Input
+ data-test-id='commit-comment-text'
+ onChange={comment => this.setState({comment: comment})}
+ label={i18n('Enter Commit Comment:')}
+ value={this.state.comment}
+ type='textarea'/>
+ </Form>
+ );
+ }
+}
+
+export default connect(null, mapActionToProps)(CommitCommentModal);
diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx
new file mode 100644
index 0000000000..952bd4fb58
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx
@@ -0,0 +1,65 @@
+/*!
+ * 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 SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
+
+const Contributor = ({name, role, id, userInfo}) => {
+
+ const selected = id === userInfo.userId ? 'selected' : '';
+
+ return(
+ <div className='contributor'>
+ <div className='contributor-content'>
+ <div className={`contributor-icon-circle ${selected}`}>
+ <div className={`contributer-icon ${selected}`}>
+ <SVGIcon name='user'/>
+ </div>
+ </div>
+ <div className='contributer-info'>
+ <div className='contributer-name'>{name}</div>
+ <div className='contributer-role'><p>{role}</p></div>
+ </div>
+ </div>
+ </div>
+ );
+};
+
+const Permissions = ({permissions: {owner, contributors}, onManagePermissions, userInfo, onClosePermissions}) => {
+
+ return (
+ <div className='permissions-overlay'>
+ <div className='permissions-overlay-header'>
+ <h4 className='permissions-overlay-header-title'>{i18n('PERMISSIONS')}</h4>
+ </div>
+ <div className='permissions-overlay-content'>
+ <Contributor userInfo={userInfo} id={owner.userId} key={owner.fullName} name={owner.fullName} role={owner.role}/>
+ {contributors.map(item => item.userId !== owner.userId && <Contributor userInfo={userInfo} id={item.userId} key={item.fullName} name={item.fullName} role={item.role}/>)}
+ </div>
+ <div className='permissions-overlay-footer'>
+ {
+ owner.userId === userInfo.userId &&
+ <div onClick={() => { onClosePermissions(); onManagePermissions(); }} className='manage-permissions-btn'>
+ {i18n('Manage Permissions')}
+ </div>
+ }
+ </div>
+ </div>
+ );
+};
+
+export default Permissions;