update odlux for notification change

update due new notification protocol

Issue-ID: CCSDK-3253
Signed-off-by: Michael DÜrre <michael.duerre@highstreet-technologies.com>
Change-Id: Iad65459fdc18603cd1ddbd97bb2211308744bd8b
diff --git a/sdnr/wt/odlux/framework/package.json b/sdnr/wt/odlux/framework/package.json
index 3ecd34c..345fc8b 100644
--- a/sdnr/wt/odlux/framework/package.json
+++ b/sdnr/wt/odlux/framework/package.json
@@ -25,18 +25,18 @@
   "license": "Apache-2.0",

   "peerDependencies": {

     "@types/node": "11.11.6",

-    "@types/react": "16.9.19",

-    "@types/react-dom": "16.9.5",

-    "@types/react-router-dom": "4.3.1",

+    "@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",

     "@types/classnames": "2.2.6",

     "@types/flux": "3.1.8",

     "@types/jquery": "3.3.10",

     "jquery": "3.3.1",

-    "react": "16.12.0",

-    "react-dom": "16.12.0",

-    "react-router-dom": "4.3.1",

+    "react": "17.0.1",

+    "react-dom": "17.0.1",

+    "react-router-dom": "5.2.0",

     "@fortawesome/react-fontawesome": "0.1.3",

     "@fortawesome/fontawesome-svg-core": "1.2.12",

     "@fortawesome/free-solid-svg-icons": "5.6.3",

diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml
index 3f9ecbe..9d648b5 100644
--- a/sdnr/wt/odlux/framework/pom.xml
+++ b/sdnr/wt/odlux/framework/pom.xml
@@ -46,7 +46,7 @@
     <properties>
         <buildtime>${maven.build.timestamp}</buildtime>
         <distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion>
-        <buildno>90.49cc396(21/02/17)</buildno>
+        <buildno>96.078ad12(21/03/25)</buildno>
         <odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version>
     </properties>
 
@@ -126,7 +126,7 @@
                         </goals>
                         <phase>initialize</phase>
                         <configuration>
-                            <arguments>add lerna@3.13.1 -W --exact</arguments>
+                            <arguments>add lerna@3.22.1 -W --exact</arguments>
                             <installDirectory>${project.basedir}</installDirectory>
                             <workingDirectory>${project.basedir}/../</workingDirectory>
                         </configuration>
diff --git a/sdnr/wt/odlux/framework/src/app.tsx b/sdnr/wt/odlux/framework/src/app.tsx
index 23ae2fb..2d913be 100644
--- a/sdnr/wt/odlux/framework/src/app.tsx
+++ b/sdnr/wt/odlux/framework/src/app.tsx
@@ -68,6 +68,10 @@
   const initialToken = localStorage.getItem("userToken");

   const applicationStore = applicationStoreCreator();

 

+  if (initialToken) {

+    applicationStore.dispatch(new UpdateUser(User.fromString(initialToken) || undefined));

+  }

+

   window.onerror = function (msg: string, url: string, line: number, col: number, error: Error) {

     // Note that col & error are new to the HTML 5 spec and may not be

     // supported in every browser.  It worked for me in Chrome.

@@ -98,9 +102,7 @@
 

   ReactDOM.render(<App />, document.getElementById('app'));

 

-  if (initialToken) {

-    applicationStore.dispatch(new UpdateUser(User.fromString(initialToken) || undefined));

-  }

+  

 

 };

 

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 7d4633b..c74fd1a 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
@@ -32,13 +32,14 @@
 import { EnhancedTableFilter } from './tableFilter';
 
 import { ColumnModel, ColumnType } from './columnModel';
-import { Omit, Menu } from '@material-ui/core';
+import { Omit, Menu, makeStyles } from '@material-ui/core';
 
 import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
 
 import { DividerTypeMap } from '@material-ui/core/Divider';
 import { MenuItemProps } from '@material-ui/core/MenuItem';
 import { flexbox } from '@material-ui/system';
+import { RowDisabled } from './utilities';
 export { ColumnModel, ColumnType } from './columnModel';
 
 type propType = string | number | null | undefined | (string | number)[];
@@ -103,6 +104,34 @@
   }
 });
 
