2 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing
14 * permissions and limitations under the License.
16 import React from 'react';
17 import PropTypes from 'prop-types';
18 import ReactDOM from 'react-dom';
19 import i18n from 'nfvo-utils/i18n/i18n.js';
20 import classNames from 'classnames';
21 import Select from 'nfvo-components/input/SelectInput.jsx';
22 import Overlay from 'react-bootstrap/lib/Overlay.js';
23 import Tooltip from 'react-bootstrap/lib/Tooltip.js';
25 export const other = {OTHER: 'Other'};
27 class InputOptions extends React.Component {
30 values: PropTypes.arrayOf(PropTypes.shape({
31 enum: PropTypes.string,
32 title: PropTypes.string
34 isEnabledOther: PropTypes.bool,
35 label: PropTypes.string,
36 selectedValue: PropTypes.string,
37 multiSelectedEnum: PropTypes.oneOfType([
41 selectedEnum: PropTypes.string,
42 otherValue: PropTypes.string,
43 overlayPos: PropTypes.string,
44 onEnumChange: PropTypes.func,
45 onOtherChange: PropTypes.func,
46 onBlur: PropTypes.func,
47 isRequired: PropTypes.bool,
48 isMultiSelect: PropTypes.bool,
49 isValid: PropTypes.bool,
50 disabled: PropTypes.bool
54 otherInputDisabled: !this.props.otherValue
64 let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, isValid, children, isReadOnlyMode} = this.props;
65 const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {};
66 let currentMultiSelectedEnum = [];
67 let currentSelectedEnum = '';
68 let otherInputDisabled = (isMultiSelect && (multiSelectedEnum === undefined || multiSelectedEnum.length === 0 || multiSelectedEnum[0] !== other.OTHER))
69 || (!isMultiSelect && (selectedEnum === undefined || selectedEnum !== other.OTHER));
71 currentMultiSelectedEnum = multiSelectedEnum;
72 if(!otherInputDisabled) {
73 currentSelectedEnum = multiSelectedEnum ? multiSelectedEnum.toString() : undefined;
76 else if(selectedEnum){
77 currentSelectedEnum = selectedEnum;
84 <div className='validation-input-wrapper' >
85 <div className={classNames('form-group', {'required' : isRequired, 'has-error' : !isValid})} >
86 {label && <label className='control-label'>{label}</label>}
87 {isMultiSelect && otherInputDisabled ?
90 ref={(input) => this.input = input}
91 value={currentMultiSelectedEnum}
92 className='options-input'
95 disabled={isReadOnlyMode || Boolean(this.props.disabled)}
96 onBlur={() => onBlur()}
97 onMultiSelectChanged={value => this.multiSelectEnumChanged(value)}
98 options={this.renderMultiSelectOptions(values)}
100 <div className={classNames('input-options',{'has-error' : !isValid})} >
103 ref={(input) => this.input = input}
105 className='form-control input-options-select'
106 value={currentSelectedEnum}
107 style={{'width' : otherInputDisabled ? '100%' : '100px'}}
108 onBlur={() => onBlur()}
109 disabled={isReadOnlyMode || Boolean(this.props.disabled)}
110 onChange={ value => this.enumChanged(value)}
112 {children || (values && values.length && values.map((val, index) => this.renderOptions(val, index)))}
113 {onOtherChange && <option key='other' value={other.OTHER}>{i18n(other.OTHER)}</option>}
116 {!otherInputDisabled && <div className='input-options-separator'/>}
118 className='form-control input-options-other'
119 placeholder={i18n('other')}
120 ref={(otherValue) => this.otherValue = otherValue}
121 style={{'display' : otherInputDisabled ? 'none' : 'block'}}
122 disabled={isReadOnlyMode || Boolean(this.props.disabled)}
123 value={otherValue || ''}
124 onBlur={() => onBlur()}
125 onChange={() => this.changedOtherInput()}/>
129 { this.renderErrorOverlay() }
134 renderOptions(val, index){
136 <option key={index} value={val.enum}>{val.title}</option>
141 renderMultiSelectOptions(values) {
142 let {onOtherChange} = this.props;
143 let optionsList = [];
145 optionsList = values.map(option => {
151 label: i18n(other.OTHER),
152 value: i18n(other.OTHER),
156 optionsList = values.map(option => {
163 if (optionsList.length > 0 && optionsList[0].value === '') {
169 renderErrorOverlay() {
170 let position = 'right';
171 const {errorText = '', isValid = true, type, overlayPos} = this.props;
174 position = overlayPos;
176 else if (type === 'text'
179 || type === 'password') {
188 let {otherInputDisabled} = this.state;
189 let target = otherInputDisabled ? ReactDOM.findDOMNode(this.input) : ReactDOM.findDOMNode(this.otherValue);
190 return target.offsetParent ? target : undefined;
194 id={`error-${errorText.replace(' ', '-')}`}
195 className='validation-error-message'>
204 let {isMultiSelect} = this.props;
205 let {otherInputDisabled} = this.state;
207 if (otherInputDisabled) {
208 res = isMultiSelect ? this.input.getValue() : this.input.value;
210 res = this.otherValue.value;
216 let enumValue = this.input.value;
217 let {onEnumChange, onOtherChange, isMultiSelect, onChange} = this.props;
219 otherInputDisabled: !Boolean(onOtherChange) || enumValue !== other.OTHER
222 let value = isMultiSelect ? [enumValue] : enumValue;
231 multiSelectEnumChanged(enumValue) {
232 let {onEnumChange, onOtherChange} = this.props;
233 let selectedValues = enumValue.map(enumVal => {
234 return enumVal.value;
237 if (this.state.otherInputDisabled === false) {
238 selectedValues.shift();
240 else if (selectedValues.includes(i18n(other.OTHER))) {
241 selectedValues = [i18n(other.OTHER)];
245 otherInputDisabled: !Boolean(onOtherChange) || !selectedValues.includes(i18n(other.OTHER))
247 onEnumChange(selectedValues);
250 changedOtherInput() {
251 let {onOtherChange} = this.props;
252 onOtherChange(this.otherValue.value);
255 componentDidUpdate() {
256 let {otherValue, selectedEnum, onInputChange, multiSelectedEnum} = this.props;
257 if (this.oldProps.otherValue !== otherValue
258 || this.oldProps.selectedEnum !== selectedEnum
259 || this.oldProps.multiSelectedEnum !== multiSelectedEnum) {
269 static getTitleByName(values, name) {
270 for (let key of Object.keys(values)) {
271 let option = values[key].find(option => option.enum === name);
281 export default InputOptions;