diff options
Diffstat (limited to 'sdnr/wt-odlux/odlux/apps/connectApp/src/components')
6 files changed, 1226 insertions, 0 deletions
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx new file mode 100644 index 000000000..6a8c92438 --- /dev/null +++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ +import React from 'react'; + +import Refresh from '@mui/icons-material/Refresh'; + +import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; +import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; + +import { createConnectionStatusLogActions, createConnectionStatusLogProperties } from '../handlers/connectionStatusLogHandler'; +import { NetworkElementConnectionLog } from '../models/networkElementConnectionLog'; +import RefreshConnectionStatusLogDialog, { RefreshConnectionStatusLogDialogMode } from './refreshConnectionStatusLogDialog'; + +const mapProps = (state: IApplicationStoreState) => ({ + connectionStatusLogProperties: createConnectionStatusLogProperties(state), +}); + +const mapDispatch = (dispatcher: IDispatcher) => ({ + connectionStatusLogActions: createConnectionStatusLogActions(dispatcher.dispatch), +}); + +const ConnectionStatusTable = MaterialTable as MaterialTableCtorType<NetworkElementConnectionLog>; + +type ConnectionStatusLogComponentProps = Connect<typeof mapProps, typeof mapDispatch>; +type ConnectionStatusLogComponentState = { + refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode; +}; + +let initialSorted = false; + + +class ConnectionStatusLogComponent extends React.Component<ConnectionStatusLogComponentProps, ConnectionStatusLogComponentState > { + constructor(props: ConnectionStatusLogComponentProps) { + super(props); + + this.state = { + refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.None, + }; + } + + render(): JSX.Element { + const refreshConnectionStatusLogAction = { + icon: Refresh, tooltip: 'Refresh Connection Status Log Table', ariaLabel:'refresh', onClick: () => { + this.setState({ + refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.RefreshConnectionStatusLogTable, + }); + }, + }; + + return ( + <> + <ConnectionStatusTable stickyHeader tableId="connection-status-table" customActionButtons={[refreshConnectionStatusLogAction]} columns={[ + { property: 'timestamp', title: 'Timestamp', type: ColumnType.text }, + { property: 'nodeId', title: 'Node ID', type: ColumnType.text }, + { property: 'status', title: 'Connection Status', type: ColumnType.text }, + ]} idProperty="id" {...this.props.connectionStatusLogActions} {...this.props.connectionStatusLogProperties} > + </ConnectionStatusTable> + <RefreshConnectionStatusLogDialog + mode={ this.state.refreshConnectionStatusLogEditorMode } + onClose={ this.onCloseRefreshConnectionStatusLogDialog } + /> + </> + ); + } + + private onCloseRefreshConnectionStatusLogDialog = () => { + this.setState({ + refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.None, + }); + }; + + componentDidMount() { + if (!initialSorted) { + initialSorted = true; + this.props.connectionStatusLogActions.onHandleExplicitRequestSort('timestamp', 'desc'); + } else { + this.props.connectionStatusLogActions.onRefresh(); + } + } +} + +export const ConnectionStatusLog = connect(mapProps, mapDispatch)(ConnectionStatusLogComponent); +export default ConnectionStatusLog;
\ No newline at end of file diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx new file mode 100644 index 000000000..b0db63476 --- /dev/null +++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx @@ -0,0 +1,425 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ +import React from 'react'; + +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import FormControl from '@mui/material/FormControl'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import Radio from '@mui/material/Radio'; +import RadioGroup from '@mui/material/RadioGroup'; +import Select from '@mui/material/Select'; +import TextField from '@mui/material/TextField'; +import Typography from '@mui/material/Typography'; + +import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect'; + +import { removeWebUriAction } from '../actions/commonNetworkElementsActions'; +import { mountNetworkElementAsyncActionCreator, unmountNetworkElementAsyncActionCreator } from '../actions/mountedNetworkElementsActions'; +import { + addNewNetworkElementAsyncActionCreator, editNetworkElementAsyncActionCreator, removeNetworkElementAsyncActionCreator, +} from '../actions/networkElementsActions'; +import { loadAllTlsKeyListAsync } from '../actions/tlsKeyActions'; +import { NetworkElementConnection, propertyOf, UpdateNetworkElement } from '../models/networkElementConnection'; + +export enum EditNetworkElementDialogMode { + None = 'none', + EditNetworkElement = 'editNetworkElement', + RemoveNetworkElement = 'removeNetworkElement', + AddNewNetworkElement = 'addNewNetworkElement', + MountNetworkElement = 'mountNetworkElement', + UnmountNetworkElement = 'unmountNetworkElement', +} + +const mapDispatch = (dispatcher: IDispatcher) => ({ + addNewNetworkElement: async (element: NetworkElementConnection) => { + await dispatcher.dispatch(addNewNetworkElementAsyncActionCreator(element)); + await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(element)); + }, + mountNetworkElement: (element: NetworkElementConnection) => dispatcher.dispatch(mountNetworkElementAsyncActionCreator(element)), + unmountNetworkElement: (element: NetworkElementConnection) => { + dispatcher.dispatch(unmountNetworkElementAsyncActionCreator(element && element.nodeId)); + }, + editNetworkElement: async (element: UpdateNetworkElement, mountElement: NetworkElementConnection) => { + + const values = Object.keys(element); + console.log('edit element'); + console.log(values); + + //make sure properties are there in case they get renamed + const idProperty = propertyOf<UpdateNetworkElement>('id'); + const isRequiredProperty = propertyOf<UpdateNetworkElement>('isRequired'); + + + if (values.length === 2 && values.includes(idProperty as string) && values.includes(isRequiredProperty as string)) { + // do not mount network element/node, if only isRequired is changed + await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element)); + + } else if (!(values.length === 1 && values.includes(idProperty as string))) { //do not edit or mount network element/node , if only id was saved into object (no changes made!) + await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element)); + await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement)); + } + }, + removeNetworkElement: async (element: UpdateNetworkElement) => { + await dispatcher.dispatch(removeNetworkElementAsyncActionCreator(element)); + dispatcher.dispatch(removeWebUriAction(element.id)); + }, + getAvailableTlsKeys: async () => dispatcher.dispatch(loadAllTlsKeyListAsync()), +}); + +type DialogSettings = { + dialogTitle: string; + dialogDescription: string; + applyButtonText: string; + cancelButtonText: string; + enableMountIdEditor: boolean; + enableUsernameEditor: boolean; + enableExtendedEditor: boolean; +}; + +const settings: { [key: string]: DialogSettings } = { + [EditNetworkElementDialogMode.None]: { + dialogTitle: '', + dialogDescription: '', + applyButtonText: '', + cancelButtonText: '', + enableMountIdEditor: false, + enableUsernameEditor: false, + enableExtendedEditor: false, + }, + + [EditNetworkElementDialogMode.AddNewNetworkElement]: { + dialogTitle: 'Add New Node', + dialogDescription: 'Add this new node:', + applyButtonText: 'Add node', + cancelButtonText: 'Cancel', + enableMountIdEditor: true, + enableUsernameEditor: true, + enableExtendedEditor: true, + }, + [EditNetworkElementDialogMode.MountNetworkElement]: { + dialogTitle: 'Mount Node', + dialogDescription: 'Mount this node:', + applyButtonText: 'Mount node', + cancelButtonText: 'Cancel', + enableMountIdEditor: false, + enableUsernameEditor: false, + enableExtendedEditor: false, + }, + [EditNetworkElementDialogMode.UnmountNetworkElement]: { + dialogTitle: 'Unmount Node', + dialogDescription: 'Unmount this node:', + applyButtonText: 'Unmount node', + cancelButtonText: 'Cancel', + enableMountIdEditor: false, + enableUsernameEditor: false, + enableExtendedEditor: false, + }, + [EditNetworkElementDialogMode.EditNetworkElement]: { + dialogTitle: 'Modify Node', + dialogDescription: 'Modify this node', + applyButtonText: 'Modify', + cancelButtonText: 'Cancel', + enableMountIdEditor: false, + enableUsernameEditor: true, + enableExtendedEditor: false, + }, + [EditNetworkElementDialogMode.RemoveNetworkElement]: { + dialogTitle: 'Remove Node', + dialogDescription: 'Do you really want to remove this node?', + applyButtonText: 'Remove node', + cancelButtonText: 'Cancel', + enableMountIdEditor: false, + enableUsernameEditor: false, + enableExtendedEditor: false, + }, +}; + +type EditNetworkElementDialogComponentProps = Connect<undefined, typeof mapDispatch> & { + mode: EditNetworkElementDialogMode; + initialNetworkElement: NetworkElementConnection; + onClose: () => void; + radioChecked: string; +}; + +type EditNetworkElementDialogComponentState = NetworkElementConnection & { + isNameValid: boolean; + isHostSet: boolean; + isPasswordSelected: boolean; + isTlsSelected: boolean; + radioSelected: string; + showPasswordTextField: boolean; + showTlsDropdown: boolean; +}; + +class EditNetworkElementDialogComponent extends React.Component<EditNetworkElementDialogComponentProps, EditNetworkElementDialogComponentState> { + constructor(props: EditNetworkElementDialogComponentProps) { + super(props); + this.handleRadioChange = this.handleRadioChange.bind(this); + // Initialization of state is partly overwritten by update via react getDerivedStateFromProps() below. + // Change initialization values in parent "networkElements.tsx" in "const emptyRequireNetworkElement" + this.state = { + nodeId: this.props.initialNetworkElement.nodeId, + isRequired: this.props.initialNetworkElement.isRequired, + host: this.props.initialNetworkElement.host, + port: this.props.initialNetworkElement.port, + isNameValid: true, + isHostSet: true, + isPasswordSelected: true, + isTlsSelected: false, + radioSelected: '', + showPasswordTextField: true, + showTlsDropdown: false, + }; + } + + public handleRadioChange = (event: any) => { + this.setState({ + radioSelected: event.target.value, + showPasswordTextField: event.target.value === 'password', + showTlsDropdown: event.target.value === 'tlsKey', + }); + }; + + render(): JSX.Element { + const setting = settings[this.props.mode]; + let { showPasswordTextField, showTlsDropdown, radioSelected } = this.state; + radioSelected = this.state.radioSelected.length > 0 ? this.state.radioSelected : this.props.radioChecked; + + if (radioSelected === 'password') { + radioSelected = 'password'; + showPasswordTextField = true; + showTlsDropdown = false; + } else if (radioSelected === 'tlsKey') { + radioSelected = 'tlsKey'; + showPasswordTextField = false; + showTlsDropdown = true; + } + + let tlsKeysList = this.props.state.connect.availableTlsKeys ? this.props.state.connect.availableTlsKeys.tlsKeysList ? this.props.state.connect.availableTlsKeys.tlsKeysList : [] : []; + + return ( + <Dialog open={this.props.mode !== EditNetworkElementDialogMode.None}> + <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, '-').toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle> + <DialogContent> + <DialogContentText> + {setting.dialogDescription} + </DialogContentText> + <TextField variant="standard" disabled={!setting.enableMountIdEditor} spellCheck={false} autoFocus margin="dense" + id="name" label="Node ID" aria-label="name" type="text" fullWidth value={this.state.nodeId} onChange={(event) => { this.setState({ nodeId: event.target.value }); }} /> + {!this.state.isNameValid && <Typography variant="body1" color="error">Node ID cannot be empty.</Typography>} + <TextField variant="standard" disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense" + id="ipaddress" label="Host/IP address" aria-label="ip adress" type="text" fullWidth value={this.state.host} onChange={(event) => { this.setState({ host: event.target.value }); }} /> + {!this.state.isHostSet && <Typography variant="body1" color="error">Host/IP address cannot be empty.</Typography>} + + <TextField variant="standard" disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense" + id="netconfport" label="NETCONF port" aria-label="netconf port" type="number" fullWidth value={this.state.port.toString()} + onChange={(event) => { this.setState({ port: +event.target.value }); }} /> + {setting.enableUsernameEditor && <TextField variant="standard" disabled={!setting.enableUsernameEditor} spellCheck={false} margin="dense" + id="username" label="Username" aria-label="username" type="text" fullWidth value={this.state.username} onChange={(event) => { this.setState({ username: event.target.value }); }} /> || null} + + {setting.enableUsernameEditor && + <RadioGroup row aria-label="password-tls-key" name="password-tls-key" value={radioSelected} + onChange={this.handleRadioChange} > + <FormControlLabel aria-label="passwordSelection" value='password' control={<Radio color="secondary" />} label="Password" onChange={this.onRadioSelect} /> + <FormControlLabel aria-label="tlsKeySelection" value='tlsKey' control={<Radio color="secondary" />} label="TlsKey" onChange={this.onRadioSelect} /> + </RadioGroup> || null} + + {setting.enableUsernameEditor && showPasswordTextField && + <TextField variant="standard" disabled={!setting.enableUsernameEditor || !showPasswordTextField} spellCheck={false} margin="dense" + id="password" aria-label="password" type="password" fullWidth value={this.state.password} + onChange={(event) => { this.setState({ password: event.target.value }); }} + /> || null} + + <FormControl variant="standard" fullWidth disabled={!setting.enableUsernameEditor}> + {setting.enableUsernameEditor && showTlsDropdown && + <div> + <InputLabel htmlFor="pass">--Select tls-key--</InputLabel> + <Select variant="standard" disabled={!setting.enableUsernameEditor || !showTlsDropdown} + id="tlsKey" aria-label="tlsKey" value={this.state.tlsKey} fullWidth // displayEmpty + onChange={(event) => { this.setState({ tlsKey: event.target.value as any }); }} + inputProps={{ name: 'tlsKey', id: 'tlsKey' }} > + <MenuItem value={''} disabled >--Select tls-key--</MenuItem> + {tlsKeysList.map(tlsKey => + (<MenuItem value={tlsKey.key} key={tlsKey.key} aria-label={tlsKey.key} >{tlsKey.key}</MenuItem>))} + </Select> + </div> + } + </FormControl> + + <FormControl variant="standard" fullWidth disabled={!setting.enableUsernameEditor}> + <InputLabel htmlFor="active">Required</InputLabel> + <Select variant="standard" aria-label="required-selection" value={this.state.isRequired || false} onChange={(event) => { + this.setState({ isRequired: event.target.value as any as boolean }); + }} inputProps={{ name: 'required', id: 'required' }} fullWidth > + <MenuItem value={true as any as string} aria-label="true">True</MenuItem> + <MenuItem value={false as any as string} aria-label="false">False</MenuItem> + </Select> + </FormControl> + </DialogContent> + <DialogActions> + <Button aria-label="dialog-confirm-button" onClick={(event) => { + + if (this.areRequieredFieldsValid()) { + this.onApply({ + isRequired: this.state.isRequired, + id: this.state.nodeId, + nodeId: this.state.nodeId, + host: this.state.host, + port: this.state.port, + username: this.state.username, + password: this.state.password, + tlsKey: this.state.tlsKey, + }); + } + event.preventDefault(); + event.stopPropagation(); + }} color="inherit" > {setting.applyButtonText} </Button> + <Button aria-label="dialog-cancel-button" onClick={(event) => { + this.onCancel(); + event.preventDefault(); + event.stopPropagation(); + }} color="secondary"> {setting.cancelButtonText} </Button> + </DialogActions> + </Dialog> + ); + } + + public renderTlsKeys = () => { + try { + this.props.getAvailableTlsKeys(); + } catch (err) { + console.log(err); + } + }; + + public componentDidMount() { + this.renderTlsKeys(); + } + + public onRadioSelect = (e: any) => { + if (e.target.value == 'password') { + this.setState({ isPasswordSelected: true, isTlsSelected: false }); + } else if (e.target.value == 'tlsKey') { + this.setState({ isPasswordSelected: false, isTlsSelected: true }); + } + }; + + private onApply = (element: NetworkElementConnection) => { + if (this.props.onClose) this.props.onClose(); + let updateElement: UpdateNetworkElement = { + id: this.state.nodeId, + }; + if (this.state.isPasswordSelected) { + element.tlsKey = ''; + } else if (this.state.isTlsSelected) { //check here + element.password = ''; + } + + switch (this.props.mode) { + case EditNetworkElementDialogMode.AddNewNetworkElement: + if (element) this.props.addNewNetworkElement(element); + this.setState({ + radioSelected: '', + isPasswordSelected: true, + }); + break; + case EditNetworkElementDialogMode.MountNetworkElement: + if (element) this.props.mountNetworkElement(element); + break; + case EditNetworkElementDialogMode.UnmountNetworkElement: + if (element) this.props.unmountNetworkElement(element); + break; + case EditNetworkElementDialogMode.EditNetworkElement: + if (this.props.initialNetworkElement.isRequired !== this.state.isRequired) + updateElement.isRequired = this.state.isRequired; + if (this.props.initialNetworkElement.username !== this.state.username) + updateElement.username = this.state.username; + if (this.props.initialNetworkElement.password !== this.state.password && this.state.isPasswordSelected) { + updateElement.password = this.state.password; + updateElement.tlsKey = ''; + } + if (this.props.initialNetworkElement.tlsKey !== this.state.tlsKey && this.state.isTlsSelected) { + updateElement.tlsKey = this.state.tlsKey; + updateElement.password = ''; + } + if (element) this.props.editNetworkElement(updateElement, element); + this.setState({ + radioSelected: '', + }); + break; + case EditNetworkElementDialogMode.RemoveNetworkElement: + if (element) this.props.removeNetworkElement(updateElement); + break; + } + + this.setState({ password: '', username: '', tlsKey: '' }); + this.resetRequieredFields(); + }; + + private onCancel = () => { + if (this.props.onClose) this.props.onClose(); + this.setState({ password: '', username: '', tlsKey: '', radioSelected: '' }); + this.resetRequieredFields(); + }; + + private resetRequieredFields() { + this.setState({ isNameValid: true, isHostSet: true }); + } + + private areRequieredFieldsValid() { + let areFieldsValid = true; + + if (this.state.nodeId == undefined || this.state.nodeId.trim().length === 0) { + this.setState({ isNameValid: false }); + areFieldsValid = false; + } else { + this.setState({ isNameValid: true }); + } + + if (this.state.host == undefined || this.state.host.trim().length === 0) { + this.setState({ isHostSet: false }); + areFieldsValid = false; + } else { + this.setState({ isHostSet: true }); + } + + return areFieldsValid; + } + + static getDerivedStateFromProps(props: EditNetworkElementDialogComponentProps, state: EditNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection }): EditNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection } { + let returnState = state; + if (props.initialNetworkElement !== state.initialNetworkElement) { + returnState = { + ...state, + ...props.initialNetworkElement, + initialNetworkElement: props.initialNetworkElement, + }; + } + return returnState; + } +} + +export const EditNetworkElementDialog = connect(undefined, mapDispatch)(EditNetworkElementDialogComponent); +export default EditNetworkElementDialog;
\ No newline at end of file diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx new file mode 100644 index 000000000..4841b9389 --- /dev/null +++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx @@ -0,0 +1,160 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ +import * as React from 'react'; + +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogTitle from '@mui/material/DialogTitle'; + +import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; +import { connect, Connect } from '../../../../framework/src/flux/connect'; + +import { NetworkElementConnection } from '../models/networkElementConnection'; +import { AvailableCapabilities } from '../models/yangCapabilitiesType'; + +export enum InfoNetworkElementDialogMode { + None = 'none', + InfoNetworkElement = 'infoNetworkElement', +} + +const mapDispatch = () => ({ +}); + +const InfoElementTable = MaterialTable as MaterialTableCtorType<AvailableCapabilities>; + +type DialogSettings = { + dialogTitle: string; + dialogDescription: string; + cancelButtonText: string; +}; + +const settings: { [key: string]: DialogSettings } = { + [InfoNetworkElementDialogMode.None]: { + dialogTitle: '', + dialogDescription: '', + cancelButtonText: '', + }, + [InfoNetworkElementDialogMode.InfoNetworkElement]: { + dialogTitle: 'YANG Capabilities of the Node', + dialogDescription: '', + cancelButtonText: 'OK', + }, +}; + +type InfoNetworkElementDialogComponentProps = Connect<undefined, typeof mapDispatch> & { + mode: InfoNetworkElementDialogMode; + initialNetworkElement: NetworkElementConnection; + onClose: () => void; +}; + +type InfoNetworkElementDialogComponentState = NetworkElementConnection; + +class InfoNetworkElementDialogComponent extends React.Component<InfoNetworkElementDialogComponentProps, InfoNetworkElementDialogComponentState> { + constructor(props: InfoNetworkElementDialogComponentProps) { + super(props); + + this.state = { + nodeId: this.props.initialNetworkElement.nodeId, + isRequired: false, + host: this.props.initialNetworkElement.host, + port: this.props.initialNetworkElement.port, + }; + } + + render(): JSX.Element { + const setting = settings[this.props.mode]; + const availableCapabilities = this.props.state.connect.elementInfo.elementInfo['netconf-node-topology:available-capabilities']['available-capability']; + let yangFeatures = this.props.state.connect.elementFeatureInfo.elementFeatureInfo; + let yangCapabilities: AvailableCapabilities[] = []; + + availableCapabilities.forEach(value => { + const capabilty = value.capability; + const indexRevision = capabilty.indexOf('revision='); + const indexModule = capabilty.indexOf(')', indexRevision); + if (indexRevision > 0 && indexModule > 0) { + let moduleName = capabilty.substring(indexModule + 1); + let ModuleFeaturesList; + for (let index = 0; index < yangFeatures.length; index++) { + if (yangFeatures[index].name == moduleName) { + ModuleFeaturesList = yangFeatures[index].feature ? yangFeatures[index].feature : null; + break; + } + } + const featuresListCommaSeparated = ModuleFeaturesList ? ModuleFeaturesList.toString() : ''; + let featuresList = featuresListCommaSeparated.replace(',', ', '); + + yangCapabilities.push({ + module: moduleName, + revision: capabilty.substring(indexRevision + 9, indexRevision + 19), + features: featuresList, + }); + } + }); + + yangCapabilities = yangCapabilities.sort((a, b) => a.module === b.module ? 0 : a.module > b.module ? 1 : -1); + + return ( + <> + <Dialog open={this.props.mode !== InfoNetworkElementDialogMode.None} > + <DialogTitle id="form-dialog-title">{`${setting.dialogTitle}: "${this.state.nodeId}"`}</DialogTitle> + <InfoElementTable stickyHeader isPopup tableId="info-element-table" asynchronus columns={[ + { property: 'module', title: 'YANG Capability', type: ColumnType.text, width: 900 }, + { + property: 'revision', title: 'Revision', type: ColumnType.custom, customControl: ({ rowData }) => { + return ( + <div> + <a href={`/yang-schema/${rowData.module}/${rowData.revision}`} target="_blank" > {rowData.revision} </a> + </div> + ); + }, + }, + { property: 'features', title: 'Features', type: ColumnType.text, width: 500 }, + ]} idProperty="id" rows={yangCapabilities} > + </InfoElementTable> + <DialogActions> + <Button aria-label="ok-button" onClick={(event) => { + this.onCancel(); + event.preventDefault(); + event.stopPropagation(); + }} color="secondary"> {setting.cancelButtonText} </Button> + </DialogActions> + </Dialog> + </> + ); + } + + private onCancel = () => { + this.props.onClose(); + }; + + static getDerivedStateFromProps(props: InfoNetworkElementDialogComponentProps, state: InfoNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection }): InfoNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection } { + let returnState = state; + if (props.initialNetworkElement !== state.initialNetworkElement) { + returnState = { + ...state, + ...props.initialNetworkElement, + initialNetworkElement: props.initialNetworkElement, + }; + } + return returnState; + } +} + +export const InfoNetworkElementDialog = connect(undefined, mapDispatch)(InfoNetworkElementDialogComponent); +export default InfoNetworkElementDialog;
\ No newline at end of file diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx new file mode 100644 index 000000000..1ce8f0c3b --- /dev/null +++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx @@ -0,0 +1,314 @@ +/** +* ============LICENSE_START======================================================================== +* ONAP : ccsdk feature sdnr wt odlux +* ================================================================================================= +* Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. +* ================================================================================================= +* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +* in compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software distributed under the License +* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +* or implied. See the License for the specific language governing permissions and limitations under +* the License. +* ============LICENSE_END========================================================================== +*/ +import React from 'react'; + +import AddIcon from '@mui/icons-material/Add'; +import ComputerIcon from '@mui/icons-material/Computer'; +import EditIcon from '@mui/icons-material/Edit'; +import Info from '@mui/icons-material/Info'; +import LinkIcon from '@mui/icons-material/Link'; +import LinkOffIcon from '@mui/icons-material/LinkOff'; +import Refresh from '@mui/icons-material/Refresh'; +import RemoveIcon from '@mui/icons-material/RemoveCircleOutline'; +import { Divider, MenuItem, Typography } from '@mui/material'; +import { Theme } from '@mui/material/styles'; +import { WithStyles } from '@mui/styles'; +import createStyles from '@mui/styles/createStyles'; +import withStyles from '@mui/styles/withStyles'; + +import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions'; +import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; +import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import { getAccessPolicyByUrl } from '../../../../framework/src/services/restService'; + +import { loadAllInfoElementAsync, loadAllInfoElementFeaturesAsync } from '../actions/infoNetworkElementActions'; +import { createNetworkElementsActions, createNetworkElementsProperties } from '../handlers/networkElementsHandler'; +import { NetworkElementConnection } from '../models/networkElementConnection'; +import { ModuleSet, TopologyNode } from '../models/topologyNetconf'; +import { connectService } from '../services/connectService'; + +import EditNetworkElementDialog, { EditNetworkElementDialogMode } from './editNetworkElementDialog'; +import InfoNetworkElementDialog, { InfoNetworkElementDialogMode } from './infoNetworkElementDialog'; +import RefreshNetworkElementsDialog, { RefreshNetworkElementsDialogMode } from './refreshNetworkElementsDialog'; + +const styles = (theme: Theme) => createStyles({ + connectionStatusConnected: { + color: 'darkgreen', + }, + connectionStatusConnecting: { + color: 'blue', + }, + connectionStatusDisconnected: { + color: 'red', + }, + button: { + margin: 0, + padding: '6px 6px', + minWidth: 'unset', + }, + spacer: { + marginLeft: theme.spacing(1), + marginRight: theme.spacing(1), + display: 'inline', + }, +}); + +type GetStatelessComponentProps<T> = T extends (props: infer P & { children?: React.ReactNode }) => any ? P : any; +const MenuItemExt: React.FC<GetStatelessComponentProps<typeof MenuItem>> = (props) => { + const [disabled, setDisabled] = React.useState(true); + const onMouseDown = (ev: React.MouseEvent<HTMLElement>) => { + if (ev.button === 1) { + setDisabled(!disabled); + ev.preventDefault(); + } + }; + return ( + <div onMouseDown={onMouseDown} > + <MenuItem {...{ ...props, disabled: props.disabled && disabled }} /> + </div> + ); +}; + +const mapProps = (state: IApplicationStoreState) => ({ + networkElementsProperties: createNetworkElementsProperties(state), + applicationState: state, +}); + +const mapDispatch = (dispatcher: IDispatcher) => ({ + networkElementsActions: createNetworkElementsActions(dispatcher.dispatch), + navigateToApplication: (applicationName: string, path?: string) => dispatcher.dispatch(new NavigateToApplication(applicationName, path)), + networkElementInfo: async (nodeId: string) => dispatcher.dispatch(loadAllInfoElementAsync(nodeId)), + networkElementFeaturesInfo: async (nodeId: string) => dispatcher.dispatch(loadAllInfoElementFeaturesAsync(nodeId)), +}); + +type NetworkElementsListComponentProps = WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>; +type NetworkElementsListComponentState = { + networkElementToEdit: NetworkElementConnection; + networkElementEditorMode: EditNetworkElementDialogMode; + refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode; + infoNetworkElementEditorMode: InfoNetworkElementDialogMode; + elementInfo: TopologyNode | null; + elementInfoFeature: ModuleSet | null; +}; + +const emptyRequireNetworkElement: NetworkElementConnection = { id: '', nodeId: '', host: '', port: 830, status: 'Disconnected', isRequired: true }; +let initialSorted = false; +const NetworkElementTable = MaterialTable as MaterialTableCtorType<NetworkElementConnection>; + +export class NetworkElementsListComponent extends React.Component<NetworkElementsListComponentProps, NetworkElementsListComponentState> { + + constructor(props: NetworkElementsListComponentProps) { + super(props); + + this.state = { + networkElementToEdit: emptyRequireNetworkElement, + networkElementEditorMode: EditNetworkElementDialogMode.None, + refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None, + elementInfo: null, + elementInfoFeature: null, + infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None, + }; + } + + getContextMenu(rowData: NetworkElementConnection): JSX.Element[] { + const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id); + const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri); + const canMount = mountPolicy && mountPolicy.POST || false; + + const { configuration } = this.props.applicationState as any; + const buttonArray = [ + <MenuItemExt aria-label={'mount-button'} onClick={event => this.onOpenMountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkIcon /><Typography>Mount</Typography></MenuItemExt>, + <MenuItemExt aria-label={'unmount-button'} onClick={event => this.onOpenUnmountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkOffIcon /><Typography>Unmount</Typography></MenuItemExt>, + <Divider />, + <MenuItem aria-label={'info-button'} onClick={event => this.onOpenInfoNetworkElementDialog(event, rowData)} disabled={rowData.status !== 'Connected'} ><Info /><Typography>Info</Typography></MenuItem>, + <MenuItem aria-label={'edit-button'} onClick={event => this.onOpenEditNetworkElementDialog(event, rowData)}><EditIcon /><Typography>Edit</Typography></MenuItem>, + <MenuItem aria-label={'remove-button'} onClick={event => this.onOpenRemoveNetworkElementDialog(event, rowData)} ><RemoveIcon /><Typography>Remove</Typography></MenuItem>, + <Divider />, + <MenuItem aria-label={'inventory-button'} onClick={() => this.props.navigateToApplication('inventory', rowData.nodeId)}><Typography>Inventory</Typography></MenuItem>, + <Divider />, + <MenuItem aria-label={'fault-button'} onClick={() => this.props.navigateToApplication('fault', rowData.nodeId)} ><Typography>Fault</Typography></MenuItem>, + <MenuItem aria-label={'configure-button'} onClick={() => this.props.navigateToApplication('configuration', rowData.nodeId)} disabled={rowData.status === 'Connecting' || rowData.status === 'Disconnected' || !configuration}><Typography>Configure</Typography></MenuItem>, + <MenuItem onClick={() => this.props.navigateToApplication('accounting', rowData.nodeId)} disabled={true}><Typography>Accounting</Typography></MenuItem>, + <MenuItem aria-label={'performance-button'} onClick={() => this.props.navigateToApplication('performanceHistory', rowData.nodeId)}><Typography>Performance</Typography></MenuItem>, + <MenuItem onClick={() => this.props.navigateToApplication('security', rowData.nodeId)} disabled={true} ><Typography>Security</Typography></MenuItem>, + ]; + + if (rowData.weburi) { + // add an icon for gui cuttrough, if weburi is available + return [<MenuItem aria-label={'web-client-button'} onClick={() => window.open(rowData.weburi, '_blank')} ><ComputerIcon /><Typography>Web Client</Typography></MenuItem>].concat(buttonArray); + } else { + return buttonArray; + } + } + + // private navigationCreator + + render(): JSX.Element { + //const { classes } = this.props; + const { networkElementToEdit } = this.state; + let savedRadio = 'password'; + if (this.state.networkElementToEdit.password && this.state.networkElementToEdit.password.length > 0) { + savedRadio = 'password'; + } else if (this.state.networkElementToEdit.tlsKey && this.state.networkElementToEdit.tlsKey.length > 0) { + savedRadio = 'tlsKey'; + } + + // const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id); + // const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri); + // const canAdd = mountPolicy && mountPolicy.POST || false; + const canAdd = true; + + const addRequireNetworkElementAction = { + icon: AddIcon, tooltip: 'Add node', ariaLabel: 'add-element', onClick: () => { + this.setState({ + networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement, + networkElementToEdit: emptyRequireNetworkElement, + }); + }, + }; + + const refreshNetworkElementsAction = { + icon: Refresh, tooltip: 'Refresh table', ariaLabel: 'refresh', onClick: () => { + this.setState({ + refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable, + }); + }, + }; + + return <> + <NetworkElementTable stickyHeader tableId="network-element-table" customActionButtons={[refreshNetworkElementsAction, ...(canAdd ? [addRequireNetworkElementAction] : [])]} columns={[ + { property: 'nodeId', title: 'Node ID', type: ColumnType.text }, + { property: 'status', title: 'Connection Status', type: ColumnType.text, width:'15%' }, + { property: 'host', title: 'Host', type: ColumnType.text }, + { property: 'port', title: 'Port', type: ColumnType.numeric }, + { property: 'isRequired', title: 'Required', type: ColumnType.boolean }, + { property: 'deviceType', title: 'Type', type: ColumnType.text }, + // { property: "coreModelCapability", title: "Core Model", type: ColumnType.text }, + { property: 'deviceFunction', title: 'Function', type: ColumnType.text, width: '25%' }, + ]} idProperty="id" {...this.props.networkElementsActions} {...this.props.networkElementsProperties} asynchronus createContextMenu={rowData => { + + return this.getContextMenu(rowData); + }} > + </NetworkElementTable> + <EditNetworkElementDialog + initialNetworkElement={networkElementToEdit} + mode={this.state.networkElementEditorMode} + onClose={this.onCloseEditNetworkElementDialog} + radioChecked={savedRadio} + /> + <RefreshNetworkElementsDialog + mode={this.state.refreshNetworkElementsEditorMode} + onClose={this.onCloseRefreshNetworkElementsDialog} + /> + <InfoNetworkElementDialog + initialNetworkElement={networkElementToEdit} + mode={this.state.infoNetworkElementEditorMode} + onClose={this.onCloseInfoNetworkElementDialog} + /> + </>; + } + + public componentDidMount() { + if (!initialSorted) { + initialSorted = true; + this.props.networkElementsActions.onHandleRequestSort('node-id'); + } else { + this.props.networkElementsActions.onRefresh(); + } + } + + private onOpenAddNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => { + this.setState({ + networkElementToEdit: element, + networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement, + }); + }; + + private onOpenRemoveNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => { + this.setState({ + networkElementToEdit: element, + networkElementEditorMode: EditNetworkElementDialogMode.RemoveNetworkElement, + }); + }; + + private onOpenEditNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => { + //let radioSaved; + //if (element.password && element.password.length > 0) + // radioSaved = 'password'; + //else if (element.tlsKey && element.tlsKey.length > 0) + // radioSaved = 'tlsKey'; + this.setState({ + networkElementToEdit: { + nodeId: element.nodeId, + isRequired: element.isRequired, + host: element.host, + port: element.port, + username: element.username, + password: element.password, + tlsKey: element.tlsKey, + }, + networkElementEditorMode: EditNetworkElementDialogMode.EditNetworkElement, + }); + }; + + private onOpenUnmountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => { + this.setState({ + networkElementToEdit: element, + networkElementEditorMode: EditNetworkElementDialogMode.UnmountNetworkElement, + }); + }; + + private onOpenMountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => { + this.setState({ + networkElementToEdit: element, + networkElementEditorMode: EditNetworkElementDialogMode.MountNetworkElement, + }); + }; + + private onOpenInfoNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => { + this.props.networkElementInfo(element.nodeId); + this.props.networkElementFeaturesInfo(element.nodeId); + this.setState({ + networkElementToEdit: element, + infoNetworkElementEditorMode: InfoNetworkElementDialogMode.InfoNetworkElement, + }); + }; + + private onCloseEditNetworkElementDialog = () => { + this.setState({ + networkElementEditorMode: EditNetworkElementDialogMode.None, + networkElementToEdit: emptyRequireNetworkElement, + }); + }; + + private onCloseInfoNetworkElementDialog = () => { + this.setState({ + infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None, + networkElementToEdit: emptyRequireNetworkElement, + }); + }; + + private onCloseRefreshNetworkElementsDialog = () => { + this.setState({ + refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None, + }); + }; +} + +export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent)); diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx new file mode 100644 index 000000000..a4aea7f82 --- /dev/null +++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx @@ -0,0 +1,114 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ +import React from 'react'; + +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; + +import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect'; + +import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler'; +import { ConnectionStatusLogType } from '../models/connectionStatusLog'; + +export enum RefreshConnectionStatusLogDialogMode { + None = 'none', + RefreshConnectionStatusLogTable = 'RefreshConnectionStatusLogTable', +} + +const mapDispatch = (dispatcher: IDispatcher) => ({ + refreshConnectionStatusLog: () => dispatcher.dispatch(connectionStatusLogReloadAction), +}); + +type DialogSettings = { + dialogTitle: string; + dialogDescription: string; + applyButtonText: string; + cancelButtonText: string; + enableMountIdEditor: boolean; + enableUsernameEditor: boolean; + enableExtendedEditor: boolean; +}; + +const settings: { [key: string]: DialogSettings } = { + [RefreshConnectionStatusLogDialogMode.None]: { + dialogTitle: '', + dialogDescription: '', + applyButtonText: '', + cancelButtonText: '', + enableMountIdEditor: false, + enableUsernameEditor: false, + enableExtendedEditor: false, + }, + [RefreshConnectionStatusLogDialogMode.RefreshConnectionStatusLogTable]: { + dialogTitle: 'Do you want to refresh the Connection Status Log table?', + dialogDescription: '', + applyButtonText: 'Yes', + cancelButtonText: 'Cancel', + enableMountIdEditor: true, + enableUsernameEditor: true, + enableExtendedEditor: true, + }, +}; + +type RefreshConnectionStatusLogDialogComponentProps = Connect<undefined, typeof mapDispatch> & { + mode: RefreshConnectionStatusLogDialogMode; + onClose: () => void; +}; + +type RefreshConnectionStatusLogDialogComponentState = ConnectionStatusLogType & { isNameValid: boolean; isHostSet: boolean }; + +class RefreshConnectionStatusLogDialogComponent extends React.Component<RefreshConnectionStatusLogDialogComponentProps, RefreshConnectionStatusLogDialogComponentState> { + + render(): JSX.Element { + const setting = settings[this.props.mode]; + return ( + <Dialog open={this.props.mode !== RefreshConnectionStatusLogDialogMode.None}> + <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, '-').toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle> + <DialogContent> + <DialogContentText> + {setting.dialogDescription} + </DialogContentText> + </DialogContent> + <DialogActions> + <Button aria-label="dialog-confirm-button" onClick={() => { + this.onRefresh(); + }} color="inherit" > {setting.applyButtonText} </Button> + <Button aria-label="dialog-cancel-button" onClick={() => { + this.onCancel(); + }} color="secondary"> {setting.cancelButtonText} </Button> + </DialogActions> + </Dialog> + ); + } + + private onRefresh = () => { + this.props.refreshConnectionStatusLog(); + this.props.onClose(); + }; + + private onCancel = () => { + this.props.onClose(); + }; +} + +export const RefreshConnectionStatusLogDialog = connect(undefined, mapDispatch)(RefreshConnectionStatusLogDialogComponent); +export default RefreshConnectionStatusLogDialog;
\ No newline at end of file diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx new file mode 100644 index 000000000..e41fd27aa --- /dev/null +++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx @@ -0,0 +1,114 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ +import React from 'react'; + +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; + +import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect'; + +import { networkElementsReloadAction } from '../handlers/networkElementsHandler'; +import { NetworkElementConnection } from '../models/networkElementConnection'; + +export enum RefreshNetworkElementsDialogMode { + None = 'none', + RefreshNetworkElementsTable = 'RefreshNetworkElementsTable', +} + +const mapDispatch = (dispatcher: IDispatcher) => ({ + refreshNetworkElement: () => dispatcher.dispatch(networkElementsReloadAction), +}); + +type DialogSettings = { + dialogTitle: string; + dialogDescription: string; + applyButtonText: string; + cancelButtonText: string; + enableMountIdEditor: boolean; + enableUsernameEditor: boolean; + enableExtendedEditor: boolean; +}; + +const settings: { [key: string]: DialogSettings } = { + [RefreshNetworkElementsDialogMode.None]: { + dialogTitle: '', + dialogDescription: '', + applyButtonText: '', + cancelButtonText: '', + enableMountIdEditor: false, + enableUsernameEditor: false, + enableExtendedEditor: false, + }, + [RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable]: { + dialogTitle: 'Do you want to refresh the nodes table?', + dialogDescription: '', + applyButtonText: 'Yes', + cancelButtonText: 'Cancel', + enableMountIdEditor: true, + enableUsernameEditor: true, + enableExtendedEditor: true, + }, +}; + +type RefreshNetworkElementsDialogComponentProps = Connect<undefined, typeof mapDispatch> & { + mode: RefreshNetworkElementsDialogMode; + onClose: () => void; +}; + +type RefreshNetworkElementsDialogComponentState = NetworkElementConnection & { isNameValid: boolean; isHostSet: boolean }; + +class RefreshNetworkElementsDialogComponent extends React.Component<RefreshNetworkElementsDialogComponentProps, RefreshNetworkElementsDialogComponentState> { + + render(): JSX.Element { + const setting = settings[this.props.mode]; + return ( + <Dialog open={this.props.mode !== RefreshNetworkElementsDialogMode.None}> + <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, '-').toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle> + <DialogContent> + <DialogContentText> + {setting.dialogDescription} + </DialogContentText> + </DialogContent> + <DialogActions> + <Button aria-label="dialog-confirm-button" onClick={() => { + this.onRefresh(); + }} color="inherit" > {setting.applyButtonText} </Button> + <Button aria-label="dialog-cancel-button" onClick={() => { + this.onCancel(); + }} color="secondary"> {setting.cancelButtonText} </Button> + </DialogActions> + </Dialog> + ); + } + + private onRefresh = () => { + this.props.refreshNetworkElement(); + this.props.onClose(); + }; + + private onCancel = () => { + this.props.onClose(); + }; +} + +export const RefreshNetworkElementsDialog = connect(undefined, mapDispatch)(RefreshNetworkElementsDialogComponent); +export default RefreshNetworkElementsDialog;
\ No newline at end of file |