fix oauth code
[ccsdk/features.git] / sdnr / wt-odlux / odlux / apps / connectApp / src / components / networkElements.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
20 import AddIcon from '@mui/icons-material/Add';
21 import ComputerIcon from '@mui/icons-material/Computer';
22 import EditIcon from '@mui/icons-material/Edit';
23 import Info from '@mui/icons-material/Info';
24 import LinkIcon from '@mui/icons-material/Link';
25 import LinkOffIcon from '@mui/icons-material/LinkOff';
26 import Refresh from '@mui/icons-material/Refresh';
27 import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
28 import { Divider, MenuItem, Typography } from '@mui/material';
29 import { Theme } from '@mui/material/styles';
30 import { WithStyles } from '@mui/styles';
31 import createStyles from '@mui/styles/createStyles';
32 import withStyles from '@mui/styles/withStyles';
33
34 import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions';
35 import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
36 import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
37 import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
38 import { getAccessPolicyByUrl } from '../../../../framework/src/services/restService';
39
40 import { loadAllInfoElementAsync, loadAllInfoElementFeaturesAsync } from '../actions/infoNetworkElementActions';
41 import { createNetworkElementsActions, createNetworkElementsProperties } from '../handlers/networkElementsHandler';
42 import { NetworkElementConnection } from '../models/networkElementConnection';
43 import { ModuleSet, TopologyNode } from '../models/topologyNetconf';
44 import { connectService } from '../services/connectService';
45
46 import EditNetworkElementDialog, { EditNetworkElementDialogMode } from './editNetworkElementDialog';
47 import InfoNetworkElementDialog, { InfoNetworkElementDialogMode } from './infoNetworkElementDialog';
48 import RefreshNetworkElementsDialog, { RefreshNetworkElementsDialogMode } from './refreshNetworkElementsDialog';
49
50 const styles = (theme: Theme) => createStyles({
51   connectionStatusConnected: {
52     color: 'darkgreen',
53   },
54   connectionStatusConnecting: {
55     color: 'blue',
56   },
57   connectionStatusDisconnected: {
58     color: 'red',
59   },
60   button: {
61     margin: 0,
62     padding: '6px 6px',
63     minWidth: 'unset',
64   },
65   spacer: {
66     marginLeft: theme.spacing(1),
67     marginRight: theme.spacing(1),
68     display: 'inline',
69   },
70 });
71
72 type GetStatelessComponentProps<T> = T extends (props: infer P & { children?: React.ReactNode }) => any ? P : any;
73 const MenuItemExt: React.FC<GetStatelessComponentProps<typeof MenuItem>> = (props) => {
74   const [disabled, setDisabled] = React.useState(true);
75   const onMouseDown = (ev: React.MouseEvent<HTMLElement>) => {
76     if (ev.button === 1) {
77       setDisabled(!disabled);
78       ev.preventDefault();
79     }
80   };
81   return (
82     <div onMouseDown={onMouseDown} >
83       <MenuItem {...{ ...props, disabled: props.disabled && disabled }} />
84     </div>
85   );
86 };
87
88 const mapProps = (state: IApplicationStoreState) => ({
89   networkElementsProperties: createNetworkElementsProperties(state),
90   applicationState: state,
91 });
92
93 const mapDispatch = (dispatcher: IDispatcher) => ({
94   networkElementsActions: createNetworkElementsActions(dispatcher.dispatch),
95   navigateToApplication: (applicationName: string, path?: string) => dispatcher.dispatch(new NavigateToApplication(applicationName, path)),
96   networkElementInfo: async (nodeId: string) => dispatcher.dispatch(loadAllInfoElementAsync(nodeId)),
97   networkElementFeaturesInfo: async (nodeId: string) => dispatcher.dispatch(loadAllInfoElementFeaturesAsync(nodeId)),
98 });
99
100 type NetworkElementsListComponentProps = WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>;
101 type NetworkElementsListComponentState = {
102   networkElementToEdit: NetworkElementConnection;
103   networkElementEditorMode: EditNetworkElementDialogMode;
104   refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode;
105   infoNetworkElementEditorMode: InfoNetworkElementDialogMode;
106   elementInfo: TopologyNode | null;
107   elementInfoFeature: ModuleSet | null;
108 };
109
110 const emptyRequireNetworkElement: NetworkElementConnection = { id: '', nodeId: '', host: '', port: 830, status: 'Disconnected', isRequired: true };
111 let initialSorted = false;
112 const NetworkElementTable = MaterialTable as MaterialTableCtorType<NetworkElementConnection>;
113
114 export class NetworkElementsListComponent extends React.Component<NetworkElementsListComponentProps, NetworkElementsListComponentState> {
115
116   constructor(props: NetworkElementsListComponentProps) {
117     super(props);
118
119     this.state = {
120       networkElementToEdit: emptyRequireNetworkElement,
121       networkElementEditorMode: EditNetworkElementDialogMode.None,
122       refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None,
123       elementInfo: null,
124       elementInfoFeature: null,
125       infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None,
126     };
127   }
128
129   getContextMenu(rowData: NetworkElementConnection): JSX.Element[] {
130     const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id);
131     const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri);
132     const canMount = mountPolicy && mountPolicy.POST || false;
133
134     const { configuration } = this.props.applicationState as any;
135     const buttonArray = [
136       <MenuItemExt aria-label={'mount-button'} onClick={event => this.onOpenMountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkIcon /><Typography>Mount</Typography></MenuItemExt>,
137       <MenuItemExt aria-label={'unmount-button'} onClick={event => this.onOpenUnmountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkOffIcon /><Typography>Unmount</Typography></MenuItemExt>,
138       <Divider />,
139       <MenuItem aria-label={'info-button'} onClick={event => this.onOpenInfoNetworkElementDialog(event, rowData)} disabled={rowData.status !== 'Connected'} ><Info /><Typography>Info</Typography></MenuItem>,
140       <MenuItem aria-label={'edit-button'} onClick={event => this.onOpenEditNetworkElementDialog(event, rowData)}><EditIcon /><Typography>Edit</Typography></MenuItem>,
141       <MenuItem aria-label={'remove-button'} onClick={event => this.onOpenRemoveNetworkElementDialog(event, rowData)} ><RemoveIcon /><Typography>Remove</Typography></MenuItem>,
142       <Divider />,
143       <MenuItem aria-label={'inventory-button'} onClick={() => this.props.navigateToApplication('inventory', rowData.nodeId)}><Typography>Inventory</Typography></MenuItem>,
144       <Divider />,
145       <MenuItem aria-label={'fault-button'} onClick={() => this.props.navigateToApplication('fault', rowData.nodeId)} ><Typography>Fault</Typography></MenuItem>,
146       <MenuItem aria-label={'configure-button'} onClick={() => this.props.navigateToApplication('configuration', rowData.nodeId)} disabled={rowData.status === 'Connecting' || rowData.status === 'Disconnected' || !configuration}><Typography>Configure</Typography></MenuItem>,
147       <MenuItem onClick={() => this.props.navigateToApplication('accounting', rowData.nodeId)} disabled={true}><Typography>Accounting</Typography></MenuItem>,
148       <MenuItem aria-label={'performance-button'} onClick={() => this.props.navigateToApplication('performanceHistory', rowData.nodeId)}><Typography>Performance</Typography></MenuItem>,
149       <MenuItem onClick={() => this.props.navigateToApplication('security', rowData.nodeId)} disabled={true} ><Typography>Security</Typography></MenuItem>,
150     ];
151
152     if (rowData.weburi) {
153       // add an icon for gui cuttrough, if weburi is available
154       return [<MenuItem aria-label={'web-client-button'} onClick={() => window.open(rowData.weburi, '_blank')} ><ComputerIcon /><Typography>Web Client</Typography></MenuItem>].concat(buttonArray);
155     } else {
156       return buttonArray;
157     }
158   }
159
160   //  private navigationCreator
161
162   render(): JSX.Element {
163     //const { classes } = this.props;
164     const { networkElementToEdit } = this.state;
165     let savedRadio = 'password';
166     if (this.state.networkElementToEdit.password && this.state.networkElementToEdit.password.length > 0) {
167       savedRadio = 'password';
168     } else if (this.state.networkElementToEdit.tlsKey && this.state.networkElementToEdit.tlsKey.length > 0) {
169       savedRadio = 'tlsKey';
170     }
171
172     // const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id);
173     // const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri);
174     // const canAdd =  mountPolicy && mountPolicy.POST || false;
175     const canAdd = true;
176
177     const addRequireNetworkElementAction = {
178       icon: AddIcon, tooltip: 'Add node', ariaLabel: 'add-element', onClick: () => {
179         this.setState({
180           networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement,
181           networkElementToEdit: emptyRequireNetworkElement,
182         });
183       },
184     };
185
186     const refreshNetworkElementsAction = {
187       icon: Refresh, tooltip: 'Refresh table', ariaLabel: 'refresh', onClick: () => {
188         this.setState({
189           refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable,
190         });
191       },
192     };
193
194     return <>
195       <NetworkElementTable stickyHeader tableId="network-element-table" customActionButtons={[refreshNetworkElementsAction, ...(canAdd ? [addRequireNetworkElementAction] : [])]} columns={[
196         { property: 'nodeId', title: 'Node ID', type: ColumnType.text },
197         { property: 'status', title: 'Connection Status', type: ColumnType.text, width:'15%' },
198         { property: 'host', title: 'Host', type: ColumnType.text },
199         { property: 'port', title: 'Port', type: ColumnType.numeric },
200         { property: 'isRequired', title: 'Required', type: ColumnType.boolean },
201         { property: 'deviceType', title: 'Type', type: ColumnType.text },
202         //  { property: "coreModelCapability", title: "Core Model", type: ColumnType.text },
203         { property: 'deviceFunction', title: 'Function', type: ColumnType.text, width: '25%' },
204       ]} idProperty="id" {...this.props.networkElementsActions} {...this.props.networkElementsProperties} asynchronus createContextMenu={rowData => {
205
206         return this.getContextMenu(rowData);
207       }} >
208       </NetworkElementTable>
209       <EditNetworkElementDialog 
210         initialNetworkElement={networkElementToEdit}
211         mode={this.state.networkElementEditorMode}
212         onClose={this.onCloseEditNetworkElementDialog}
213         radioChecked={savedRadio}
214       />
215       <RefreshNetworkElementsDialog
216         mode={this.state.refreshNetworkElementsEditorMode}
217         onClose={this.onCloseRefreshNetworkElementsDialog}
218       />
219       <InfoNetworkElementDialog
220         initialNetworkElement={networkElementToEdit}
221         mode={this.state.infoNetworkElementEditorMode}
222         onClose={this.onCloseInfoNetworkElementDialog}
223       />
224     </>;
225   }
226
227   public componentDidMount() {
228     if (!initialSorted) {
229       initialSorted = true;
230       this.props.networkElementsActions.onHandleRequestSort('node-id');
231     } else {
232       this.props.networkElementsActions.onRefresh();
233     }
234   }
235
236   private onOpenAddNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
237     this.setState({
238       networkElementToEdit: element,
239       networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement,
240     });
241   };
242
243   private onOpenRemoveNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
244     this.setState({
245       networkElementToEdit: element,
246       networkElementEditorMode: EditNetworkElementDialogMode.RemoveNetworkElement,
247     });
248   };
249
250   private onOpenEditNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
251     //let radioSaved;
252     //if (element.password && element.password.length > 0)
253     //  radioSaved = 'password';
254     //else if (element.tlsKey && element.tlsKey.length > 0)
255     //  radioSaved = 'tlsKey';
256     this.setState({
257       networkElementToEdit: {
258         nodeId: element.nodeId,
259         isRequired: element.isRequired,
260         host: element.host,
261         port: element.port,
262         username: element.username,
263         password: element.password,
264         tlsKey: element.tlsKey,
265       },
266       networkElementEditorMode: EditNetworkElementDialogMode.EditNetworkElement,
267     });
268   };
269
270   private onOpenUnmountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
271     this.setState({
272       networkElementToEdit: element,
273       networkElementEditorMode: EditNetworkElementDialogMode.UnmountNetworkElement,
274     });
275   };
276
277   private onOpenMountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
278     this.setState({
279       networkElementToEdit: element,
280       networkElementEditorMode: EditNetworkElementDialogMode.MountNetworkElement,
281     });
282   };
283
284   private onOpenInfoNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
285     this.props.networkElementInfo(element.nodeId);
286     this.props.networkElementFeaturesInfo(element.nodeId);
287     this.setState({
288       networkElementToEdit: element,
289       infoNetworkElementEditorMode: InfoNetworkElementDialogMode.InfoNetworkElement,
290     });
291   };
292
293   private onCloseEditNetworkElementDialog = () => {
294     this.setState({
295       networkElementEditorMode: EditNetworkElementDialogMode.None,
296       networkElementToEdit: emptyRequireNetworkElement,
297     });
298   };
299
300   private onCloseInfoNetworkElementDialog = () => {
301     this.setState({
302       infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None,
303       networkElementToEdit: emptyRequireNetworkElement,
304     });
305   };
306
307   private onCloseRefreshNetworkElementsDialog = () => {
308     this.setState({
309       refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None,
310     });
311   };
312 }
313
314 export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent));