11feb46aea546cdb8a433e0049dd1c439202cc9d
[ccsdk/features.git] / sdnr / wt / odlux / apps / mediatorApp / src / views / mediatorApplication.tsx
1 import * as React from 'react';
2 import { Theme, createStyles, WithStyles, withStyles, Tooltip } from '@material-ui/core';
3
4 import AddIcon from '@material-ui/icons/Add';
5 import IconButton from '@material-ui/core/IconButton';
6 import EditIcon from '@material-ui/icons/Edit';
7 import DeleteIcon from '@material-ui/icons/Delete';
8 import InfoIcon from '@material-ui/icons/Info';
9 import StartIcon from '@material-ui/icons/PlayArrow';
10 import StopIcon from '@material-ui/icons/Stop';
11
12 import CircularProgress from '@material-ui/core/CircularProgress'
13
14 import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
15 import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect';
16 import MaterialTable, { MaterialTableCtorType, ColumnType } from '../../../../framework/src/components/material-table';
17
18 import { MediatorConfig, BusySymbol, MediatorConfigResponse } from '../models/mediatorServer';
19 import EditMediatorConfigDialog, { EditMediatorConfigDialogMode } from '../components/editMediatorConfigDialog';
20 import { startMediatorByNameAsyncActionCreator, stopMediatorByNameAsyncActionCreator } from '../actions/mediatorConfigActions';
21 import mediatorService from '../services/mediatorService';
22
23 const styles = (theme: Theme) => createStyles({
24   root: {
25     display: 'flex',
26     flexDirection: 'column',
27     flex: '1',
28   },
29   formControl: {
30     margin: theme.spacing.unit,
31     minWidth: 300,
32   },
33   button: {
34     margin: 0,
35     padding: "6px 6px",
36     minWidth: 'unset'
37   },
38   spacer: {
39     marginLeft: theme.spacing.unit,
40     marginRight: theme.spacing.unit,
41     display: "inline"
42   },
43   progress: {
44     flex: '1 1 100%',
45     display: 'flex',
46     alignItems: 'center',
47     justifyContent: 'center',
48     pointerEvents: 'none'
49   }
50 });
51
52 const mapProps = (state: IApplicationStoreState) => ({
53   serverName: state.mediatorApp.mediatorServerState.name,
54   serverUrl: state.mediatorApp.mediatorServerState.url,
55   serverVersion: state.mediatorApp.mediatorServerState.serverVersion,
56   mediatorVersion: state.mediatorApp.mediatorServerState.mediatorVersion,
57   configurations: state.mediatorApp.mediatorServerState.configurations,
58   supportedDevices: state.mediatorApp.mediatorServerState.supportedDevices,
59   busy: state.mediatorApp.mediatorServerState.busy,
60 });
61
62 const mapDispatch = (dispatcher: IDispatcher) => ({
63   startMediator: (name: string) => dispatcher.dispatch(startMediatorByNameAsyncActionCreator(name)),
64   stopMediator: (name: string) => dispatcher.dispatch(stopMediatorByNameAsyncActionCreator(name)),
65 });
66
67 const emptyMediatorConfig: MediatorConfig = {
68   Name: "",
69   DeviceIp: "127.0.0.1",
70   DevicePort: 161,
71   NcUsername: "admin",
72   NcPassword: "admin",
73   DeviceType: -1,
74   NcPort: 4020,
75   TrapPort: 10020,
76   NeXMLFile: "",
77   ODLConfig: []
78 };
79
80 const MediatorServerConfigurationsTable = MaterialTable as MaterialTableCtorType<MediatorConfigResponse>;
81
82 type MediatorApplicationComponentProps = Connect<typeof mapProps, typeof mapDispatch> & WithStyles<typeof styles>;
83
84 type MediatorServerSelectionComponentState = {
85   busy: boolean,
86   mediatorConfigToEdit: MediatorConfig,
87   mediatorConfigEditorMode: EditMediatorConfigDialogMode
88 }
89
90 class MediatorApplicationComponent extends React.Component<MediatorApplicationComponentProps, MediatorServerSelectionComponentState> {
91
92   constructor (props: MediatorApplicationComponentProps) {
93     super(props);
94
95     this.state = {
96       busy: false,
97       mediatorConfigToEdit: emptyMediatorConfig,
98       mediatorConfigEditorMode: EditMediatorConfigDialogMode.None,
99     }
100   }
101
102   render() {
103     const { classes } = this.props;
104
105     const renderActions = (rowData: MediatorConfigResponse) => (
106       <>
107         <div className={classes.spacer}>
108           <Tooltip title={"Start"} >
109             <IconButton disabled={rowData[BusySymbol]} className={classes.button}>
110               <StartIcon onClick={(event) => { event.preventDefault(); event.stopPropagation(); this.props.startMediator(rowData.Name); }} />
111             </IconButton>
112           </Tooltip>
113           <Tooltip title={"Stop"} >
114             <IconButton disabled={rowData[BusySymbol]} className={classes.button}>
115               <StopIcon onClick={(event) => { event.preventDefault(); event.stopPropagation(); this.props.stopMediator(rowData.Name); }} />
116             </IconButton>
117           </Tooltip>
118         </div>
119         <div className={classes.spacer}>
120           <Tooltip title={"Info"} ><IconButton className={classes.button}><InfoIcon /></IconButton></Tooltip>
121         </div>
122         <div className={classes.spacer}>
123           {process.env.NODE_ENV === "development" ? <Tooltip title={"Edit"} ><IconButton disabled={rowData[BusySymbol]} className={classes.button} onClick={event => this.onOpenEditConfigurationDialog(event, rowData)}><EditIcon /></IconButton></Tooltip> : null}
124           <Tooltip title={"Remove"} ><IconButton disabled={rowData[BusySymbol]} className={classes.button} onClick={event => this.onOpenRemoveConfigutationDialog(event, rowData)}><DeleteIcon /></IconButton></Tooltip>
125         </div>
126       </>
127     );
128
129     const addMediatorConfigAction = { icon: AddIcon, tooltip: 'Add', onClick: this.onOpenAddConfigurationDialog };
130     return (
131       <div className={classes.root}>
132         {this.props.busy || this.state.busy
133           ? <div className={classes.progress}> <CircularProgress color={"secondary"} size={48} /> </div>
134           : <MediatorServerConfigurationsTable title={this.props.serverName || ''} customActionButtons={[addMediatorConfigAction]} idProperty={"Name"} rows={this.props.configurations} asynchronus columns={[
135             { property: "Name", title: "Mediator", type: ColumnType.text },
136             { property: "Status", title: "Status", type: ColumnType.custom, customControl: ({ rowData }) => rowData.pid ? (<span>Running</span>) : (<span>Stopped</span>) },
137             { property: "DeviceIp", title: "IP Adress", type: ColumnType.text },
138             {
139               property: "Device", title: "Device", type: ColumnType.custom, customControl: ({ rowData }) => {
140                 const dev = this.props.supportedDevices && this.props.supportedDevices.find(dev => dev.id === rowData.DeviceType);
141                 return (
142                   <span> {dev && `${dev.vendor} - ${dev.device} (${dev.version || '0.0.0'})`} </span>
143                 )
144               }
145             },
146             { property: "actions", title: "Actions", type: ColumnType.custom, customControl: ({ rowData }) => renderActions(rowData) },
147           ]} />
148         }
149
150         <EditMediatorConfigDialog
151           mediatorConfig={this.state.mediatorConfigToEdit}
152           mode={this.state.mediatorConfigEditorMode}
153           onClose={this.onCloseEditMediatorConfigDialog} />
154
155       </div>
156     );
157   }
158
159   private onOpenAddConfigurationDialog = () => {
160     // Tries to determine a free port for netconf listener and snpm listener
161     // it it could not determine free ports the dialog will open any way
162     // those ports should not be configured from the fontend, furthermore 
163     // the backend should auto configure them and tell the user the result 
164     // after the creation process.
165
166     this.setState({
167       busy: true,
168     });
169     this.props.serverUrl && Promise.all([
170       mediatorService.getMediatorServerFreeNcPorts(this.props.serverUrl, 1),
171       mediatorService.getMediatorServerFreeSnmpPorts(this.props.serverUrl, 1),
172     ]).then(([freeNcPorts, freeSnmpPorts]) => {
173       if (freeNcPorts && freeSnmpPorts && freeNcPorts.length > 0 && freeSnmpPorts.length > 0) {
174         this.setState({
175           busy: false,
176           mediatorConfigEditorMode: EditMediatorConfigDialogMode.AddMediatorConfig,
177           mediatorConfigToEdit: {
178             ...emptyMediatorConfig,
179             NcPort: freeNcPorts[0],
180             TrapPort: freeSnmpPorts[0],
181           },
182         });
183       } else {
184         this.setState({
185           busy: false,
186           mediatorConfigEditorMode: EditMediatorConfigDialogMode.AddMediatorConfig,
187           mediatorConfigToEdit: { ...emptyMediatorConfig },
188         });
189       }
190     })
191
192   }
193
194   private onOpenEditConfigurationDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfig) => {
195     event.preventDefault();
196     event.stopPropagation();
197     this.setState({
198       mediatorConfigEditorMode: EditMediatorConfigDialogMode.EditMediatorConfig,
199       mediatorConfigToEdit: configEntry,
200     });
201   }
202
203   private onOpenRemoveConfigutationDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfig) => {
204     event.preventDefault();
205     event.stopPropagation();
206     this.setState({
207       mediatorConfigEditorMode: EditMediatorConfigDialogMode.RemoveMediatorConfig,
208       mediatorConfigToEdit: configEntry,
209     });
210   }
211
212   private onCloseEditMediatorConfigDialog = () => {
213     this.setState({
214       mediatorConfigEditorMode: EditMediatorConfigDialogMode.None,
215       mediatorConfigToEdit: emptyMediatorConfig,
216     });
217   }
218 }
219
220 export const MediatorApplication = withStyles(styles)(connect(mapProps, mapDispatch)(MediatorApplicationComponent));