diff options
Diffstat (limited to 'sdnr/wt/odlux/apps/networkMapApp')
23 files changed, 289 insertions, 139 deletions
diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/README.md b/sdnr/wt/odlux/apps/networkMapApp/icons/README.md index b26fbc29b..acfbcf823 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/README.md +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/README.md @@ -19,7 +19,7 @@ Copyright of icons is as followes: */ --> -datacenter.png and lamp.png +datacenter.png, lamp.png, factory.png, datacenterred.png, lampred.png, factoryred.png, Taken from MS Word diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png Binary files differnew file mode 100644 index 000000000..5d5a6c523 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts new file mode 100644 index 000000000..33f3061e2 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts @@ -0,0 +1,2 @@ +declare const datacenterred: string; +export default datacenterred;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png Binary files differnew file mode 100644 index 000000000..a38781baa --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts new file mode 100644 index 000000000..b5c4f19d9 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts @@ -0,0 +1,2 @@ +declare const factory: string; +export default factory;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png Binary files differnew file mode 100644 index 000000000..959603ab1 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts new file mode 100644 index 000000000..1fac0a943 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts @@ -0,0 +1,2 @@ +declare const factoryRed: string; +export default factoryRed;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png Binary files differnew file mode 100644 index 000000000..4678ce91c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts new file mode 100644 index 000000000..12a8f91cb --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts @@ -0,0 +1,2 @@ +declare const lampred: string; +export default lampred;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts index 8a005bcaf..5288f61d9 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts @@ -117,8 +117,6 @@ running=true; result.forEach((res: any, index)=>{ - console.log("value") - console.log(res); if(res !==null && res.node!==null){ list[index].status = res.node[0]["netconf-node-topology:connection-status"]; @@ -137,28 +135,4 @@ running=true; dispatcher(new IsBusyCheckingDeviceListAction(false)); }); - - /* result.forEach((res: Promise<any>, index)=>{ - console.log("value") - console.log(res); - console.log(res.value); - if(res.value!==null){ - list[index].status = res.value.node[0]["netconf-node-topology:connection-status"]; - }else{ - list[index].status = "Not connected"; - }*/ - - - - - - - //get devices - //wait on all to finish - //update array - - - - - }
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx index 9846a22c0..1506df5ab 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx @@ -26,7 +26,7 @@ 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, 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, ariaLabel: string, onClick?(id: string): void, actions?:boolean }; const styles = makeStyles({ @@ -81,13 +81,13 @@ const DenseTable: React.FunctionComponent<props> = (props) => { return ( - <TableRow key={index} hover={props.hover} onMouseOver={e => handleHover(e,row.name)} onClick={ e => handleClick(e, row.name)}> + <TableRow aria-label={props.ariaLabel} key={index} hover={props.hover} onMouseOver={e => handleHover(e,row.name)} onClick={ e => handleClick(e, row.name)}> { values.map((data:any) => { if(data!== undefined) - return <TableCell > {data} </TableCell> + return <TableCell> {data} </TableCell> else return null; }) @@ -95,12 +95,15 @@ const DenseTable: React.FunctionComponent<props> = (props) => { { props.actions && <TableCell > -<div style={{display:"flex"}}> +<div style={{display:"flex"}}> + <Tooltip title="Connect"> + <Button className={classes.button} disabled={true} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("connect", row.simulatorId ? row.simulatorId : row.name)}}>C</Button> + </Tooltip> <Tooltip title="Configure"> - <Button className={classes.button} disabled={row.status!=="connected"} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("configuration", row.simulatorId ? row.simulatorId : row.name)}}>C</Button> + <Button className={classes.button} disabled={true} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("configuration", row.simulatorId ? row.simulatorId : row.name)}}>C</Button> </Tooltip> <Tooltip title="Fault"> - <Button className={classes.button} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("fault", row.simulatorId ? row.simulatorId : row.name)}}>F</Button> + <Button className={classes.button} disabled={true} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("fault", row.simulatorId ? row.simulatorId : row.name)}}>F</Button> </Tooltip> </div> </TableCell> diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx index a2e51d30f..081276b5c 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx @@ -50,10 +50,9 @@ const Details: React.FunctionComponent<porps> = (props) => { }, []); - // if url changed + // if url changed, load details data React.useEffect(() => { const detailsId = getDetailsIdFromUrl(); - console.log(detailsId) if (detailsId !== null && props.data?.name !== detailsId) { loadDetailsData(detailsId) } @@ -154,16 +153,17 @@ const Details: React.FunctionComponent<porps> = (props) => { }) } + const panelId = props.data!== null ? (isSite(props.data) ? 'site-details-panel' : 'link-details-panel' ): 'details-panel'; return (<div style={{ width: '30%', background: "#bbbdbf", padding: "20px", alignSelf:"stretch" }}> - <Paper style={{ height:"100%"}} id="site-details-panel" > + <Paper style={{ height:"100%"}} id={panelId} aria-label={panelId} > { props.breadcrumbs.length > 0 && - <Breadcrumbs style={{ marginLeft: "15px", marginTop: "5px" }} aria-label="breadcrumb"> - <Link color="inherit" href="/" onClick={backClick}> + <Breadcrumbs style={{ marginLeft: "15px", marginTop: "5px" }} aria-label="breadcrumbs-navigation"> + <Link aria-label="parent-element" color="inherit" href="/" onClick={backClick}> {props.breadcrumbs[0].id} </Link> - <Link> + <Link aria-label="child-element" color="textSecondary"> {props.data?.name} </Link> </Breadcrumbs> @@ -171,7 +171,7 @@ const Details: React.FunctionComponent<porps> = (props) => { { props.data !== null ? createDetailPanel(props.data) - : <Typography style={{ marginTop: "5px" }} align="center" variant="body1">{message}</Typography> + : <Typography aria-label="details-panel-alt-message" style={{ marginTop: "5px" }} align="center" variant="body1">{message}</Typography> } </Paper> 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 de1bf6b16..0c9f6034f 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx @@ -32,8 +32,7 @@ const LinkDetails: React.FunctionComponent<props> = (props) => { const [height, setHeight] = React.useState(330); const handleResize = () =>{ - console.log("resize") - const el = document.getElementById('site-details-panel')?.getBoundingClientRect(); + const el = document.getElementById('link-details-panel')?.getBoundingClientRect(); const el2 = document.getElementById('site-tabs')?.getBoundingClientRect(); if(el && el2){ @@ -69,7 +68,7 @@ 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; - window.open(`/#/linkCalculation?lat1=${siteA.lat}&lon1=${siteA.lon}&lat2=${siteB.lat}&lon2=${siteB.lon}&siteA=${nameA}&siteB=${nameB}&azimuthA=${azimuthA}&azimuthB=${azimuthB}&distance=${distance}`) + window.open(`/#/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}`) } @@ -83,15 +82,15 @@ const LinkDetails: React.FunctionComponent<props> = (props) => { return (<div style={{ paddingLeft: "15px", paddingRight: "15px", paddingTop: "0px", display: 'flex', flexDirection: 'column' }}> <h2>{props.link.name}</h2> - <TextField disabled style={{ marginTop: "5px" }} value="Unkown" label="Operator" /> - <TextField disabled style={{ marginTop: "5px" }} value={props.link.type} label="Type" /> - <TextField disabled style={{ marginTop: "5px" }} value={props.link.length.toFixed(2)} label="Distance planned in km" /> - <TextField disabled style={{ marginTop: "5px" }} value={props.link.calculatedLength.toFixed(2)} label="Distance calculated in km" /> + <TextField aria-label="operator" disabled style={{ marginTop: "5px" }} value="Unkown" label="Operator" /> + <TextField aria-label="type" disabled style={{ marginTop: "5px" }} value={props.link.type} label="Type" /> + <TextField aria-label="planned-distance-in-km" disabled style={{ marginTop: "5px" }} value={props.link.length.toFixed(2)} label="Distance planned in km" /> + <TextField aria-label="calculated-distance-in-km" disabled style={{ marginTop: "5px" }} value={props.link.calculatedLength.toFixed(2)} label="Distance calculated in km" /> <AppBar position="static" id="site-tabs" style={{ marginTop: "20px", background: '#2E3B55' }}> - <Typography style={{ margin:"5px"}}>SITE DETAILS</Typography> + <Typography aria-label="details-of-link-sites" style={{ margin:"5px"}}>SITE DETAILS</Typography> </AppBar> - <DenseTable height={height} hover={false} headers={["", "Site A", "Site B"]} data={data} /> + <DenseTable ariaLabel="site-information-table-entry" 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> } 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 a95666e38..92643d0c4 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx @@ -81,28 +81,28 @@ const SiteDetails: React.FunctionComponent<props> = (props) => { <h2 >{props.site.name}</h2> { props.site.operator !== '' && props.site.operator !== null ? - <TextField disabled={true} value={props.site.operator} label="Operator" /> : - <TextField disabled={true} value="Unkown" label="Operator" style={{ marginTop: "5px" }} /> + <TextField aria-label="operator" disabled={true} value={props.site.operator} label="Operator" /> : + <TextField aria-label="operator" disabled={true} value="Unkown" label="Operator" style={{ marginTop: "5px" }} /> } { props.site.type !== undefined && props.site.type.length > 0 && - <TextField disabled={true} value={props.site.type} label="Type" style={{ marginTop: "5px" }} /> + <TextField aria-label="type" disabled={true} value={props.site.type} label="Type" style={{ marginTop: "5px" }} /> } { props.site.address !== undefined && props.site.address.length > 0 && - <TextField disabled={true} value={props.site.address} label="Adress" style={{ marginTop: "5px" }} /> + <TextField aria-label="adress" disabled={true} value={props.site.address} label="Adress" style={{ marginTop: "5px" }} /> } { props.site.heighAGLInMeters !== undefined && props.site.heighAGLInMeters > 0 && - <TextField disabled={true} value={props.site.heighAGLInMeters} label="AMSL in meters" style={{ marginTop: "5px" }} /> + <TextField aria-label="amsl-in-meters" disabled={true} value={props.site.heighAGLInMeters} label="AMSL in meters" style={{ marginTop: "5px" }} /> } { props.site.antennaHeightAGLInMeters !== undefined && props.site.antennaHeightAGLInMeters > 0 && - <TextField disabled={true} value={props.site.antennaHeightAGLInMeters} label="Atenna above ground in meters" style={{ marginTop: "5px" }} /> + <TextField aria-label="antenna-above-ground-in-meters" disabled={true} value={props.site.antennaHeightAGLInMeters} label="Atenna above ground in meters" style={{ marginTop: "5px" }} /> } - <TextField style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.geoLocation.lat)} label="Latitude" /> - <TextField style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.geoLocation.lon, true)} label="Longitude" /> + <TextField aria-label="latitude" style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.geoLocation.lat)} label="Latitude" /> + <TextField aria-label="longitude" style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.geoLocation.lon, true)} label="Longitude" /> <AppBar position="static" style={{ marginTop: "5px", background: '#2E3B55' }}> <Tabs id="site-tabs" value={value} onChange={onHandleTabChange} aria-label="simple tabs example"> @@ -115,12 +115,12 @@ const SiteDetails: React.FunctionComponent<props> = (props) => { <> { props.site.links.length === 0 && - <Typography variant="body1" style={{ marginTop: '10px' }}>No links available.</Typography> + <Typography aria-label="no-links-available" variant="body1" style={{ marginTop: '10px' }}>No links available.</Typography> } { props.site.links.length > 0 && - <DenseTable height={height} hover={true} headers={["Link Name", "Azimuth in °"]} data={linkRows} onClick={props.onLinkClick} ></DenseTable> + <DenseTable ariaLabel="available-links-table-entry" height={height} hover={true} headers={["Link Name", "Azimuth in °"]} data={linkRows} onClick={props.onLinkClick} ></DenseTable> /** * * */ @@ -136,12 +136,12 @@ const SiteDetails: React.FunctionComponent<props> = (props) => { <> { props.site.devices.length === 0 && - <Typography variant="body1" style={{ marginTop: '10px' }}>No nodes available.</Typography> + <Typography aria-label="no-nodes-avilable" variant="body1" style={{ marginTop: '10px' }}>No nodes available.</Typography> } { props.site.devices.length>0 && props.updatedDevices !== null && - <DenseTable navigate={props.navigate} height={height} hover={false} headers={["ID","Name","Type", "Manufacturer","Owner","Status", "Ports", "Actions"]} actions={true} data={props.updatedDevices!} /> + <DenseTable ariaLabel="available-nodes-table-entry" navigate={props.navigate} height={height} hover={false} headers={["ID","Name","Type", "Manufacturer","Owner","Status", "Ports", "Actions"]} actions={true} data={props.updatedDevices!} /> } </> } diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/iconSwitch.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/iconSwitch.tsx new file mode 100644 index 000000000..8df1385d0 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/iconSwitch.tsx @@ -0,0 +1,53 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 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 { FormControlLabel, Switch, Paper } from "@material-ui/core"; +import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import { SetIconSwitchAction } from '../actions/mapActions'; + +type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps> & {visible: boolean} + +const IconSwitch: React.FunctionComponent<props> = (props) =>{ + + const toggleChecked = () => { + props.toogle(!props.areIconsEnabled) + }; + + return ( + props.visible ? + <FormControlLabel style={{ padding:5, position: 'absolute',top: 190}} + value="end" + control={<Switch color="secondary" checked={props.areIconsEnabled} onChange={toggleChecked} />} + label="Show icons" + labelPlacement="end" + />: null) +} + +const mapStateToProps = (state: IApplicationStoreState) => ({ + areIconsEnabled: state.network.map.allowIconSwitch +}); + + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + toogle : (enable:boolean) => dispatcher.dispatch(new SetIconSwitchAction(enable)) + +});; + +export default (connect(mapStateToProps,mapDispatchToProps)(IconSwitch)) diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx index 363178e9b..ceb51d41a 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx @@ -30,24 +30,18 @@ import { SetPopupPositionAction, SelectMultipleLinksAction, SelectMultipleSitesA import { Feature } from '../model/Feature'; import { HighlightLinkAction, HighlightSiteAction, SetCoordinatesAction, SetStatistics } from '../actions/mapActions'; import { addDistance, getUniqueFeatures } from '../utils/mapUtils'; -import { location } from '../handlers/mapReducer' -import { Typography, Paper, Tooltip } from '@material-ui/core'; -import { elementCount } from '../model/count'; -import lamp from '../../icons/lamp.png'; -import apartment from '../../icons/apartment.png'; -import datacenter from '../../icons/datacenter.png'; import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; import connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect'; import SearchBar from './searchBar'; import { verifyResponse, IsTileServerReachableAction, handleConnectionError } from '../actions/connectivityAction'; import ConnectionInfo from './connectionInfo' -import { ApplicationStore } from '../../../../framework/src/store/applicationStore'; -import { showIconLayers, addBaseLayers, swapLayersBack } from '../utils/mapLayers'; -import Statistics from './statistics' - - - - +import { showIconLayers, addBaseLayers } from '../utils/mapLayers'; +import lamp from '../../icons/lamp.png'; +import apartment from '../../icons/apartment.png'; +import datacenter from '../../icons/datacenter.png'; +import factory from '../../icons/factory.png'; +import Statistics from './statistics'; +import IconSwitch from './iconSwitch'; type coordinates = { lat: number, lon: number, zoom: number } @@ -71,8 +65,11 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { componentDidMount() { + // resize the map, if menu gets collapsed window.addEventListener("menu-resized", this.handleResize); + // try if connection to tile + topologyserver is available + fetch(URL_TILE_API + '/10/0/0.png') .then(res => { if (res.ok) { @@ -138,6 +135,13 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { map.addImage('house', image); }); + map.loadImage( + factory, + function (error: any, image: any) { + if (error) throw error; + map.addImage('factory', image); + }); + const boundingBox = map.getBounds(); @@ -145,7 +149,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { .then(result => verifyResponse(result)) .then(result => result.json()) .then(features => { - if (map.getLayer('lines')) { + if (map.getLayer('fibre-lines')) { (map.getSource('lines') as mapboxgl.GeoJSONSource).setData(features); } }) @@ -160,8 +164,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { (map.getSource('points') as mapboxgl.GeoJSONSource).setData(features); } }) - .catch(error => this.props.handleConnectionError(error));; - + .catch(error => this.props.handleConnectionError(error)); }); map.on('click', (e: any) => { @@ -170,7 +173,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { var clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5], [e.point.x + 5, e.point.y + 5]], { - layers: ['lines'] + layers: ['microwave-lines', 'fibre-lines'] }), "id"); const clickedPoints = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['points'] }), "id"); @@ -182,14 +185,12 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { if (alarmedSites.length > 0) { alarmedSites.forEach(alarm => { const index = clickedPoints.findIndex(item => item.properties!.id === alarm.properties!.id); - console.log(index); if (index !== -1) { clickedPoints[index].properties!.alarmed = true; clickedPoints[index].properties!.type = "alarmed"; } }); - console.log(clickedPoints); } this.showSitePopup(clickedPoints, e.point.x, e.point.y); @@ -203,12 +204,13 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { const clickedLamps = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-lamps'] }), "id"); const buildings = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-building'] }), "id"); const houses = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-data-center'] }), "id"); + const factories = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-factory'] }), "id"); - const combinedFeatures = [...clickedLamps, ...buildings, ...houses]; + const combinedFeatures = [...clickedLamps, ...buildings, ...houses, ...factories]; const clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5], [e.point.x + 5, e.point.y + 5]], { - layers: ['lines'] + layers: ['microwave-lines', 'fibre-lines'] }), "id"); if (combinedFeatures.length > 0) @@ -231,6 +233,8 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { this.props.updateMapPosition(lat, lon, mapZoom) } + // update the url to current lat,lon,zoom values + const currentUrl = window.location.href; const parts = currentUrl.split(URL_BASEPATH); const detailsPath = parts[1].split("/details/"); @@ -241,16 +245,17 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { 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 + showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); + //update statistics const boundingBox = map.getBounds(); - showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); - fetch(`${URL_API}/info/count/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`) .then(result => verifyResponse(result)) .then(res => res.json()) .then(result => { - console.log(result); if (result.links !== this.props.linkCount || result.sites !== this.props.siteCount) { this.props.setStatistics(result.links, result.sites); } @@ -277,9 +282,12 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { map.setLayoutProperty('selectedPoints', 'visibility', 'none'); if (mapZoom <= 4) { - map.setPaintProperty('lines', 'line-width', 1); + map.setPaintProperty('fibre-lines', 'line-width', 1); + map.setPaintProperty('microwave-lines', 'line-width', 1); + } else { - map.setPaintProperty('lines', 'line-width', 2); + map.setPaintProperty('fibre-lines', 'line-width', 2); + map.setPaintProperty('microwave-lines', 'line-width', 2); } } }); @@ -301,7 +309,8 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { map.setFilter('point-lamps', ['==', 'type', 'street lamp']); map.setFilter('point-data-center', ['==', 'type', 'data center']); - map.setFilter('point-building', ['==', 'type', 'high rise building']) + map.setFilter('point-building', ['==', 'type', 'high rise building']); + map.setFilter('point-factory', ['==', 'type', 'factory']) if (this.props.selectedSite?.properties.type !== undefined) { switch (this.props.selectedSite?.properties.type) { @@ -313,7 +322,9 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { break; case 'high rise building': map.setFilter('point-building', ["all", ['==', 'type', 'high rise building'], ['!=', 'id', this.props.selectedSite.properties.id]]) - + break; + case 'factory': + map.setFilter('point-factory', ["all", ['==', 'type', 'factory'], ['!=', 'id', this.props.selectedSite.properties.id]]); break; } } @@ -336,6 +347,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { map.setFilter('point-lamps', ['==', 'type', 'street lamp']); map.setFilter('point-data-center', ['==', 'type', 'data center']); map.setFilter('point-building', ['==', 'type', 'high rise building']); + map.setFilter('point-factory', ['==', 'type', 'factory']); } if (map.getSource("selectedLine") !== undefined) { @@ -367,7 +379,6 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { if (prevProps.showIcons !== this.props.showIcons) { if (map && map.getZoom() > 11) { - console.log(this.props.showIcons); showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); } } @@ -388,6 +399,10 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { } } + componentWillUnmount(){ + window.removeEventListener("menu-resized", this.handleResize); + } + handleResize = () => { if (map) { // wait a moment until resizing actually happened @@ -432,10 +447,6 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { } } - - //TODO: how to handle if too much data gets loaded? (1 mio points...?) - // data might have gotten collected, reload if necessary! - //always save count, if count and current view count differ -> reload last boundingbox loadNetworkData = async (bbox: mapboxgl.LngLatBounds) => { if (!isLoadingInProgress) { // only load data if loading not in progress isLoadingInProgress = true; @@ -458,7 +469,6 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { await this.draw('lines', `${URL_API}/links/geoJson/${increasedBoundingBox.west},${increasedBoundingBox.south},${increasedBoundingBox.east},${increasedBoundingBox.north}`); await this.draw('points', `${URL_API}/sites/geoJson/${increasedBoundingBox.west},${increasedBoundingBox.south},${increasedBoundingBox.east},${increasedBoundingBox.north}`); - console.log("bbox is bigger"); } else if (lastBoundingBox.contains(bbox.getNorthEast()) && lastBoundingBox.contains(bbox.getSouthWest())) { // last one contains new one // bbox is contained in last one, do nothing @@ -506,17 +516,13 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { }) .catch(error => this.props.handleConnectionError(error));; } - } - - showLinkPopup = (links: mapboxgl.MapboxGeoJSONFeature[], top: number, left: number) => { if (links.length > 1) { const ids = links.map(feature => feature.properties!.id as string); - this.props.setPopupPosition(top, left); this.props.selectMultipleLinks(ids); this.setState({ isPopupOpen: true }); @@ -562,6 +568,7 @@ class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { } <SearchBar /> <Statistics /> + <IconSwitch visible={this.props.zoom>11} /> <ConnectionInfo /> </div> </> diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx index 0c7607bb7..c825e5ae0 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx @@ -79,11 +79,13 @@ const SearchBar: React.FunctionComponent<searchBarProps> = (props) =>{ const linkResult = fetch(`${URL_API}/link/${props.searchterm}`); Promise.all([ siteResult, linkResult]).then((result)=>{ - const suceededResults = result.filter(el=> el!==undefined); + const suceededResults = result.filter(el=> el.ok); if(suceededResults.length==0){ setAnchorEl(divRef.current); setErrorMessage("No element found.") + // hide message after 3 sec + window.setTimeout(()=>{setAnchorEl(null)}, 3000); }else{ suceededResults[0].json().then(result =>{ @@ -115,7 +117,7 @@ const SearchBar: React.FunctionComponent<searchBarProps> = (props) =>{ disabled={!reachabe} className={classes.input} placeholder="Find sites or links by name" - inputProps={{ 'aria-label': 'search sites or links' }} + inputProps={{ 'aria-label': 'networkmap-searchbar' }} value={props.searchterm} onChange={e=> props.setSearchTerm(e.currentTarget.value)} /> diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/config.ts b/sdnr/wt/odlux/apps/networkMapApp/src/config.ts index bdfcd2407..e2e5718d5 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/config.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/config.ts @@ -27,11 +27,10 @@ export const OSM_STYLE = { 'type': 'raster', 'tiles': [ URL_TILE_API+'/{z}/{x}/{y}.png' - ], 'tileSize': 256, 'attribution': - 'Data by <a target="_top" rel="noopener" href="http://openstreetmap.org">OpenStreetMap</a>, under <a target="_top" rel="noopener" href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>' + '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' } }, 'layers': [ @@ -40,7 +39,7 @@ export const OSM_STYLE = { 'type': 'raster', 'source': 'raster-tiles', 'minzoom': 0, - 'maxzoom': 22 + 'maxzoom': 18 } ] }; diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts index a140e9b77..6f6277347 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts @@ -50,7 +50,7 @@ export const MapReducer: IActionHandler<mapState> = (state=initialState, action: if(action instanceof HighlightLinkAction){ - state = Object.assign({}, state, {selectedSite: null, selectedLink:{type: "Feature", geometry:{type:"LineString", coordinates:[[action.link.locationA.lon,action.link.locationA.lat ],[action.link.locationB.lon,action.link.locationB.lat ]]}}}) + state = Object.assign({}, state, {selectedSite: null, selectedLink:{type: "Feature", properties:{id:action.link.id, type: action.link.type}, geometry:{type:"LineString", coordinates:[[action.link.locationA.lon,action.link.locationA.lat ],[action.link.locationB.lon,action.link.locationB.lat ]]}}}) } diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/index.html b/sdnr/wt/odlux/apps/networkMapApp/src/index.html index f68e8c13b..9a7f77a29 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/index.html +++ b/sdnr/wt/odlux/apps/networkMapApp/src/index.html @@ -17,10 +17,11 @@ <script> // run the application - require(["app","connectApp","faultApp", "networkMapApp", "configurationApp"], function (app, connectApp, faultApp, networkMapApp, configurationApp) { + require(["app","connectApp","faultApp", "networkMapApp", "configurationApp", "linkCalculationApp"], function (app, connectApp, faultApp, networkMapApp, configurationApp, linkCalculationApp) { connectApp.register(); //faultApp.register(); configurationApp.register(); + linkCalculationApp.register(); networkMapApp.register(); app("./app.tsx").runApplication(); }); diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts index a6ef65c98..e11be1a68 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts @@ -25,6 +25,6 @@ export type link = {id: string, siteB: string, azimuthA: number, azimuthB: number, - locationA:{lon: number, lat: number}, - locationB:{lon: number, lat: number} + locationA: { lon: number, lat: number, amsl?:number, antennaHeight?: number }, + locationB: { lon: number, lat: number, amsl?:number, antennaHeight?: number }, };
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx index 0ff9418ac..67c75cecf 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx @@ -1,25 +1,4 @@ /** -* ============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========================================================================== -*/ -// app configuration and main entry point for the app - -import * as React from "react"; -import { faMapMarked } from '@fortawesome/free-solid-svg-icons'; // select app icon -/** * ============LICENSE_START======================================================================== * ONAP : ccsdk feature sdnr wt odlux * ================================================================================================= @@ -37,6 +16,10 @@ import { faMapMarked } from '@fortawesome/free-solid-svg-icons'; // select app i * ============LICENSE_END========================================================================== */ +// app configuration and main entry point for the app + +import * as React from "react"; +import { faMapMarked } from '@fortawesome/free-solid-svg-icons'; // select app icon import applicationManager from '../../../framework/src/services/applicationManager'; @@ -80,7 +63,7 @@ type FaultAlarmNotification = { type: string; sourceType: string; } - +/* // subscribe to the websocket notifications from connect subscribe<ObjectNotification & IFormatedMessage>(["ObjectCreationNotification", "ObjectDeletionNotification", "AttributeValueChangedNotification"], (msg => { const store = applicationApi.applicationStore; @@ -99,3 +82,4 @@ subscribe<FaultAlarmNotification & IFormatedMessage>("ProblemNotification", (fau } })); +*/
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts index e11d96493..f2cabf501 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts @@ -19,6 +19,9 @@ import * as mapboxgl from 'mapbox-gl'; import { Feature } from 'model/Feature'; +const fibreLinkColor = "#1154d9"; +const microwaveLinkColor="#039903"; + export const addBaseLayers = (map: mapboxgl.Map, selectedPoint: Feature|null, selectedLine: Feature|null) => { @@ -50,7 +53,7 @@ export const addBaseLayers = (map: mapboxgl.Map, selectedPoint: Feature|null, se }); map.addLayer({ - 'id': 'lines', + 'id': 'microwave-lines', 'type': 'line', 'source': 'lines', 'layout': { @@ -58,13 +61,29 @@ export const addBaseLayers = (map: mapboxgl.Map, selectedPoint: Feature|null, se 'line-cap': 'round' }, 'paint': { - 'line-color': '#888', + 'line-color': microwaveLinkColor, 'line-width': 2 - } + }, + 'filter': ['==', 'type', 'microwave'] }); map.addLayer({ - 'id': 'selectedLine', + 'id': 'fibre-lines', + 'type': 'line', + 'source': 'lines', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': fibreLinkColor, + 'line-width': 2 + }, + 'filter': ['==', 'type', 'fibre'] + }); + + map.addLayer({ + 'id': 'selectedLineMicrowave', 'type': 'line', 'source': 'selectedLine', 'layout': { @@ -72,9 +91,25 @@ export const addBaseLayers = (map: mapboxgl.Map, selectedPoint: Feature|null, se 'line-cap': 'round' }, 'paint': { - 'line-color': '#888', + 'line-color': microwaveLinkColor, 'line-width': 4 - } + }, + 'filter': ['==', 'type', 'microwave'] + }); + + map.addLayer({ + 'id': 'selectedLineFibre', + 'type': 'line', + 'source': 'selectedLine', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': fibreLinkColor, + 'line-width': 4 + }, + 'filter': ['==', 'type', 'fibre'] }); @@ -136,7 +171,7 @@ export const removeBaseLayers = (map: mapboxgl.Map) => { let checkedLayers = false; -const createFilter = (type:'street lamp'|'high rise building'|'data center', selectedSiteId?:string) =>{ +const createFilter = (type:'street lamp'|'high rise building'|'data center'|'factory', selectedSiteId?:string) =>{ return selectedSiteId === undefined ? ['==', 'type', type] : ["all", ['==', 'type', type], ['!=', 'id', selectedSiteId]] } @@ -159,11 +194,11 @@ export const showIconLayers = (map: mapboxgl.Map, show: boolean, selectedSiteId? }); checkedLayers=true; - if(elements.length>0 && elements.length<1000){ + if(elements.length>0 && elements.length<1000){ if (map.getLayer('point-lamps') === undefined) { map.removeLayer('points'); - + map.setLayoutProperty('alarmedPoints', 'visibility', 'none'); map.setLayoutProperty('selectedPoints', 'visibility', 'none'); map.addLayer({ @@ -202,6 +237,70 @@ export const showIconLayers = (map: mapboxgl.Map, show: boolean, selectedSiteId? 'icon-size': 0.1 } }); + map.addLayer({ + 'id': 'point-factory', + 'type': 'symbol', + 'source': 'points', + 'filter': createFilter("factory", selectedSiteId), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'factory', + 'icon-size': 0.2 + } + }); + + //alarm layers + + map.addLayer({ + 'id': 'point-lamps-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'lamp-red', + 'icon-size': 0.1 + + }, + 'filter': createFilter("street lamp"), + }); + + map.addLayer({ + 'id': 'point-building-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'filter': createFilter("high rise building"), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'house-red', + 'icon-size': 0.1 + } + }); + + map.addLayer({ + 'id': 'point-data-center-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'filter': createFilter("data center"), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'data-center_red', + 'icon-size': 0.1 + } }); + + map.addLayer({ + 'id': 'point-factory-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'filter': createFilter("factory"), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'factory-red', + 'icon-size': 0.2 + } + }); + + + map.addLayer({ id: 'point-remaining', source: 'points', @@ -251,6 +350,19 @@ export const showIconLayers = (map: mapboxgl.Map, show: boolean, selectedSiteId? 'icon-size': 0.15 } }); + + + map.addLayer({ + 'id': 'select-point-factory', + 'type': 'symbol', + 'source': 'selectedPoints', + 'filter': ['==', 'type', 'factory'], + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'factory', + 'icon-size': 0.3 + } + }); } } } @@ -270,14 +382,22 @@ export const swapLayersBack = (map: mapboxgl.Map) =>{ if (map.getLayer('points') === undefined) { map.setLayoutProperty('selectedPoints', 'visibility', 'visible'); + map.setLayoutProperty('alarmedPoints', 'visibility', 'visible'); + map.removeLayer('point-building'); map.removeLayer('point-lamps'); map.removeLayer('point-data-center'); + map.removeLayer('point-factory'); map.removeLayer('point-remaining'); map.removeLayer('select-point-data-center'); map.removeLayer('select-point-buildings'); map.removeLayer('select-point-lamps'); + map.removeLayer('select-point-factory'); + map.removeLayer('point-building-alarm'); + map.removeLayer('point-lamps-alarm'); + map.removeLayer('point-data-center-alarm'); + map.removeLayer('point-factory-alarm'); |