Add many jests tests and implement block on element type and
[clamp.git] / ui-react / src / components / dialogs / ManageDictionaries / ManageDictionaries.js
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END============================================
19  * ===================================================================
20  *
21  */
22
23
24 import React, { forwardRef } from 'react';
25 import Button from 'react-bootstrap/Button';
26 import Modal from 'react-bootstrap/Modal';
27 import Row from 'react-bootstrap/Row';
28 import Col from 'react-bootstrap/Col';
29 import styled from 'styled-components';
30 import TemplateMenuService from '../../../api/TemplateService';
31 import CsvToJson from '../../../utils/CsvToJson';
32 import MaterialTable, {MTableToolbar} from "material-table";
33 import IconButton from '@material-ui/core/IconButton';
34 import Tooltip from '@material-ui/core/Tooltip';
35 import AddBox from '@material-ui/icons/AddBox';
36 import ArrowUpward from '@material-ui/icons/ArrowUpward';
37 import Check from '@material-ui/icons/Check';
38 import ChevronLeft from '@material-ui/icons/ChevronLeft';
39 import VerticalAlignTopIcon from '@material-ui/icons/VerticalAlignTop';
40 import VerticalAlignBottomIcon from '@material-ui/icons/VerticalAlignBottom';
41 import ChevronRight from '@material-ui/icons/ChevronRight';
42 import Clear from '@material-ui/icons/Clear';
43 import DeleteOutline from '@material-ui/icons/DeleteOutline';
44 import Edit from '@material-ui/icons/Edit';
45 import FilterList from '@material-ui/icons/FilterList';
46 import FirstPage from '@material-ui/icons/FirstPage';
47 import LastPage from '@material-ui/icons/LastPage';
48 import Remove from '@material-ui/icons/Remove';
49 import Search from '@material-ui/icons/Search';
50 import ViewColumn from '@material-ui/icons/ViewColumn';
51
52
53 const ModalStyled = styled(Modal)`
54         @media (min-width: 1200px) {
55                 .modal-xl {
56                         max-width: 96%;
57                 }
58         }
59         background-color: transparent;
60 `
61
62 const MTableToolbarStyled = styled(MTableToolbar)`
63         display: flex;
64         flex-direction: row;
65         align-items: center;
66 `
67 const ColPullLeftStyled = styled(Col)`
68         display: flex;
69         flex-direction: row;
70         align-items: center;
71         margin-left: -40px;
72 `
73
74 const cellStyle = { border: '1px solid black' };
75 const headerStyle = { backgroundColor: '#ddd',  border: '2px solid black'       };
76 const rowHeaderStyle = {backgroundColor:'#ddd',  fontSize: '15pt', text: 'bold', border: '1px solid black'};
77
78 let dictList = [];
79 let subDictFlag = false;
80
81 function SelectSubDictType(props) {
82         const {onChange} = props;
83         const selectedValues = (e) => {
84                 let options = e.target.options;
85                 let SelectedDictTypes = '';
86                 for (let dictType = 0, values = options.length; dictType < values; dictType++) {
87                         if (options[dictType].selected) {
88                                 SelectedDictTypes = SelectedDictTypes.concat(options[dictType].value);
89                                 SelectedDictTypes = SelectedDictTypes.concat('|');
90                         }
91                 }
92                 SelectedDictTypes = SelectedDictTypes.slice(0,-1);
93                 onChange(SelectedDictTypes);
94         }
95         // When the subDictFlag is true, we need to disable selection of element "type"
96         return(
97                 <div>
98                         <select disabled={subDictFlag} multiple={true} onChange={selectedValues}>
99                                 <option value="string">string</option>
100                                 <option value="number">number</option>
101                                 <option value="datetime">datetime</option>
102                                 <option value="map">map</option>
103                                 <option value="json">json</option>
104                         </select>
105                 </div>
106         );
107 }
108
109 function SubDict(props) {
110         const {onChange} = props;
111         const subDicts = [];
112         subDicts.push('none');
113         if (dictList !== undefined  && dictList.length > 0) {
114                 let item;
115                 for(item in dictList) {
116                         if(dictList[item].secondLevelDictionary === 1) {
117                                 subDicts.push(dictList[item].name);
118                         }
119                 }
120         }
121         let optionItems = [];
122         for (let i=0; i<subDicts.length; ++i) {
123                 if (i === 0) {
124                         optionItems.push(<option selected key={subDicts[i]}>{subDicts[i]}</option>);
125                 } else {
126                         optionItems.push(<option key={subDicts[i]}>{subDicts[i]}</option>);
127                 }
128         }
129
130         function selectedValue (e) {
131                 onChange(e.target.value);
132         }
133         // When the subDictFlag is true, we need to disable selection of
134         // the sub-dictionary flag
135         return(
136                         <select disabled={subDictFlag} onChange={selectedValue} >
137                                 {optionItems}
138                         </select>
139         );
140 }
141
142 export default class ManageDictionaries extends React.Component {
143         constructor(props, context) {
144                 super(props, context);
145                 this.addDictionaryElementRow = this.addDictionaryElementRow.bind(this);
146                 this.addDictionaryRow = this.addDictionaryRow.bind(this);
147                 this.addReplaceDictionaryRequest = this.addReplaceDictionaryRequest.bind(this);
148                 this.clickHandler = this.clickHandler.bind(this);
149                 this.deleteDictionaryElementRow = this.deleteDictionaryElementRow.bind(this);
150                 this.deleteDictionaryRequest = this.deleteDictionaryRequest.bind(this);
151                 this.deleteDictionaryRow = this.deleteDictionaryRow.bind(this);
152                 this.fileSelectedHandler = this.fileSelectedHandler.bind(this);
153                 this.getDictionaries = this.getDictionaries.bind(this);
154                 this.getDictionaryElements = this.getDictionaryElements.bind(this);
155                 this.handleClose = this.handleClose.bind(this);
156                 this.handleDictionaryRowClick = this.handleDictionaryRowClick.bind(this);
157                 this.importCsvData = this.importCsvData.bind(this);
158                 this.updateDictionaryElementRow = this.updateDictionaryElementRow.bind(this);
159                 this.updateDictionaryElementsRequest = this.updateDictionaryElementsRequest.bind(this);
160                 this.updateDictionaryRow = this.updateDictionaryRow.bind(this);
161                 this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
162                 this.state = {
163                         show: true,
164                         currentSelectedDictionary: null,
165                         exportFilename: '',
166                         content: null,
167                         dictionaryElements: [],
168                         tableIcons: {
169                                 Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
170                                 Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
171                                 DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
172                                 Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
173                                 Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
174                                 Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
175                                 Export: forwardRef((props, ref) => <VerticalAlignBottomIcon {...props} ref={ref} />),
176                                 Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
177                                 FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
178                                 LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
179                                 NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
180                                 PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
181                                 ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
182                                 Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
183                                 SortArrow: forwardRef((props, ref) => <ArrowUpward {...props} ref={ref} />),
184                                 ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
185                                 ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
186                         },
187                         dictColumns: [
188                                 {
189                                         title: "Dictionary Name", field: "name",editable: 'onAdd',
190                                         cellStyle: cellStyle,
191                                         headerStyle: headerStyle
192                                 },
193                                 {
194                                         title: "Sub Dictionary ?", field: "secondLevelDictionary", lookup: {0: 'No', 1: 'Yes'},
195                                         cellStyle: cellStyle,
196                                         headerStyle: headerStyle
197                                 },
198                                 {
199                                         title: "Dictionary Type", field: "subDictionaryType",lookup: {string: 'string', number: 'number'},
200                                         cellStyle: cellStyle,
201                                         headerStyle: headerStyle
202                                 },
203                                 {
204                                         title: "Updated By", field: "updatedBy", editable: 'never',
205                                         cellStyle: cellStyle,
206                                         headerStyle: headerStyle
207                                 },
208                                 {
209                                         title: "Last Updated Date", field: "updatedDate", editable: 'never',
210                                         cellStyle: cellStyle,
211                                         headerStyle: headerStyle
212                                 }
213                         ],
214                         dictElementColumns: [
215                                 {
216                                         title: "Element Short Name", field: "shortName",editable: 'onAdd',
217                                         cellStyle: cellStyle,
218                                         headerStyle: headerStyle
219                                 },
220                                 {
221                                         title: "Element Name", field: "name",
222                                         cellStyle: cellStyle,
223                                         headerStyle: headerStyle
224                                 },
225                                 {
226                                         title: "Element Description", field: "description",
227                                         cellStyle: cellStyle,
228                                         headerStyle: headerStyle
229                                 },
230                                 {
231                                         title: "Element Type", field: "type",
232                                         editComponent: props => (
233                                                 <div>
234                                                         <SelectSubDictType  value={props.value} onChange={props.onChange} />
235                                                 </div>
236                                         ),
237                                         cellStyle: cellStyle,
238                                         headerStyle: headerStyle
239                                 },
240                                 {
241                                         title: "Sub-Dictionary", field: "subDictionary",
242                                         editComponent: props => (
243                                                  <div>
244                                                          <SubDict value={props.value} onChange={props.onChange} />
245                                                  </div>
246                                       ),
247                                     cellStyle: cellStyle,
248                                     headerStyle: headerStyle
249                                 },
250                                 {
251                                         title: "Updated By", field: "updatedBy", editable: 'never',
252                                         cellStyle: cellStyle,
253                                         headerStyle: headerStyle
254                                 },
255                                 {
256                                         title: "Updated Date", field: "updatedDate", editable: 'never',
257                                         cellStyle: cellStyle,
258                                         headerStyle: headerStyle
259                                 }
260                         ]
261                 }
262         }
263
264         componentDidMount() {
265                 this.getDictionaries();
266         }
267
268         getDictionaries() {
269                 TemplateMenuService.getDictionary().then(arrayOfdictionaries => {
270                         this.setState({ dictionaries: arrayOfdictionaries, currentSelectedDictionary: null })
271                         // global variable setting used functional components in this file
272                         dictList = arrayOfdictionaries;
273                 }).catch(() => {
274                         console.error('Failed to retrieve dictionaries');
275                         this.setState({ dictionaries: [], currentSelectedDictionary: null })
276                 });
277         }
278
279         getDictionaryElements(dictionaryName) {
280                 TemplateMenuService.getDictionaryElements(dictionaryName).then(dictionaryElements => {
281                         this.setState({ dictionaryElements: dictionaryElements.dictionaryElements} );
282                         this.setState({ currentSelectDictionary: dictionaryName });
283                 }).catch(() => console.error('Failed to retrieve dictionary elements'))
284         }
285
286         clickHandler(rowData) {
287                 this.getDictionaries();
288         }
289
290         handleClose() {
291                 this.setState({ show: false });
292                 this.props.history.push('/');
293         }
294
295         addReplaceDictionaryRequest(dictionaryEntry) {
296                 TemplateMenuService.insDictionary(dictionaryEntry)
297                 .then(resp => {
298                         this.getDictionaries();
299                 })
300                 .catch(() => console.error('Failed to insert new dictionary elements'));
301         }
302
303         updateDictionaryElementsRequest(dictElements) {
304                 let reqData = { "name": this.state.currentSelectedDictionary, 'dictionaryElements': dictElements };
305                 TemplateMenuService.insDictionaryElements(reqData)
306                 .then(resp => { this.getDictionaryElements(this.state.currentSelectedDictionary) })
307                 .catch(() => console.error('Failed to update dictionary elements'));
308         }
309
310         deleteDictionaryRequest(dictionaryName) {
311                 TemplateMenuService.deleteDictionary(dictionaryName)
312                 .then(resp => {
313                         this.getDictionaries();
314                 })
315                 .catch(() => console.error('Failed to delete dictionary'));
316         }
317
318         deleteDictionaryElementRequest(dictionaryName, elemenetShortName) {
319                 TemplateMenuService.deleteDictionaryElements({ 'name': dictionaryName, 'shortName': elemenetShortName })
320                 .then(resp => {
321                         this.getDictionaryElements(dictionaryName);
322                 })
323                 .catch(() => console.error('Failed to delete dictionary elements'));
324         }
325
326         fileSelectedHandler = (event) => {
327
328                 if (event.target.files[0].type === 'text/csv' || event.target.files[0].type === 'application/vnd.ms-excel') {
329                         if (event.target.files && event.target.files[0]) {
330                                 const reader = new FileReader();
331                                 reader.onload = (e) => {
332                                         let errorMessages = this.importCsvData(reader.result);
333                                         if (errorMessages !== '') {
334                                                 alert(errorMessages);
335                                         }
336                                 }
337                                 reader.readAsText(event.target.files[0]);
338                         }
339                 } else {
340                         alert('Please upload .csv extention files only.');
341                 }
342         }
343
344         importCsvData(rawCsvData) {
345
346                 const jsonKeyNames = [ 'shortName', 'name', 'description', 'type', 'subDictionary' ];
347                 const userHeaderNames = [ 'Element Short Name', 'Element Name', 'Element Description', 'Element Type', 'Sub-Dictionary'  ];
348                 const validTypes = ['string','number','datetime','json','map'];
349
350                 let mandatory;
351
352                 if (subDictFlag) {
353                         mandatory = [ true, true, true, false, false ];
354                 } else {
355                         mandatory = [ true, true, true, true, false ];
356                 }
357
358                 let result = CsvToJson(rawCsvData, ',', '||||', userHeaderNames, jsonKeyNames, mandatory);
359
360                 let errorMessages = result.errorMessages;
361                 let jsonObjArray = result.jsonObjArray;
362
363                 let validTypesErrorMesg = '';
364
365                 for (let i=0; i < validTypes.length; ++i) {
366                         if (i === 0) {
367                                 validTypesErrorMesg = validTypes[i];
368                         } else {
369                                 validTypesErrorMesg += ',' + validTypes[i];
370                         }
371                 }
372
373                 if (errorMessages !== '') {
374                         return errorMessages;
375                 }
376
377                 // Perform further checks on data that is now in JSON form
378                 let subDictionaries = [];
379
380                 // NOTE: dictList is a global variable  maintained faithfully
381                 //       by the getDictionaries() method outside this import
382                 //       functionality.
383                 let item;
384                 for (item in dictList) {
385                         if (dictList[item].secondLevelDictionary === 1) {
386                                 subDictionaries.push(dictList[item].name);
387                         }
388                 };
389
390                 // Check for valid Sub-Dictionary and Element Type values
391                 subDictionaries = subDictionaries.toString();
392                 let row = 2;
393                 let dictElem;
394                 for (dictElem of jsonObjArray) {
395                         let itemKey;
396                         for (itemKey in dictElem){
397                                 let value = dictElem[itemKey].trim();
398                                 let keyIndex = jsonKeyNames.indexOf(itemKey);
399                                 if (itemKey === 'shortName' && /[^a-zA-Z0-9-_.]/.test(value)) {
400                                         errorMessages += '\n' + userHeaderNames[keyIndex] +
401                                                 ' at row #' + row +
402                                                 ' can only contain alphanumeric characters and periods, hyphens or underscores';
403                                 }
404                                 if (itemKey === 'type' && validTypes.indexOf(value) < 0) {
405                                         errorMessages += '\nInvalid value of "' + value + '" for "' + userHeaderNames[keyIndex] + '" at row #' + row;
406                                         errorMessages += '\nValid types are: ' + validTypesErrorMesg;
407                                 }
408                                 if (value !== "" && itemKey === 'subDictionary' && subDictionaries.indexOf(value) < 0) {
409                                         errorMessages += '\nInvalid Sub-Dictionary value of "' + value + '" at row #' + row;
410                                 }
411                         }
412                         ++row;
413                 }
414                 if (errorMessages === '') {
415                         // We made it through all the checks. Send it to back end
416                         this.updateDictionaryElementsRequest(jsonObjArray);
417                 }
418
419                 return errorMessages;
420         }
421
422         addDictionaryRow(newData) {
423                 let validData = true;
424                 return new Promise((resolve, reject) => {
425                         setTimeout(() => {
426                                         if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
427                                                 validData = false;
428                                                 alert('Please enter alphanumeric input. Only allowed special characters are:(period, hyphen, underscore)');
429                                                 reject();
430                                         }
431                                         for (let i = 0; i < this.state.dictionaries.length; i++) {
432                                                 if (this.state.dictionaries[i].name === newData.name) {
433                                                         validData = false;
434                                                         alert(newData.name + ' dictionary name already exists')
435                                                         reject();
436                                                 }
437                                         }
438                                         if (validData) {
439                                                 this.addReplaceDictionaryRequest(newData);
440                                         }
441                                         resolve();
442                         }, 1000);
443                 });
444         }
445
446
447         updateDictionaryRow(newData, oldData) {
448                 let validData = true;
449                 return new Promise((resolve, reject) => {
450                         setTimeout(() => {
451                                 if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
452                                         validData = false;
453                                         alert('Please enter alphanumberic input. Only allowed special characters are:(period, hyphen, underscore)');
454                                         reject();
455                                 }
456                                 if (validData) {
457                                         this.addReplaceDictionaryRequest(newData);
458                                 }
459                                 resolve();
460                         }, 1000);
461                 });
462         }
463
464         deleteDictionaryRow(oldData) {
465                 return new Promise((resolve, reject) => {
466                         setTimeout(() => {
467                                 this.deleteDictionaryRequest(oldData.name);
468                                 resolve();
469                         }, 1000);
470                 });
471         }
472
473         addDictionaryElementRow(newData) {
474                 return new Promise((resolve, reject) => {
475                         setTimeout(() => {
476                                 let dictionaryElements = this.state.dictionaryElements;
477                                 let errorMessages = '';
478                                 for (let i = 0; i < this.state.dictionaryElements.length; i++) {
479                                         if (this.state.dictionaryElements[i].shortName === newData.shortName) {
480                                                 alert('Short Name "' + newData.shortName + '" already exists');
481                                                 reject("");
482                                         }
483                                 }
484                                 // MaterialTable returns no property at all if the user has not touched a
485                                 // new column, so we want to add the property with an emptry string
486                                 // for several cases if that is the case to simplify other checks.
487                                 if (newData.description === undefined) {
488                                         newData.description = "";
489                                 }
490                                 if (newData.subDictionary === undefined) {
491                                         newData.subDictionary = null;
492                                 }
493                                 if (newData.type === undefined) {
494                                         newData.type = "";
495                                 }
496                                 if (!newData.shortName && /[^a-zA-Z0-9-_.]/.test(newData.shortName)) {
497                                         errorMessages += '\nShort Name is limited to alphanumeric characters and also period, hyphen, and underscore';
498                                 }
499                                 if (!newData.shortName){
500                                         errorMessages += '\nShort Name must be specified';
501                                 }
502                                 if (!newData.name){
503                                         errorMessages += '\nElement Name must be specified';
504                                 }
505                                 if (!newData.type && !subDictFlag){
506                                         errorMessages += '\nElement Type must be specified';
507                                 }
508                                 if (errorMessages === '') {
509                                         dictionaryElements.push(newData);
510                                         this.updateDictionaryElementsRequest([newData]);
511                                         resolve();
512                                 } else {
513                                         alert(errorMessages);
514                                         reject("");
515                                 }
516                         }, 1000);
517                 });
518         }
519
520         updateDictionaryElementRow(newData, oldData) {
521                 return new Promise((resolve, reject) => {
522                         setTimeout(() => {
523                                 let dictionaryElements = this.state.dictionaryElements;
524                                 let validData =  true;
525                                 if (!newData.type) {
526                                         validData = false;
527                                         alert('Element Type cannot be null');
528                                         reject();
529                                 }
530                                 if (validData) {
531                                         const index = dictionaryElements.indexOf(oldData);
532                                         dictionaryElements[index] = newData;
533                                         this.updateDictionaryElementsRequest([newData]);
534                                 }
535                                 resolve();
536                         }, 1000);
537                 });
538         }
539
540
541         deleteDictionaryElementRow(oldData) {
542                 return new Promise((resolve) => {
543                         setTimeout(() => {
544                                 this.deleteDictionaryElementRequest(this.state.currentSelectedDictionary, oldData.shortName);
545                                 resolve();
546                         }, 1000);
547                 });
548         }
549
550         handleDictionaryRowClick(event, rowData) {
551                 subDictFlag = rowData.secondLevelDictionary === 1 ? true : false;
552                 this.setState({
553                         currentSelectedDictionary : rowData.name,
554                         exportFilename: rowData.name
555                 })
556                 this.getDictionaryElements(rowData.name);
557         }
558
559         render() {
560                 return (
561                         <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
562                                 <Modal.Header closeButton>
563                                         <Modal.Title>Manage Dictionaries</Modal.Title>
564                                 </Modal.Header>
565                                 <Modal.Body>
566                                         {this.state.currentSelectedDictionary === null ?
567                                                 <MaterialTable
568                                                         title={"Dictionary List"}
569                                                         data={this.state.dictionaries}
570                                                         columns={this.state.dictColumns}
571                                                         icons={this.state.tableIcons}
572                                                         onRowClick={this.handleDictionaryRowClick}
573                                                         options={{
574                                                                 headerStyle: rowHeaderStyle,
575                                                         }}
576                                                         editable={!this.readOnly ?
577                                                                 {
578                                                                         onRowAdd: this.addDictionaryRow,
579                                                                         onRowUpdate: this.updateDictionaryRow,
580                                                                         onRowDelete: this.deleteDictionaryRow
581                                                                 } : undefined }
582                                                 /> : null
583                                         }
584                                         {this.state.currentSelectedDictionary !== null ?
585                                                 <MaterialTable
586                                                         title={'Dictionary Elements List for ' + (subDictFlag ? 'Sub-Dictionary "' : '"') + this.state.currentSelectedDictionary + '"'}
587                                                         data={this.state.dictionaryElements}
588                                                         columns={this.state.dictElementColumns}
589                                                         icons={this.state.tableIcons}
590                                                         options={{
591                                                                 exportAllData: true,
592                                                                 exportButton: true,
593                                                                 exportFileName: this.state.exportFilename,
594                                                                 headerStyle:{backgroundColor:'white',  fontSize: '15pt', text: 'bold', border: '1px solid black'}
595                                                         }}
596                                                         components={{
597                                                                 Toolbar: props => (
598                                                                         <Row>
599                                                                                 <Col sm="11">
600                                                                                         <MTableToolbarStyled {...props} />
601                                                                                 </Col>
602                                                                                 <ColPullLeftStyled sm="1">
603                                                                                         <Tooltip title="Import" placement = "bottom">
604                                                                                                 <IconButton aria-label="import" disabled={this.readOnly} onClick={() => this.fileUpload.click()}>
605                                                                                                         <VerticalAlignTopIcon />
606                                                                                                 </IconButton>
607                                                                                         </Tooltip>
608                                                                                         <input type="file" ref={(fileUpload) => {this.fileUpload = fileUpload;}}
609                                                                                                 style={{ visibility: 'hidden', width: '1px' }} onChange={this.fileSelectedHandler} />
610                                                                                 </ColPullLeftStyled>
611                                                                         </Row>
612                                                                 )
613                                                         }}
614                                                         editable={!this.readOnly ?
615                                                                 {
616                                                                         onRowAdd: this.addDictionaryElementRow,
617                                                                         onRowUpdate: this.updateDictionaryElementRow,
618                                                                         onRowDelete: this.deleteDictionaryElementRow
619                                                                 } : undefined
620                                                          }
621                                                 /> : null
622                                         }
623                                         {this.state.currentSelectedDictionary !== null ? <button onClick={this.clickHandler} style={{marginTop: '25px'}}>Go Back to Dictionaries List</button>:""}
624                                 </Modal.Body>
625                                 <Modal.Footer>
626                                         <Button variant="secondary" type="null" onClick={this.handleClose}>Close</Button>
627                                 </Modal.Footer>
628                         </ModalStyled>
629                 );
630         }
631 }