+const useTableRowExtStyles = makeStyles((theme: Theme) => createStyles({
+  disabled: {
+    color: "rgba(180, 180, 180, 0.7)",
+  },
+}));
+
+type GetStatelessComponentProps<T> = T extends (props: infer P & { children?: React.ReactNode }) => any ? P : any;
+type TableRowExtProps = GetStatelessComponentProps<typeof TableRow> & { disabled: boolean };
+const TableRowExt : React.FC<TableRowExtProps> = (props) => {
+  const [disabled, setDisabled] = React.useState(true);
+  const classes = useTableRowExtStyles();
+  
+  const onMouseDown = (ev: React.MouseEvent<HTMLElement>) => {
+      if (ev.button ===1){
+        setDisabled(!disabled);  
+        ev.preventDefault();
+        ev.stopPropagation();
+      } else if (props.disabled && disabled) {
+        ev.preventDefault();
+        ev.stopPropagation();
+      }
+  }; 
+
+  return (   
+    <TableRow {...{...props,  color: props.disabled && disabled ? '#a0a0a0' : undefined , className: props.disabled && disabled ? classes.disabled : '', onMouseDown, onContextMenu: props.disabled && disabled ? onMouseDown : props.onContextMenu } }  /> 
+  );
+};
+
 export type MaterialTableComponentState<TData = {}> = {
   order: 'asc' | 'desc';
   orderBy: string | null;
@@ -130,7 +159,7 @@
   enableSelection?: boolean;
   disableSorting?: boolean;
   disableFilter?: boolean;
-  customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[];
+  customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void, disabled?: boolean }[];
   onHandleClick?(event: React.MouseEvent<HTMLTableRowElement>, rowData: TData): void;
   createContextMenu?: (row: TData) => React.ReactElement<MenuItemProps | DividerTypeMap<{}, "hr">, React.ComponentType<MenuItemProps | DividerTypeMap<{}, "hr">>>[];
 };
