summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/apps/networkMapApp/src/components
diff options
context:
space:
mode:
authorAijana Schumann <aijana.schumann@highstreet-technologies.com>2021-08-04 11:59:18 +0200
committerAijana Schumann <aijana.schumann@highstreet-technologies.com>2021-08-04 16:06:05 +0200
commit437f67407aece6f7aed8e989638b0d64075f0c0a (patch)
tree53e9e336cd8544edf8a06c889e33f5b9c98fe083 /sdnr/wt/odlux/apps/networkMapApp/src/components
parent1c4995eb199437e9c86336efff9972f2049e1532 (diff)
Update ODLUX
Add various updates and bugfixes to NetworkMap, Configuration, LinkCalculation and ConnectApp Issue-ID: CCSDK-3414 Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com> Change-Id: I6ea5c3a9d6ccbe9c450da43220654a53fd2f262b Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com>
Diffstat (limited to 'sdnr/wt/odlux/apps/networkMapApp/src/components')
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx15
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx34
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx77
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/details/stadokDetailsPopup.tsx274
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/map/connectionInfo.tsx2
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/map/iconSwitch.tsx4
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/map/map.tsx204
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/map/searchBar.tsx1
-rw-r--r--sdnr/wt/odlux/apps/networkMapApp/src/components/map/statistics.tsx2
9 files changed, 490 insertions, 123 deletions
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx
index 7e378b81e..e04fda547 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx
@@ -26,7 +26,16 @@ import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import { makeStyles, Button, Tooltip } from '@material-ui/core';
-type props = { headers: string[], height: number, navigate?(applicationName: string, path?: string): void, onLinkClick?(id: string): void, data: any[], hover: boolean, ariaLabelRow: string, ariaLabelColumn: string[], verticalTable?: boolean, onClick?(id: string): void, actions?: boolean };
+type props = { headers: string[],
+ height: number,
+ navigate?(applicationName: string, path?: string): void,
+ onLinkClick?(id: string): void, data: any[],
+ hover: boolean,
+ ariaLabelRow: string,
+ ariaLabelColumn?: string[],
+ verticalTable?: boolean,
+ onClick?(id: string): void,
+ actions?: boolean };
const styles = makeStyles({
@@ -81,7 +90,7 @@ const DenseTable: React.FunctionComponent<props> = (props) => {
if (data !== undefined) {
if (!props.verticalTable) {
- const ariaLabel = props.ariaLabelColumn[i];
+ const ariaLabel = props.ariaLabelColumn === undefined ? props.headers[i].toLowerCase() : props.ariaLabelColumn[i];
if (ariaLabel.length > 0) {
return <TableCell aria-label={ariaLabel}>{data}</TableCell>
} else {
@@ -93,7 +102,7 @@ const DenseTable: React.FunctionComponent<props> = (props) => {
if (i === 0) {
return <TableCell>{data}</TableCell>
} else {
- const ariaLabel = props.ariaLabelColumn[index];
+ const ariaLabel = props.ariaLabelColumn === undefined ? props.headers[index].toLowerCase() : props.ariaLabelColumn[index];
return <TableCell aria-label={ariaLabel}>{data}</TableCell>
}
}
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx
index 57091aebf..96727cc0d 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx
@@ -37,7 +37,7 @@ const LinkDetails: React.FunctionComponent<props> = (props) => {
if(el && el2){
if(props.link.type==="microwave")
- setHeight(el!.height - el2!.y -30);
+ setHeight(el!.height - el2!.y -50);
else
setHeight(el!.height - el2!.y +20);
@@ -68,10 +68,34 @@ const LinkDetails: React.FunctionComponent<props> = (props) => {
const distance = props.link.length > 0 ? props.link.length : props.link.calculatedLength;
const azimuthA = props.link.azimuthA;
const azimuthB = props.link.azimuthB;
+ const antennaA = props.link.locationA.antenna;
+ const antennaB = props.link.locationB.antenna;
+
+
+ let antennaData = "";
+ if(antennaA!==null && antennaB!==null){
+ antennaData = `&antennaNameA=${antennaA.name}&antennaGainA=${antennaA.gain}&waveguideLossA=${antennaA.waveguideLossIndB}&antennaNameB=${antennaB.name}&antennaGainB=${antennaB.gain}&waveguideLossB=${antennaB.waveguideLossIndB}`;
+ }
+
+
const baseUrl = window.location.pathname.split('#')[0];
- window.open(`${baseUrl}#/linkCalculation?lat1=${siteA.lat}&lon1=${siteA.lon}&lat2=${siteB.lat}&lon2=${siteB.lon}&siteA=${nameA}&siteB=${nameB}&azimuthA=${azimuthA}&azimuthB=${azimuthB}&distance=${distance}&amslSiteA=${siteA.amsl}&AGLsiteA=${siteA.antennaHeight}&amslSiteB=${siteB.amsl}&AGLsiteB=${siteB.antennaHeight}`)
+ window.open(`${baseUrl}#/linkCalculation?lat1=${siteA.lat}&lon1=${siteA.lon}&lat2=${siteB.lat}&lon2=${siteB.lon}&siteA=${nameA}&siteB=${nameB}&azimuthA=${azimuthA}&azimuthB=${azimuthB}&distance=${distance}&amslSiteA=${siteA.amsl}&AGLsiteA=${siteA.antennaHeight}&amslSiteB=${siteB.amsl}&AGLsiteB=${siteB.antennaHeight}${antennaData}`)
+
+ }
+
+ const onLineofSightClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) =>{
+ e.preventDefault();
+
+ const siteA= props.link.locationA;
+ const siteB =props.link.locationB;
+
+ //TODO: add check if available
+ let heightPart = `&amslA=${siteA.amsl}&antennaHeightA=${siteA.antennaHeight}&amslB=${siteB.amsl}&antennaHeightB=${siteB.antennaHeight}`;
+
+ const baseUrl = window.location.pathname.split('#')[0];
+ window.open(`${baseUrl}#/lineofsight/los?lat1=${siteA.lat}&lon1=${siteA.lon}&lat2=${siteB.lat}&lon2=${siteB.lon}${heightPart}`);
}
const data = [
@@ -94,7 +118,11 @@ const LinkDetails: React.FunctionComponent<props> = (props) => {
</AppBar>
<DenseTable ariaLabelRow="site-information-table-entry" ariaLabelColumn={["site-name", "latitude", "longitude", "azimuth"]} verticalTable height={height} hover={false} headers={["", "Site A", "Site B"]} data={data} />
{
- props.link.type==="microwave" && <Button style={{marginTop:20}} fullWidth variant="contained" color="primary" onClick={onCalculateLinkClick}>Calculate link</Button>
+ props.link.type==="microwave" &&<>
+ <Button style={{marginTop:20}} fullWidth variant="contained" color="primary" onClick={onCalculateLinkClick}>Calculate link</Button>
+ <Button style={{marginTop:20}} fullWidth variant="contained" color="primary" onClick={onLineofSightClick}>Line of Sight</Button>
+
+ </>
}
</div>)
}
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx
index 3aa35c348..7f0c1c926 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx
@@ -30,6 +30,9 @@ import { CheckDeviceList, InitializeLoadedDevicesAction } from '../../actions/de
import { NavigateToApplication } from '../../../../../framework/src/actions/navigationActions';
import connect, { Connect, IDispatcher } from '../../../../../framework/src/flux/connect';
import { IApplicationStoreState } from '../../../../../framework/src/store/applicationStore';
+import StadokSite from '../../model/stadokSite';
+import { requestRest } from '../../../../../framework/src/services/restService';
+import StadokDetailsPopup from './stadokDetailsPopup';
type linkRow = { name: string, azimuth?: string}
type deviceRow = { id: string;type: string,name: string,manufacturer: string,owner: string,status?: string,port: number[]}
@@ -48,6 +51,8 @@ const SiteDetails: React.FunctionComponent<siteDetailProps> = (props) => {
const [value, setValue] = React.useState<panelId>("links");
const [height, setHeight] = React.useState(330);
+ const [openPopup, setOpenPopup] = React.useState(false);
+ const [staSite, setStaSite] = React.useState<StadokSite|null>(null);
const handleResize = () =>{
const el = document.getElementById('site-details-panel')?.getBoundingClientRect();
@@ -82,35 +87,55 @@ const SiteDetails: React.FunctionComponent<siteDetailProps> = (props) => {
setValue(newValue);
}
+ const getFurtherInformation = (url: string) =>{
+
+ const request = requestRest<StadokSite>(url, { method: "GET"});
+
+ request.then(result =>{
+ if(result){
+ setStaSite(result);
+ setOpenPopup(true);
+ }else{
+ console.error(result);
+ }
+
+
+ });
+ }
+
+ const closePopup = () =>{
+ setOpenPopup(false);
+ }
+
//prepare link table
let hasAzimuth = false;
- const linkRows: linkRow[] = props.site.links.map(link=>
+ const linkRows: linkRow[] = props.site.links?.map(link=>
{
if(link.azimuthB!==null){
hasAzimuth=true;
- return {name: link.name, azimuth: link.azimuthB.toFixed(2) }
+ return {name: link.name, azimuth: link.azimuthB.toFixed(2) }
- }else{
- return {name: link.name }
- }
-
- });
+ }else{
+ return {name: link.name }
+ }
+ });
const linkTableHeader = hasAzimuth ? ["Link Name", "Azimuth in °"] : ["Link Name"];
//prepare device table
- const deviceRows : deviceRow[] = props.updatedDevices.map(device=>{
- return{
- id: device.id,
- name: device.name,
- type: device.type,
- status: device.status,
- manufacturer: device.manufacturer,
- owner: device.owner,
- port: device.port
- }
- });
+ const deviceRows : deviceRow[] = props.updatedDevices?.map(device=>{
+ return{
+ id: device.id,
+ name: device.name,
+ type: device.type,
+ status: device.status,
+ manufacturer: device.manufacturer,
+ owner: device.owner,
+ port: device.port
+ }
+ });
+
const adressString = props.site.address == null ? null : buildAdress(props.site.address);
@@ -152,12 +177,12 @@ const SiteDetails: React.FunctionComponent<siteDetailProps> = (props) => {
value === "links" &&
<>
{
- props.site.links.length === 0 &&
+ props.site.links==null &&
<Typography aria-label="no-links-available" variant="body1" style={{ marginTop: '10px' }}>No links available.</Typography>
}
{
- props.site.links.length > 0 &&
+ props.site.links?.length > 0 &&
<DenseTable ariaLabelRow="available-links-table" ariaLabelColumn={["link-name", "azimuth"]} height={height} hover={true} headers={linkTableHeader} data={linkRows} onClick={props.onLinkClick} ></DenseTable>
}
@@ -178,6 +203,15 @@ const SiteDetails: React.FunctionComponent<siteDetailProps> = (props) => {
}
</>
}
+ {
+ props.isSitedocReachable && props.site.furtherInformation!==null && props.site.furtherInformation.length>0 &&
+ <Button style={{marginTop:20}} fullWidth variant="contained" color="primary" onClick={e => getFurtherInformation(props.site.furtherInformation) }>Further information available</Button>
+ }
+
+ {
+ staSite !== null && openPopup && <StadokDetailsPopup site={staSite} onClose={closePopup} open={true} />
+ }
+
</div>
)
}
@@ -200,7 +234,8 @@ const buildAdress = (adress: Address) =>{
}
const mapStateToProps = (state: IApplicationStoreState) => ({
- updatedDevices: state.network.details.checkedDevices
+ updatedDevices: state.network.details.checkedDevices,
+ isSitedocReachable: state.network.details.isSitedocReachable
});
const mapDispatchToProps = (dispatcher: IDispatcher) => ({
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/stadokDetailsPopup.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/stadokDetailsPopup.tsx
new file mode 100644
index 000000000..4f3235db7
--- /dev/null
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/stadokDetailsPopup.tsx
@@ -0,0 +1,274 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 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 MuiDialogTitle from '@material-ui/core/DialogTitle';
+import { AppBar, Dialog, DialogContent, IconButton, Tab, Tabs, TextField, Typography } from '@material-ui/core';
+import CloseIcon from '@material-ui/icons/Close';
+import { withStyles, WithStyles, createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+
+
+import StadokSite from '../../model/stadokSite';
+import { LatLonToDMS } from '../../utils/mapUtils';
+import DenseTable from '../../components/denseTable';
+import { requestRest } from '../../../../../framework/src/services/restService';
+import { OrderToDisplay, StadokOrder } from '../../model/stadokOrder';
+import { CSSProperties } from '@material-ui/core/styles/withStyles';
+import { SITEDOC_URL } from '../../config';
+
+
+type props = { site: StadokSite; onClose(): void; open:boolean };
+
+const styles = (theme: Theme) => createStyles({
+ root: {
+ margin: 0,
+ padding: theme.spacing(2),
+ },
+ closeButton: {
+ position: 'absolute',
+ right: theme.spacing(1),
+ top: theme.spacing(1),
+ color: theme.palette.grey[500],
+ },
+});
+
+const useStyles = makeStyles({
+ largeImage:{cursor:'pointer', width:300},
+ smallImage:{cursor:'pointer', width: 50, marginTop:'10px', marginLeft:'10px'}
+});
+
+const StadokDetailsPopup: React.FunctionComponent<props> = (props) => {
+ const classes = useStyles();
+
+ const [open, setOpen] = React.useState(props.open);
+ const [value, setValue] = React.useState("devices");
+ const [orders, setOrders] = React.useState<OrderToDisplay[]|null>(null);
+
+ const DialogTitle = withStyles(styles)((props: any) => {
+ const { children, classes, onClose, ...other } = props;
+ return (
+ <MuiDialogTitle disableTypography className={classes.root} {...other}>
+ <Typography variant="h6">{children}</Typography>
+ {onClose ? (
+ <IconButton aria-label="close" style={{position: 'absolute', top:0, right:0, color: 'black'}} onClick={onClose}>
+ <CloseIcon />
+ </IconButton>
+ ) : null}
+ </MuiDialogTitle>
+ );
+ });
+
+ const getContacts = (site: StadokSite) =>{
+ const contacts = [];
+
+ if(site.createdBy){
+ contacts.push({h: "Site Creator",col1: site.createdBy.firstName, col2: site.createdBy.lastName, col3: site.createdBy.email, col4: site.createdBy.telephoneNumber });
+ }
+
+ if(site.contacts.manager){
+ contacts.push({h: "Manager",col1: site.contacts.manager.firstName, col2: site.contacts.manager.lastName, col3: site.contacts.manager.email, col4: site.contacts.manager.telephoneNumber });
+ }
+
+ if(site.contacts.owner){
+ contacts.push({h: "Owner",col1: site.contacts.owner.firstName, col2: site.contacts.owner.lastName, col3: site.contacts.owner.email, col4: site.contacts.owner.telephoneNumber });
+ }
+ return contacts;
+ }
+
+ const onClose = () =>{
+ // setOpen(false);
+ props.onClose()
+ }
+
+ //todo: use a set 'panelId' -> which values are allowed
+ const onHandleTabChange = (event: React.ChangeEvent<{}>, newValue: string) => {
+ setValue(newValue);
+}
+console.log(props.site)
+ const contacts = getContacts(props.site);
+
+ const orderUrl=`${SITEDOC_URL}/site/${props.site.siteId}/orders`;
+
+ if(orders==null){
+ requestRest<StadokOrder[]>(orderUrl,{ method: "GET"}).then(result =>{
+ if(result){
+ const orderList = result.map(order =>{
+ return OrderToDisplay.parse(order);
+ });
+ setOrders(orderList);
+
+ }else{
+ setOrders([]);
+ }
+ });
+ }
+
+ const createOrderInfo = () => {
+
+ if (orders === null) {
+ return (<div style={{ height: 300 }}>
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ Loading orders
+ </Typography>
+ </div>)
+ } else if (orders.length === 0) {
+ return (<div style={{ height: 300 }}>
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ No orders available
+ </Typography>
+ </div>)
+ } else {
+ return <DenseTable data={orders} height={300} headers={["Person", "State", "Current Task"]} hover={false} ariaLabelRow="activity-log-table" />
+ }
+ }
+
+ const displayImages = () => {
+
+ if (props.site.images.length === 1) {
+ return stadokImage(props.site.siteId, props.site.images[0],"large")
+ } else {
+ return <>
+ {
+ stadokImage(props.site.siteId, props.site.images[0], "large")
+ }
+ <div style={{ display: 'flex', flexDirection: 'row', flexWrap:'wrap' }}>
+
+ {
+ props.site.images.length<=9 ?
+ props.site.images.slice(1, props.site.images.length).map(image =>
+ stadokImage(props.site.siteId, image, "small")
+ )
+ :
+ <>
+ {
+ props.site.images.slice(1, 9).map(image =>
+ stadokImage(props.site.siteId, image, "small")
+ )
+ }
+
+ </>
+ }
+ </div>
+ </>
+ }
+
+ }
+
+ const stadokImage = (siteId: string, imagename: string, size: 'large' | 'small') => {
+ const url = `${SITEDOC_URL}/site/${siteId}/files/${imagename}`;
+ const className = size === "small" ? classes.smallImage : classes.largeImage;
+ return <img className={className} src={url} onClick={e => window.open(url)} />
+
+ }
+
+
+ return (<Dialog onClose={onClose} fullWidth maxWidth="md" aria-labelledby="customized-dialog-title" open={open}>
+ <DialogTitle id="customized-dialog-title" onClose={onClose}>
+ {props.site.siteId}
+ </DialogTitle>
+ <DialogContent style={{minWidth:'900px'}} dividers>
+ <div style={{ display: 'flex', flexDirection: 'row', flexGrow: 1 }}>
+ <div style={{ width: '60%', display:'flex', flexDirection: 'column' }}>
+
+ <TextField inputProps={{ 'aria-label': 'type' }} disabled={true} value={props.site.updatedOn} label="Updated on" style={{ marginTop: "5px" }} />
+
+
+ {
+ props.site.type !== undefined && props.site.type.length > 0 &&
+ <TextField inputProps={{ 'aria-label': 'type' }} disabled={true} value={props.site.type} label="Type" style={{ marginTop: "5px" }} />
+ }
+
+
+ <TextField inputProps={{ 'aria-label': 'adress' }} disabled={true} value={`${props.site.address.streetAndNr}, ${props.site.address.zipCode !== null ? props.site.address.zipCode : ''} ${props.site.address.city}`} label="Address" style={{ marginTop: "5px" }} />
+
+
+ <TextField inputProps={{ 'aria-label': 'latitude' }} style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.location.lat)} label="Latitude" />
+ <TextField inputProps={{ 'aria-label': 'longitude' }} style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.location.lon, true)} label="Longitude" />
+ <AppBar position="static" style={{ marginTop: "5px", background: '#2E3B55' }}>
+ <Tabs id="site-tabs" variant="scrollable" scrollButtons="on" value={value} onChange={onHandleTabChange} aria-label="simple tabs example">
+ <Tab label="Devices" value="devices" />
+ <Tab label="Contacts" value="contacts" />
+ <Tab label="Saftey" value="safteyInfo" />
+ <Tab label="Logs" value="logs" />
+ <Tab label="Orders" value="orders" />
+ </Tabs>
+ </AppBar>
+ {
+ value == "devices" && (props.site.devices?.length>0 ?
+ <DenseTable data={props.site.devices} height={300} headers={["Device", "Antenna"]} hover={false} ariaLabelRow="devices-table" />
+ :
+ <div style={{height:300}}>
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ No devices available
+ </Typography>
+ </div>)
+ }
+ {
+ value == "contacts" && (contacts.length>0 ?
+ <DenseTable data={contacts} height={300} headers={["Person", "Firstname", "Lastname", "Email", "Phone No."]} hover={false} ariaLabelRow="contacts-table" ariaLabelColumn={["person", "firstname", "lastname", "email", "phoneno"]} />
+ :
+ <div style={{height:300}}>
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ No contacts available
+ </Typography>
+ </div>)
+ }
+ {
+ value == "safteyInfo" && (props.site.safteyNotices.length>0 ?
+ <DenseTable data={props.site.safteyNotices} height={300} headers={["Note"]} hover={false} ariaLabelRow="saftey-info-table" />
+ :
+ <div style={{height:300}}>
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ No saftey notices applicable
+ </Typography>
+ </div>)
+ }
+ {
+ value == "logs" && (props.site.logs.length>0 ?
+ <DenseTable data={props.site.logs} height={300} headers={["Date","Person", "Activity"]} hover={false} ariaLabelRow="activity-log-table" />
+ :
+ <div style={{height:300}}>
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ No activity log available
+ </Typography>
+ </div>)
+ }
+
+ {
+ value ==="orders" && createOrderInfo()
+ }
+
+ </div>
+ <div style={{padding: '10px', display: 'flex', alignItems:'center', flexDirection:'column', justifyContent: 'start', width:'40%'}}>
+ {
+ props.site.images.length == 0 ?
+ <Typography variant="body1" style={{ marginTop: '10px' }}>
+ No images available
+ </Typography>
+ : displayImages()
+ }
+ </div>
+ </div>
+
+ </DialogContent>
+ </Dialog>)
+
+}
+
+export default StadokDetailsPopup; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/connectionInfo.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/connectionInfo.tsx
index c1fdccfb8..3b5a15ce5 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/connectionInfo.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/connectionInfo.tsx
@@ -29,7 +29,7 @@ type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps>;
const ConnectionInfo: React.FunctionComponent<props> = (props) => {
- return ((props.isTopoServerReachable === false || props.isTileServerReachable === false )? <Paper style={{padding:5, position: 'absolute', top: 160, width: 230, left:"40%"}}>
+ return ((props.isTopoServerReachable === false || props.isTileServerReachable === false )? <Paper style={{padding:5, position: 'absolute', top: 160, width: 230, left:"40%", zIndex:1}}>
<div style={{display: 'flex', flexDirection: 'column'}}>
<div style={{'alignSelf': 'center', marginBottom:5}}> <Typography> <FontAwesomeIcon icon={faExclamationTriangle} /> Connection Error</Typography></div>
{props.isTileServerReachable === false && <Typography> Tile data can't be loaded.</Typography>}
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/iconSwitch.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/iconSwitch.tsx
index bb98cb467..221e7dab8 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/iconSwitch.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/iconSwitch.tsx
@@ -32,9 +32,9 @@ const IconSwitch: React.FunctionComponent<props> = (props) =>{
return (
props.visible ?
- <FormControlLabel style={{ padding:5, position: 'absolute',top: 190}}
+ <FormControlLabel style={{ padding:5, position: 'absolute',top: 190, zIndex:1}}
value="end"
- control={<Switch color="secondary" checked={props.areIconsEnabled} onChange={toggleChecked} />}
+ control={<Switch color="secondary" style={{zIndex:1}} checked={props.areIconsEnabled} onChange={toggleChecked} />}
label="Show icons"
labelPlacement="end"
/>: null)
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/map.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/map.tsx
index 9637d745e..1314edbba 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/map.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/map.tsx
@@ -54,6 +54,7 @@ let notLoadedBoundingBoxes: mapboxgl.LngLatBounds[] = [];
let lastBoundingBox: mapboxgl.LngLatBounds | null = null;
let myRef = React.createRef<HTMLDivElement>();
+import 'mapbox-gl/dist/mapbox-gl.css';
class Map extends React.Component<mapProps, { isPopupOpen: boolean }> {
@@ -158,7 +159,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> {
mapLayerService.addBaseSources(map, this.props.selectedSite, this.props.selectedLink);
addImages(map, (result: boolean)=>{
- if(map.getZoom()>11)
+ if(map.getZoom()>11 && this.props.showIcons)
{
mapLayerService.addIconLayers(map, this.props.selectedSite?.properties.id)
}else{
@@ -190,134 +191,142 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> {
}
})
.catch(error => this.props.handleConnectionError(error));
+
+ map.on('click', this.mapClick);
+ map.on('moveend', this.mapMoveEnd);
+ map.on('move', this.mapMove);
+
});
+ }
- map.on('click', (e: any) => {
+ mapMove = () => {
+
+ const mapZoom = map.getZoom();
- if (map.getLayer('points')) { // data is shown as points
+ const boundingBox = map.getBounds();
+
+ this.loadNetworkData(boundingBox);
+ if (mapZoom > 9) {
- var clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5],
- [e.point.x + 5, e.point.y + 5]], {
- layers: ['microwave-lines', 'fibre-lines']
- }), "id");
+ if (map.getLayer('points')) {
+ map.setLayoutProperty('selectedPoints', 'visibility', 'visible');
+ map.setPaintProperty('points', 'circle-radius', 7);
+ }
+ } else {
- const clickedPoints = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['points'] }), "id");
- const alarmedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['alarmedPoints'] }), "id");
+ // reduce size of points / lines if zoomed out
+ map.setPaintProperty('points', 'circle-radius', 2);
+ map.setLayoutProperty('selectedPoints', 'visibility', 'none');
- if (clickedPoints.length != 0) {
+ if (mapZoom <= 4) {
+ map.setPaintProperty('fibre-lines', 'line-width', 1);
+ map.setPaintProperty('microwave-lines', 'line-width', 1);
+
+ } else {
+ map.setPaintProperty('fibre-lines', 'line-width', 2);
+ map.setPaintProperty('microwave-lines', 'line-width', 2);
+ }
+ }
+ };
+ mapClick = (e: any) => {
- if (alarmedSites.length > 0) {
- alarmedSites.forEach(alarm => {
- const index = clickedPoints.findIndex(item => item.properties!.id === alarm.properties!.id);
+
+ if (map.getLayer('points')) { // data is shown as points
- if (index !== -1) {
- clickedPoints[index].properties!.alarmed = true;
- clickedPoints[index].properties!.type = "alarmed";
- }
- });
- }
+ var clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5],
+ [e.point.x + 5, e.point.y + 5]], {
+ layers: ['microwave-lines', 'fibre-lines']
+ }), "id");
- this.showSitePopup(clickedPoints, e.point.x, e.point.y);
- } else if (clickedLines.length != 0) {
- this.showLinkPopup(clickedLines, e.point.x, e.point.y);
- }
+ const clickedPoints = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['points'] }), "id");
+ const alarmedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['alarmedPoints'] }), "id");
+ if (clickedPoints.length != 0) {
- } else { // data is shown as icons
- const clickedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-lamps', 'point-building', 'point-data-center', 'point-factory', 'point-remaining'] }), "id");
- const clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5],
- [e.point.x + 5, e.point.y + 5]], {
- layers: ['microwave-lines', 'fibre-lines']
- }), "id");
+ if (alarmedSites.length > 0) {
+ alarmedSites.forEach(alarm => {
+ const index = clickedPoints.findIndex(item => item.properties!.id === alarm.properties!.id);
- if (clickedSites.length > 0)
- this.showSitePopup(clickedSites, e.point.x, e.point.y);
- else if (clickedLines.length != 0) {
- this.showLinkPopup(clickedLines, e.point.x, e.point.y);
+ if (index !== -1) {
+ clickedPoints[index].properties!.alarmed = true;
+ clickedPoints[index].properties!.type = "alarmed";
+ }
+ });
}
- }
- });
+ this.showSitePopup(clickedPoints, e.point.x, e.point.y);
+ } else if (clickedLines.length != 0) {
+ this.showLinkPopup(clickedLines, e.point.x, e.point.y);
+ }
- map.on('moveend', () => {
- const mapZoom = Number(map.getZoom().toFixed(2));
- const lat = Number(map.getCenter().lat.toFixed(4));
- const lon = Number(map.getCenter().lng.toFixed(4));
+ } else { // data is shown as icons
+ const clickedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-lamps', 'point-building', 'point-data-center', 'point-factory', 'point-remaining'] }), "id");
+ const clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5],
+ [e.point.x + 5, e.point.y + 5]], {
+ layers: ['microwave-lines', 'fibre-lines']
+ }), "id");
- if (this.props.lat !== lat || this.props.lon !== lon || this.props.zoom !== mapZoom) {
- this.props.updateMapPosition(lat, lon, mapZoom)
+ if (clickedSites.length > 0)
+ this.showSitePopup(clickedSites, e.point.x, e.point.y);
+ else if (clickedLines.length != 0) {
+ this.showLinkPopup(clickedLines, e.point.x, e.point.y);
}
+ }
+ };
- // update the url to current lat,lon,zoom values
+ mapMoveEnd = () => {
- const currentUrl = window.location.href;
- const parts = currentUrl.split(URL_BASEPATH);
- if(parts.length>0){
+ const mapZoom = Number(map.getZoom().toFixed(2));
+ const lat = Number(map.getCenter().lat.toFixed(4));
+ const lon = Number(map.getCenter().lng.toFixed(4));
- const detailsPath = parts[1].split("/details/");
- if (detailsPath[1] !== undefined && detailsPath[1].length > 0) {
- this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}/details/${detailsPath[1]}`)
- }
- else {
- this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}`)
- }
- }
-
-
- //switch icon layers if applicable
- mapLayerService.showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id);
+ if (this.props.lat !== lat || this.props.lon !== lon || this.props.zoom !== mapZoom) {
+ this.props.updateMapPosition(lat, lon, mapZoom)
+ }
- //update statistics
- const boundingBox = map.getBounds();
+ // update the url to current lat,lon,zoom values
- fetch(`${URL_API}/info/count/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`)
- .then(result => verifyResponse(result))
- .then(res => res.json())
- .then(result => {
- if (result.links !== this.props.linkCount || result.sites !== this.props.siteCount) {
- this.props.setStatistics(result.links, result.sites);
- }
- })
- .catch(error => this.props.handleConnectionError(error));;
- })
+ const currentUrl = window.location.href;
+ const parts = currentUrl.split(URL_BASEPATH);
+ if (parts.length > 0) {
- map.on('move', () => {
- const mapZoom = map.getZoom();
+ const detailsPath = parts[1].split("/details/");
- const boundingBox = map.getBounds();
+ if (detailsPath[1] !== undefined && detailsPath[1].length > 0) {
+ this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}/details/${detailsPath[1]}`)
+ }
+ else {
+ this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}`)
+ }
+ }
- this.loadNetworkData(boundingBox);
- if (mapZoom > 9) {
- if (map.getLayer('points')) {
- map.setLayoutProperty('selectedPoints', 'visibility', 'visible');
- map.setPaintProperty('points', 'circle-radius', 7);
- }
- } else {
+ //switch icon layers if applicable
- // reduce size of points / lines if zoomed out
- map.setPaintProperty('points', 'circle-radius', 2);
- map.setLayoutProperty('selectedPoints', 'visibility', 'none');
+ mapLayerService.showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id);
- if (mapZoom <= 4) {
- map.setPaintProperty('fibre-lines', 'line-width', 1);
- map.setPaintProperty('microwave-lines', 'line-width', 1);
+ //update statistics
+ const boundingBox = map.getBounds();
- } else {
- map.setPaintProperty('fibre-lines', 'line-width', 2);
- map.setPaintProperty('microwave-lines', 'line-width', 2);
+ fetch(`${URL_API}/info/count/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`)
+ .then(result => verifyResponse(result))
+ .then(res => res.json())
+ .then(result => {
+ if (result.links !== this.props.linkCount || result.sites !== this.props.siteCount) {
+ this.props.setStatistics(result.links, result.sites);
}
- }
- });
+ })
+ .catch(error => this.props.handleConnectionError(error));;
}
componentDidUpdate(prevProps: mapProps, prevState: {}) {
+ if(prevProps !== this.props){
//(load map)
//triggered if either settings were done loading or tile/topology server connectivity checked
if(prevProps.settings !== this.props.settings || this.props.isConnectivityCheckBusy !== prevProps.isConnectivityCheckBusy){
@@ -329,6 +338,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> {
//if everything done loading/reachable, load map
if(!this.props.isConnectivityCheckBusy && this.props.isTileServerReachable && !this.props.settings.isLoadingData && (prevProps.settings.isLoadingData !==this.props.settings.isLoadingData || prevProps.isConnectivityCheckBusy !== this.props.isConnectivityCheckBusy)){
+
if(map == undefined){
this.setupMap();
}
@@ -443,12 +453,22 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> {
}
}
}
+ }
}
componentWillUnmount(){
+
+ //unregister events
window.removeEventListener("menu-resized", this.handleResize);
- lastBoundingBox=null;
+
+ if(map){
+ map.off('click', this.mapClick);
+ map.off('moveend', this.mapMoveEnd);
+ map.off('move', this.mapMove);
+ }
+ lastBoundingBox=null;
+
// will be checked again on next load
this.props.setConnectivityCheck(true);
}
@@ -624,7 +644,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> {
<ConnectionInfo />
<Button
disabled={!this.props.isTopoServerReachable}
- style={{'position': 'absolute', 'right':5, top:5, backgroundColor:'white'}}
+ style={{'position': 'absolute', 'right':5, top:5, backgroundColor:'white', zIndex:1}}
onClick={e => this.props.navigateToApplication("network", "customize")} >
<img src={customize} />
</Button>
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/searchBar.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/searchBar.tsx
index 45bc6092d..307c5d203 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/searchBar.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/searchBar.tsx
@@ -46,6 +46,7 @@ const styles = makeStyles({
top: 15,
marginLeft: 5,
width: 400,
+ zIndex:1
},
input: {
flex: 1,
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/statistics.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/statistics.tsx
index 116b789d7..562689198 100644
--- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map/statistics.tsx
+++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map/statistics.tsx
@@ -41,7 +41,7 @@ const Statistics: React.FunctionComponent<props> = (props: props) =>{
const reachabe = props.isTopoServerReachable && props.isTileServerReachable;
- return (<Paper style={{ padding: 5, position: 'absolute', display: 'flex', flexDirection: "column", top: 70, width: 200, marginLeft: 5 }}>
+ return (<Paper style={{ padding: 5, position: 'absolute', display: 'flex', flexDirection: "column", top: 70, width: 200, marginLeft: 5, zIndex:1 }}>
<div style={{ display: 'flex', flexDirection: "row" }}>
<Typography style={{ fontWeight: "bold", flex: "1", color: reachabe ? "black" : "lightgrey" }} >Statistics</Typography>
<Tooltip style={{ alignSelf: "flex-end" }} title="Gets updated when the map stops moving.">