2 * Copyright © 2016-2018 European Support Limited
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 or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 import React from 'react';
17 import PropTypes from 'prop-types';
18 import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
19 import Input from 'nfvo-components/input/validation/Input.jsx';
21 class DualListboxView extends React.Component {
24 this.availableListRef = React.createRef();
25 this.availableListFilterRef = React.createRef();
26 this.selectedValuesListFilterRef = React.createRef();
27 this.selectedValuesRef = React.createRef();
30 availableList: PropTypes.arrayOf(
32 id: PropTypes.string.isRequired,
33 name: PropTypes.string.isRequired
36 filterTitle: PropTypes.shape({
37 left: PropTypes.string,
38 right: PropTypes.string
40 selectedValuesList: PropTypes.arrayOf(PropTypes.string),
42 onChange: PropTypes.func.isRequired
45 static defaultProps = {
46 selectedValuesList: [],
55 availableListFilter: '',
56 selectedValuesListFilter: '',
68 let { availableListFilter, selectedValuesListFilter } = this.state;
70 let unselectedList = availableList.filter(
72 !selectedValuesList.find(value => value === availableItem.id)
74 let selectedList = availableList.filter(availableItem =>
75 selectedValuesList.find(value => value === availableItem.id)
77 selectedList = selectedList.sort(
78 (a, b) => availableList.indexOf(a.id) - availableList.indexOf(b.id)
81 <div className="dual-list-box">
86 value: availableListFilter,
87 ref: this.availableListFilterRef,
88 disabled: isReadOnlyMode,
90 this.setState({ availableListFilter: value })
93 ref: this.availableListRef,
94 disabled: isReadOnlyMode,
98 {this.renderOperationsBar(isReadOnlyMode)}
103 value: selectedValuesListFilter,
104 ref: this.selectedValuesListFilterRef,
105 disabled: isReadOnlyMode,
107 this.setState({ selectedValuesListFilter: value })
110 ref: this.selectedValuesRef,
111 disabled: isReadOnlyMode,
119 renderListbox(filterTitle, list, filterProps, props) {
120 let regExFilter = new RegExp(escape(filterProps.value), 'i');
121 let matchedItems = list.filter(item => item.name.match(regExFilter));
122 let unMatchedItems = list.filter(item => !item.name.match(regExFilter));
124 <div className="dual-search-multi-select-section">
126 <div className="dual-text-box-search search-wrapper">
128 data-test-id={`${props.testId}-search-input`}
129 name="search-input-control"
131 groupClassName="search-input-control"
134 <SVGIcon name="search" className="search-icon" />
139 this.onSelectItems(event.target.selectedOptions)
141 groupClassName="dual-list-box-multi-select"
143 name="dual-list-box-multi-select"
144 data-test-id={`${props.testId}-select-input`}
145 disabled={props.disabled}
147 {matchedItems.map(item =>
148 this.renderOption(item.id, item.name)
150 {matchedItems.length &&
151 unMatchedItems.length && (
152 <option style={{ pointerEvents: 'none' }}>
156 {unMatchedItems.map(item =>
157 this.renderOption(item.id, item.name)
164 onSelectItems(selectedOptions) {
165 let selectedValues = Object.keys(selectedOptions).map(
166 k => selectedOptions[k].value
168 this.setState({ selectedValues });
171 renderOption(value, name) {
174 className="dual-list-box-multi-select-text"
182 renderOperationsBar(isReadOnlyMode) {
185 className={`dual-list-options-bar${
186 isReadOnlyMode ? ' disabled' : ''
188 {this.renderOperationBarButton(
189 () => this.addToSelectedList(),
192 {this.renderOperationBarButton(
193 () => this.removeFromSelectedList(),
196 {this.renderOperationBarButton(
197 () => this.addAllToSelectedList(),
200 {this.renderOperationBarButton(
201 () => this.removeAllFromSelectedList(),
208 renderOperationBarButton(onClick, iconName) {
211 className="dual-list-option"
212 data-test-id={`operation-icon-${iconName}`}
214 <SVGIcon name={iconName} />
219 addToSelectedList() {
221 this.props.selectedValuesList.concat(this.state.selectedValues)
223 this.setState({ selectedValues: [] });
226 removeFromSelectedList() {
227 const selectedValues = this.state.selectedValues;
229 this.props.selectedValuesList.filter(
231 !selectedValues.find(
232 selectedValue => selectedValue === value
236 this.setState({ selectedValues: [] });
239 addAllToSelectedList() {
240 this.props.onChange(this.props.availableList.map(item => item.id));
243 removeAllFromSelectedList() {
244 this.props.onChange([]);
247 // fix for auto-selection of first value in the list on the first render
248 componentDidMount() {
249 this.availableListRef.current.input.value = '';
250 this.selectedValuesRef.current.input.value = '';
254 export default DualListboxView;