@@ -222,12 +251,12 @@
             <TableBody>
               {showFilter && <EnhancedTableFilter columns={columns} filter={filter} onFilterChanged={this.onFilterChanged} enableSelection={this.props.enableSelection} /> || null}
               {rows // may need ordering here
-                .map((entry: TData & { [key: string]: any }, index) => {
+                .map((entry: TData & { [RowDisabled]?: boolean, [kex: string]: any }, index) => {
                   const entryId = getId(entry);
                   const isSelected = this.isSelected(entryId);
                   const contextMenu = (this.props.createContextMenu && this.state.contextMenuInfo.index === index && this.props.createContextMenu(entry)) || null;
                   return (
-                    <TableRow
+                    <TableRowExt
                       hover
                       onClick={event => {
                         if (this.props.createContextMenu) {
@@ -252,9 +281,10 @@
                       tabIndex={-1}
                       key={entryId}
                       selected={isSelected}
+                      disabled={entry[RowDisabled] || false}
                     >
                       {this.props.enableSelection
-                        ? <TableCell padding="checkbox" style={{ width: "50px" }}>
+                        ? <TableCell padding="checkbox" style={{ width: "50px", color:  entry[RowDisabled] || false ? "inherit" : undefined } }>
                           <Checkbox checked={isSelected} />
                         </TableCell>
                         : null
@@ -264,7 +294,7 @@
                           col => {
                             const style = col.width ? { width: col.width } : {};
                             return (
-                              <TableCell aria-label={col.title? col.title.toLowerCase().replace(/\s/g, "-") : col.property.toLowerCase().replace(/\s/g, "-")} key={col.property} align={col.type === ColumnType.numeric && !col.align ? "right" : col.align} style={style}>
+                              <TableCell style={ entry[RowDisabled] || false ? { ...style, color: "inherit"  } : style } aria-label={col.title? col.title.toLowerCase().replace(/\s/g, "-") : col.property.toLowerCase().replace(/\s/g, "-")} key={col.property} align={col.type === ColumnType.numeric && !col.align ? "right" : col.align} >
                                 {col.type === ColumnType.custom && col.customControl
                                   ? <col.customControl className={col.className} style={col.style} rowData={entry} />
                                   : col.type === ColumnType.boolean
@@ -280,7 +310,7 @@
                         anchorPosition={this.state.contextMenuInfo.mouseY != null && this.state.contextMenuInfo.mouseX != null ? { top: this.state.contextMenuInfo.mouseY, left: this.state.contextMenuInfo.mouseX } : undefined}>
                         {contextMenu}
                       </Menu> || null}
-                    </TableRow>
+                    </TableRowExt>
                   );
                 })}
               {emptyRows > 0 && (
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx
index 3b2f8e0..f7de0a0 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx
@@ -67,7 +67,7 @@
   numSelected: number | null;
   title?: string;
   tableId?: string;
-  customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[];
+  customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void, disabled?: boolean }[];
   onToggleFilter: () => void;
   onExportToCsv: () => void;
 }
@@ -110,7 +110,7 @@
           {this.props.customActionButtons
             ? this.props.customActionButtons.map((action, ind) => (
               <Tooltip key={`custom-action-${ind}`} title={action.tooltip || ''}>
-                <IconButton aria-label={buttonPrefix + `custom-action-${ind}`} onClick={() => action.onClick()}>
+                <IconButton disabled={action.disabled} aria-label={buttonPrefix + `custom-action-${ind}`} onClick={() => action.onClick()}>
                   <action.icon />
                 </IconButton>
               </Tooltip>
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
index 07ffe2f..544e14e 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
+++ b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
@@ -21,12 +21,14 @@
 import { AddErrorInfoAction } from '../../actions/errorActions';
 import { IApplicationStoreState } from '../../store/applicationStore';
 
+export const RowDisabled = Symbol("RowDisabled");
 import { DataCallback } from ".";
+
 export interface IExternalTableState<TData> {
   order: 'asc' | 'desc';
   orderBy: string | null;
   selected: any[] | null;
-  rows: TData[];
+  rows: (TData & { [RowDisabled]?: boolean })[];
   total: number;
   page: number;
   rowsPerPage: number;
@@ -36,8 +38,31 @@
   preFilter: { [property: string]: string };
 }
 
+export type ExternalMethodes<TData> = {
+  reloadAction: (dispatch: Dispatch, getAppState: () => IApplicationStoreState) => Promise<void | AddErrorInfoAction>;
+  createActions: (dispatch: Dispatch, skipRefresh?: boolean) => {
+    onRefresh: () => void;
+    onHandleRequestSort: (orderBy: string) => void;
+    onHandleExplicitRequestSort: (property: string, sortOrder: "asc" | "desc") => void;
+    onToggleFilter: (refresh?: boolean | undefined) => void;
+    onFilterChanged: (property: string, filterTerm: string) => void;
+    onHandleChangePage: (page: number) => void;
+    onHandleChangeRowsPerPage: (rowsPerPage: number | null) => void;
+ };
+ createPreActions: (dispatch: Dispatch, skipRefresh?: boolean) => {
+  onPreFilterChanged: (preFilter: {
+      [key: string]: string;
+  }) => void;
+ };
+ createProperties: (state: IApplicationStoreState) => IExternalTableState<TData>;
+ actionHandler: IActionHandler<IExternalTableState<TData>, Action>;
+}
+
+
 /** Create an actionHandler and actions for external table states. */
-export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>) {
+export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>) : ExternalMethodes<TData> ;
+export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>, disableRow: (data: TData) => boolean) : ExternalMethodes<TData>;
+export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>, disableRow?: (data: TData) => boolean) : ExternalMethodes<TData> {
 
   //#region Actions
   abstract class TableAction extends Action { }
@@ -131,7 +156,9 @@
       state = {
         ...state,
         loading: false,
-        rows: action.result.rows,
+        rows: disableRow 
+          ? action.result.rows.map((row: TData) => ({...row, [RowDisabled]: disableRow(row) })) 
+          : action.result.rows,
         total: action.result.total,
         page: action.result.page,
       }
@@ -191,7 +218,7 @@
     dispatch(new RefreshAction());
     const ownState = selectState(getAppState());
     const filter = { ...ownState.preFilter, ...(ownState.showFilter && ownState.filter || {}) };
-    Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter)).then(result => {
+    return Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter)).then(result => {
 
       if (ownState.page > 0 && ownState.rowsPerPage * ownState.page > result.total) { //if result is smaller than the currently shown page, new search and repaginate
 
@@ -207,30 +234,7 @@
       }
 
 
-    }).catch(error => new AddErrorInfoAction(error));
-  };
-
-  const reloadActionAsync = async (dispatch: Dispatch, getAppState: () => IApplicationStoreState) => {
-    dispatch(new RefreshAction());
-    const ownState = selectState(getAppState());
-    const filter = { ...ownState.preFilter, ...(ownState.showFilter && ownState.filter || {}) };
-
-    try {
-      const result = await Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter));
-
-
-      if (ownState.page > 0 && ownState.rowsPerPage * ownState.page > result.total) { //if result is smaller than the currently shown page, new search and repaginate
-
-        let newPage = Math.floor(result.total / ownState.rowsPerPage);
-
-        const repaginationResult = await Promise.resolve(callback(newPage, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter));
-        dispatch(new SetResultAction(repaginationResult));
-      } else {
-        dispatch(new SetResultAction(result));
-      }
-    } catch (error) {
-      new AddErrorInfoAction(error);
-    }
+    }).catch(error => dispatch(new AddErrorInfoAction(error)));
   };
 
   const createPreActions = (dispatch: Dispatch, skipRefresh: boolean = false) => {
@@ -303,6 +307,6 @@
     createProperties: createProperties,
     createPreActions: createPreActions,
     actionHandler: externalTableStateActionHandler,
-    reloadActionAsync: reloadActionAsync,
   }
-}
\ No newline at end of file
+}
+
diff --git a/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts b/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts
index b5c1ee7..06df670 100644
--- a/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts
+++ b/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts
@@ -58,7 +58,7 @@
 
 export const configureApplication = (config: ApplicationConfig) => {
   applicationStateInit.authentication = config.authentication === "oauth" ? "oauth" : "basic";
-  applicationStateInit.enablePolicy = config.authentication ? true : false;
+  applicationStateInit.enablePolicy = config.enablePolicy ? true : false;
 }
 
 export const applicationStateHandler: IActionHandler<IApplicationState> = (state = applicationStateInit, action) => {
diff --git a/sdnr/wt/odlux/framework/src/services/notificationService.ts b/sdnr/wt/odlux/framework/src/services/notificationService.ts
index 30091b5..5625b1f 100644
--- a/sdnr/wt/odlux/framework/src/services/notificationService.ts
+++ b/sdnr/wt/odlux/framework/src/services/notificationService.ts
@@ -15,7 +15,6 @@
  * the License.
  * ============LICENSE_END==========================================================================
  */
-import * as X2JS from 'x2js';
 import { ApplicationStore } from '../store/applicationStore';
 import { SetWebsocketAction } from '../actions/websocketAction';
 
@@ -26,83 +25,97 @@
 let wasWebsocketConnectionEstablished: undefined | boolean;
 let applicationStore: ApplicationStore | null;
 
-
 export interface IFormatedMessage {
-  notifType: string | null;
-  time: string;
+    "event-time": string,
+    "data": {
+        "counter": number,
+        "attribute-name": string,
+        "time-stamp": string,
+        "object-id-ref": string,
+        "new-value": string
+    },
+    "node-id": string,
+    "type": {
+        "namespace": string,
+        "revision": string,
+        "type": string
+    }
 }
 
 export type SubscriptionCallback<TMessage extends IFormatedMessage = IFormatedMessage> = (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;
-
+function setCurrentSubscriptions(notificationSocket: WebSocket) {
+  const scopesToSubscribe = Object.keys(subscriptions);
+  if (notificationSocket.readyState === notificationSocket.OPEN) {
+    const data = {
+      'data': 'scopes',
+      'scopes':[{
+        "schema":{
+            "namespace":"*",
+            "revision":"*",
+            "notification": scopesToSubscribe 
+         }
+      }]
+    };
+    notificationSocket.send(JSON.stringify(data));
+    return true;
+  };
+  return false;
 }
 
-export function subscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): boolean {
+function addScope<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>) {
   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);
+    // 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);
       }
