20ece4c22afe4f8d27c369d8a92c6e8f54fc5522
[ccsdk/features.git] / sdnr / wt / odlux / apps / mediatorApp / src / components / editMediatorConfigDialog.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 import * as React from 'react';
19 import { Theme, createStyles, WithStyles, withStyles, Typography, FormControlLabel, Checkbox } from '@material-ui/core';
20
21 import Button from '@material-ui/core/Button';
22 import TextField from '@material-ui/core/TextField';
23 import Select from '@material-ui/core/Select';
24 import Dialog from '@material-ui/core/Dialog';
25 import DialogActions from '@material-ui/core/DialogActions';
26 import DialogContent from '@material-ui/core/DialogContent';
27 import DialogContentText from '@material-ui/core/DialogContentText';
28 import DialogTitle from '@material-ui/core/DialogTitle';
29
30 import Tabs from '@material-ui/core/Tabs';
31 import Tab from '@material-ui/core/Tab';
32
33 import Fab from '@material-ui/core/Fab';
34 import AddIcon from '@material-ui/icons/Add';
35 import DeleteIcon from '@material-ui/icons/Delete';
36 import IconButton from '@material-ui/core/IconButton';
37
38 import { addMediatorConfigAsyncActionCreator, updateMediatorConfigAsyncActionCreator, removeMediatorConfigAsyncActionCreator } from '../actions/mediatorConfigActions';
39 import { MediatorConfig, ODLConfig } from '../models/mediatorServer';
40 import FormControl from '@material-ui/core/FormControl';
41 import InputLabel from '@material-ui/core/InputLabel';
42 import MenuItem from '@material-ui/core/MenuItem';
43
44 import { Panel } from '../../../../framework/src/components/material-ui/panel';
45
46 import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
47 import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
48
49
50 const styles = (theme: Theme) => createStyles({
51   root: {
52     display: 'flex',
53     flexDirection: 'column',
54     flex: '1',
55   },
56   fab: {
57     position: 'absolute',
58     bottom: theme.spacing.unit,
59     right: theme.spacing.unit,
60   },
61   title: {
62     fontSize: 14,
63   },
64   center: {
65     flex: "1",
66     display: "flex",
67     alignItems: "center",
68     justifyContent: "center",
69   },
70   alignInOneLine: {
71     display: 'flex',
72     flexDirection: 'row'
73   },
74   left: {
75     marginRight: theme.spacing.unit,
76   },
77   right: {
78     marginLeft: 0,
79   }
80 });
81
82 const TabContainer: React.SFC = ({ children }) => {
83   return (
84     <div style={{ width: "430px", height: "530px", position: "relative", display: 'flex', flexDirection: 'column' }}>
85       {children}
86     </div>
87   );
88 }
89
90 export enum EditMediatorConfigDialogMode {
91   None = "none",
92   AddMediatorConfig = "addMediatorConfig",
93   EditMediatorConfig = "editMediatorConfig",
94   RemoveMediatorConfig = "removeMediatorConfig",
95 }
96
97 const mapProps = (state: IApplicationStoreState) => ({
98   supportedDevices: state.mediator.mediatorServerState.supportedDevices
99 });
100
101 const mapDispatch = (dispatcher: IDispatcher) => ({
102   addMediatorConfig: (config: MediatorConfig) => {
103     dispatcher.dispatch(addMediatorConfigAsyncActionCreator(config));
104   },
105   updateMediatorConfig: (config: MediatorConfig) => {
106     dispatcher.dispatch(updateMediatorConfigAsyncActionCreator(config));
107   },
108   removeMediatorConfig: (config: MediatorConfig) => {
109     dispatcher.dispatch(removeMediatorConfigAsyncActionCreator(config));
110   },
111 });
112
113 type DialogSettings = {
114   dialogTitle: string;
115   dialogDescription: string;
116   applyButtonText: string;
117   cancelButtonText: string;
118   readonly: boolean;
119   readonlyName: boolean;
120 };
121
122 const settings: { [key: string]: DialogSettings } = {
123   [EditMediatorConfigDialogMode.None]: {
124     dialogTitle: "",
125     dialogDescription: "",
126     applyButtonText: "",
127     cancelButtonText: "",
128     readonly: true,
129     readonlyName: true,
130   },
131   [EditMediatorConfigDialogMode.AddMediatorConfig]: {
132     dialogTitle: "Add Mediator Configuration",
133     dialogDescription: "",
134     applyButtonText: "Add",
135     cancelButtonText: "Cancel",
136     readonly: false,
137     readonlyName: false,
138   },
139   [EditMediatorConfigDialogMode.EditMediatorConfig]: {
140     dialogTitle: "Edit Mediator Configuration",
141     dialogDescription: "",
142     applyButtonText: "Update",
143     cancelButtonText: "Cancel",
144     readonly: false,
145     readonlyName: true,
146   },
147   [EditMediatorConfigDialogMode.RemoveMediatorConfig]: {
148     dialogTitle: "Remove Mediator Configuration",
149     dialogDescription: "",
150     applyButtonText: "Remove",
151     cancelButtonText: "Cancel",
152     readonly: true,
153     readonlyName: true,
154   },
155 };
156
157 type EditMediatorConfigDialogComponentProps = WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch> & {
158   mode: EditMediatorConfigDialogMode;
159   mediatorConfig: MediatorConfig;
160   onClose: () => void;
161 };
162
163 type EditMediatorConfigDialogComponentState = MediatorConfig & { activeTab: number; activeOdlConfig: string };
164
165 class EditMediatorConfigDialogComponent extends React.Component<EditMediatorConfigDialogComponentProps, EditMediatorConfigDialogComponentState> {
166   constructor (props: EditMediatorConfigDialogComponentProps) {
167     super(props);
168
169     this.state = {
170       ...this.props.mediatorConfig,
171       activeTab: 0,
172       activeOdlConfig: ""
173     };
174   }
175
176   private odlConfigValueChangeHandlerCreator = <THtmlElement extends HTMLElement, TKey extends keyof ODLConfig>(index: number, property: TKey, mapValue: (event: React.ChangeEvent<THtmlElement>) => any) => (event: React.ChangeEvent<THtmlElement>) => {
177     event.stopPropagation();
178     event.preventDefault();
179     this.setState({
180       ODLConfig: [
181         ...this.state.ODLConfig.slice(0, index),
182         { ...this.state.ODLConfig[index], [property]: mapValue(event) },
183         ...this.state.ODLConfig.slice(index + 1)
184       ]
185     });
186   }
187
188   render(): JSX.Element {
189     const setting = settings[this.props.mode];
190     const { classes } = this.props;
191     return (
192       <Dialog open={this.props.mode !== EditMediatorConfigDialogMode.None}>
193         <DialogTitle id="form-dialog-title">{setting.dialogTitle}</DialogTitle>
194         <DialogContent>
195           <DialogContentText>
196             {setting.dialogDescription}
197           </DialogContentText>
198           <Tabs value={this.state.activeTab} indicatorColor="primary" textColor="primary" onChange={(event, value) => this.setState({ activeTab: value })} >
199             <Tab label="Config" />
200             <Tab label="ODL AutoConnect" />
201           </Tabs>
202           {this.state.activeTab === 0 ? <TabContainer >
203             <TextField disabled={setting.readonly || setting.readonlyName} spellCheck={false} autoFocus margin="dense" id="name" label="Name" type="text" fullWidth value={this.state.Name} onChange={(event) => { this.setState({ Name: event.target.value }); }} />
204             <FormControl fullWidth disabled={setting.readonly}>
205               <InputLabel htmlFor="deviceType">Device</InputLabel>
206               <Select value={this.state.DeviceType} onChange={(event) => {
207                 const device = this.props.supportedDevices.find(device => device.id === +event.target.value);
208                 if (device) {
209                   this.setState({
210                     DeviceType: device.id,
211                     NeXMLFile: device.xml
212                   });
213                 } else {
214                   this.setState({
215                     DeviceType: -1,
216                     NeXMLFile: ""
217                   });
218                 }
219               }} inputProps={{ name: 'deviceType', id: 'deviceType' }} fullWidth >
220                 <MenuItem value={-1}><em>None</em></MenuItem>
221                 {this.props.supportedDevices.map(device => (<MenuItem key={device.id} value={device.id} >{`${device.vendor} - ${device.device} (${device.version || '0.0.0'}) `}</MenuItem>))}
222               </Select>
223             </FormControl>
224             <TextField disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ipAddress" label="Device IP" type="text" fullWidth value={this.state.DeviceIp} onChange={(event) => { this.setState({ DeviceIp: event.target.value }); }} />
225             <TextField disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="devicePort" label="Device SNMP Port" type="number" fullWidth value={this.state.DevicePort || ""} onChange={(event) => { this.setState({ DevicePort: +event.target.value }); }} />
226             <TextField disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="trapsPort" label="TrapsPort" type="number" fullWidth value={this.state.TrapPort || ""} onChange={(event) => { this.setState({ TrapPort: +event.target.value }); }} />
227             <TextField disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ncUser" label="Netconf User" type="text" fullWidth value={this.state.NcUsername} onChange={(event) => { this.setState({ NcUsername: event.target.value }); }} />
228             <TextField disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ncPassword" label="Netconf Password" type="password" fullWidth value={this.state.NcPassword} onChange={(event) => { this.setState({ NcPassword: event.target.value }); }} />
229             <TextField disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ncPort" label="Netconf Port" type="number" fullWidth value={this.state.NcPort || ""} onChange={(event) => { this.setState({ NcPort: +event.target.value }); }} />
230           </TabContainer> : null}
231           {this.state.activeTab === 1 ? <TabContainer >
232             {this.state.ODLConfig && this.state.ODLConfig.length > 0
233               ? this.state.ODLConfig.map((cfg, ind) => {
234                 const panelId = `panel-${ind}`;
235                 const deleteButton = (<IconButton onClick={() => {
236                   this.setState({
237                     ODLConfig: [
238                       ...this.state.ODLConfig.slice(0, ind),
239                       ...this.state.ODLConfig.slice(ind + 1)
240                     ]
241                   });
242                 }} ><DeleteIcon /></IconButton>)
243                 return (
244                   <Panel title={cfg.Server && `${cfg.User ? `${cfg.User}@` : ''}${cfg.Protocol}://${cfg.Server}:${cfg.Port}` || "new odl config"} key={panelId} panelId={panelId} activePanel={this.state.activeOdlConfig} customActionButtons={[deleteButton]}
245                     onToggle={(id) => this.setState({ activeOdlConfig: (this.state.activeOdlConfig === id) ? "" : (id || "") })} >
246                     <div className={classes.alignInOneLine}>
247                       <FormControl className={classes.left} margin={"dense"} >
248                         <InputLabel htmlFor={`protocol-${ind}`}>Protocoll</InputLabel>
249                         <Select value={cfg.Protocol} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Protocol", e => (e.target.value))} inputProps={{ name: `protocol-${ind}`, id: `protocol-${ind}` }} fullWidth >
250                           <MenuItem value={"http"}>http</MenuItem>
251                           <MenuItem value={"https"}>https</MenuItem>
252                         </Select>
253                       </FormControl>
254                       <TextField className={classes.left} spellCheck={false} margin="dense" id="hostname" label="Hostname" type="text" value={cfg.Server} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Server", e => e.target.value)} />
255                       <TextField className={classes.right} style={{ maxWidth: "65px" }} spellCheck={false} margin="dense" id="port" label="Port" type="number" value={cfg.Port || ""} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Port", e => +e.target.value)} />
256                     </div>
257                     <div className={classes.alignInOneLine}>
258                       <TextField className={classes.left} spellCheck={false} margin="dense" id="username" label="Username" type="text" value={cfg.User} onChange={this.odlConfigValueChangeHandlerCreator(ind, "User", e => e.target.value)} />
259                       <TextField className={classes.right} spellCheck={false} margin="dense" id="password" label="Password" type="password" value={cfg.Password} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Password", e => e.target.value)} />
260                     </div>
261                     <div className={classes.alignInOneLine}>
262                       <FormControlLabel className={classes.right} control={<Checkbox checked={cfg.Trustall} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Trustall", e => e.target.checked)} />} label="Trustall" />
263                     </div>
264                   </Panel>
265                 );
266               })
267               : <div className={classes.center} >
268                 <Typography component={"div"} className={classes.title} color="textSecondary" gutterBottom>Please add an ODL auto connect configuration.</Typography>
269               </div>
270             }
271             <Fab className={classes.fab} color="primary" aria-label="Add" onClick={() => this.setState({
272               ODLConfig: [...this.state.ODLConfig, { Server: '', Port: 8181, Protocol: 'https', User: 'admin', Password: 'admin', Trustall: false }]
273             })} > <AddIcon /> </Fab>
274
275           </TabContainer> : null}
276
277         </DialogContent>
278         <DialogActions>
279           <Button onClick={(event) => {
280             this.onApply(Object.keys(this.state).reduce<MediatorConfig & { [kex: string]: any }>((acc, key) => {
281               // do not copy activeTab and activeOdlConfig
282               if (key !== "activeTab" && key !== "activeOdlConfig" && key !== "_initialMediatorConfig") acc[key] = (this.state as any)[key];
283               return acc;
284             }, {} as MediatorConfig));
285             event.preventDefault();
286             event.stopPropagation();
287           }} > {setting.applyButtonText} </Button>
288           <Button onClick={(event) => {
289             this.onCancel();
290             event.preventDefault();
291             event.stopPropagation();
292           }} color="secondary"> {setting.cancelButtonText} </Button>
293         </DialogActions>
294       </Dialog>
295     )
296   }
297
298   private onApply = (config: MediatorConfig) => {
299     this.props.onClose && this.props.onClose();
300     switch (this.props.mode) {
301       case EditMediatorConfigDialogMode.AddMediatorConfig:
302         config && this.props.addMediatorConfig(config);
303         break;
304       case EditMediatorConfigDialogMode.EditMediatorConfig:
305         config && this.props.updateMediatorConfig(config);
306         break;
307       case EditMediatorConfigDialogMode.RemoveMediatorConfig:
308         config && this.props.removeMediatorConfig(config);
309         break;
310     }
311   };
312
313   private onCancel = () => {
314     this.props.onClose && this.props.onClose();
315   }
316
317   static getDerivedStateFromProps(props: EditMediatorConfigDialogComponentProps, state: EditMediatorConfigDialogComponentState & { _initialMediatorConfig: MediatorConfig }): EditMediatorConfigDialogComponentState & { _initialMediatorConfig: MediatorConfig } {
318     if (props.mediatorConfig !== state._initialMediatorConfig) {
319       state = {
320         ...state,
321         ...props.mediatorConfig,
322         _initialMediatorConfig: props.mediatorConfig,
323       };
324     }
325     return state;
326   }
327 }
328
329 export const EditMediatorConfigDialog = withStyles(styles)(connect(mapProps, mapDispatch)(EditMediatorConfigDialogComponent));
330 export default EditMediatorConfigDialog;