aboutsummaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/nfvo-components
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
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')
-rw-r--r--openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx9
-rw-r--r--openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx29
-rw-r--r--openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx10
-rw-r--r--openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx7
-rw-r--r--openecomp-ui/src/nfvo-components/grid/GridItem.jsx4
-rw-r--r--openecomp-ui/src/nfvo-components/grid/GridSection.jsx9
-rw-r--r--openecomp-ui/src/nfvo-components/icon/Icon.jsx45
-rw-r--r--openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx7
-rw-r--r--openecomp-ui/src/nfvo-components/input/ToggleInput.jsx9
-rw-r--r--openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx17
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/Form.jsx37
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/Input.jsx18
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx39
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx10
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx3
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx15
-rw-r--r--openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx11
-rw-r--r--openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx19
-rw-r--r--openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js10
-rw-r--r--openecomp-ui/src/nfvo-components/loader/Loader.jsx3
-rw-r--r--openecomp-ui/src/nfvo-components/modal/GlobalModal.js27
-rw-r--r--openecomp-ui/src/nfvo-components/overlay/Overlay.jsx40
-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
-rw-r--r--openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx5
-rw-r--r--openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx4
-rw-r--r--openecomp-ui/src/nfvo-components/tree/Tree.jsx181
-rw-r--r--openecomp-ui/src/nfvo-components/tree/Tree.stories.js119
33 files changed, 835 insertions, 372 deletions
diff --git a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx
index 40daeff9c5..c15cd1d0e8 100644
--- a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx
+++ b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx
@@ -60,7 +60,7 @@ class SubmitErrorResponse extends Component {
return (
<ErrorBlock errorType={i18n('VSP Errors')}>
<div>
- {errors.length && errors.map(error=>{return (<ErrorMessage error={error.message}/>);})}
+ {errors.length && errors.map((error, i) => {return (<ErrorMessage key={i} error={error.message}/>);})}
</div>
</ErrorBlock>
);
@@ -71,7 +71,7 @@ class SubmitErrorResponse extends Component {
return (
<ErrorBlock errorType={i18n('Components Errors')}>
<div>
- {errors.validationData.length && errors.validationData.map(item =>{ return (<ComponentError item={item}/>);})}
+ {errors.validationData.length && errors.validationData.map((item, i) =>{ return (<ComponentError key={i} item={item}/>);})}
</div>
</ErrorBlock>
);
@@ -90,11 +90,10 @@ class SubmitErrorResponse extends Component {
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}/>);})}
+ {item.errors.map((error, i) => {return(<ErrorMessage key={i} error={error}/>);})}
</div>
);
};
@@ -110,7 +109,7 @@ const UploadErrorList = ({items}) => {
let errors = [];
for (let item of generator) {errors.push(
- <div>
+ <div key={item.header}>
<div className='component-name-header'>{item.header}</div>
{item.list.map((error, i) => <ErrorMessage key={i} warning={error.level === 'WARNING'} error={error.message}/> )}
</div>
diff --git a/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx b/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx
index f4673c1c93..25e7e7e02d 100644
--- a/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx
+++ b/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import DatePicker from 'react-datepicker';
import moment from 'moment';
import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
@@ -6,10 +7,10 @@ import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
class CustomInput extends React.Component {
static propTypes = {
- placeHolderText: React.PropTypes.string,
- onChange: React.PropTypes.func,
- onClick: React.PropTypes.func,
- value: React.PropTypes.string
+ placeHolderText: PropTypes.string,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ value: PropTypes.string
};
render() {
@@ -32,16 +33,16 @@ const parseDate = (date, format) => {
class Datepicker extends React.Component {
static propTypes = {
- date: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
- format: React.PropTypes.string,
- onChange: React.PropTypes.func,
- selectsStart: React.PropTypes.bool,
- selectsEnd: React.PropTypes.bool,
- startDate: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
- endDate: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
- disabled: React.PropTypes.bool,
- label: React.PropTypes.string,
- isRequired: React.PropTypes.bool
+ date: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ format: PropTypes.string,
+ onChange: PropTypes.func,
+ selectsStart: PropTypes.bool,
+ selectsEnd: PropTypes.bool,
+ startDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ disabled: PropTypes.bool,
+ label: PropTypes.string,
+ isRequired: PropTypes.bool
}
render() {
let {date, format, onChange, selectsStart = false, startDate = null, endDate = null, selectsEnd = false,
diff --git a/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx b/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx
index 2a0b7d4d2a..3c9ceed0d8 100644
--- a/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx
+++ b/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx
@@ -22,7 +22,8 @@ import NavigationSideBar from 'nfvo-components/panel/NavigationSideBar.jsx';
export default class TabulatedEditor extends React.Component {
render() {
- const {navigationBarProps, onToggle, onVersionSwitching, onCreate, onSave, onClose, onVersionControllerAction, onNavigate, children, meta} = this.props;
+ const {navigationBarProps, onToggle, onVersionSwitching, onMoreVersionsClick, onCreate, onSave, onClose,
+ onVersionControllerAction, onNavigate, children, meta, onManagePermissions, onOpenCommentCommitModal, onOpenPermissions, onOpenRevisionsModal} = this.props;
let {versionControllerProps} = this.props;
const {className = ''} = React.Children.only(children).props;
const child = this.prepareChild();
@@ -42,7 +43,12 @@ export default class TabulatedEditor extends React.Component {
<VersionController
{...versionControllerProps}
onVersionSwitching={version => onVersionSwitching(version, meta)}
- callVCAction={(action, version) => onVersionControllerAction(action, version, meta)}
+ onMoreVersionsClick={onMoreVersionsClick}
+ onManagePermissions={onManagePermissions}
+ onOpenCommentCommitModal={onOpenCommentCommitModal}
+ onOpenPermissions={onOpenPermissions}
+ onOpenRevisionsModal={onOpenRevisionsModal}
+ callVCAction={(action, version, comment) => onVersionControllerAction(action, version, comment, meta)}
onCreate={onCreate && this.handleCreate}
onSave={onSave && this.handleSave}/>
<div className={classnames('content-area', `${className}`)}>
diff --git a/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx b/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx
index 629b9449a2..5b4e0a8bee 100644
--- a/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx
+++ b/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx
@@ -34,11 +34,10 @@ class DraggableUploadFileBox extends Component {
render() {
let {className, onClick, dataTestId, isReadOnlyMode} = this.props;
return (
- <div
- className={`${className}${isReadOnlyMode ? ' disabled' : ''}`}>
- <div className={`${'drag-text'}${isReadOnlyMode ? ' disabled' : ''}`}>{i18n('Drag & drop for upload')}</div>
+ <div className={`file-upload-box ${className} ${isReadOnlyMode ? 'disabled' : ''}`}>
+ <div className={`drag-text ${isReadOnlyMode ? 'disabled' : ''}`}>{i18n('Drag & drop for upload')}</div>
<div className='or-text'>{i18n('or')}</div>
- <Button type='button' data-test-id={dataTestId} btnType='outline' onClick={onClick} disabled={isReadOnlyMode === true}>{i18n('Select File')}</Button>
+ <Button type='button' data-test-id={dataTestId} btnType='outline' onClick={onClick} disabled={isReadOnlyMode}>{i18n('Select File')}</Button>
</div>
);
}
diff --git a/openecomp-ui/src/nfvo-components/grid/GridItem.jsx b/openecomp-ui/src/nfvo-components/grid/GridItem.jsx
index 8819ab78a3..c62e042bf4 100644
--- a/openecomp-ui/src/nfvo-components/grid/GridItem.jsx
+++ b/openecomp-ui/src/nfvo-components/grid/GridItem.jsx
@@ -15,8 +15,8 @@
*/
import React from 'react';
-const GridItem = ({colSpan = 1, children, stretch = false}) => (
- <div className={`grid-col-${colSpan}`}>
+const GridItem = ({colSpan = 1, children, lastColInRow = false, stretch = false, className = ''}) => (
+ <div className={`grid-col-${colSpan} ${lastColInRow ? 'last-col-in-row' : ''} ${className}`}>
<div className={`grid-item${stretch ? '-stretch' : ''}`}>
{children}
</div>
diff --git a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx
index de8a4f3e64..8f4a024fdb 100644
--- a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx
+++ b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx
@@ -14,11 +14,12 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import classnames from 'classnames';
-const GridSection = ({title, children, className, titleClassName}) => {
+const GridSection = ({title, children, className = '', titleClassName, hasLastColSet = false}) => {
return (
- <div className={classnames('grid-section', className)}>
+ <div className={classnames('grid-section', className, {'has-last-col-set': hasLastColSet})}>
{title && <div className={`section-title ${titleClassName || ''}`}>{title}</div>}
<div className='grid-items'>
{children}
@@ -28,7 +29,9 @@ const GridSection = ({title, children, className, titleClassName}) => {
};
GridSection.propTypes = {
- title: React.PropTypes.string,
+ title: PropTypes.string,
+ titleClassName: PropTypes.string,
+ hasLastColSet: PropTypes.bool
};
export default GridSection;
diff --git a/openecomp-ui/src/nfvo-components/icon/Icon.jsx b/openecomp-ui/src/nfvo-components/icon/Icon.jsx
deleted file mode 100644
index 125577664b..0000000000
--- a/openecomp-ui/src/nfvo-components/icon/Icon.jsx
+++ /dev/null
@@ -1,45 +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 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/input/ExpandableInput.jsx b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx
index eab1d45ef4..82fbe1deed 100644
--- a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx
+++ b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import Input from 'nfvo-components/input/validation/InputWrapper.jsx';
@@ -76,9 +77,9 @@ class ExpandableInputOpened extends React.Component {
class ExpandableInput extends React.Component {
static propTypes = {
- iconType: React.PropTypes.string,
- onChange: React.PropTypes.func,
- value: React.PropTypes.string
+ iconType: PropTypes.string,
+ onChange: PropTypes.func,
+ value: PropTypes.string
};
state = {showInput: false};
diff --git a/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx b/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx
index 23af72a26a..31a8a66d86 100644
--- a/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx
+++ b/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx
@@ -14,15 +14,16 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
export default
class ToggleInput extends React.Component {
static propTypes = {
- label: React.PropTypes.node,
- value: React.PropTypes.bool,
- onChange: React.PropTypes.func,
- disabled: React.PropTypes.bool
+ label: PropTypes.node,
+ value: PropTypes.bool,
+ onChange: PropTypes.func,
+ disabled: PropTypes.bool
}
static defaultProps = {
diff --git a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx
index a3be363ba4..a689c50778 100644
--- a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx
+++ b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import Input from 'nfvo-components/input/validation/InputWrapper.jsx';
@@ -21,17 +22,17 @@ class DualListboxView extends React.Component {
static propTypes = {
- availableList: React.PropTypes.arrayOf(React.PropTypes.shape({
- id: React.PropTypes.string.isRequired,
- name: React.PropTypes.string.isRequired
+ availableList: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired
})),
- filterTitle: React.PropTypes.shape({
- left: React.PropTypes.string,
- right: React.PropTypes.string
+ filterTitle: PropTypes.shape({
+ left: PropTypes.string,
+ right: PropTypes.string
}),
- selectedValuesList: React.PropTypes.arrayOf(React.PropTypes.string),
+ selectedValuesList: PropTypes.arrayOf(PropTypes.string),
- onChange: React.PropTypes.func.isRequired
+ onChange: PropTypes.func.isRequired
};
static defaultProps = {
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
index 8d53322587..6df0bf9009 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
@@ -15,6 +15,7 @@
*/
import React from 'react';
+import PropTypes from 'prop-types';
import ValidationButtons from './ValidationButtons.jsx';
class Form extends React.Component {
@@ -31,18 +32,18 @@ class Form extends React.Component {
};
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,
- submitButtonText: React.PropTypes.string,
- cancelButtonText: React.PropTypes.string,
- onValidChange : React.PropTypes.func,
- onValidityChanged: React.PropTypes.func,
- onValidateForm: React.PropTypes.func
+ isValid : PropTypes.bool,
+ formReady : PropTypes.bool,
+ isReadOnlyMode : PropTypes.bool,
+ hasButtons : PropTypes.bool,
+ onSubmit : PropTypes.func,
+ onReset : PropTypes.func,
+ labledButtons: PropTypes.bool,
+ submitButtonText: PropTypes.string,
+ cancelButtonText: PropTypes.string,
+ onValidChange : PropTypes.func,
+ onValidityChanged: PropTypes.func,
+ onValidateForm: PropTypes.func
};
constructor(props) {
@@ -124,13 +125,21 @@ class Form extends React.Component {
export class TabsForm extends Form {
render() {
// eslint-disable-next-line no-unused-vars
- let {isValid, formReady, onValidateForm, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, onDataChanged, children, ...formProps} = this.props;
+ let {submitButtonText, cancelButtonText, 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'>
{children}
</div>
- {hasButtons && <ValidationButtons labledButtons={labledButtons} ref={(buttons) => this.buttons = buttons} isReadOnlyMode={isReadOnlyMode}/>}
+ {hasButtons &&
+ <ValidationButtons
+ labledButtons={labledButtons}
+ submitButtonText={submitButtonText}
+ cancelButtonText={cancelButtonText}
+ ref={buttons => this.buttons = buttons}
+ isReadOnlyMode={isReadOnlyMode}/>
+ }
</form>
);
}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
index eef8fee1ce..9f0e9acca8 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
@@ -17,7 +17,7 @@ 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 Radio from 'sdc-ui/lib/react/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';
@@ -85,7 +85,7 @@ class Input extends React.Component {
className={classNames({'required' : isRequired , 'has-error' : !isValid})}
onChange={(e)=>this.onChangeCheckBox(e)}
disabled={isReadOnlyMode || Boolean(disabled)}
- checked={value}
+ checked={checked}
data-test-id={this.props['data-test-id']}>{label}</Checkbox>}
{type === 'radio' &&
@@ -93,9 +93,10 @@ class Input extends React.Component {
checked={checked}
disabled={isReadOnlyMode || Boolean(disabled)}
value={value}
- onChange={(e)=>this.onChangeRadio(e)}
+ onChange={(isChecked)=>this.onChangeRadio(isChecked)}
inputRef={(input) => this.input = input}
- data-test-id={this.props['data-test-id']}>{label}</Radio>}
+ label={label}
+ data-test-id={this.props['data-test-id']} />}
{type === 'select' &&
<FormControl onClick={ (e) => this.optionSelect(e) }
componentClass={type}
@@ -156,16 +157,17 @@ class Input extends React.Component {
onChangeCheckBox(e) {
let {onChange} = this.props;
+ let checked = e.target.checked;
this.setState({
- checked: e.target.checked
+ checked
});
- onChange(e.target.checked);
+ onChange(checked);
}
- onChangeRadio(e) {
+ onChangeRadio(isChecked) {
let {onChange} = this.props;
this.setState({
- checked: e.target.checked
+ checked: isChecked
});
onChange(this.state.value);
}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
index 9b11d27c2b..11b07ba9da 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import i18n from 'nfvo-utils/i18n/i18n.js';
import classNames from 'classnames';
@@ -26,27 +27,27 @@ 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
+ values: PropTypes.arrayOf(PropTypes.shape({
+ enum: PropTypes.string,
+ title: PropTypes.string
})),
- isEnabledOther: React.PropTypes.bool,
- label: React.PropTypes.string,
- selectedValue: React.PropTypes.string,
- multiSelectedEnum: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.array
+ isEnabledOther: PropTypes.bool,
+ label: PropTypes.string,
+ selectedValue: PropTypes.string,
+ multiSelectedEnum: PropTypes.oneOfType([
+ PropTypes.string,
+ 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
+ selectedEnum: PropTypes.string,
+ otherValue: PropTypes.string,
+ overlayPos: PropTypes.string,
+ onEnumChange: PropTypes.func,
+ onOtherChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ isRequired: PropTypes.bool,
+ isMultiSelect: PropTypes.bool,
+ isValid: PropTypes.bool,
+ disabled: PropTypes.bool
};
state = {
diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
index 6c8115deee..e440fcda69 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
@@ -17,7 +17,7 @@ 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 Radio from 'sdc-ui/lib/react/Radio.js';
import FormGroup from 'react-bootstrap/lib/FormGroup.js';
import FormControl from 'react-bootstrap/lib/FormControl.js';
@@ -72,8 +72,8 @@ class InputWrapper extends React.Component {
disabled={isReadOnlyMode || Boolean(disabled)}
value={value}
ref={(input) => this.inputWrapper = input}
- onChange={(e)=>this.onChangeRadio(e)}
- data-test-id={this.props['data-test-id']}>{label}</Radio>}
+ onChange={(isChecked)=>this.onChangeRadio(isChecked)} label={label}
+ data-test-id={this.props['data-test-id']} />}
{type === 'select' &&
<FormControl onClick={ (e) => this.optionSelect(e) }
componentClass={type}
@@ -119,10 +119,10 @@ class InputWrapper extends React.Component {
onChange(e.target.checked);
}
- onChangeRadio(e) {
+ onChangeRadio(isChecked) {
let {onChange} = this.props;
this.setState({
- checked: e.target.checked
+ checked: isChecked
});
onChange(this.state.value);
}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
index 6f33536b04..0982c133e6 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import {default as SDCTabs} from 'sdc-ui/lib/react/Tabs.js';
import Overlay from 'react-bootstrap/lib/Overlay.js';
@@ -25,7 +26,7 @@ export default
class Tabs extends React.Component {
static propTypes = {
- children: React.PropTypes.node
+ children: PropTypes.node
};
cloneTab(element) {
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
index c3808dd2c3..151d3fe859 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
@@ -21,6 +21,7 @@
* labledButtons - whether or not to use labeled buttons or icons only
*/
import React from 'react';
+import PropTypes from 'prop-types';
import i18n from 'nfvo-utils/i18n/i18n.js';
import Button from 'sdc-ui/lib/react/Button.js';
import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
@@ -28,10 +29,10 @@ import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
class ValidationButtons extends React.Component {
static propTypes = {
- labledButtons: React.PropTypes.bool.isRequired,
- isReadOnlyMode: React.PropTypes.bool,
- submitButtonText: React.PropTypes.string,
- cancelButtonText: React.PropTypes.string
+ labledButtons: PropTypes.bool.isRequired,
+ isReadOnlyMode: PropTypes.bool,
+ submitButtonText: PropTypes.string,
+ cancelButtonText: PropTypes.string
};
state = {
@@ -45,10 +46,10 @@ class ValidationButtons extends React.Component {
<div className='validation-buttons'>
{!this.props.isReadOnlyMode ?
<div>
- <Button type='submit' disabled={!this.state.isValid}>{submitBtn}</Button>
- <Button btnType='outline' type='reset'>{closeBtn}</Button>
+ <Button type='submit' data-test-id='form-submit-button' disabled={!this.state.isValid}>{submitBtn}</Button>
+ <Button btnType='outline' type='reset' data-test-id='form-close-button'>{closeBtn}</Button>
</div>
- : <Button btnType='outline' type='reset'>{i18n('Close')}</Button>
+ : <Button btnType='outline' type='reset' data-test-id='form-close-button'>{i18n('Close')}</Button>
}
</div>
);
diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx
index bed304b756..60c559a3d1 100644
--- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx
+++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import classnames from 'classnames';
import i18n from 'nfvo-utils/i18n/i18n.js';
import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
@@ -22,11 +23,11 @@ import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModal
class ListEditorItem extends React.Component {
static propTypes = {
- onSelect: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]),
- onDelete: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]),
- onEdit: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]),
- children: React.PropTypes.node,
- isReadOnlyMode: React.PropTypes.bool
+ onSelect: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
+ onDelete: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
+ onEdit: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
+ children: PropTypes.node,
+ isReadOnlyMode: PropTypes.bool
};
render() {
diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx
index df7d69b4ff..16823b7dc5 100644
--- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx
+++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import Button from 'sdc-ui/lib/react/Button.js';
import classnames from 'classnames';
import ExpandableInput from 'nfvo-components/input/ExpandableInput.jsx';
@@ -60,15 +61,15 @@ class ListEditorView extends React.Component {
};
static propTypes = {
- title: React.PropTypes.string,
- plusButtonTitle: React.PropTypes.string,
- children: React.PropTypes.node,
- filterValue: React.PropTypes.string,
- onFilter: React.PropTypes.func,
- className: React.PropTypes.string,
- isReadOnlyMode: React.PropTypes.bool,
- placeholder: React.PropTypes.string,
- twoColumns: React.PropTypes.bool
+ title: PropTypes.string,
+ plusButtonTitle: PropTypes.string,
+ children: PropTypes.node,
+ filterValue: PropTypes.string,
+ onFilter: PropTypes.func,
+ className: PropTypes.string,
+ isReadOnlyMode: PropTypes.bool,
+ placeholder: PropTypes.string,
+ twoColumns: PropTypes.bool
};
render() {
diff --git a/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js b/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js
index 276b05e270..81125c84ba 100644
--- a/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js
+++ b/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js
@@ -2,7 +2,7 @@ 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 ListEditorItemField from './ListEditorItemViewField.jsx';
import {text, number} from '@kadira/storybook-addon-knobs';
import {withKnobs} from '@kadira/storybook-addon-knobs';
@@ -13,12 +13,12 @@ function makeChildren({onEdit = false, onDelete = false} = {}) {
key={index}
onEdit={onEdit ? onEdit : undefined}
onDelete={onDelete ? onDelete : undefined}>
- <ListEditorItemViewField>
+ <ListEditorItemField>
<div>{text('field 1', 'Lorum Ipsum')}</div>
- </ListEditorItemViewField>
- <ListEditorItemViewField>
+ </ListEditorItemField>
+ <ListEditorItemField>
<div>{text('field 2', 'Lorum Ipsum')}</div>
- </ListEditorItemViewField>
+ </ListEditorItemField>
</ListEditorItemView>)
)
);
diff --git a/openecomp-ui/src/nfvo-components/loader/Loader.jsx b/openecomp-ui/src/nfvo-components/loader/Loader.jsx
index 675b04c8ea..cbfed1b214 100644
--- a/openecomp-ui/src/nfvo-components/loader/Loader.jsx
+++ b/openecomp-ui/src/nfvo-components/loader/Loader.jsx
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import {connect} from 'react-redux';
const mapStateToProps = ({loader}) => {
@@ -25,7 +26,7 @@ const mapStateToProps = ({loader}) => {
class Loader extends React.Component {
static propTypes = {
- isLoading: React.PropTypes.bool.isRequired
+ isLoading: PropTypes.bool.isRequired
};
static defaultProps = {
diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js
index 4e7a1a16a4..a47c42a1fb 100644
--- a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js
+++ b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js
@@ -15,6 +15,7 @@
*/
import React from 'react';
+import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import Modal from 'nfvo-components/modal/Modal.jsx';
@@ -25,7 +26,7 @@ import {actionTypes, typeEnum} from './GlobalModalConstants.js';
const typeClass = {
- 'default': 'default',
+ 'default': 'primary',
error: 'negative',
warning: 'warning',
success: 'positive'
@@ -47,11 +48,11 @@ const ModalFooter = ({type, onConfirmed, onDeclined, onClose, confirmationButton
return (
<Modal.Footer>
<div className='sdc-modal-footer'>
- {onConfirmed && <Button color={typeClass[type]} onClick={() => {
+ {onConfirmed && <Button data-test-id='sdc-modal-confirm-button' color={typeClass[type]} onClick={() => {
onConfirmed();
onClose();
}}>{confirmationButtonText}</Button>}
- <Button {...myPropsForNoConfirmed} color={typeClass[type]} onClick={onDeclined ? () => {
+ <Button {...myPropsForNoConfirmed} data-test-id='sdc-modal-cancel-button' btnType='outline' color={typeClass[type]} onClick={onDeclined ? () => {
onDeclined();
onClose();} : () => onClose()}>
{cancelButtonText}
@@ -85,15 +86,15 @@ export const mapActionToProps = (dispatch) => {
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
+ show: PropTypes.bool,
+ type: PropTypes.oneOf(['default', 'error', 'warning', 'success']),
+ title: PropTypes.string,
+ modalComponentProps: PropTypes.object,
+ modalComponentName: PropTypes.string,
+ onConfirmed: PropTypes.func,
+ onDeclined: PropTypes.func,
+ confirmationButtonText: PropTypes.string,
+ cancelButtonText: PropTypes.string
};
static defaultProps = {
@@ -115,7 +116,7 @@ export class GlobalModalView extends React.Component {
{ComponentToRender ?
<ComponentToRender {...modalComponentProps}/> :
msg && typeof msg === 'string' ?
- <div> {msg.split('\n').map(txt => <span> {txt} <br/> </span>)} </div> :
+ <div> {msg.split('\n').map((txt, i) => <span key={i}> {txt} <br/> </span>)} </div> :
msg
}
</Modal.Body>
diff --git a/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx b/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx
new file mode 100644
index 0000000000..054c1e2852
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx
@@ -0,0 +1,40 @@
+/*!
+ * 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 enhanceWithClickOutside from 'react-click-outside';
+
+class Overlay extends React.Component {
+
+ handleClickOutside() {
+ if (this.props.onClose) {
+ this.props.onClose();
+ }
+ }
+
+ render() {
+ return (
+ <div className='onboarding-overlay'>
+ <div className='arrow-up'></div>
+ <div className='arrow-border'/>
+ {this.props.children}
+ </div>
+ );
+ }
+
+};
+
+export default enhanceWithClickOutside(Overlay);
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;
diff --git a/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx b/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx
index 40720c39f4..ca5cb3d765 100644
--- a/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx
+++ b/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx
@@ -14,11 +14,12 @@
* permissions and limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
class ProgressBar extends React.Component {
static propTypes = {
- label: React.PropTypes.string,
- now: React.PropTypes.string.isRequired
+ label: PropTypes.string,
+ now: PropTypes.string.isRequired
}
render() {
let {label, now} = this.props;
diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx
index a03f8441a4..260d39d31c 100644
--- a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx
+++ b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx
@@ -27,12 +27,12 @@ function renderErrorOrCheck({hasError, overlayMsg}) {
return <SVGIcon name='checkCircle' color='positive'/>;
}
-const SelectActionTableRow = ({children, onDelete, hasError, hasErrorIndication, overlayMsg, showDelete}) => (
+const SelectActionTableRow = ({children, actionIcon, onAction, showAction, hasError, hasErrorIndication, overlayMsg}) => (
<div className='select-action-table-row-wrapper'>
<div className={`select-action-table-row ${hasError ? 'has-error' : ''}`}>
{children}
</div>
- {onDelete && <SVGIcon color='secondary' name='trashO' data-test-id='select-action-table-delete' onClick={onDelete} iconClassName={(showDelete) ? '' : 'hideDelete'}/>}
+ {onAction && <SVGIcon color='secondary' name={actionIcon} data-test-id={`select-action-table-${actionIcon}`} onClick={onAction} iconClassName={(showAction) ? '' : 'hideDelete'}/>}
{hasErrorIndication && renderErrorOrCheck({hasError, overlayMsg})}
</div>
);
diff --git a/openecomp-ui/src/nfvo-components/tree/Tree.jsx b/openecomp-ui/src/nfvo-components/tree/Tree.jsx
new file mode 100644
index 0000000000..682f3b6d50
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/tree/Tree.jsx
@@ -0,0 +1,181 @@
+import React, {Component} from 'react';
+import PropTypes from 'prop-types';
+import {select} from 'd3-selection';
+import {tree, stratify} from 'd3-hierarchy';
+
+
+function diagonal(d) {
+
+ const offset = 50;
+ return 'M' + d.y + ',' + d.x
+ + 'C' + (d.parent.y + offset) + ',' + d.x
+ + ' ' + (d.parent.y + offset) + ',' + d.parent.x
+ + ' ' + d.parent.y + ',' + d.parent.x;
+}
+
+const nodeRadius = 8;
+const verticalSpaceBetweenNodes = 70;
+const NARROW_HORIZONTAL_SPACES = 47;
+const WIDE_HORIZONTAL_SPACES = 65;
+
+const stratifyFn = stratify().id(d => d.id).parentId(d => d.parent);
+
+class Tree extends Component {
+
+ // state = {
+ // startingCoordinates: null,
+ // isDown: false
+ // }
+
+ static propTypes = {
+ name: PropTypes.string,
+ width: PropTypes.number,
+ allowScaleWidth: PropTypes.bool,
+ nodes: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.string,
+ name: PropTypes.string,
+ parent: PropTypes.string
+ })),
+ selectedNodeId: PropTypes.string,
+ onNodeClick: PropTypes.func,
+ onRenderedBeyondWidth: PropTypes.func
+ };
+
+ static defaultProps = {
+ width: 500,
+ allowScaleWidth : true,
+ name: 'default-name'
+ };
+
+ render() {
+ let {width, name, scrollable = false} = this.props;
+ return (
+ <div
+ className={`tree-view ${name}-container ${scrollable ? 'scrollable' : ''}`}>
+ <svg width={width} className={name}></svg>
+ </div>
+ );
+ }
+
+ componentDidMount() {
+ this.renderTree();
+ }
+
+ // handleMouseMove(e) {
+ // if (!this.state.isDown) {
+ // return;
+ // }
+ // const container = select(`.tree-view.${this.props.name}-container`);
+ // let coordinates = this.getCoordinates(e);
+ // container.property('scrollLeft' , container.property('scrollLeft') + coordinates.x - this.state.startingCoordinates.x);
+ // container.property('scrollTop' , container.property('scrollTop') + coordinates.y - this.state.startingCoordinates.y);
+ // }
+
+ // handleMouseDown(e) {
+ // let startingCoordinates = this.getCoordinates(e);
+ // this.setState({
+ // startingCoordinates,
+ // isDown: true
+ // });
+ // }
+
+ // handleMouseUp() {
+ // this.setState({
+ // startingCorrdinates: null,
+ // isDown: false
+ // });
+ // }
+
+ // getCoordinates(e) {
+ // var bounds = e.target.getBoundingClientRect();
+ // var x = e.clientX - bounds.left;
+ // var y = e.clientY - bounds.top;
+ // return {x, y};
+ // }
+
+ componentDidUpdate(prevProps) {
+ if (this.props.nodes.length !== prevProps.nodes.length ||
+ this.props.selectedNodeId !== prevProps.selectedNodeId) {
+ console.log('update');
+ this.renderTree();
+ }
+ }
+
+ renderTree() {
+ let {width, nodes, name, allowScaleWidth, selectedNodeId, onRenderedBeyondWidth, toWiden} = this.props;
+ if (nodes.length > 0) {
+
+ let horizontalSpaceBetweenLeaves = toWiden ? WIDE_HORIZONTAL_SPACES : NARROW_HORIZONTAL_SPACES;
+ const treeFn = tree().nodeSize([horizontalSpaceBetweenLeaves, verticalSpaceBetweenNodes]);//.size([width - 50, height - 50])
+ let root = stratifyFn(nodes).sort((a, b) => a.data.name.localeCompare(b.data.name));
+ let svgHeight = verticalSpaceBetweenNodes * root.height + nodeRadius * 6;
+
+ treeFn(root);
+
+ let nodesXValue = root.descendants().map(node => node.x);
+ let maxX = Math.max(...nodesXValue);
+ let minX = Math.min(...nodesXValue);
+
+ let svgTempWidth = (maxX - minX) / 30 * (horizontalSpaceBetweenLeaves);
+ let svgWidth = svgTempWidth < width ? (width - 5) : svgTempWidth;
+ const svgEL = select(`svg.${name}`);
+ const container = select(`.tree-view.${name}-container`);
+ svgEL.html('');
+ svgEL.attr('height', svgHeight);
+ let canvasWidth = width;
+ if (svgTempWidth > width) {
+ if (allowScaleWidth) {
+ canvasWidth = svgTempWidth;
+ }
+ // we seems to have a margin of 25px that we can still see with text
+ if (((svgTempWidth - 25) > width) && onRenderedBeyondWidth !== undefined) {
+ onRenderedBeyondWidth();
+ }
+ };
+ svgEL.attr('width', canvasWidth);
+ let rootGroup = svgEL.append('g').attr('transform', `translate(${svgWidth / 2 + nodeRadius},${nodeRadius * 4}) rotate(90)`);
+
+ // handle link
+ rootGroup.selectAll('.link')
+ .data(root.descendants().slice(1))
+ .enter().append('path')
+ .attr('class', 'link')
+ .attr('d', diagonal);
+
+ let node = rootGroup.selectAll('.node')
+ .data(root.descendants())
+ .enter().append('g')
+ .attr('class', node => `node ${node.children ? ' has-children' : ' leaf'} ${node.id === selectedNodeId ? 'selectedNode' : ''} ${this.props.onNodeClick ? 'clickable' : ''}`)
+ .attr('transform', node => 'translate(' + node.y + ',' + node.x + ')')
+ .on('click', node => this.onNodeClick(node));
+
+ node.append('circle').attr('r', nodeRadius).attr('class', 'outer-circle');
+ node.append('circle').attr('r', nodeRadius - 3).attr('class', 'inner-circle');
+
+ node.append('text')
+ .attr('y', nodeRadius / 4 + 1)
+ .attr('x', - nodeRadius * 1.8)
+ .text(node => node.data.name)
+ .attr('transform', 'rotate(-90)');
+
+ let selectedNode = selectedNodeId ? root.descendants().find(node => node.id === selectedNodeId) : null;
+ if (selectedNode) {
+
+ container.property('scrollLeft', (svgWidth / 4) + (svgWidth / 4 - 100) - (selectedNode.x / 30 * horizontalSpaceBetweenLeaves));
+ container.property('scrollTop', (selectedNode.y / 100 * verticalSpaceBetweenNodes));
+
+ } else {
+ container.property('scrollLeft', (svgWidth / 4) + (svgWidth / 4 - 100));
+ }
+ }
+ }
+
+ onNodeClick(node) {
+ if (this.props.onNodeClick) {
+ this.props.onNodeClick(node.data);
+ }
+ }
+
+}
+
+export default Tree;
diff --git a/openecomp-ui/src/nfvo-components/tree/Tree.stories.js b/openecomp-ui/src/nfvo-components/tree/Tree.stories.js
new file mode 100644
index 0000000000..b29920b3ec
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/tree/Tree.stories.js
@@ -0,0 +1,119 @@
+import React from 'react';
+import {storiesOf} from '@kadira/storybook';
+import {withKnobs} from '@kadira/storybook-addon-knobs';
+import Tree from './Tree.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
+
+const stories = storiesOf('Version Tree', module);
+stories.addDecorator(withKnobs);
+
+const response = {
+ listCount: 6,
+ results: [
+ {
+ 'id': '123',
+ 'name': '1.0',
+ 'description': 'string',
+ 'baseId': '',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '1234',
+ 'name': '1.1',
+ 'description': 'string',
+ 'baseId': '123',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '12345',
+ 'name': '2.0',
+ 'description': 'string',
+ 'baseId': '123',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '123456',
+ 'name': '3.0',
+ 'description': 'string',
+ 'baseId': '12345',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '1234567',
+ 'name': '1.2',
+ 'description': 'string',
+ 'baseId': '1234',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '12345678',
+ 'name': '2.1',
+ 'description': 'string',
+ 'baseId': '12345',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '123456789',
+ 'name': '4.0',
+ 'description': 'string',
+ 'baseId': '123456',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ },
+ {
+ 'id': '12345678910',
+ 'name': '3.1',
+ 'description': 'string',
+ 'baseId': '123456',
+ 'status': 'Draft',
+ 'creationTime': '2017-06-08T08:55:37.831Z',
+ 'modificationTime': '2017-06-08T08:55:37.831Z'
+ }
+ ]
+};
+const divStyle = { width: '200px', borderStyle: 'solid', borderColor: 'black', border: '1px solid black'};
+const tree = response.results.map(item => ({id: item.id, name: item.name, parent: item.baseId}));
+const nodeClickHandler = function (node) {
+ window.alert(node.name);
+};
+stories.add('Classic Version Tree', () => (
+ <div>
+ <Tree nodes={tree} onNodeClick={nodeClickHandler} selectedNodeId={'1234'}/>
+ </div>
+)).add('Single Version Tree', () => (
+ <div>
+ <Tree nodes={[tree[0]]} onNodeClick={nodeClickHandler}/>
+ </div>
+)).add('Single Path Version Tree', () => (
+ <div>
+ <Tree nodes={[tree[0], tree[1]]} onNodeClick={nodeClickHandler}/>
+ </div>
+)).add('Empty Tree', () => (
+ <div>
+ <Tree nodes={[]}/>
+ </div>
+)).add('Add Tree in Version Page Frame', () => (
+ <div style={divStyle}>
+ Tree wider than frame<br/><br/><br/>
+ <Tree
+ name={'versions-tree'}
+ width={200}
+ nodes={tree}
+ onRenderedBeyondWidth={() => {console.log('rendered beyond width')}}
+ allowScaleWidth={false}
+ onNodeClick={nodeClickHandler}/>
+ </div>
+));