-    } else {
-      subscriptions[cur] = [callback];
-      acc.push(cur);
-    }
-    return acc;
-  }, []);
+      return acc;
+    }, []);
 
-  if (newScopesToSubscribe.length === 0) {
-    return true;
-  }
-
-  return true;
-}
-
-
-export function unsubscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {
-  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));
+    if (newScopesToSubscribe.length === 0) {
       return true;
     }
     return false;
+}
+
+function removeScope<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>) {
+  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;
+    }
   });
 }
 
+export function subscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {
+  addScope(scope, callback)
+  return socketReady && socketReady.then((notificationSocket) => {
+    // send a subscription to all active scopes
+    return setCurrentSubscriptions(notificationSocket);
+  }) || true;
+}
+
+export function unsubscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {
+  removeScope(scope, callback);
+  return socketReady && socketReady.then((notificationSocket) => {
+    // send a subscription to all active scopes
+    return setCurrentSubscriptions(notificationSocket);
+  }) || true;
+}
+
 export const startNotificationService = (store: ApplicationStore) => {
   applicationStore = store;
 }
@@ -111,24 +124,24 @@
   return new Promise((resolve, reject) => {
     const notificationSocket = new WebSocket(socketUrl);
 
-    notificationSocket.onmessage = (event) => {
+    notificationSocket.onmessage = (event: MessageEvent<string>) => {
       // process received event
-      if (typeof event.data === 'string') {
-        const formated = formatData(event);
-        if (formated && formated.notifType) {
-          const callbacks = subscriptions[formated.notifType];
+      
+        if (event.data && typeof event.data === "string" ) {
+          const msg = JSON.parse(event.data) as IFormatedMessage;
+          const callbacks = msg?.type?.type && subscriptions[msg.type.type];
           if (callbacks) {
             callbacks.forEach(cb => {
               // ensure all callbacks will be called
               try {
-                return cb(formated);
+                return cb(msg);
               } catch (reason) {
                 console.error(reason);
               }
             });
           }
         }
-      }
+       
     };
 
     notificationSocket.onerror = function (error) {
@@ -148,14 +161,7 @@
       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));
-      };
+      setCurrentSubscriptions(notificationSocket);
     };
 
     notificationSocket.onclose = function (event) {
@@ -171,8 +177,6 @@
 }
 
 
-
-
 export const startWebsocketSession = () => {
   socketReady = connect();
   userLoggedOut = false;
diff --git a/sdnr/wt/odlux/framework/src/services/restService.ts b/sdnr/wt/odlux/framework/src/services/restService.ts
index f05c7b8..c7b1224 100644
--- a/sdnr/wt/odlux/framework/src/services/restService.ts
+++ b/sdnr/wt/odlux/framework/src/services/restService.ts
@@ -15,6 +15,8 @@
  * the License.
  * ============LICENSE_END==========================================================================
  */
+
+
 import { ApplicationStore } from "../store/applicationStore";
 import { ReplaceAction } from "../actions/navigationActions";
 
@@ -30,6 +32,46 @@
   return encodeURIComponent(key) + '=' + encodeURIComponent(params[key].toString());
 }).join('&');
 
