c705b982fac41987ef7b7e0f3c0b3ee7c6f1e724
[ccsdk/features.git] / sdnr / wt / 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 * as React from "react"
20 import { FormControl, InputLabel, Paper, Chip, FormHelperText, Dialog, DialogTitle, DialogContentText, DialogActions, Button, DialogContent } from "@material-ui/core";
21 import { makeStyles } from '@material-ui/core/styles';
22 import AddIcon from '@material-ui/icons/Add';
23
24 import { ViewElement } from "../models/uiModels";
25
26 import { BaseProps } from "./baseProps";
27
28 type LeafListProps = BaseProps<any []> & {
29   getEditorForViewElement:  (uiElement: ViewElement) => (null | React.ComponentType<BaseProps<any>>)  
30 };
31
32 const useStyles = makeStyles((theme) => {
33   const light = theme.palette.type === 'light';
34   const bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)';
35
36   return ({
37     root: {
38       display: 'flex',
39       justifyContent: 'left',
40       verticalAlign: 'bottom',
41       flexWrap: 'wrap',
42       listStyle: 'none',
43       margin: 0,
44       padding: 0,
45       paddingTop: theme.spacing(0.5),
46       marginTop: theme.spacing(1),
47     },
48     chip: {
49       margin: theme.spacing(0.5),
50     },
51     underline: {
52         '&:after': {
53           borderBottom: `2px solid ${theme.palette.primary.main}`,
54           left: 0,
55           bottom: 0,
56           // Doing the other way around crash on IE 11 "''" https://github.com/cssinjs/jss/issues/242
57           content: '""',
58           position: 'absolute',
59           right: 0,
60           transform: 'scaleX(0)',
61           transition: theme.transitions.create('transform', {
62             duration: theme.transitions.duration.shorter,
63             easing: theme.transitions.easing.easeOut,
64           }),
65           pointerEvents: 'none', // Transparent to the hover style.
66         },
67         '&$focused:after': {
68           transform: 'scaleX(1)',
69         },
70         '&$error:after': {
71           borderBottomColor: theme.palette.error.main,
72           transform: 'scaleX(1)', // error is always underlined in red
73         },
74         '&:before': {
75           borderBottom: `1px solid ${bottomLineColor}`,
76           left: 0,
77           bottom: 0,
78           // Doing the other way around crash on IE 11 "''" https://github.com/cssinjs/jss/issues/242
79           content: '"\\00a0"',
80           position: 'absolute',
81           right: 0,
82           transition: theme.transitions.create('border-bottom-color', {
83             duration: theme.transitions.duration.shorter,
84           }),
85           pointerEvents: 'none', // Transparent to the hover style.
86         },
87         '&:hover:not($disabled):before': {
88           borderBottom: `2px solid ${theme.palette.text.primary}`,
89           // Reset on touch devices, it doesn't add specificity
90           '@media (hover: none)': {
91             borderBottom: `1px solid ${bottomLineColor}`,
92           },
93         },
94         '&$disabled:before': {
95           borderBottomStyle: 'dotted',
96         },
97       },
98   })
99 });
100
101 export const UiElementLeafList = (props: LeafListProps) => {
102   const { value: element, inputValue, onChange } = props;
103
104   const classes = useStyles();
105
106   const [open, setOpen] = React.useState(false);
107   const [editorValue, setEditorValue] = React.useState("");
108   const [editorValueIndex, setEditorValueIndex] = React.useState(-1);
109   
110
111   const handleClickOpen = () => {
112     setOpen(true);
113   };
114
115   const handleClose = () => {
116     setOpen(false);
117   };
118
119   const onApplyButton = () => { 
120      if (editorValue != null && editorValue != "" && editorValueIndex < 0) {
121        props.onChange([
122          ...inputValue,
123          editorValue,
124        ]);
125      } else if (editorValue != null && editorValue != "") {
126        props.onChange([
127          ...inputValue.slice(0, editorValueIndex),
128          editorValue,
129          ...inputValue.slice(editorValueIndex+1),
130        ]);
131      }
132      setOpen(false);
133   };
134
135   const onDelete = (index : number) => {
136     const newValue : any[] = [
137       ...inputValue.slice(0, index),
138       ...inputValue.slice(index+1),
139     ];
140     onChange(newValue);
141   };
142
143   const ValueEditor = props.getEditorForViewElement(props.value); 
144
145   return (
146     <>
147       <FormControl style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
148         <InputLabel htmlFor={`list-${element.id}`} shrink={!props.readOnly || !!(inputValue && inputValue.length)} >{element.label}</InputLabel>
149         <ul className={`${classes.root} ${classes.underline}`} id={`list-${element.id}`}>
150         { !props.readOnly ? <li>
151           <Chip
152             icon={<AddIcon />}
153             label={"Add"}
154             className={classes.chip}
155             size="small"
156             color="secondary"
157             onClick={ () => { 
158               setOpen(true); 
159               setEditorValue("");
160               setEditorValueIndex(-1);
161              } 
162             }
163           />
164         </li> : null }  
165         { inputValue.map((val, ind) => (
166           <li key={ind}>
167             <Chip
168               className={classes.chip}
169               size="small"
170               variant="outlined"
171               label={String(val)}
172               onDelete={ !props.readOnly ? () => { onDelete(ind); } : undefined }  
173               onClick={ !props.readOnly ? () => { 
174                   setOpen(true); 
175                   setEditorValue(val);
176                   setEditorValueIndex(ind);
177                   } : undefined
178               }   
179             />
180             </li>
181           ))
182         }
183         </ul>
184         {/* <FormHelperText>{ "Value is mandetory"}</FormHelperText> */}
185         </FormControl>
186         <Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
187           <DialogTitle id="form-dialog-title">{editorValueIndex < 0 ? "Add new value" : "Edit value" } </DialogTitle>
188           <DialogContent>
189             { ValueEditor && <ValueEditor 
190                 inputValue={ editorValue }
191                 value={{ ...element, isList: false}}
192                 disabled={false}
193                 readOnly={props.readOnly}
194                 onChange={ setEditorValue }
195             /> || null }
196           </DialogContent>
197           <DialogActions>
198             <Button onClick={ handleClose }> Cancel </Button>
199             <Button disabled={editorValue == null || editorValue === "" } onClick={ onApplyButton } color="secondary"> {editorValueIndex < 0 ? "Add" : "Apply"} </Button>
200           </DialogActions>
201         </Dialog>
202       </>
203   );
204 };