disable undo and empty name validation
[sdc/sdc-workflow-designer.git] / workflow-designer-ui / src / main / frontend / src / features / version / inputOutput / InputOutputView.jsx
1 /*
2 * Copyright © 2018 European Support Limited
3 *
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
7 *
8 *      http: //www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 import React from 'react';
18 import PropTypes from 'prop-types';
19 import { Translate, I18n } from 'react-redux-i18n';
20 import cn from 'classnames';
21 import { SVGIcon } from 'sdc-ui/lib/react';
22
23 import SearchInput from 'shared/searchInput/SearchInput';
24 import { getValidationsError } from 'features/version/inputOutput/inputOutputValidations';
25 import Tab from 'features/version/inputOutput/views/Tab';
26 import TableHead from 'features/version/inputOutput/views/TableHead';
27 import TableBody from 'features/version/inputOutput/views/TableBody';
28 import NoDataRow from 'features/version/inputOutput/views/NoDataRow';
29 import DataRow from 'features/version/inputOutput/views/DataRow';
30
31 class InputOutputView extends React.Component {
32     componentDidUpdate() {
33         const { dataRows, error, handleChangeError } = this.props;
34
35         const validationsError = getValidationsError(dataRows);
36
37         const isDiff = Object.keys(validationsError).some(errorKey => {
38             if (!error.hasOwnProperty(errorKey)) {
39                 return true;
40             }
41
42             return (
43                 JSON.stringify(validationsError[errorKey].sort()) !==
44                 JSON.stringify(error[errorKey].sort())
45             );
46         });
47
48         if (isDiff) {
49             handleChangeError(validationsError);
50         }
51     }
52
53     handleInputsTabClick = () => {
54         if (!this.props.isShowInputs) {
55             this.props.handleShowInputs();
56         }
57     };
58
59     handleOutputsTabClick = () => {
60         if (this.props.isShowInputs) {
61             this.props.handleShowOutputs();
62         }
63     };
64
65     handleSearchChange = value => {
66         this.props.handleSearch(value);
67     };
68
69     handleNameChange = (key, isBlur = false) => value => {
70         let name = isBlur ? value.target.value : value;
71         name = name.replace(/\s+/g, ' ');
72         name = isBlur
73             ? name.replace(/^\s+|\s+$/g, '')
74             : name.replace(/^\s+/g, '');
75
76         this.props.handleNameChange(name, key);
77     };
78
79     handleTypeChange = key => event => {
80         this.props.handleTypeChange(event.target.value, key);
81     };
82
83     handleMandatoryChange = key => value => {
84         this.props.handleMandatoryChange(value, key);
85     };
86
87     handleRemoveClick = key => () => {
88         const { name } = this.props.dataRows[key];
89
90         let alertProps = false;
91
92         if (name.replace(/\s+/g, '')) {
93             const title = I18n.t('workflow.inputOutput.DELETE');
94             const body = I18n.t('workflow.inputOutput.confirmDlete', {
95                 name: name.replace(/s+$/g, '')
96             });
97             const closeButtonText = I18n.t('workflow.inputOutput.CANCEL');
98             const actionButtonText = title;
99
100             alertProps = {
101                 title,
102                 body,
103                 closeButtonText,
104                 actionButtonText
105             };
106         }
107
108         this.props.handleRemove(alertProps, key);
109     };
110
111     renderDataRows = () => {
112         const { dataRows, types, error } = this.props;
113
114         if (dataRows.length < 1) {
115             return (
116                 <NoDataRow>
117                     <Translate value="workflow.inputOutput.noData" />
118                 </NoDataRow>
119             );
120         }
121
122         return dataRows.map((data, i) => {
123             let errorMessage = '';
124
125             if (
126                 error.invalidCharacters &&
127                 error.invalidCharacters.includes(i)
128             ) {
129                 errorMessage = I18n.t('workflow.inputOutput.invalidCharacters');
130             } else if (error.alreadyExists && error.alreadyExists.includes(i)) {
131                 errorMessage = I18n.t('workflow.inputOutput.alreadyExists');
132             } else if (error.emptyName && error.emptyName.includes(i)) {
133                 errorMessage = I18n.t('workflow.inputOutput.emptyName');
134             }
135
136             return (
137                 <DataRow
138                     key={`data.${i}`}
139                     data={data}
140                     types={types}
141                     nameErrorMessage={errorMessage}
142                     dataTestId="wf-input-output-row"
143                     handleNameChange={this.handleNameChange(i)}
144                     handleNameBlur={this.handleNameChange(i, true)}
145                     handleTypeChange={this.handleTypeChange(i)}
146                     handleMandatoryChange={this.handleMandatoryChange(i)}
147                     handleRemoveClick={this.handleRemoveClick(i)}
148                 />
149             );
150         });
151     };
152
153     render() {
154         const { isShowInputs, search, handleAdd, isCertified } = this.props;
155
156         const addLabel = isShowInputs
157             ? I18n.t('workflow.inputOutput.addInput')
158             : I18n.t('workflow.inputOutput.addOutput');
159
160         const dataRowsView = this.renderDataRows();
161
162         return (
163             <div className="input-output">
164                 <div className="input-output__header">
165                     <Tab
166                         isActive={isShowInputs}
167                         dataTestId="wf-input-output-inputs"
168                         handleTabClick={this.handleInputsTabClick}>
169                         <Translate value="workflow.inputOutput.inputs" />
170                     </Tab>
171                     <Tab
172                         isActive={!isShowInputs}
173                         dataTestId="wf-input-output-outputs"
174                         handleTabClick={this.handleOutputsTabClick}>
175                         <Translate value="workflow.inputOutput.outputs" />
176                     </Tab>
177                     <div className="input-output__header__right">
178                         <div className="input-output__search">
179                             <SearchInput
180                                 dataTestId="wf-input-output-search"
181                                 onChange={this.handleSearchChange}
182                                 value={search}
183                             />
184                         </div>
185                         <div
186                             className={cn('input-output__add', {
187                                 disabled: isCertified
188                             })}
189                             data-test-id="wf-input-output-add"
190                             onClick={handleAdd}>
191                             <SVGIcon
192                                 label={addLabel}
193                                 labelPosition="right"
194                                 color="primary"
195                                 name="plusThin"
196                             />
197                         </div>
198                     </div>
199                 </div>
200                 <div className="input-output__table">
201                     <TableHead />
202                     <TableBody isCertified={isCertified}>
203                         {dataRowsView}
204                     </TableBody>
205                 </div>
206             </div>
207         );
208     }
209 }
210
211 InputOutputView.propTypes = {
212     isShowInputs: PropTypes.bool,
213     search: PropTypes.string,
214     dataRows: PropTypes.arrayOf(
215         PropTypes.shape({
216             name: PropTypes.string,
217             type: PropTypes.string,
218             mandatory: PropTypes.bool
219         })
220     ),
221     types: PropTypes.array,
222     error: PropTypes.object,
223     isCertified: PropTypes.bool,
224     handleChangeError: PropTypes.func,
225     handleShowInputs: PropTypes.func,
226     handleShowOutputs: PropTypes.func,
227     handleSearch: PropTypes.func,
228     handleAdd: PropTypes.func,
229     handleCurrentDataChange: PropTypes.func,
230     handleNameChange: PropTypes.func,
231     handleTypeChange: PropTypes.func,
232     handleMandatoryChange: PropTypes.func,
233     handleRemove: PropTypes.func
234 };
235
236 export default InputOutputView;