diff options
Diffstat (limited to 'openecomp-ui/src/nfvo-components/panel/versionController')
6 files changed, 316 insertions, 182 deletions
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; |