diff options
author | AviZi <avi.ziv@amdocs.com> | 2017-06-09 02:39:56 +0300 |
---|---|---|
committer | AviZi <avi.ziv@amdocs.com> | 2017-06-09 02:39:56 +0300 |
commit | 280f8015d06af1f41a3ef12e8300801c7a5e0d54 (patch) | |
tree | 9c1d3978c04cd28068f02073038c936bb49ca9e0 /openecomp-ui/src/nfvo-components/panel | |
parent | fd3821dad11780d33c5373d74c957c442489945e (diff) |
[SDC-29] Amdocs OnBoard 1707 initial commit.
Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370
Signed-off-by: AviZi <avi.ziv@amdocs.com>
Diffstat (limited to 'openecomp-ui/src/nfvo-components/panel')
5 files changed, 258 insertions, 289 deletions
diff --git a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx index feb0f813ea..3b89137090 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 @@ class NavigationSideBar extends React.Component { 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 NavigationSideBar extends React.Component { } } +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 10c5326300..0000000000 --- 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 78525f84c6..6d900dd0bb 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 @@ class VersionController extends React.Component { }; 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); + } + + revertCheckout(callVCAction, version) { + const action = actionsEnum.UNDO_CHECK_OUT; + callVCAction(action, version); } - checkinCheckoutVersion(callVCAction) { + 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 9251fd12c4..9af142433c 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 @@ export const statusEnum = keyMirror({ 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 de9914454c..e8c12abec3 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 @@ import {statusEnum} from './VersionControllerConstants.js'; 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); } }; |