+const wildcardToRegexp = (pattern: string) =>  {
+  return new RegExp('^' + pattern.split(/\*\*/).map((p) => p.split(/\*+/).map((i) => i.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')).join('^[/]')).join('.*') + '$');
+};
+
+export const getAccessPolicyByUrl = (url: string) => {
+  const result = {
+    GET : false,
+    POST: false,
+    PUT: false,
+    PATCH: false,
+    DELETE: false,
+  };
+  
+  if (!applicationStore) return result;
+
+  const { state: { framework: { applicationState: { enablePolicy }, authenticationState: { policies }}} } = applicationStore!;
+  
+  result.GET = true;
+  result.POST = true;
+  result.PUT = true;
+  result.PATCH = true;
+  result.DELETE = true; 
+
+  if (!enablePolicy || !policies || policies.length === 0) return result;
+
+  policies.forEach(p => {
+    const re = wildcardToRegexp(p.path);
+    if (re.test(url)) {
+      result.GET = p.methods.get != null ? p.methods.get : result.GET ;
+      result.POST = p.methods.post != null ? p.methods.post : result.POST ;
+      result.PUT = p.methods.put != null ? p.methods.put : result.PUT ;
+      result.PATCH = p.methods.patch != null ? p.methods.patch : result.PATCH ;
+      result.DELETE = p.methods.delete != null ? p.methods.delete : result.DELETE ;
+    }
+  }); 
+
+  return result;
+
+}
+
 /** Sends a rest request to the given path. 
  * @returns The data, or null it there was any error
  */
diff --git a/sdnr/wt/odlux/framework/src/views/about.tsx b/sdnr/wt/odlux/framework/src/views/about.tsx
index f97d6ff..5d2257a 100644
--- a/sdnr/wt/odlux/framework/src/views/about.tsx
+++ b/sdnr/wt/odlux/framework/src/views/about.tsx
@@ -20,6 +20,7 @@
 import * as hljs from 'highlight.js';
 import { requestRestExt } from '../services/restService';
 import { Button, Typography } from '@material-ui/core';
+import createBreakpoints from '@material-ui/core/styles/createBreakpoints';
 const defaultRenderer = new marked.Renderer();
 defaultRenderer.link = (href, title, text) => (
   `<a target="_blank" rel="noopener noreferrer" href="${href}" title="${title}">${text}</a>`
@@ -30,6 +31,23 @@
   isContentLoadedSucessfully: boolean;
 }
 
+type odluxVersion= {version:string,build:string, framework: string, 
+  applications:{
+    configurationApp: string,
+    connectApp: string,
+    eventLogApp: string,
+    faultApp: string,
+    helpApp: string,
+    inventoryApp: string,
+    linkCalculationApp: string,
+    maintenanceApp: string,
+    mediatorApp: string,
+    networkMapApp: string,
+    permanceHistoryApp: string
+  }};
+
+type topologyVersion = {version: string};
+
 class AboutComponent extends React.Component<any, AboutState> {
   textarea: React.RefObject<HTMLTextAreaElement>;
 
@@ -40,23 +58,58 @@
     this.textarea = React.createRef();
     this.loadAboutContent();
   }
-  private getMarkOdluxVersionMarkdownTable(data:{version:string,build:string}|null|undefined):string{
+
+  private getMarkOdluxVersionMarkdownTable(data:odluxVersion|null|undefined):string{
     if(!data) {
       return "";
+    }else{
+      let applicationVersions= '';
+      if(data.applications){
+
+        applicationVersions = `| Framework | ${data.framework}|\n `+
+        `| ConnectApp | ${data.applications.connectApp}|\n `+
+        `| FaultApp | ${data.applications.faultApp}|\n `+
+        `| MaintenanceApp | ${data.applications.maintenanceApp}|\n `+
+        `| ConfigurationApp | ${data.applications.configurationApp}|\n `+
+        `| PerformanceHistoryApp | ${data.applications.permanceHistoryApp}|\n `+
+        `| InventoryApp | ${data.applications.inventoryApp}|\n `+
+        `| EventLogApp | ${data.applications.eventLogApp}|\n `+
+        `| MediatorApp | ${data.applications.mediatorApp}|\n `+
+        `| NetworkMapApp | ${data.applications.networkMapApp}|\n `+
+        `| LinkCalculatorApp | ${data.applications.linkCalculationApp}|\n `+
+        `| HelpApp | ${data.applications.helpApp}|\n `;
+      }
+    
+    return `| | |\n| --- | --- |\n| Version | ${data.version} |\n| Build timestamp | ${data.build}|\n`+
+    applicationVersions;
     }
-    return `| | |\n| --- | --- |\n| Version | ${data.version} |\n| Build timestamp | ${data.build}|`
   }
+
+  private getTopologyVersionMarkdownTable(data: topologyVersion|null|undefined){ 
+    if(!data){
+      return "No version";
+    }
+    else
+    {
+      return `| | |\n| --- | --- |\n| Version | ${data.version} |\n`
+    }
+  }
+
   private loadAboutContent(): void {
     const baseUri = window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/")+1);
     const p1 = requestRestExt<string>('/about');
-    const p2 = requestRestExt<{version:string,build:string}>(`${baseUri}version.json`);
-    Promise.all([p1,p2]).then((responses) => {
+    const p2 = requestRestExt<odluxVersion>(`${baseUri}version.json`);
+    const p3 = requestRestExt<any>(`/topology/info/version`);
+
+    Promise.all([p1,p2, p3]).then((responses) => {
       const response = responses[0];
-      const response2 = responses[1];    
+      const response2 = responses[1]; 
+      const response3 = responses[2];   
       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 content2 = `\n## ODLUX Version Info\n`+(response2.status == 200 ? this.getMarkOdluxVersionMarkdownTable(response2.data) : `${response2.message}` || "ODLUX Server error");
+      const content3 =  `\n## Topology API Version Info\n`+(response3.status == 200 ? this.getTopologyVersionMarkdownTable(response3.data): `Topology API not available`);
       const loadedSucessfully = response.status == 200 ? true : false;
-      this.setState({ content: (content + content2) || null, isContentLoadedSucessfully: loadedSucessfully });
+      this.setState({ content: (content + content2 + content3 ) || null, isContentLoadedSucessfully: loadedSucessfully });
     }).catch((error) => {
       this.setState({ content: error })
     })
diff --git a/sdnr/wt/odlux/framework/tsconfig.json b/sdnr/wt/odlux/framework/tsconfig.json
index d801f7c..cb36bc8 100644
--- a/sdnr/wt/odlux/framework/tsconfig.json
+++ b/sdnr/wt/odlux/framework/tsconfig.json
@@ -4,7 +4,7 @@
     "outDir": "./dist",
     "sourceMap": true,
     "forceConsistentCasingInFileNames": true,
-    "allowSyntheticDefaultImports": false,
+    "allowSyntheticDefaultImports": true,
     "allowUnreachableCode": false,
     "allowUnusedLabels": false,
     "noFallthroughCasesInSwitch": true,
diff --git a/sdnr/wt/odlux/framework/webpack.config.js b/sdnr/wt/odlux/framework/webpack.config.js
index 5d0d8fc..b5d31c2 100644
--- a/sdnr/wt/odlux/framework/webpack.config.js
+++ b/sdnr/wt/odlux/framework/webpack.config.js
@@ -201,55 +201,55 @@
       proxy: {

         "/about": {

           // target: "http://10.20.6.29:48181",

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         }, 

         "/yang-schema/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },   

         "/oauth/": {

           // target: "https://10.20.35.188:30205",

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/oauth2/": {

           // target: "https://10.20.35.188:30205",

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/database/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/restconf/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/rests/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/help/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

          "/about/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/tree/": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           secure: false

         },

         "/websocket": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           ws: true,

           changeOrigin: true,

           secure: false

         },

         "/apidoc": {

-          target: "http://sdnr:8181",

+          target: "http://localhost:18181",

           ws: true,

           changeOrigin: true,

           secure: false