From 4bd84bebdaa0c2d82050fbedd1fa8260eb62146d Mon Sep 17 00:00:00 2001 From: Aijana Schumann Date: Thu, 27 Aug 2020 09:01:53 +0200 Subject: Add link calculation app Add link calculation app to odlux Issue-ID: CCSDK-2562 Signed-off-by: Aijana Schumann Change-Id: Ifc0a5b2a8bb974dfd85d70a9f05990b1f11925a3 Signed-off-by: Aijana Schumann --- sdnr/wt/odlux/framework/pom.xml | 2 +- .../src/components/material-table/index.tsx | 6 +- .../src/components/material-table/tableFilter.tsx | 6 +- .../src/components/material-ui/listItemLink.tsx | 36 +- .../framework/src/components/navigationMenu.tsx | 5 + .../wt/odlux/framework/src/components/titleBar.tsx | 4 +- .../framework/src/services/notificationService.ts | 386 ++++++++++----------- sdnr/wt/odlux/framework/src/views/about.tsx | 16 +- sdnr/wt/odlux/framework/src/views/login.tsx | 1 + sdnr/wt/odlux/framework/webpack.config.js | 10 +- 10 files changed, 249 insertions(+), 223 deletions(-) (limited to 'sdnr/wt/odlux/framework') diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml index db42ef1ac..a7c81ebb1 100644 --- a/sdnr/wt/odlux/framework/pom.xml +++ b/sdnr/wt/odlux/framework/pom.xml @@ -46,7 +46,7 @@ ${maven.build.timestamp} ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version}) - 57.3e1d5cf(20/08/11) + 62.ad364be(20/08/21) ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version} diff --git a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx index 3dfbe0b91..c5be81914 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx @@ -234,7 +234,7 @@ class MaterialTableComponent extends React.Component extends React.Component - + None - {col.labels ? col.labels["true"] : "true"} - {col.labels ? col.labels["false"] : "false"} + {col.labels ? col.labels["true"] : "true"} + {col.labels ? col.labels["false"] : "false"} : } diff --git a/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx b/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx index 1a7e58f77..23bad66ea 100644 --- a/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx @@ -1,20 +1,20 @@ -/** - * ============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========================================================================== - */ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ import * as React from 'react'; import { NavLink, Link, Route } from 'react-router-dom'; @@ -50,7 +50,7 @@ export const ListItemLink = withStyles(styles)((props: IListItemLinkProps) => { : null } { typeof Primary === 'string' - ? + ? : } diff --git a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx index 620abd708..790677ae3 100644 --- a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx +++ b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx @@ -120,6 +120,11 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di } }) + React.useEffect(()=>{ + // trigger a resize if menu changed in case elements have to re-arrange + window.dispatchEvent(new Event('menu-resized')); + }, [isOpen]) + return ( Notifications | : Notifications |) - : Notifications N/A |; + Notifications | : Notifications |) + : Notifications N/A |; // add notificationInfo element before help diff --git a/sdnr/wt/odlux/framework/src/services/notificationService.ts b/sdnr/wt/odlux/framework/src/services/notificationService.ts index c90da0946..4bcc05cc3 100644 --- a/sdnr/wt/odlux/framework/src/services/notificationService.ts +++ b/sdnr/wt/odlux/framework/src/services/notificationService.ts @@ -1,193 +1,193 @@ -/** - * ============LICENSE_START======================================================================== - * ONAP : ccsdk feature sdnr wt odlux - * ================================================================================================= - * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. - * ================================================================================================= - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * ============LICENSE_END========================================================================== - */ -import * as X2JS from 'x2js'; -import { ApplicationStore } from '../store/applicationStore'; -import { SetWebsocketAction } from '../actions/websocketAction'; - -const socketUrl = [location.protocol === 'https:' ? 'wss://' : 'ws://', 'admin', ':', 'admin', '@', location.hostname, ':', location.port, '/websocket'].join(''); -const subscriptions: { [scope: string]: SubscriptionCallback[] } = {}; -let socketReady: Promise; -let userLoggedOut = false; -let wasWebsocketConnectionEstablished: undefined | boolean; -let applicationStore: ApplicationStore | null; - - -export interface IFormatedMessage { - notifType: string | null; - time: string; -} - -export type SubscriptionCallback = (msg: TMessage) => void; - -function formatData(event: MessageEvent): IFormatedMessage | undefined { - - var x2js = new X2JS(); - var jsonObj: { [key: string]: IFormatedMessage } = x2js.xml2js(event.data); - if (jsonObj && typeof (jsonObj) === 'object') { - - const notifType = Object.keys(jsonObj)[0]; - const formated = jsonObj[notifType]; - formated.notifType = notifType; - formated.time = new Date().toISOString(); - return formated; - } - return undefined; - -} - -export function subscribe(scope: string | string[], callback: SubscriptionCallback): boolean { - const scopes = scope instanceof Array ? scope : [scope]; - - // send all new scopes to subscribe - const newScopesToSubscribe: string[] = scopes.reduce((acc: string[], cur: string) => { - const currentCallbacks = subscriptions[cur]; - if (currentCallbacks) { - if (!currentCallbacks.some(c => c === callback)) { - currentCallbacks.push(callback); - } - } else { - subscriptions[cur] = [callback]; - acc.push(cur); - } - return acc; - }, []); - - if (newScopesToSubscribe.length === 0) { - return true; - } - - return true; -} - - -export function unsubscribe(scope: string | string[], callback: SubscriptionCallback): Promise { - return socketReady.then((notificationSocket) => { - const scopes = scope instanceof Array ? scope : [scope]; - scopes.forEach(s => { - const callbacks = subscriptions[s]; - const index = callbacks && callbacks.indexOf(callback); - if (index > -1) { - callbacks.splice(index, 1); - } - if (callbacks.length === 0) { - subscriptions[s] === undefined; - } - }); - - // send a subscription to all active scopes - const scopesToSubscribe = Object.keys(subscriptions); - if (notificationSocket.readyState === notificationSocket.OPEN) { - const data = { - 'data': 'scopes', - 'scopes': scopesToSubscribe - }; - notificationSocket.send(JSON.stringify(data)); - return true; - } - return false; - }); -} - -export const startNotificationService = (store: ApplicationStore) => { - applicationStore = store; -} - -const connect = (): Promise => { - return new Promise((resolve, reject) => { - const notificationSocket = new WebSocket(socketUrl); - - notificationSocket.onmessage = (event) => { - // process received event - if (typeof event.data === 'string') { - const formated = formatData(event); - if (formated && formated.notifType) { - const callbacks = subscriptions[formated.notifType]; - if (callbacks) { - callbacks.forEach(cb => { - // ensure all callbacks will be called - try { - return cb(formated); - } catch (reason) { - console.error(reason); - } - }); - } - } - } - }; - - notificationSocket.onerror = function (error) { - console.log("Socket error:"); - console.log(error); - reject("Socket error: " + error); - if (applicationStore) { - applicationStore.dispatch(new SetWebsocketAction(false)); - } - }; - - notificationSocket.onopen = function (event) { - if (applicationStore) { - applicationStore.dispatch(new SetWebsocketAction(true)); - } - console.log("Socket connection opened."); - resolve(notificationSocket); - - // send a subscription to all active scopes - const scopesToSubscribe = Object.keys(subscriptions); - if (notificationSocket.readyState === notificationSocket.OPEN) { - const data = { - 'data': 'scopes', - 'scopes': scopesToSubscribe - }; - notificationSocket.send(JSON.stringify(data)); - }; - }; - - notificationSocket.onclose = function (event) { - console.log("socket connection closed"); - if (applicationStore) { - applicationStore.dispatch(new SetWebsocketAction(false)); - } - if (!userLoggedOut) { - socketReady = connect(); - } - }; - }); -} - - - - -export const startWebsocketSession = () => { - socketReady = connect(); - userLoggedOut = false; -} - -export const endWebsocketSession = () => { - if (socketReady) { - socketReady.then(websocket => { - websocket.close(); - userLoggedOut = true; - }); - } - -} - - - - +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * ============LICENSE_END========================================================================== + */ +import * as X2JS from 'x2js'; +import { ApplicationStore } from '../store/applicationStore'; +import { SetWebsocketAction } from '../actions/websocketAction'; + +const socketUrl = [location.protocol === 'https:' ? 'wss://' : 'ws://', 'admin', ':', 'admin', '@', location.hostname, ':', location.port, '/websocket'].join(''); +const subscriptions: { [scope: string]: SubscriptionCallback[] } = {}; +let socketReady: Promise; +let userLoggedOut = false; +let wasWebsocketConnectionEstablished: undefined | boolean; +let applicationStore: ApplicationStore | null; + + +export interface IFormatedMessage { + notifType: string | null; + time: string; +} + +export type SubscriptionCallback = (msg: TMessage) => void; + +function formatData(event: MessageEvent): IFormatedMessage | undefined { + + var x2js = new X2JS(); + var jsonObj: { [key: string]: IFormatedMessage } = x2js.xml2js(event.data); + if (jsonObj && typeof (jsonObj) === 'object') { + + const notifType = Object.keys(jsonObj)[0]; + const formated = jsonObj[notifType]; + formated.notifType = notifType; + formated.time = new Date().toISOString(); + return formated; + } + return undefined; + +} + +export function subscribe(scope: string | string[], callback: SubscriptionCallback): boolean { + const scopes = scope instanceof Array ? scope : [scope]; + + // send all new scopes to subscribe + const newScopesToSubscribe: string[] = scopes.reduce((acc: string[], cur: string) => { + const currentCallbacks = subscriptions[cur]; + if (currentCallbacks) { + if (!currentCallbacks.some(c => c === callback)) { + currentCallbacks.push(callback); + } + } else { + subscriptions[cur] = [callback]; + acc.push(cur); + } + return acc; + }, []); + + if (newScopesToSubscribe.length === 0) { + return true; + } + + return true; +} + + +export function unsubscribe(scope: string | string[], callback: SubscriptionCallback): Promise { + return socketReady.then((notificationSocket) => { + const scopes = scope instanceof Array ? scope : [scope]; + scopes.forEach(s => { + const callbacks = subscriptions[s]; + const index = callbacks && callbacks.indexOf(callback); + if (index > -1) { + callbacks.splice(index, 1); + } + if (callbacks.length === 0) { + subscriptions[s] === undefined; + } + }); + + // send a subscription to all active scopes + const scopesToSubscribe = Object.keys(subscriptions); + if (notificationSocket.readyState === notificationSocket.OPEN) { + const data = { + 'data': 'scopes', + 'scopes': scopesToSubscribe + }; + notificationSocket.send(JSON.stringify(data)); + return true; + } + return false; + }); +} + +export const startNotificationService = (store: ApplicationStore) => { + applicationStore = store; +} + +const connect = (): Promise => { + return new Promise((resolve, reject) => { + const notificationSocket = new WebSocket(socketUrl); + + notificationSocket.onmessage = (event) => { + // process received event + if (typeof event.data === 'string') { + const formated = formatData(event); + if (formated && formated.notifType) { + const callbacks = subscriptions[formated.notifType]; + if (callbacks) { + callbacks.forEach(cb => { + // ensure all callbacks will be called + try { + return cb(formated); + } catch (reason) { + console.error(reason); + } + }); + } + } + } + }; + + notificationSocket.onerror = function (error) { + console.log("Socket error:"); + console.log(error); + reject("Socket error: " + error); + if (applicationStore) { + applicationStore.dispatch(new SetWebsocketAction(false)); + } + }; + + notificationSocket.onopen = function (event) { + if (applicationStore) { + applicationStore.dispatch(new SetWebsocketAction(true)); + } + console.log("Socket connection opened."); + resolve(notificationSocket); + + // send a subscription to all active scopes + const scopesToSubscribe = Object.keys(subscriptions); + if (notificationSocket.readyState === notificationSocket.OPEN) { + const data = { + 'data': 'scopes', + 'scopes': scopesToSubscribe + }; + notificationSocket.send(JSON.stringify(data)); + }; + }; + + notificationSocket.onclose = function (event) { + console.log("socket connection closed"); + if (applicationStore) { + applicationStore.dispatch(new SetWebsocketAction(false)); + } + if (!userLoggedOut) { + socketReady = connect(); + } + }; + }); +} + + + + +export const startWebsocketSession = () => { + socketReady = connect(); + userLoggedOut = false; +} + +export const endWebsocketSession = () => { + if (socketReady) { + socketReady.then(websocket => { + websocket.close(); + userLoggedOut = true; + }); + } + +} + + + + diff --git a/sdnr/wt/odlux/framework/src/views/about.tsx b/sdnr/wt/odlux/framework/src/views/about.tsx index c4a5488e0..f97d6ffb3 100644 --- a/sdnr/wt/odlux/framework/src/views/about.tsx +++ b/sdnr/wt/odlux/framework/src/views/about.tsx @@ -40,11 +40,23 @@ class AboutComponent extends React.Component { this.textarea = React.createRef(); this.loadAboutContent(); } + private getMarkOdluxVersionMarkdownTable(data:{version:string,build:string}|null|undefined):string{ + if(!data) { + return ""; + } + return `| | |\n| --- | --- |\n| Version | ${data.version} |\n| Build timestamp | ${data.build}|` + } private loadAboutContent(): void { - requestRestExt('/about').then((response) => { + const baseUri = window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/")+1); + const p1 = requestRestExt('/about'); + const p2 = requestRestExt<{version:string,build:string}>(`${baseUri}version.json`); + Promise.all([p1,p2]).then((responses) => { + const response = responses[0]; + const response2 = responses[1]; const content = response.status == 200 ? response.data : `${response.status} ${response.message}` || "Server error"; + const content2 = `\n## ODLUX Version Info\n`+(response2.status == 200 ? this.getMarkOdluxVersionMarkdownTable(response2.data) : `${response2.status} ${response2.message}` || "ODLUX Server error"); const loadedSucessfully = response.status == 200 ? true : false; - this.setState({ content: content || null, isContentLoadedSucessfully: loadedSucessfully }); + this.setState({ content: (content + content2) || null, isContentLoadedSucessfully: loadedSucessfully }); }).catch((error) => { this.setState({ content: error }) }) diff --git a/sdnr/wt/odlux/framework/src/views/login.tsx b/sdnr/wt/odlux/framework/src/views/login.tsx index 30b9c85a2..b06cf7631 100644 --- a/sdnr/wt/odlux/framework/src/views/login.tsx +++ b/sdnr/wt/odlux/framework/src/views/login.tsx @@ -142,6 +142,7 @@ class LoginComponent extends React.Component { label="Remember me" />