AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 1 | /*! |
| 2 | * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| 13 | * or implied. See the License for the specific language governing |
| 14 | * permissions and limitations under the License. |
| 15 | */ |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 16 | import React from 'react'; |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 17 | import i18n from 'nfvo-utils/i18n/i18n.js'; |
| 18 | |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 19 | import {actionsEnum, statusEnum, statusBarTextMap } from './VersionControllerConstants.js'; |
Avi Ziv | b8e2faf | 2017-07-18 19:45:38 +0300 | [diff] [blame] | 20 | import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 21 | import Tooltip from 'react-bootstrap/lib/Tooltip.js'; |
| 22 | import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 23 | |
| 24 | |
| 25 | class VersionController extends React.Component { |
| 26 | |
| 27 | static propTypes = { |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 28 | version: React.PropTypes.object, |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 29 | viewableVersions: React.PropTypes.array, |
| 30 | onVersionSwitching: React.PropTypes.func, |
| 31 | isCheckedOut: React.PropTypes.bool.isRequired, |
| 32 | status: React.PropTypes.string.isRequired, |
| 33 | callVCAction: React.PropTypes.func, |
| 34 | onSave: React.PropTypes.func, |
| 35 | onClose: React.PropTypes.func, |
| 36 | isFormDataValid: React.PropTypes.bool |
| 37 | }; |
| 38 | |
| 39 | render() { |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 40 | let {status, isCheckedOut, version = {}, viewableVersions = [], onVersionSwitching, callVCAction, onSave, isFormDataValid, onClose} = this.props; |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 41 | let isCheckedIn = Boolean(status === statusEnum.CHECK_IN_STATUS); |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 42 | let isLatestVersion = Boolean(version.id === viewableVersions[viewableVersions.length - 1].id); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 43 | if (!isLatestVersion) { |
| 44 | status = statusEnum.PREVIOUS_VERSION; |
| 45 | } |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 46 | return ( |
| 47 | <div className='version-controller-bar'> |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 48 | <div className='vc-container'> |
| 49 | <div className='version-status-container'> |
| 50 | <VersionSelector viewableVersions={viewableVersions} version={version} onVersionSwitching={onVersionSwitching} /> |
| 51 | <StatusBarUpdates status={status}/> |
| 52 | </div> |
| 53 | <div className='save-submit-cancel-container'> |
| 54 | <ActionButtons onSubmit={callVCAction ? () => this.submit(callVCAction, version) : undefined} |
| 55 | onRevert={callVCAction ? () => this.revertCheckout(callVCAction, version) : undefined} |
| 56 | status={status} |
| 57 | onCheckinCheckout={callVCAction ? () => this.checkinCheckoutVersion(callVCAction, version) : undefined} |
| 58 | onSave={onSave ? () => onSave() : undefined} |
| 59 | isLatestVersion={isLatestVersion} |
| 60 | isCheckedOut={isCheckedOut} |
| 61 | isCheckedIn={isCheckedIn} isFormDataValid={isFormDataValid} version={version}/> |
| 62 | {onClose && <div className='vc-nav-item-close' onClick={() => onClose()} data-test-id='vc-cancel-btn'> X</div>} |
| 63 | </div> |
| 64 | </div> |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 65 | </div> |
| 66 | ); |
| 67 | } |
| 68 | |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 69 | submit(callVCAction, version) { |
| 70 | const action = actionsEnum.SUBMIT; |
| 71 | callVCAction(action, version); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 72 | } |
| 73 | |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 74 | revertCheckout(callVCAction, version) { |
| 75 | const action = actionsEnum.UNDO_CHECK_OUT; |
| 76 | callVCAction(action, version); |
| 77 | } |
| 78 | |
| 79 | checkinCheckoutVersion(callVCAction, version) { |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 80 | if (this.props.isCheckedOut) { |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 81 | this.checkin(callVCAction, version); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 82 | } |
| 83 | else { |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 84 | this.checkout(callVCAction, version); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 85 | } |
| 86 | } |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 87 | checkin(callVCAction, version) { |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 88 | const action = actionsEnum.CHECK_IN; |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 89 | if (this.props.onSave) { |
| 90 | this.props.onSave().then(()=>{ |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 91 | callVCAction(action, version); |
| 92 | }); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 93 | }else{ |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 94 | callVCAction(action, version); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | } |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 98 | checkout(callVCAction, version) { |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 99 | const action = actionsEnum.CHECK_OUT; |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 100 | callVCAction(action, version); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 101 | } |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 102 | } |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 103 | |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 104 | class ActionButtons extends React.Component { |
| 105 | static propTypes = { |
| 106 | version: React.PropTypes.object, |
| 107 | onSubmit: React.PropTypes.func, |
| 108 | onRevert: React.PropTypes.func, |
| 109 | onSave: React.PropTypes.func, |
| 110 | isLatestVersion: React.PropTypes.bool, |
| 111 | isCheckedIn: React.PropTypes.bool, |
| 112 | isCheckedOut: React.PropTypes.bool, |
| 113 | isFormDataValid: React.PropTypes.bool |
| 114 | }; |
| 115 | render() { |
| 116 | const {onSubmit, onRevert, onSave, isLatestVersion, isCheckedIn, isCheckedOut, isFormDataValid, version, status, onCheckinCheckout} = this.props; |
| 117 | const [checkinBtnIconSvg, checkinCheckoutBtnTitle] = status === statusEnum.CHECK_OUT_STATUS ? |
Avi Ziv | b8e2faf | 2017-07-18 19:45:38 +0300 | [diff] [blame] | 118 | ['versionControllerLockOpen', i18n('Check In')] : |
| 119 | ['versionControllerLockClosed', i18n('Check Out')]; |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 120 | const disabled = (isLatestVersion && onCheckinCheckout && status !== statusEnum.LOCK_STATUS) ? false : true; |
| 121 | return ( |
| 122 | <div className='action-buttons'> |
| 123 | <VCButton dataTestId='vc-checkout-btn' onClick={onCheckinCheckout} isDisabled={disabled} |
| 124 | name={checkinBtnIconSvg} tooltipText={checkinCheckoutBtnTitle}/> |
| 125 | {onSubmit && onRevert && |
| 126 | <div className='version-control-buttons'> |
| 127 | <VCButton dataTestId='vc-submit-btn' onClick={onSubmit} isDisabled={!isCheckedIn || !isLatestVersion} |
Avi Ziv | b8e2faf | 2017-07-18 19:45:38 +0300 | [diff] [blame] | 128 | name='versionControllerSubmit' tooltipText={i18n('Submit')}/> |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 129 | <VCButton dataTestId='vc-revert-btn' onClick={onRevert} isDisabled={!isCheckedOut || version.label === '0.1' || !isLatestVersion} |
Avi Ziv | b8e2faf | 2017-07-18 19:45:38 +0300 | [diff] [blame] | 130 | name='versionControllerRevert' tooltipText={i18n('Revert')}/> |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 131 | </div> |
| 132 | } |
| 133 | {onSave && |
| 134 | <VCButton dataTestId='vc-save-btn' onClick={() => onSave()} isDisabled={!isCheckedOut || !isFormDataValid || !isLatestVersion} |
Avi Ziv | b8e2faf | 2017-07-18 19:45:38 +0300 | [diff] [blame] | 135 | name='versionControllerSave' tooltipText={i18n('Save')}/> |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 136 | } |
| 137 | </div> |
| 138 | ); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 139 | } |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 140 | } |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 141 | |
AviZi | 280f801 | 2017-06-09 02:39:56 +0300 | [diff] [blame] | 142 | function StatusBarUpdates({status}) { |
| 143 | return ( |
| 144 | <div className='vc-status'> |
| 145 | <span className='status-text'>{i18n(statusBarTextMap[status])}</span> |
| 146 | </div> |
| 147 | ); |
| 148 | } |
| 149 | |
| 150 | function VCButton({name, tooltipText, isDisabled, onClick, dataTestId}) { |
| 151 | let onClickAction = isDisabled ? ()=>{} : onClick; |
| 152 | let disabled = isDisabled ? 'disabled' : ''; |
| 153 | |
| 154 | return ( |
| 155 | <OverlayTrigger placement='top' overlay={<Tooltip id='vc-tooltip'>{tooltipText}</Tooltip>}> |
| 156 | <div disabled={disabled} className='action-buttons-svg'> |
| 157 | <SVGIcon data-test-id={dataTestId} iconClassName={disabled} onClick={onClickAction ? onClickAction : undefined} name={name}/> |
| 158 | </div> |
| 159 | </OverlayTrigger> |
| 160 | ); |
| 161 | } |
| 162 | |
| 163 | function VersionSelector(props) { |
| 164 | let {version = {}, viewableVersions = [], onVersionSwitching} = props; |
| 165 | const includedVersions = viewableVersions.filter(ver => {return ver.id === version.id;}); |
| 166 | return (<div className='version-section-wrapper'> |
| 167 | <select className='version-selector' |
| 168 | onChange={ev => onVersionSwitching && onVersionSwitching({id: ev.target.value, label: ev.target.value})} |
| 169 | value={version.label}> |
| 170 | {viewableVersions && viewableVersions.map(viewVersion => { |
| 171 | return ( |
| 172 | <option key={viewVersion.id} value={viewVersion.id} data-test-id='vc-version-option'>{`V ${viewVersion.label}`}</option> |
| 173 | ); |
| 174 | }) |
| 175 | } |
| 176 | {!includedVersions.length && |
| 177 | <option key={version.id} value={version.id}>{`V ${version.label}`}</option>} |
| 178 | </select> |
| 179 | </div>); |
Michael Lando | efa037d | 2017-02-19 12:57:33 +0200 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | export default VersionController; |