diff options
author | Aijana Schumann <aijana.schumann@highstreet-technologies.com> | 2021-08-04 11:59:18 +0200 |
---|---|---|
committer | Aijana Schumann <aijana.schumann@highstreet-technologies.com> | 2021-08-04 16:06:05 +0200 |
commit | 437f67407aece6f7aed8e989638b0d64075f0c0a (patch) | |
tree | 53e9e336cd8544edf8a06c889e33f5b9c98fe083 /sdnr/wt/odlux/apps/networkMapApp | |
parent | 1c4995eb199437e9c86336efff9972f2049e1532 (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')
31 files changed, 665 insertions, 284 deletions
diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/README.md b/sdnr/wt/odlux/apps/networkMapApp/icons/README.md index 85c75c4e9..b26fbc29b 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, lamp.png and customize.png with all variations (different colors) +datacenter.png and lamp.png Taken from MS Word diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts index 9f956f813..bf398f5a4 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const apartment: string; export default apartment;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/customize.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/customize.png.d.ts index 16327f5af..7bcffb2ca 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/customize.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/customize.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const customize: string; export default customize;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts index dc7019766..a58a9f5af 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const datacenter: string; export default datacenter;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts index 74836be8d..33f3061e2 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const datacenterred: string; export default datacenterred;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts index e341c5f95..b5c4f19d9 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const factory: string; export default factory;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts index 317ff7e85..1fac0a943 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const factoryRed: string; export default factoryRed;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts index eeedc7fcd..9634b1275 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const lamp: string; export default lamp;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts index b053df0b8..12a8f91cb 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts @@ -1,20 +1,2 @@ -/** - * ============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========================================================================== - */ - declare const lampred: string; export default lampred;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/package.json b/sdnr/wt/odlux/apps/networkMapApp/package.json index cde312ce3..160537045 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/package.json +++ b/sdnr/wt/odlux/apps/networkMapApp/package.json @@ -30,8 +30,8 @@ "@types/react": "17.0.3", "@types/react-dom": "17.0.2", "@types/react-router-dom": "5.1.7", - "@material-ui/core": "4.11.0", - "@material-ui/icons": "4.9.1", + "@material-ui/core": "4.11.4", + "@material-ui/icons": "4.11.2", "@types/classnames": "2.2.6", "@types/flux": "3.1.8", "@types/jquery": "3.3.10", diff --git a/sdnr/wt/odlux/apps/networkMapApp/pom.xml b/sdnr/wt/odlux/apps/networkMapApp/pom.xml index 8284149e0..76da05dc1 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/pom.xml +++ b/sdnr/wt/odlux/apps/networkMapApp/pom.xml @@ -140,8 +140,8 @@ <!-- optional: default phase is "generate-resources" --> <phase>initialize</phase> <configuration> - <nodeVersion>v10.16.3</nodeVersion> - <yarnVersion>v1.19.0</yarnVersion> + <nodeVersion>v12.13.0</nodeVersion> + <yarnVersion>v1.22.10</yarnVersion> </configuration> </execution> <execution> diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts index 34cf10915..a9bea4fc2 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts @@ -25,6 +25,7 @@ import { link } from '../model/link'; import { HistoryEntry } from "../model/historyEntry"; import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; import { Dispatch } from '../../../../framework/src/flux/store'; +import { SITEDOC_URL } from '../config'; export class SelectSiteAction extends Action { constructor(public site: Site){ @@ -80,6 +81,12 @@ export class InitializeLoadedDevicesAction extends Action{ } } +export class IsSitedocReachableAction extends Action{ + constructor(public isReachable: boolean){ + super(); + } +} + let running=false; export const UpdateDetailsView = (nodeId: string) =>(dispatcher: Dispatch, getState: () => IApplicationStoreState) =>{ @@ -137,4 +144,18 @@ running=true; dispatcher(new IsBusyCheckingDeviceListAction(false)); }); +} + +export const checkSitedockReachablity = () => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) =>{ + console.log("searching for sitedoc server...") + requestRest<any>(SITEDOC_URL+'/app/versioninfo').then(response =>{ + console.log(response); + if(response){ + + dispatcher(new IsSitedocReachableAction(true)); + + }else{ + dispatcher(new IsSitedocReachableAction(false)); + } + }) }
\ 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 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."> diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/config.ts b/sdnr/wt/odlux/apps/networkMapApp/src/config.ts index 633bd3732..bdb7d15e6 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/config.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/config.ts @@ -17,6 +17,7 @@ */ export const URL_API="/topology/network" +export const SITEDOC_URL="/sitedoc"; export const URL_TILE_API = '/tiles'; // http://tile.openstreetmap.org can be used for local testing, never commit with tile url changed! /tiles diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts index 67e10e629..8a7fc6ada 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts @@ -20,13 +20,14 @@ import { IActionHandler } from '../../../../framework/src/flux/action'; import { link } from "../model/link"; import { Site, Device } from "../model/site"; import { HistoryEntry } from "../model/historyEntry"; -import { SelectSiteAction, SelectLinkAction, AddToHistoryAction, ClearHistoryAction, IsBusyCheckingDeviceListAction, FinishedLoadingDeviceListAction, ClearLoadedDevicesAction, ClearDetailsAction, InitializeLoadedDevicesAction } from '../actions/detailsAction'; +import { SelectSiteAction, SelectLinkAction, AddToHistoryAction, ClearHistoryAction, IsBusyCheckingDeviceListAction, FinishedLoadingDeviceListAction, ClearLoadedDevicesAction, ClearDetailsAction, InitializeLoadedDevicesAction, IsSitedocReachableAction } from '../actions/detailsAction'; export type DetailsStoreState={ data: Site | link | null, history: HistoryEntry[], isBusyCheckingDeviceList: boolean, - checkedDevices: Device[] + checkedDevices: Device[], + isSitedocReachable: boolean } @@ -34,7 +35,8 @@ const initialState: DetailsStoreState = { data: null, history:[], isBusyCheckingDeviceList: false, - checkedDevices: [] + checkedDevices: [], + isSitedocReachable: false } export const DetailsReducer:IActionHandler<DetailsStoreState>=(state = initialState, action)=>{ @@ -63,6 +65,8 @@ export const DetailsReducer:IActionHandler<DetailsStoreState>=(state = initialSt }else if(action instanceof InitializeLoadedDevicesAction){ state = Object.assign({}, state, {checkedDevices: action.devices}); + }else if(action instanceof IsSitedocReachableAction){ + state = Object.assign({}, state, {isSitedocReachable: action.isReachable}); } diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/index.html b/sdnr/wt/odlux/apps/networkMapApp/src/index.html index e64c08c1e..f70571152 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/index.html +++ b/sdnr/wt/odlux/apps/networkMapApp/src/index.html @@ -13,15 +13,14 @@ <div id="app"></div> <script type="text/javascript" src="./require.js"></script> <script type="text/javascript" src="./config.js"></script> - <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.css' rel='stylesheet' /> <script> // run the application require(["app","connectApp","faultApp", "networkMapApp", "configurationApp", "linkCalculationApp"], function (app, connectApp, faultApp, networkMapApp, configurationApp, linkCalculationApp) { connectApp.register(); - //faultApp.register(); + faultApp.register(); //configurationApp.register(); - //linkCalculationApp.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 d992c66db..c1612098d 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts @@ -16,6 +16,12 @@ * ============LICENSE_END========================================================================== */ +type Antenna = { + name:string, + waveguideLossIndB: number, + gain: number +} + export type link = {id: string, name: string, length: number, @@ -25,6 +31,6 @@ export type link = {id: string, siteB: string, azimuthA: number | null, azimuthB: number | null, - locationA: { lon: number, lat: number, amsl:number | null, antennaHeight: number | null }, - locationB: { lon: number, lat: number, amsl:number | null, antennaHeight: number | null }, + locationA: { lon: number, lat: number, amsl:number | null, antennaHeight: number | null, antenna: Antenna |null }, + locationB: { lon: number, lat: number, amsl:number | null, antennaHeight: number | null, antenna: Antenna |null }, };
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts index b9102e871..13a7361f6 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts @@ -28,7 +28,8 @@ export type Site = { operator: string, location:{lon: number, lat: number}, devices: Device[], - links: link[] + links: link[], + furtherInformation:string } export type Address={ diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/stadokOrder.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/stadokOrder.ts new file mode 100644 index 000000000..1aad3aa97 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/stadokOrder.ts @@ -0,0 +1,56 @@ +/** + * ============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========================================================================== + */ + +export type StadokOrder = { + date: Date, + assignedUser: string, + state: string, //todo: type restrict + tasks: Task[], + + +}; + +export class OrderToDisplay { + + static parse = (stadokOrder: StadokOrder) =>{ + let order = new OrderToDisplay(); + order.assignedUser=stadokOrder.assignedUser; + order.state=stadokOrder.state; + + const firstOpenTask = stadokOrder.tasks.find(task => !task.status); + + if(firstOpenTask){ + order.currentTask=firstOpenTask.description; + }else{ + order.currentTask="No task description available"; + } + + return order; + } + + state: string; + assignedUser: string; + currentTask: string; + +}; + +type Task = { + type: string, + description: string, + status: boolean +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/stadokSite.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/stadokSite.ts new file mode 100644 index 000000000..ed0ca397f --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/stadokSite.ts @@ -0,0 +1,54 @@ +/** + * ============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 { Address } from "./site"; + +type StadokSite = { + + siteId: string; + createdBy: Contact; + updatedOn: Date; + location: { lat: number, lon: number }, + address: Address; + contacts: { manager: Contact, owner: Contact }; + safteyNotices: string[]; + images: string[]; + type: string; + devices: Device[]; + logs: Log[]; + +}; + +type Contact = { + firstName: string; + lastName: string; + email: string; + telephoneNumber: string; +}; +type Log = { + date: Date, //string? + person: string; + entry: string; +}; + +type Device = { + "device": string, + "antenna": string +}; + +export default StadokSite;
\ 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 e93368524..24a46994a 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx +++ b/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx @@ -27,7 +27,7 @@ import { networkmapRootHandler } from './handlers/rootReducer'; import MainView from "./App"; import { subscribe, IFormatedMessage } from "../../../framework/src/services/notificationService"; import applicationApi from "../../../framework/src/services/applicationApi"; -import { UpdateDetailsView } from "./actions/detailsAction"; +import { checkSitedockReachablity, IsSitedocReachableAction, UpdateDetailsView } from "./actions/detailsAction"; import { findSiteToAlarm } from "./actions/mapActions"; import { URL_BASEPATH } from "./config"; import { Redirect, Route, RouteComponentProps, Switch, withRouter } from "react-router-dom"; @@ -40,7 +40,8 @@ const mapProps = (state: IApplicationStoreState) => ({ }); const mapDisp = (dispatcher: IDispatcher) => ({ - getSettings: () => dispatcher.dispatch(getSettings()) + getSettings: () => dispatcher.dispatch(getSettings()), + tryReachSitedoc: () => dispatcher.dispatch(checkSitedockReachablity()) }); @@ -51,6 +52,8 @@ const NetworkRouterApp = withRouter(connect(mapProps, mapDisp)((props: RouteComp (async function waitFor() { await props.getSettings(); })(); + + props.tryReachSitedoc(); }, []); diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts index 6dfd7983a..7ce4bfa92 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts +++ b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts @@ -141,6 +141,8 @@ class MapLayerService { public addBaseLayers = (map: mapboxgl.Map, themesettings?: ThemeElement) => { const theme = !themesettings ? this.pickTheme() : themesettings; + console.log("user selected theme: " + this.selectedTheme) + console.log("found theme:" + theme); this.addCommonLayers(map); diff --git a/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js b/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js index 3e80514f5..5684040b7 100644 --- a/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js +++ b/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js @@ -67,6 +67,10 @@ module.exports = (env) => { name: './icons/[hash].[ext]' } }] + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], }] }, @@ -168,8 +172,15 @@ module.exports = (env) => { target: "http://localhost:3002", secure: false }, + "/sitedoc/": { + target: "http://localhost:3002", + secure: false, + pathRewrite(pathname) { + return pathname.replace(/^\/sitedoc/, '/topology/stadok') + } + }, "/tiles/": { - target: "http://www.openstreetmap.org", + target: "http://tile.openstreetmap.org", secure: false }, "/help/": { |