Create wt-odlux directory
[ccsdk/features.git] / sdnr / wt-odlux / odlux / apps / configurationApp / src / components / uiElementLeafList.tsx
1 /**
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt odlux
4  * =================================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18
19 import React from 'react';
20 import FormControl from '@mui/material/FormControl';
21 import InputLabel from '@mui/material/InputLabel';
22 import Chip from '@mui/material/Chip';
23 import Dialog from '@mui/material/Dialog';
24 import DialogTitle from '@mui/material/DialogTitle';
25 import DialogContent from '@mui/material/DialogContent';
26 import DialogActions from '@mui/material/DialogActions';
27 import Button from '@mui/material/Button';
28
29 import makeStyles from '@mui/styles/makeStyles';
30 import AddIcon from '@mui/icons-material/Add';
31
32 import { Theme } from '@mui/material/styles';
33 import { ViewElement } from '../models/uiModels';
34
35 import { BaseProps } from './baseProps';
36
37 const useStyles = makeStyles((theme: Theme) => {
38   const light = theme.palette.mode === 'light';
39   const bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)';
40
41   return ({
42     root: {
43       display: 'flex',
44       justifyContent: 'left',
45       verticalAlign: 'bottom',
46       flexWrap: 'wrap',
47       listStyle: 'none',
48       margin: 0,
49       padding: 0,
50       paddingTop: theme.spacing(0.5),
51       marginTop: theme.spacing(1),
52     },
53     chip: {
54       margin: theme.spacing(0.5),
55     },
56     underline: {
57       '&:after': {
58         borderBottom: `2px solid ${theme.palette.primary.main}`,
59         left: 0,
60         bottom: 0,
61         // Doing the other way around crash on IE 11 "''" https://github.com/cssinjs/jss/issues/242
62         content: '""',
63         position: 'absolute',
64         right: 0,
65         transform: 'scaleX(0)',
66         transition: theme.transitions.create('transform', {
67           duration: theme.transitions.duration.shorter,
68           easing: theme.transitions.easing.easeOut,
69         }),
70         pointerEvents: 'none', // Transparent to the hover style.
71       },
72       '&.Mui-focused:after': {
73         transform: 'scaleX(1)',
74       },
75       '&.Mui-error:after': {
76         borderBottomColor: theme.palette.error.main,
77         transform: 'scaleX(1)', // error is always underlined in red
78       },
79       '&:before': {
80         borderBottom: `1px solid ${bottomLineColor}`,
81         left: 0,
82         bottom: 0,
83         // Doing the other way around crash on IE 11 "''" https://github.com/cssinjs/jss/issues/242
84         content: '"\\00a0"',
85         position: 'absolute',
86         right: 0,
87         transition: theme.transitions.create('border-bottom-color', {
88           duration: theme.transitions.duration.shorter,
89         }),
90         pointerEvents: 'none', // Transparent to the hover style.
91       },
92       '&:hover:not($disabled):before': {
93         borderBottom: `2px solid ${theme.palette.text.primary}`,
94         // Reset on touch devices, it doesn't add specificity
95         // eslint-disable-next-line @typescript-eslint/naming-convention
96         '@media (hover: none)': {
97           borderBottom: `1px solid ${bottomLineColor}`,
98         },
99       },
100       '&.Mui-disabled:before': {
101         borderBottomStyle: 'dotted',
102       },
103     },
104   });
105 });
106
107 type LeafListProps = BaseProps<any []> & {
108   getEditorForViewElement:  (uiElement: ViewElement) => (null | React.ComponentType<BaseProps<any>>);  
109 };
110
111 export const UiElementLeafList = (props: LeafListProps) => {
112   const { value: element, inputValue, onChange } = props;
113
114   const classes = useStyles();
115
116   const [open, setOpen] = React.useState(false);
117   const [editorValue, setEditorValue] = React.useState('');
118   const [editorValueIndex, setEditorValueIndex] = React.useState(-1);
119   
120   const handleClose = () => {
121     setOpen(false);
122   };
123
124   const onApplyButton = () => { 
125     if (editorValue != null && editorValue != '' && editorValueIndex < 0) {
126       props.onChange([
127         ...inputValue,
128         editorValue,
129       ]);
130     } else if (editorValue != null && editorValue != '') {
131       props.onChange([
132         ...inputValue.slice(0, editorValueIndex),
133         editorValue,
134         ...inputValue.slice(editorValueIndex + 1),
135       ]);
136     }
137     setOpen(false);
138   };
139
140   const onDelete = (index : number) => {
141     const newValue : any[] = [
142       ...inputValue.slice(0, index),
143       ...inputValue.slice(index + 1),
144     ];
145     onChange(newValue);
146   };
147
148   const ValueEditor = props.getEditorForViewElement(props.value); 
149
150   return (
151     <>
152       <FormControl variant="standard" style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
153         <InputLabel htmlFor={`list-${element.id}`} shrink={!props.readOnly || !!(inputValue && inputValue.length)} >{element.label}</InputLabel>
154         <ul className={`${classes.root} ${classes.underline}`} id={`list-${element.id}`}>
155         { !props.readOnly ? <li>
156           <Chip
157             icon={<AddIcon />}
158             label={'Add'}
159             className={classes.chip}
160             size="small"
161             color="secondary"
162             onClick={ () => { 
163               setOpen(true); 
164               setEditorValue('');
165               setEditorValueIndex(-1);
166             } 
167             }
168           />
169         </li> : null }  
170         { inputValue.map((val, ind) => (
171           <li key={ind}>
172             <Chip
173               className={classes.chip}
174               size="small"
175               variant="outlined"
176               label={String(val)}
177               onDelete={ !props.readOnly ? () => { onDelete(ind); } : undefined }  
178               onClick={ !props.readOnly ? () => { 
179                 setOpen(true); 
180                 setEditorValue(val);
181                 setEditorValueIndex(ind);
182               } : undefined
183               }   
184             />
185             </li>
186         ))
187         }
188         </ul>
189         {/* <FormHelperText>{ "Value is mandetory"}</FormHelperText> */}
190         </FormControl>
191         <Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
192           <DialogTitle id="form-dialog-title">{editorValueIndex < 0 ? 'Add new value' : 'Edit value' } </DialogTitle>
193           <DialogContent>
194             { ValueEditor && <ValueEditor 
195                 inputValue={ editorValue }
196                 value={{ ...element, isList: false }}
197                 disabled={false}
198                 readOnly={props.readOnly}
199                 onChange={ setEditorValue }
200             /> || null }
201           </DialogContent>
202           <DialogActions>
203             <Button color="inherit" onClick={ handleClose }> Cancel </Button>
204             <Button disabled={editorValue == null || editorValue === '' } onClick={ onApplyButton } color="secondary"> {editorValueIndex < 0 ? 'Add' : 'Apply'} </Button>
205           </DialogActions>
206         </Dialog>
207       </>
208   );
209 };