aboutsummaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/nfvo-components/input/validation
diff options
context:
space:
mode:
authorAviZi <avi.ziv@amdocs.com>2017-06-09 02:39:56 +0300
committerAviZi <avi.ziv@amdocs.com>2017-06-09 02:39:56 +0300
commit280f8015d06af1f41a3ef12e8300801c7a5e0d54 (patch)
tree9c1d3978c04cd28068f02073038c936bb49ca9e0 /openecomp-ui/src/nfvo-components/input/validation
parentfd3821dad11780d33c5373d74c957c442489945e (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/input/validation')
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/Form.jsx114
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/Input.jsx180
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx279
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx134
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx79
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx21
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx200
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx509
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx107
-rw-r--r--openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx72
10 files changed, 804 insertions, 891 deletions
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
new file mode 100644
index 0000000000..47922f86a0
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx
@@ -0,0 +1,114 @@
+/*!
+ * 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 ValidationButtons from './ValidationButtons.jsx';
+
+class Form extends React.Component {
+
+ static defaultProps = {
+ hasButtons : true,
+ onSubmit : null,
+ onReset : null,
+ labledButtons: true,
+ onValidChange : null,
+ isValid: true
+ };
+
+ 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,
+ onValidChange : React.PropTypes.func,
+ onValidityChanged: React.PropTypes.func,
+ onValidateForm: React.PropTypes.func
+ };
+
+ constructor(props) {
+ super(props);
+ }
+
+
+ render() {
+ // eslint-disable-next-line no-unused-vars
+ let {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'>
+ <fieldset disabled={isReadOnlyMode}>
+ {children}
+ </fieldset>
+ </div>
+ {hasButtons && <ValidationButtons labledButtons={labledButtons} ref={(buttons) => this.buttons = buttons} isReadOnlyMode={isReadOnlyMode}/>}
+ </form>
+ );
+ }
+
+ handleFormValidation(event) {
+ event.preventDefault();
+ if (this.props.onValidateForm && !this.props.formReady){
+ return this.props.onValidateForm();
+ } else {
+ return this.handleFormSubmit(event);
+ }
+ }
+ handleFormSubmit(event) {
+ if (event) {
+ event.preventDefault();
+ }
+ if(this.props.onSubmit) {
+ return this.props.onSubmit(event);
+ }
+ }
+
+ componentDidMount() {
+ if (this.props.hasButtons) {
+ this.buttons.setState({isValid: this.props.isValid});
+ }
+ }
+
+
+
+ componentDidUpdate(prevProps) {
+ // only handling this programatically if the validation of the form is done outside of the view
+ // (example with a form that is dependent on the state of other forms)
+ if (prevProps.isValid !== this.props.isValid) {
+ if (this.props.hasButtons) {
+ this.buttons.setState({isValid: this.props.isValid});
+ }
+ // callback in case form is part of bigger picture in view
+ if (this.props.onValidChange) {
+ this.props.onValidChange(this.props.isValid);
+ }
+
+ // TODO - maybe this has to be part of componentWillUpdate
+ if(this.props.onValidityChanged) {
+ this.props.onValidityChanged(this.props.isValid);
+ }
+ }
+ if (this.props.formReady) { // if form validation succeeded -> continue with submit
+ this.handleFormSubmit();
+ }
+ }
+
+}
+
+
+export default Form;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
new file mode 100644
index 0000000000..59c35d7993
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx
@@ -0,0 +1,180 @@
+/*!
+ * 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 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 FormGroup from 'react-bootstrap/lib/FormGroup.js';
+import FormControl from 'react-bootstrap/lib/FormControl.js';
+import Overlay from 'react-bootstrap/lib/Overlay.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+class Input extends React.Component {
+
+ state = {
+ value: this.props.value,
+ checked: this.props.checked,
+ selectedValues: []
+ }
+
+ render() {
+ const {label, isReadOnlyMode, value, onBlur, onKeyDown, type, disabled, checked, name} = this.props;
+ // eslint-disable-next-line no-unused-vars
+ const {groupClassName, isValid = true, errorText, isRequired, ...inputProps} = this.props;
+ let wrapperClassName = (type !== 'radio') ? 'validation-input-wrapper' : 'form-group';
+ if (disabled) {
+ wrapperClassName += ' disabled';
+ }
+ return(
+ <div className={wrapperClassName}>
+ <FormGroup className={classNames('form-group', [groupClassName], {'required' : isRequired , 'has-error' : !isValid})} >
+ {(label && (type !== 'checkbox' && type !== 'radio')) && <label className='control-label'>{label}</label>}
+ {(type === 'text' || type === 'number') &&
+ <FormControl
+ bsClass={'form-control input-options-other'}
+ onChange={(e) => this.onChange(e)}
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ onBlur={onBlur}
+ onKeyDown={onKeyDown}
+ value={value || ''}
+ inputRef={(input) => this.input = input}
+ type={type}
+ data-test-id={this.props['data-test-id']}/>}
+
+ {type === 'textarea' &&
+ <FormControl
+ className='form-control input-options-other'
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ value={value || ''}
+ onBlur={onBlur}
+ onKeyDown={onKeyDown}
+ componentClass={type}
+ onChange={(e) => this.onChange(e)}
+ inputRef={(input) => this.input = input}
+ data-test-id={this.props['data-test-id']}/>}
+
+ {type === 'checkbox' &&
+ <Checkbox
+ className={classNames({'required' : isRequired , 'has-error' : !isValid})}
+ onChange={(e)=>this.onChangeCheckBox(e)}
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ checked={value}
+ data-test-id={this.props['data-test-id']}>{label}</Checkbox>}
+
+ {type === 'radio' &&
+ <Radio name={name}
+ checked={checked}
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ value={value}
+ onChange={(e)=>this.onChangeRadio(e)}
+ data-test-id={this.props['data-test-id']}>{label}</Radio>}
+ {type === 'select' &&
+ <FormControl onClick={ (e) => this.optionSelect(e) }
+ componentClass={type}
+ inputRef={(input) => this.input = input}
+ name={name} {...inputProps}
+ data-test-id={this.props['data-test-id']}/>}
+ </FormGroup>
+ { this.renderErrorOverlay() }
+ </div>
+ );
+ }
+
+ getValue() {
+ return this.props.type !== 'select' ? this.state.value : this.state.selectedValues;
+ }
+
+ getChecked() {
+ return this.state.checked;
+ }
+
+ optionSelect(e) {
+ let selectedValues = [];
+ if (e.target.value) {
+ selectedValues.push(e.target.value);
+ }
+ this.setState({
+ selectedValues
+ });
+ }
+
+ onChange(e) {
+ const {onChange, type} = this.props;
+ let value = e.target.value;
+ if (type === 'number') {
+ value = Number(value);
+ }
+ this.setState({
+ value
+ });
+ onChange(value);
+ }
+
+ onChangeCheckBox(e) {
+ let {onChange} = this.props;
+ this.setState({
+ checked: e.target.checked
+ });
+ onChange(e.target.checked);
+ }
+
+ onChangeRadio(e) {
+ let {onChange} = this.props;
+ this.setState({
+ checked: e.target.checked
+ });
+ onChange(this.state.value);
+ }
+
+ focus() {
+ ReactDOM.findDOMNode(this.input).focus();
+ }
+
+ renderErrorOverlay() {
+ let position = 'right';
+ const {errorText = '', isValid = true, type, overlayPos} = this.props;
+
+ if (overlayPos) {
+ position = overlayPos;
+ }
+ else if (type === 'text'
+ || type === 'email'
+ || type === 'number'
+ || type === 'password') {
+ position = 'bottom';
+ }
+
+ return (
+ <Overlay
+ show={!isValid}
+ placement={position}
+ target={() => {
+ let target = ReactDOM.findDOMNode(this.input);
+ return target.offsetParent ? target : undefined;
+ }}
+ container={this}>
+ <Tooltip
+ id={`error-${errorText.replace(' ', '-')}`}
+ className='validation-error-message'>
+ {errorText}
+ </Tooltip>
+ </Overlay>
+ );
+ }
+
+}
+export default Input;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
new file mode 100644
index 0000000000..6e54254eb0
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx
@@ -0,0 +1,279 @@
+/*!
+ * 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 ReactDOM from 'react-dom';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import classNames from 'classnames';
+import Select from 'nfvo-components/input/SelectInput.jsx';
+import Overlay from 'react-bootstrap/lib/Overlay.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+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
+ })),
+ isEnabledOther: React.PropTypes.bool,
+ label: React.PropTypes.string,
+ selectedValue: React.PropTypes.string,
+ multiSelectedEnum: React.PropTypes.oneOfType([
+ React.PropTypes.string,
+ React.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
+ };
+
+ state = {
+ otherInputDisabled: !this.props.otherValue
+ };
+
+ oldProps = {
+ selectedEnum: '',
+ otherValue: '',
+ multiSelectedEnum: []
+ };
+
+ render() {
+ let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, isValid, children, isReadOnlyMode} = this.props;
+ const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {};
+ let currentMultiSelectedEnum = [];
+ let currentSelectedEnum = '';
+ let {otherInputDisabled} = this.state;
+ if (isMultiSelect) {
+ currentMultiSelectedEnum = multiSelectedEnum;
+ if(!otherInputDisabled) {
+ currentSelectedEnum = multiSelectedEnum ? multiSelectedEnum.toString() : undefined;
+ }
+ }
+ else if(selectedEnum){
+ currentSelectedEnum = selectedEnum;
+ }
+ if (!onBlur) {
+ onBlur = () => {};
+ }
+
+ return(
+ <div className='validation-input-wrapper' >
+ <div className={classNames('form-group', {'required' : isRequired, 'has-error' : !isValid})} >
+ {label && <label className='control-label'>{label}</label>}
+ {isMultiSelect && otherInputDisabled ?
+ <Select
+ {...dataTestId}
+ ref={(input) => this.input = input}
+ value={currentMultiSelectedEnum}
+ className='options-input'
+ clearable={false}
+ required={isRequired}
+ disabled={isReadOnlyMode || Boolean(this.props.disabled)}
+ onBlur={() => onBlur()}
+ onMultiSelectChanged={value => this.multiSelectEnumChanged(value)}
+ options={this.renderMultiSelectOptions(values)}
+ multi/> :
+ <div className={classNames('input-options',{'has-error' : !isValid})} >
+ <select
+ {...dataTestId}
+ ref={(input) => this.input = input}
+ label={label}
+ className='form-control input-options-select'
+ value={currentSelectedEnum}
+ style={{'width' : otherInputDisabled ? '100%' : '100px'}}
+ onBlur={() => onBlur()}
+ disabled={isReadOnlyMode || Boolean(this.props.disabled)}
+ onChange={ value => this.enumChanged(value)}
+ type='select'>
+ {children || (values && values.length && values.map((val, index) => this.renderOptions(val, index)))}
+ {onOtherChange && <option key='other' value={other.OTHER}>{i18n(other.OTHER)}</option>}
+ </select>
+
+ {!otherInputDisabled && <div className='input-options-separator'/>}
+ <input
+ className='form-control input-options-other'
+ placeholder={i18n('other')}
+ ref={(otherValue) => this.otherValue = otherValue}
+ style={{'display' : otherInputDisabled ? 'none' : 'block'}}
+ disabled={isReadOnlyMode || Boolean(this.props.disabled)}
+ value={otherValue || ''}
+ onBlur={() => onBlur()}
+ onChange={() => this.changedOtherInput()}/>
+ </div>
+ }
+ </div>
+ { this.renderErrorOverlay() }
+ </div>
+ );
+ }
+
+ renderOptions(val, index){
+ return (
+ <option key={index} value={val.enum}>{val.title}</option>
+ );
+ }
+
+
+ renderMultiSelectOptions(values) {
+ let {onOtherChange} = this.props;
+ let optionsList = [];
+ if (onOtherChange) {
+ optionsList = values.map(option => {
+ return {
+ label: option.title,
+ value: option.enum,
+ };
+ }).concat([{
+ label: i18n(other.OTHER),
+ value: i18n(other.OTHER),
+ }]);
+ }
+ else {
+ optionsList = values.map(option => {
+ return {
+ label: option.title,
+ value: option.enum,
+ };
+ });
+ }
+ if (optionsList.length > 0 && optionsList[0].value === '') {
+ optionsList.shift();
+ }
+ return optionsList;
+ }
+
+ renderErrorOverlay() {
+ let position = 'right';
+ const {errorText = '', isValid = true, type, overlayPos} = this.props;
+
+ if (overlayPos) {
+ position = overlayPos;
+ }
+ else if (type === 'text'
+ || type === 'email'
+ || type === 'number'
+ || type === 'password') {
+ position = 'bottom';
+ }
+
+ return (
+ <Overlay
+ show={!isValid}
+ placement={position}
+ target={() => {
+ let {otherInputDisabled} = this.state;
+ let target = otherInputDisabled ? ReactDOM.findDOMNode(this.input) : ReactDOM.findDOMNode(this.otherValue);
+ return target.offsetParent ? target : undefined;
+ }}
+ container={this}>
+ <Tooltip
+ id={`error-${errorText.replace(' ', '-')}`}
+ className='validation-error-message'>
+ {errorText}
+ </Tooltip>
+ </Overlay>
+ );
+ }
+
+ getValue() {
+ let res = '';
+ let {isMultiSelect} = this.props;
+ let {otherInputDisabled} = this.state;
+
+ if (otherInputDisabled) {
+ res = isMultiSelect ? this.input.getValue() : this.input.value;
+ } else {
+ res = this.otherValue.value;
+ }
+ return res;
+ }
+
+ enumChanged() {
+ let enumValue = this.input.value;
+ let {onEnumChange, onOtherChange, isMultiSelect, onChange} = this.props;
+ this.setState({
+ otherInputDisabled: !Boolean(onOtherChange) || enumValue !== other.OTHER
+ });
+
+ let value = isMultiSelect ? [enumValue] : enumValue;
+ if (onEnumChange) {
+ onEnumChange(value);
+ }
+ if (onChange) {
+ onChange(value);
+ }
+ }
+
+ multiSelectEnumChanged(enumValue) {
+ let {onEnumChange, onOtherChange} = this.props;
+ let selectedValues = enumValue.map(enumVal => {
+ return enumVal.value;
+ });
+
+ if (this.state.otherInputDisabled === false) {
+ selectedValues.shift();
+ }
+ else if (selectedValues.includes(i18n(other.OTHER))) {
+ selectedValues = [i18n(other.OTHER)];
+ }
+
+ this.setState({
+ otherInputDisabled: !Boolean(onOtherChange) || !selectedValues.includes(i18n(other.OTHER))
+ });
+ onEnumChange(selectedValues);
+ }
+
+ changedOtherInput() {
+ let {onOtherChange} = this.props;
+ onOtherChange(this.otherValue.value);
+ }
+
+ componentDidUpdate() {
+ let {otherValue, selectedEnum, onInputChange, multiSelectedEnum} = this.props;
+ if (this.oldProps.otherValue !== otherValue
+ || this.oldProps.selectedEnum !== selectedEnum
+ || this.oldProps.multiSelectedEnum !== multiSelectedEnum) {
+ this.oldProps = {
+ otherValue,
+ selectedEnum,
+ multiSelectedEnum
+ };
+ onInputChange();
+ }
+ }
+
+ static getTitleByName(values, name) {
+ for (let key of Object.keys(values)) {
+ let option = values[key].find(option => option.enum === name);
+ if (option) {
+ return option.title;
+ }
+ }
+ return name;
+ }
+
+}
+
+export default InputOptions;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
new file mode 100644
index 0000000000..5ca716cc20
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx
@@ -0,0 +1,134 @@
+/*!
+ * 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 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 FormGroup from 'react-bootstrap/lib/FormGroup.js';
+import FormControl from 'react-bootstrap/lib/FormControl.js';
+
+class InputWrapper extends React.Component {
+
+ state = {
+ value: this.props.value,
+ checked: this.props.checked,
+ selectedValues: []
+ }
+
+ render() {
+ const {label, hasError, validations = {}, isReadOnlyMode, value, onBlur, onKeyDown, type, disabled, checked, name} = this.props;
+ const {groupClassName, ...inputProps} = this.props;
+ return(
+ <FormGroup className={classNames('form-group', [groupClassName], {'required' : validations.required , 'has-error' : hasError})} >
+ {(label && (type !== 'checkbox' && type !== 'radio')) && <label className='control-label'>{label}</label>}
+ {(type === 'text' || type === 'number') &&
+ <FormControl
+ bsClass={'form-control input-options-other'}
+ onChange={(e) => this.onChange(e)}
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ onBlur={onBlur}
+ onKeyDown={onKeyDown}
+ value={value || ''}
+ ref={(input) => this.inputWrapper = input}
+ type={type}
+ data-test-id={this.props['data-test-id']}/>}
+
+ {type === 'textarea' &&
+ <FormControl
+ className='form-control input-options-other'
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ value={value || ''}
+ onBlur={onBlur}
+ onKeyDown={onKeyDown}
+ componentClass={type}
+ onChange={(e) => this.onChange(e)}
+ data-test-id={this.props['data-test-id']}/>}
+
+ {type === 'checkbox' &&
+ <Checkbox
+ className={classNames({'required' : validations.required , 'has-error' : hasError})}
+ onChange={(e)=>this.onChangeCheckBox(e)}
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ checked={value}
+ data-test-id={this.props['data-test-id']}>{label}</Checkbox>}
+
+ {type === 'radio' &&
+ <Radio name={name}
+ checked={checked}
+ disabled={isReadOnlyMode || Boolean(disabled)}
+ value={value}
+ onChange={(e)=>this.onChangeRadio(e)}
+ data-test-id={this.props['data-test-id']}>{label}</Radio>}
+ {type === 'select' &&
+ <FormControl onClick={ (e) => this.optionSelect(e) }
+ componentClass={type}
+ name={name} {...inputProps}
+ data-test-id={this.props['data-test-id']}/>}
+
+ </FormGroup>
+
+ );
+ }
+
+ getValue() {
+ return this.props.type !== 'select' ? this.state.value : this.state.selectedValues;
+ }
+
+ getChecked() {
+ return this.state.checked;
+ }
+
+ optionSelect(e) {
+ let selectedValues = [];
+ if (e.target.value) {
+ selectedValues.push(e.target.value);
+ }
+ this.setState({
+ selectedValues
+ });
+ }
+
+ onChange(e) {
+ let {onChange} = this.props;
+ this.setState({
+ value: e.target.value
+ });
+ onChange(e.target.value);
+ }
+
+ onChangeCheckBox(e) {
+ let {onChange} = this.props;
+ this.setState({
+ checked: e.target.checked
+ });
+ onChange(e.target.checked);
+ }
+
+ onChangeRadio(e) {
+ let {onChange} = this.props;
+ this.setState({
+ checked: e.target.checked
+ });
+ onChange(this.state.value);
+ }
+
+ focus() {
+ ReactDOM.findDOMNode(this.inputWrapper).focus();
+ }
+
+}
+export default InputWrapper;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
new file mode 100644
index 0000000000..95144b1468
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx
@@ -0,0 +1,79 @@
+/*!
+ * 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 ReactDOM from 'react-dom';
+import {default as BTabs} from 'react-bootstrap/lib/Tabs.js';
+import Overlay from 'react-bootstrap/lib/Overlay.js';
+import Tooltip from 'react-bootstrap/lib/Tooltip.js';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+export default
+class Tabs extends React.Component {
+
+ static propTypes = {
+ children: React.PropTypes.node
+ };
+
+ cloneTab(element) {
+ const {invalidTabs} = this.props;
+ return React.cloneElement(
+ element,
+ {
+ key: element.props.eventKey,
+ tabClassName: invalidTabs.indexOf(element.props.eventKey) > -1 ? 'invalid-tab' : 'valid-tab'
+ }
+ );
+ }
+
+ showTabsError() {
+ const {invalidTabs} = this.props;
+ const showError = ((invalidTabs.length === 1 && invalidTabs[0] !== this.props.activeKey) || (invalidTabs.length > 1));
+ return showError;
+ }
+
+ render() {
+ // eslint-disable-next-line no-unused-vars
+ let {invalidTabs, ...tabProps} = this.props;
+ return (
+ <div>
+ <BTabs {...tabProps} ref='tabsList' id='tabsList' >
+ {this.props.children.map(element => this.cloneTab(element))}
+ </BTabs>
+ <Overlay
+ animation={false}
+ show={this.showTabsError()}
+ placement='bottom'
+ containerPadding={50}
+ target={() => {
+ let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.active):nth-of-type(n)');
+ return target && target.offsetParent ? target : undefined;
+ }
+ }
+ container={() => {
+ let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.active):nth-of-type(n)');
+ return target && target.offsetParent ? target.offsetParent : this;
+ }}>
+ <Tooltip
+ id='error-some-tabs-contain-errors'
+ className='validation-error-message'>
+ {i18n('One or more tabs are invalid')}
+ </Tooltip>
+ </Overlay>
+ </div>
+ );
+ }
+}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
index a87c8d6f40..ebb1473c04 100644
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
+++ b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx
@@ -1,3 +1,18 @@
+/*!
+ * 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.
+ */
/**
* Holds the buttons for save/reset for forms.
* Used by the ValidationForm that changes the state of the buttons according to its own state.
@@ -8,7 +23,7 @@
import React from 'react';
import i18n from 'nfvo-utils/i18n/i18n.js';
import Button from 'react-bootstrap/lib/Button.js';
-import FontAwesome from 'react-fontawesome';
+import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
class ValidationButtons extends React.Component {
@@ -22,8 +37,8 @@ class ValidationButtons extends React.Component {
};
render() {
- var submitBtn = this.props.labledButtons ? i18n('Save') : <FontAwesome className='check' name='check'/>;
- var closeBtn = this.props.labledButtons ? i18n('Cancel') : <FontAwesome className='close' name='close'/>;
+ var submitBtn = this.props.labledButtons ? i18n('Save') : <SVGIcon className='check' name='check'/>;
+ var closeBtn = this.props.labledButtons ? i18n('Cancel') : <SVGIcon className='close' name='close'/>;
return (
<div className='validation-buttons'>
{!this.props.isReadOnlyMode ?
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx
deleted file mode 100644
index 098ccf1fd4..0000000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationForm.jsx
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * ValidationForm should be used in order to have a form that handles it's internal validation state.
- * All ValidationInputs inside the form are checked for validity and the styling and submit buttons
- * are updated accordingly.
- *
- * The properties that ahould be given to the form:
- * labledButtons - whether or not use icons only as the form default buttons or use buttons with labels
- * onSubmit - function for click on the submit button
- * onReset - function for click on the reset button
- */
-import React from 'react';
-import JSONSchema from 'nfvo-utils/json/JSONSchema.js';
-import JSONPointer from 'nfvo-utils/json/JSONPointer.js';
-import ValidationButtons from './ValidationButtons.jsx';
-
-class ValidationForm extends React.Component {
-
- static childContextTypes = {
- validationParent: React.PropTypes.any,
- isReadOnlyMode: React.PropTypes.bool,
- validationSchema: React.PropTypes.instanceOf(JSONSchema),
- validationData: React.PropTypes.object
- };
-
- static defaultProps = {
- hasButtons : true,
- onSubmit : null,
- onReset : null,
- labledButtons: true,
- onValidChange : null,
- isValid: true
- };
-
- static propTypes = {
- isValid : React.PropTypes.bool,
- isReadOnlyMode : React.PropTypes.bool,
- hasButtons : React.PropTypes.bool,
- onSubmit : React.PropTypes.func,
- onReset : React.PropTypes.func,
- labledButtons: React.PropTypes.bool,
- onValidChange : React.PropTypes.func,
- onValidityChanged: React.PropTypes.func,
- schema: React.PropTypes.object,
- data: React.PropTypes.object
- };
-
- state = {
- isValid: this.props.isValid
- };
-
- constructor(props) {
- super(props);
- this.validationComponents = [];
- }
-
- componentWillMount() {
- let {schema, data} = this.props;
- if (schema) {
- this.processSchema(schema, data);
- }
- }
-
- componentWillReceiveProps(nextProps) {
- let {schema, data} = this.props;
- let {schema: nextSchema, data: nextData} = nextProps;
-
- if (schema !== nextSchema || data !== nextData) {
- if (!schema || !nextSchema) {
- throw new Error('ValidationForm: dynamically adding/removing schema is not supported');
- }
-
- if (schema !== nextSchema) {
- this.processSchema(nextSchema, nextData);
- } else {
- this.setState({data: nextData});
- }
- }
- }
-
- processSchema(rawSchema, rawData) {
- let schema = new JSONSchema();
- schema.setSchema(rawSchema);
- let data = schema.processData(rawData);
- this.setState({
- schema,
- data
- });
- }
-
- render() {
- // eslint-disable-next-line no-unused-vars
- let {isValid, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, schema, data, children, ...formProps} = this.props;
- return (
- <form {...formProps} onSubmit={event => this.handleFormSubmit(event)}>
- <div className='validation-form-content'>{children}</div>
- {hasButtons && <ValidationButtons labledButtons={labledButtons} ref='buttons' isReadOnlyMode={isReadOnlyMode}/>}
- </form>
- );
- }
-
- handleFormSubmit(event) {
- event.preventDefault();
- let isFormValid = true;
- this.validationComponents.forEach(validationComponent => {
- const isInputValid = validationComponent.validate().isValid;
- isFormValid = isInputValid && isFormValid;
- });
- if(isFormValid && this.props.onSubmit) {
- return this.props.onSubmit(event);
- } else if(!isFormValid) {
- this.setState({isValid: false});
- }
- }
-
- componentWillUpdate(nextProps, nextState) {
- if(this.state.isValid !== nextState.isValid && this.props.onValidityChanged) {
- this.props.onValidityChanged(nextState.isValid);
- }
- }
-
- componentDidUpdate(prevProps, prevState) {
- // only handling this programatically if the validation of the form is done outside of the view
- // (example with a form that is dependent on the state of other forms)
- if (prevProps.isValid !== this.props.isValid) {
- if (this.props.hasButtons) {
- this.refs.buttons.setState({isValid: this.state.isValid});
- }
- } else if(this.state.isValid !== prevState.isValid) {
- if (this.props.hasButtons) {
- this.refs.buttons.setState({isValid: this.state.isValid});
- }
- // callback in case form is part of bigger picture in view
- if (this.props.onValidChange) {
- this.props.onValidChange(this.state.isValid);
- }
- }
- }
-
- componentDidMount() {
- if (this.props.hasButtons) {
- this.refs.buttons.setState({isValid: this.state.isValid});
- }
- }
-
-
- getChildContext() {
- return {
- validationParent: this,
- isReadOnlyMode: this.props.isReadOnlyMode,
- validationSchema: this.state.schema,
- validationData: this.state.data
- };
- }
-
-
- /***
- * Used by ValidationInput in order to let the (parent) form know
- * the valid state. If there is a change in the state of the form,
- * the buttons will be updated.
- *
- * @param validationComponent
- * @param isValid
- */
- childValidStateChanged(validationComponent, isValid) {
- if (isValid !== this.state.isValid) {
- let oldState = this.state.isValid;
- let newState = isValid && this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent).every(otherValidationComponent => {
- return otherValidationComponent.isValid();
- });
-
- if (oldState !== newState) {
- this.setState({isValid: newState});
- }
- }
- }
-
- register(validationComponent) {
- if (this.state.schema) {
- // TODO: register
- } else {
- this.validationComponents.push(validationComponent);
- }
- }
-
- unregister(validationComponent) {
- this.childValidStateChanged(validationComponent, true);
- this.validationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent);
- }
-
- onValueChanged(pointer, value, isValid, error) {
- this.props.onDataChanged({
- data: JSONPointer.setValue(this.props.data, pointer, value),
- isValid,
- error
- });
- }
-}
-
-
-export default ValidationForm;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx
deleted file mode 100644
index 0f14307645..0000000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationInput.jsx
+++ /dev/null
@@ -1,509 +0,0 @@
-/**
- * Used for inputs on a validation form.
- * All properties will be passed on to the input element.
- *
- * The following properties can be set for OOB validations and callbacks:
- - required: Boolean: Should be set to true if the input must have a value
- - numeric: Boolean : Should be set to true id the input should be an integer
- - onChange : Function : Will be called to validate the value if the default validations are not sufficient, should return a boolean value
- indicating whether the value is valid
- - didUpdateCallback :Function: Will be called after the state has been updated and the component has rerendered. This can be used if
- there are dependencies between inputs in a form.
- *
- * The following properties of the state can be set to determine
- * the state of the input from outside components:
- - isValid : Boolean - whether the value is valid
- - value : value for the input field,
- - disabled : Boolean,
- - required : Boolean - whether the input value must be filled out.
- */
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Validator from 'validator';
-import FormGroup from 'react-bootstrap/lib/FormGroup.js';
-import Input from 'react-bootstrap/lib/Input.js';
-import Overlay from 'react-bootstrap/lib/Overlay.js';
-import Tooltip from 'react-bootstrap/lib/Tooltip.js';
-import isEqual from 'lodash/isEqual.js';
-import i18n from 'nfvo-utils/i18n/i18n.js';
-import JSONSchema from 'nfvo-utils/json/JSONSchema.js';
-import JSONPointer from 'nfvo-utils/json/JSONPointer.js';
-
-
-import InputOptions from '../inputOptions/InputOptions.jsx';
-
-const globalValidationFunctions = {
- required: value => value !== '',
- maxLength: (value, length) => Validator.isLength(value, {max: length}),
- minLength: (value, length) => Validator.isLength(value, {min: length}),
- pattern: (value, pattern) => Validator.matches(value, pattern),
- numeric: value => {
- if (value === '') {
- // to allow empty value which is not zero
- return true;
- }
- return Validator.isNumeric(value);
- },
- maxValue: (value, maxValue) => value < maxValue,
- minValue: (value, minValue) => value >= minValue,
- alphanumeric: value => Validator.isAlphanumeric(value),
- alphanumericWithSpaces: value => Validator.isAlphanumeric(value.replace(/ /g, '')),
- validateName: value => Validator.isAlphanumeric(value.replace(/\s|\.|\_|\-/g, ''), 'en-US'),
- validateVendorName: value => Validator.isAlphanumeric(value.replace(/[\x7F-\xFF]|\s/g, ''), 'en-US'),
- freeEnglishText: value => Validator.isAlphanumeric(value.replace(/\s|\.|\_|\-|\,|\(|\)|\?/g, ''), 'en-US'),
- email: value => Validator.isEmail(value),
- ip: value => Validator.isIP(value),
- url: value => Validator.isURL(value)
-};
-
-const globalValidationMessagingFunctions = {
- required: () => i18n('Field is required'),
- maxLength: (value, maxLength) => i18n('Field value has exceeded it\'s limit, {maxLength}. current length: {length}', {
- length: value.length,
- maxLength
- }),
- minLength: (value, minLength) => i18n('Field value should contain at least {minLength} characters.', {minLength}),
- pattern: (value, pattern) => i18n('Field value should match the pattern: {pattern}.', {pattern}),
- numeric: () => i18n('Field value should contain numbers only.'),
- maxValue: (value, maxValue) => i18n('Field value should be less than: {maxValue}.', {maxValue}),
- minValue: (value, minValue) => i18n('Field value should be at least: {minValue}.', {minValue}),
- alphanumeric: () => i18n('Field value should contain letters or digits only.'),
- alphanumericWithSpaces: () => i18n('Field value should contain letters, digits or spaces only.'),
- validateName: ()=> i18n('Field value should contain English letters, digits , spaces, underscores, dashes and dots only.'),
- validateVendorName: ()=> i18n('Field value should contain English letters digits and spaces only.'),
- freeEnglishText: ()=> i18n('Field value should contain English letters, digits , spaces, underscores, dashes and dots only.'),
- email: () => i18n('Field value should be a valid email address.'),
- ip: () => i18n('Field value should be a valid ip address.'),
- url: () => i18n('Field value should be a valid url address.'),
- general: () => i18n('Field value is invalid.')
-};
-
-class ValidationInput extends React.Component {
-
- static contextTypes = {
- validationParent: React.PropTypes.any,
- isReadOnlyMode: React.PropTypes.bool,
- validationSchema: React.PropTypes.instanceOf(JSONSchema),
- validationData: React.PropTypes.object
- };
-
- static defaultProps = {
- onChange: null,
- disabled: null,
- didUpdateCallback: null,
- validations: {},
- value: ''
- };
-
- static propTypes = {
- type: React.PropTypes.string.isRequired,
- onChange: React.PropTypes.func,
- disabled: React.PropTypes.bool,
- didUpdateCallback: React.PropTypes.func,
- validations: React.PropTypes.object,
- isMultiSelect: React.PropTypes.bool,
- onOtherChange: React.PropTypes.func,
- pointer: React.PropTypes.string
- };
-
-
- state = {
- isValid: true,
- style: null,
- value: this.props.value,
- error: {},
- previousErrorMessage: '',
- wasInvalid: false,
- validations: this.props.validations,
- isMultiSelect: this.props.isMultiSelect
- };
-
- componentWillMount() {
- if (this.context.validationSchema) {
- let {validationSchema: schema, validationData: data} = this.context,
- {pointer} = this.props;
-
- if (!schema.exists(pointer)) {
- console.error(`Field doesn't exists in the schema ${pointer}`);
- }
-
- let value = JSONPointer.getValue(data, pointer);
- if (value === undefined) {
- value = schema.getDefault(pointer);
- if (value === undefined) {
- value = '';
- }
- }
- this.setState({value});
-
- let enums = schema.getEnum(pointer);
- if (enums) {
- let values = enums.map(value => ({enum: value, title: value, groupName: pointer})),
- isMultiSelect = schema.isArray(pointer);
-
- if (!isMultiSelect && this.props.type !== 'radiogroup') {
- values = [{enum: '', title: i18n('Select...')}, ...values];
- }
- if (isMultiSelect && Array.isArray(value) && value.length === 0) {
- value = '';
- }
-
- this.setState({
- isMultiSelect,
- values,
- onEnumChange: value => this.changedInputOptions(value),
- value
- });
- }
-
- this.setState({validations: this.extractValidationsFromSchema(schema, pointer, this.props)});
- }
- }
-
- extractValidationsFromSchema(schema, pointer, props) {
- /* props are here to get precedence over the scheme definitions */
- let validations = {};
-
- if (schema.isRequired(pointer)) {
- validations.required = true;
- }
-
- if (schema.isNumber(pointer)) {
- validations.numeric = true;
-
- const maxValue = props.validations.maxValue || schema.getMaxValue(pointer);
- if (maxValue !== undefined) {
- validations.maxValue = maxValue;
- }
-
- const minValue = props.validations.minValue || schema.getMinValue(pointer);
- if (minValue !== undefined) {
- validations.minValue = minValue;
- }
- }
-
-
- if (schema.isString(pointer)) {
-
- const pattern = schema.getPattern(pointer);
- if (pattern) {
- validations.pattern = pattern;
- }
-
- const maxLength = schema.getMaxLength(pointer);
- if (maxLength !== undefined) {
- validations.maxLength = maxLength;
- }
-
- const minLength = schema.getMinLength(pointer);
- if (minLength !== undefined) {
- validations.minLength = minLength;
- }
- }
-
- return validations;
- }
-
- componentWillReceiveProps({value: nextValue, validations: nextValidations, pointer: nextPointer}, nextContext) {
- const {validations, value} = this.props;
- const validationsChanged = !isEqual(validations, nextValidations);
- if (nextContext.validationSchema) {
- if (this.props.pointer !== nextPointer ||
- this.context.validationData !== nextContext.validationData) {
- let currentValue = JSONPointer.getValue(this.context.validationData, this.props.pointer),
- nextValue = JSONPointer.getValue(nextContext.validationData, nextPointer);
- if(nextValue === undefined) {
- nextValue = '';
- }
- if (this.state.isMultiSelect && Array.isArray(nextValue) && nextValue.length === 0) {
- nextValue = '';
- }
- if (currentValue !== nextValue) {
- this.setState({value: nextValue});
- }
- if (validationsChanged) {
- this.setState({
- validations: this.extractValidationsFromSchema(nextContext.validationSchema, nextPointer, {validations: nextValidations})
- });
- }
- }
- } else {
- if (validationsChanged) {
- this.setState({validations: nextValidations});
- }
- if (this.state.wasInvalid && (value !== nextValue || validationsChanged)) {
- this.validate(nextValue, nextValidations);
- } else if (value !== nextValue) {
- this.setState({value: nextValue});
- }
- }
- }
-
- shouldTypeBeNumberBySchemeDefinition(pointer) {
- return this.context.validationSchema &&
- this.context.validationSchema.isNumber(pointer);
- }
-
- hasEnum(pointer) {
- return this.context.validationSchema &&
- this.context.validationSchema.getEnum(pointer);
- }
-
- render() {
- let {value, isMultiSelect, values, onEnumChange, style, isValid, validations} = this.state;
- let {onOtherChange, type, pointer} = this.props;
- if (this.shouldTypeBeNumberBySchemeDefinition(pointer) && !this.hasEnum(pointer)) {
- type = 'number';
- }
- let props = {...this.props};
-
- let groupClasses = this.props.groupClassName || '';
- if (validations.required) {
- groupClasses += ' required';
- }
- let isReadOnlyMode = this.context.isReadOnlyMode;
-
- if (value === true && (type === 'checkbox' || type === 'radio')) {
- props.checked = true;
- }
- return (
- <div className='validation-input-wrapper'>
- {
- !isMultiSelect && !onOtherChange && type !== 'select' && type !== 'radiogroup'
- && <Input
- {...props}
- type={type}
- groupClassName={groupClasses}
- ref={'_myInput'}
- value={value}
- disabled={isReadOnlyMode || Boolean(this.props.disabled)}
- bsStyle={style}
- onChange={() => this.changedInput()}
- onBlur={() => this.blurInput()}>
- {this.props.children}
- </Input>
- }
- {
- type === 'radiogroup'
- && <FormGroup>
- {
- values.map(val =>
- <Input disabled={isReadOnlyMode || Boolean(this.props.disabled)}
- inline={true}
- ref={'_myInput' + (typeof val.enum === 'string' ? val.enum.replace(/\W/g, '_') : val.enum)}
- value={val.enum} checked={value === val.enum}
- type='radio' label={val.title}
- name={val.groupName}
- onChange={() => this.changedInput()}/>
- )
- }
- </FormGroup>
- }
- {
- (isMultiSelect || onOtherChange || type === 'select')
- && <InputOptions
- onInputChange={() => this.changedInput()}
- onBlur={() => this.blurInput()}
- hasError={!isValid}
- ref={'_myInput'}
- isMultiSelect={isMultiSelect}
- values={values}
- onEnumChange={onEnumChange}
- selectedEnum={value}
- multiSelectedEnum={value}
- {...props} />
- }
- {this.renderOverlay()}
- </div>
- );
- }
-
- renderOverlay() {
- let position = 'right';
- if (this.props.type === 'text'
- || this.props.type === 'email'
- || this.props.type === 'number'
- || this.props.type === 'password'
-
- ) {
- position = 'bottom';
- }
-
- let validationMessage = this.state.error.message || this.state.previousErrorMessage;
- return (
- <Overlay
- show={!this.state.isValid}
- placement={position}
- target={() => {
- let target = ReactDOM.findDOMNode(this.refs._myInput);
- return target.offsetParent ? target : undefined;
- }}
- container={this}>
- <Tooltip
- id={`error-${validationMessage.replace(' ', '-')}`}
- className='validation-error-message'>
- {validationMessage}
- </Tooltip>
- </Overlay>
- );
- }
-
- componentDidMount() {
- if (this.context.validationParent) {
- this.context.validationParent.register(this);
- }
- }
-
- componentDidUpdate(prevProps, prevState) {
- if (this.context.validationParent) {
- if (prevState.isValid !== this.state.isValid) {
- this.context.validationParent.childValidStateChanged(this, this.state.isValid);
- }
- }
- if (this.props.didUpdateCallback) {
- this.props.didUpdateCallback();
- }
-
- }
-
- componentWillUnmount() {
- if (this.context.validationParent) {
- this.context.validationParent.unregister(this);
- }
- }
-
- isNumberInputElement() {
- return this.props.type === 'number' || this.refs._myInput.props.type === 'number';
- }
-
- /***
- * Adding same method as the actual input component
- * @returns {*}
- */
- getValue() {
- if (this.props.type === 'checkbox') {
- return this.refs._myInput.getChecked();
- }
- if (this.props.type === 'radiogroup') {
- for (let key in this.refs) { // finding the value of the radio button that was checked
- if (this.refs[key].getChecked()) {
- return this.refs[key].getValue();
- }
- }
- }
- if (this.isNumberInputElement()) {
- return Number(this.refs._myInput.getValue());
- }
-
- return this.refs._myInput.getValue();
- }
-
- resetValue() {
- this.setState({value: this.props.value});
- }
-
-
- /***
- * internal method that validated the value. includes callback to the onChange method
- * @param value
- * @param validations - map containing validation id and the limitation describing the validation.
- * @returns {object}
- */
- validateValue = (value, validations) => {
- let {customValidationFunction} = validations;
- let error = {};
- let isValid = true;
- for (let validation in validations) {
- if ('customValidationFunction' !== validation) {
- if (validations[validation]) {
- if (!globalValidationFunctions[validation](value, validations[validation])) {
- error.id = validation;
- error.message = globalValidationMessagingFunctions[validation](value, validations[validation]);
- isValid = false;
- break;
- }
- }
- } else {
- let customValidationResult = customValidationFunction(value);
-
- if (customValidationResult !== true) {
- error.id = 'custom';
- isValid = false;
- if (typeof customValidationResult === 'string') {//custom validation error message supplied.
- error.message = customValidationResult;
- } else {
- error.message = globalValidationMessagingFunctions.general();
- }
- break;
- }
-
-
- }
- }
-
- return {
- isValid,
- error
- };
- };
-
- /***
- * Internal method that handles the change event of the input. validates and updates the state.
- */
- changedInput() {
-
- let {isValid, error} = this.state.wasInvalid ? this.validate() : this.state;
- let onChange = this.props.onChange;
- if (onChange) {
- onChange(this.getValue(), isValid, error);
- }
- if (this.context.validationSchema) {
- let value = this.getValue();
- if (this.state.isMultiSelect && value === '') {
- value = [];
- }
- if (this.shouldTypeBeNumberBySchemeDefinition(this.props.pointer)) {
- value = Number(value);
- }
- this.context.validationParent.onValueChanged(this.props.pointer, value, isValid, error);
- }
- }
-
- changedInputOptions(value) {
- this.context.validationParent.onValueChanged(this.props.pointer, value, true);
- }
-
- blurInput() {
- if (!this.state.wasInvalid) {
- this.setState({wasInvalid: true});
- }
-
- let {isValid, error} = !this.state.wasInvalid ? this.validate() : this.state;
- let onBlur = this.props.onBlur;
- if (onBlur) {
- onBlur(this.getValue(), isValid, error);
- }
- }
-
- validate(value = this.getValue(), validations = this.state.validations) {
- let validationStatus = this.validateValue(value, validations);
- let {isValid, error} = validationStatus;
- let _style = isValid ? null : 'error';
- this.setState({
- isValid,
- error,
- value,
- previousErrorMessage: this.state.error.message || '',
- style: _style,
- wasInvalid: !isValid || this.state.wasInvalid
- });
-
- return validationStatus;
- }
-
- isValid() {
- return this.state.isValid;
- }
-
-}
-export default ValidationInput;
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx
deleted file mode 100644
index 6036518288..0000000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationTab.jsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import React from 'react';
-import Tab from 'react-bootstrap/lib/Tab.js';
-
-export default
-class ValidationTab extends React.Component {
-
- static propTypes = {
- children: React.PropTypes.node,
- eventKey: React.PropTypes.any.isRequired,
- onValidationStateChange: React.PropTypes.func //This property is assigned dynamically via React.cloneElement. lookup ValidationTabs.jsx. therefore it cannot be stated as required!
- };
-
- constructor(props) {
- super(props);
- this.validationComponents = [];
- }
-
- static childContextTypes = {
- validationParent: React.PropTypes.any
- };
-
- static contextTypes = {
- validationParent: React.PropTypes.any
- };
-
- getChildContext() {
- return {validationParent: this};
- }
-
- state = {
- isValid: true,
- notifyParent: false
- };
-
- componentDidMount() {
- let validationParent = this.context.validationParent;
- if (validationParent) {
- validationParent.register(this);
- }
- }
-
- componentWillUnmount() {
- let validationParent = this.context.validationParent;
- if (validationParent) {
- validationParent.unregister(this);
- }
- }
-
- register(validationComponent) {
- this.validationComponents.push(validationComponent);
- }
-
- unregister(validationComponent) {
- this.childValidStateChanged(validationComponent, true);
- this.validationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent);
- }
-
- notifyValidStateChangedToParent(isValid) {
-
- let validationParent = this.context.validationParent;
- if (validationParent) {
- validationParent.childValidStateChanged(this, isValid);
- }
- }
-
- childValidStateChanged(validationComponent, isValid) {
-
- const currentValidState = this.state.isValid;
- if (isValid !== currentValidState) {
- let filteredValidationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent);
- let newValidState = isValid && filteredValidationComponents.every(otherValidationComponent => {
- return otherValidationComponent.isValid();
- });
- this.setState({isValid: newValidState, notifyParent: true});
- }
- }
-
- validate() {
- let isValid = true;
- this.validationComponents.forEach(validationComponent => {
- const isValidationComponentValid = validationComponent.validate().isValid;
- isValid = isValidationComponentValid && isValid;
- });
- this.setState({isValid, notifyParent: false});
- return {isValid};
- }
-
- componentDidUpdate(prevProps, prevState) {
- if(prevState.isValid !== this.state.isValid) {
- if(this.state.notifyParent) {
- this.notifyValidStateChangedToParent(this.state.isValid);
- }
- this.props.onValidationStateChange(this.props.eventKey, this.state.isValid);
- }
- }
-
- isValid() {
- return this.state.isValid;
- }
-
- render() {
- let {children, ...tabProps} = this.props;
- return (
- <Tab {...tabProps}>{children}</Tab>
- );
- }
-}
diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx
deleted file mode 100644
index 6eda4b9827..0000000000
--- a/openecomp-ui/src/nfvo-components/input/validation/ValidationTabs.jsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Tabs from 'react-bootstrap/lib/Tabs.js';
-import Overlay from 'react-bootstrap/lib/Overlay.js';
-import Tooltip from 'react-bootstrap/lib/Tooltip.js';
-
-import i18n from 'nfvo-utils/i18n/i18n.js';
-
-export default
-class ValidationTab extends React.Component {
-
- static propTypes = {
- children: React.PropTypes.node
- };
-
- state = {
- invalidTabs: []
- };
-
- cloneTab(element) {
- const {invalidTabs} = this.state;
- return React.cloneElement(
- element,
- {
- key: element.props.eventKey,
- tabClassName: invalidTabs.indexOf(element.props.eventKey) > -1 ? 'invalid-tab' : 'valid-tab',
- onValidationStateChange: (eventKey, isValid) => this.validTabStateChanged(eventKey, isValid)
- }
- );
- }
-
- validTabStateChanged(eventKey, isValid) {
- let {invalidTabs} = this.state;
- let invalidTabIndex = invalidTabs.indexOf(eventKey);
- if (isValid && invalidTabIndex > -1) {
- this.setState({invalidTabs: invalidTabs.filter(otherEventKey => eventKey !== otherEventKey)});
- } else if (!isValid && invalidTabIndex === -1) {
- this.setState({invalidTabs: [...invalidTabs, eventKey]});
- }
- }
-
- showTabsError() {
- const {invalidTabs} = this.state;
- return invalidTabs.length > 0 && (invalidTabs.length > 1 || invalidTabs[0] !== this.props.activeKey);
- }
-
- render() {
- return (
- <div>
- <Tabs {...this.props} ref='tabsList'>
- {this.props.children.map(element => this.cloneTab(element))}
- </Tabs>
- <Overlay
- animation={false}
- show={this.showTabsError()}
- placement='bottom'
- target={() => {
- let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.active):nth-of-type(n)');
- return target && target.offsetParent ? target : undefined;
- }
- }
- container={this}>
- <Tooltip
- id='error-some-tabs-contain-errors'
- className='validation-error-message'>
- {i18n('One or more tabs are invalid')}
- </Tooltip>
- </Overlay>
- </div>
- );
- }
-}