Create wt-odlux directory
[ccsdk/features.git] / sdnr / wt-odlux / odlux / apps / mediatorApp / src / views / mediatorApplication.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 React from 'react';
19 import { Theme, Tooltip } from '@mui/material';
20
21 import { WithStyles } from '@mui/styles';
22 import createStyles from '@mui/styles/createStyles';
23 import withStyles from '@mui/styles/withStyles';
24
25 import AddIcon from '@mui/icons-material/Add';
26 import IconButton from '@mui/material/IconButton';
27 import EditIcon from '@mui/icons-material/Edit';
28 import DeleteIcon from '@mui/icons-material/Delete';
29 import InfoIcon from '@mui/icons-material/Info';
30 import StartIcon from '@mui/icons-material/PlayArrow';
31 import StopIcon from '@mui/icons-material/Stop';
32
33 import CircularProgress from '@mui/material/CircularProgress'
34
35 import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
36 import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
37 import MaterialTable, { MaterialTableCtorType, ColumnType } from '../../../../framework/src/components/material-table';
38
39 import { MediatorConfig, BusySymbol, MediatorConfigResponse } from '../models/mediatorServer';
40 import EditMediatorConfigDialog, { EditMediatorConfigDialogMode } from '../components/editMediatorConfigDialog';
41 import { startMediatorByNameAsyncActionCreator, stopMediatorByNameAsyncActionCreator } from '../actions/mediatorConfigActions';
42 import mediatorService from '../services/mediatorService';
43 import { ShowMediatorInfoDialog, MediatorInfoDialogMode } from '../components/showMeditaorInfoDialog'
44
45 const styles = (theme: Theme) => createStyles({
46   root: {
47     display: 'flex',
48     flexDirection: 'column',
49     flex: '1',
50   },
51   formControl: {
52     margin: theme.spacing(1),
53     minWidth: 300,
54   },
55   button: {
56     margin: 0,
57     padding: "6px 6px",
58     minWidth: 'unset'
59   },
60   spacer: {
61     marginLeft: theme.spacing(1),
62     marginRight: theme.spacing(1),
63     display: "inline"
64   },
65   progress: {
66     flex: '1 1 100%',
67     display: 'flex',
68     alignItems: 'center',
69     justifyContent: 'center',
70     pointerEvents: 'none'
71   }
72 });
73
74 const mapProps = (state: IApplicationStoreState) => ({
75   serverName: state.mediator.mediatorServerState.name,
76   serverUrl: state.mediator.mediatorServerState.url,
77   serverId: state.mediator.mediatorServerState.id,
78   serverVersion: state.mediator.mediatorServerState.serverVersion,
79   mediatorVersion: state.mediator.mediatorServerState.mediatorVersion,
80   configurations: state.mediator.mediatorServerState.configurations,
81   supportedDevices: state.mediator.mediatorServerState.supportedDevices,
82   busy: state.mediator.mediatorServerState.busy,
83   isReachable: state.mediator.mediatorServerState.isReachable
84 });
85
86 const mapDispatch = (dispatcher: IDispatcher) => ({
87   startMediator: (name: string) => dispatcher.dispatch(startMediatorByNameAsyncActionCreator(name)),
88   stopMediator: (name: string) => dispatcher.dispatch(stopMediatorByNameAsyncActionCreator(name)),
89 });
90
91 const emptyMediatorConfig: MediatorConfig = {
92   Name: "",
93   DeviceIp: "127.0.0.1",
94   DevicePort: 161,
95   NcUsername: "admin",
96   NcPassword: "admin",
97   DeviceType: -1,
98   NcPort: 4020,
99   TrapPort: 10020,
100   NeXMLFile: "",
101   ODLConfig: []
102 };
103
104 const MediatorServerConfigurationsTable = MaterialTable as MaterialTableCtorType<MediatorConfigResponse>;
105 const MediatorServerUnreachableTable = MaterialTable as MaterialTableCtorType<{ Name: string, status: string, ipAdress: string, device: string, actions: string }>
106
107 type MediatorApplicationComponentProps = Connect<typeof mapProps, typeof mapDispatch> & WithStyles<typeof styles>;
108
109 type MediatorServerSelectionComponentState = {
110   busy: boolean,
111   mediatorConfigToEdit: MediatorConfig,
112   mediatorConfigEditorMode: EditMediatorConfigDialogMode,
113   mediatorShowInfoMode: MediatorInfoDialogMode,
114   mediatorConfigToDisplay: MediatorConfigResponse | null
115 }
116
117 class MediatorApplicationComponent extends React.Component<MediatorApplicationComponentProps, MediatorServerSelectionComponentState> {
118
119   constructor(props: MediatorApplicationComponentProps) {
120     super(props);
121
122     this.state = {
123       busy: false,
124       mediatorConfigToEdit: emptyMediatorConfig,
125       mediatorConfigEditorMode: EditMediatorConfigDialogMode.None,
126       mediatorShowInfoMode: MediatorInfoDialogMode.None,
127       mediatorConfigToDisplay: null
128     }
129   }
130
131   render() {
132     const { classes } = this.props;
133
134     const renderActions = (rowData: MediatorConfigResponse) => (
135       <>
136         <div className={classes.spacer}>
137           <Tooltip disableInteractive title={"Start"} >
138             <IconButton disabled={rowData[BusySymbol]} className={classes.button} size="large">
139               <StartIcon onClick={(event) => { event.preventDefault(); event.stopPropagation(); this.props.startMediator(rowData.Name); }} />
140             </IconButton>
141           </Tooltip>
142           <Tooltip disableInteractive title={"Stop"} >
143             <IconButton disabled={rowData[BusySymbol]} className={classes.button} size="large">
144               <StopIcon onClick={(event) => { event.preventDefault(); event.stopPropagation(); this.props.stopMediator(rowData.Name); }} />
145             </IconButton>
146           </Tooltip>
147         </div>
148         <div className={classes.spacer}>
149           <Tooltip disableInteractive title={"Info"} ><IconButton
150             className={classes.button}
151             onClick={(event) => { this.onOpenInfoDialog(event, rowData) }}
152             size="large"><InfoIcon /></IconButton></Tooltip>
153         </div>
154         <div className={classes.spacer}>
155           {process.env.NODE_ENV === "development" ? <Tooltip disableInteractive title={"Edit"} ><IconButton
156             disabled={rowData[BusySymbol]}
157             className={classes.button}
158             onClick={event => this.onOpenEditConfigurationDialog(event, rowData)}
159             size="large"><EditIcon /></IconButton></Tooltip> : null}
160           <Tooltip disableInteractive title={"Remove"} ><IconButton
161             disabled={rowData[BusySymbol]}
162             className={classes.button}
163             onClick={event => this.onOpenRemoveConfigutationDialog(event, rowData)}
164             size="large"><DeleteIcon /></IconButton></Tooltip>
165         </div>
166       </>
167     );
168
169     const addMediatorConfigAction = { icon: AddIcon, tooltip: 'Add', ariaLabel: 'add-element', onClick: this.onOpenAddConfigurationDialog };
170
171     return (
172       <div className={classes.root}>
173         {this.props.busy || this.state.busy
174           ? <div className={classes.progress}> <CircularProgress color={"secondary"} size={48} /> </div>
175           :
176
177           this.props.isReachable ?
178
179             <MediatorServerConfigurationsTable defaultSortColumn={"Name"} tableId={null} defaultSortOrder="asc" stickyHeader title={this.props.serverName || ''} customActionButtons={[addMediatorConfigAction]} idProperty={"Name"} rows={this.props.configurations} asynchronus columns={[
180               { property: "Name", title: "Mediator", type: ColumnType.text },
181               { property: "Status", title: "Status", type: ColumnType.custom, customControl: ({ rowData }) => rowData.pid ? (<span>Running</span>) : (<span>Stopped</span>) },
182               { property: "DeviceIp", title: "IP Adress", type: ColumnType.text },
183               {
184                 property: "Device", title: "Device", type: ColumnType.custom, customControl: ({ rowData }) => {
185                   const dev = this.props.supportedDevices && this.props.supportedDevices.find(dev => dev.id === rowData.DeviceType);
186                   return (
187                     <span> {dev && `${dev.vendor} - ${dev.device} (${dev.version || '0.0.0'})`} </span>
188                   )
189                 }
190               },
191               { property: "actions", title: "Actions", type: ColumnType.custom, customControl: ({ rowData }) => renderActions(rowData) },
192             ]} />
193             :
194             <MediatorServerUnreachableTable title={this.props.serverName || ''} tableId={null} idProperty={"Name"} disableFilter={true} disableSorting={true} enableSelection={false} rows={[{ Name: '', status: "Mediator server not found.", ipAdress: '', device: '', actions: '' }]} columns={[
195               { property: "Name", title: "Mediator", type: ColumnType.text },
196               { property: "status", title: "Status", type: ColumnType.text },
197               { property: "ipAdress", title: "IP Adress", type: ColumnType.text },
198               { property: "device", title: "Device", type: ColumnType.text },
199               { property: "actions", title: "Actions", type: ColumnType.text },
200
201             ]} />
202         }
203
204         <EditMediatorConfigDialog
205           mediatorConfig={this.state.mediatorConfigToEdit}
206           mode={this.state.mediatorConfigEditorMode}
207           onClose={this.onCloseEditMediatorConfigDialog} />
208
209         {
210
211           this.state.mediatorShowInfoMode != MediatorInfoDialogMode.None &&
212           <ShowMediatorInfoDialog
213             config={this.state.mediatorConfigToDisplay as MediatorConfigResponse}
214             mode={this.state.mediatorShowInfoMode}
215             onClose={this.onCloseInfoDialog} />
216         }
217       </div>
218     );
219   }
220
221   private onOpenInfoDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfigResponse) => {
222     event.stopPropagation();
223     event.preventDefault();
224     this.setState({ mediatorShowInfoMode: MediatorInfoDialogMode.ShowDetails, mediatorConfigToDisplay: configEntry })
225   }
226
227   private onCloseInfoDialog = () => {
228     this.setState({ mediatorShowInfoMode: MediatorInfoDialogMode.None, mediatorConfigToDisplay: null })
229   }
230
231   private onOpenAddConfigurationDialog = () => {
232     // Tries to determine a free port for netconf listener and snpm listener
233     // it it could not determine free ports the dialog will open any way
234     // those ports should not be configured from the fontend, furthermore
235     // the backend should auto configure them and tell the user the result
236     // after the creation process.
237     this.setState({
238       busy: true,
239     });
240     this.props.serverId && Promise.all([
241       mediatorService.getMediatorServerFreeNcPorts(this.props.serverId, 1),
242       mediatorService.getMediatorServerFreeSnmpPorts(this.props.serverId, 1),
243     ]).then(([freeNcPorts, freeSnmpPorts]) => {
244       if (freeNcPorts && freeSnmpPorts && freeNcPorts.length > 0 && freeSnmpPorts.length > 0) {
245         this.setState({
246           busy: false,
247           mediatorConfigEditorMode: EditMediatorConfigDialogMode.AddMediatorConfig,
248           mediatorConfigToEdit: {
249             ...emptyMediatorConfig,
250             NcPort: freeNcPorts[0],
251             TrapPort: freeSnmpPorts[0],
252           },
253         });
254       } else {
255         this.setState({
256           busy: false,
257           mediatorConfigEditorMode: EditMediatorConfigDialogMode.AddMediatorConfig,
258           mediatorConfigToEdit: { ...emptyMediatorConfig },
259         });
260       }
261     })
262
263   }
264
265   private onOpenEditConfigurationDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfig) => {
266     event.preventDefault();
267     event.stopPropagation();
268     this.setState({
269       mediatorConfigEditorMode: EditMediatorConfigDialogMode.EditMediatorConfig,
270       mediatorConfigToEdit: configEntry,
271     });
272   }
273
274   private onOpenRemoveConfigutationDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfig) => {
275     event.preventDefault();
276     event.stopPropagation();
277     this.setState({
278       mediatorConfigEditorMode: EditMediatorConfigDialogMode.RemoveMediatorConfig,
279       mediatorConfigToEdit: configEntry,
280     });
281   }
282
283   private onCloseEditMediatorConfigDialog = () => {
284     this.setState({
285       mediatorConfigEditorMode: EditMediatorConfigDialogMode.None,
286       mediatorConfigToEdit: emptyMediatorConfig,
287     });
288   }
289 }
290
291 export const MediatorApplication = withStyles(styles)(connect(mapProps, mapDispatch)(MediatorApplicationComponent));