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