summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/framework
diff options
context:
space:
mode:
authorMichael DÜrre <michael.duerre@highstreet-technologies.com>2021-04-08 07:27:18 +0200
committerMichael DÜrre <michael.duerre@highstreet-technologies.com>2021-04-08 07:27:28 +0200
commit21e4a946cd24b8a03ea577352f0271ebf7669ffa (patch)
tree4227d8566770b75c2c25b67c764038288cacfe3d /sdnr/wt/odlux/framework
parenta252be83694ae33260d99d5371ed48c1558aa2e8 (diff)
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
Diffstat (limited to 'sdnr/wt/odlux/framework')
-rw-r--r--sdnr/wt/odlux/framework/package.json12
-rw-r--r--sdnr/wt/odlux/framework/pom.xml4
-rw-r--r--sdnr/wt/odlux/framework/src/app.tsx8
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/index.tsx44
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx4
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/utilities.ts64
-rw-r--r--sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts2
-rw-r--r--sdnr/wt/odlux/framework/src/services/notificationService.ts156
-rw-r--r--sdnr/wt/odlux/framework/src/services/restService.ts42
-rw-r--r--sdnr/wt/odlux/framework/src/views/about.tsx67
-rw-r--r--sdnr/wt/odlux/framework/tsconfig.json2
-rw-r--r--sdnr/wt/odlux/framework/webpack.config.js24
12 files changed, 282 insertions, 147 deletions
diff --git a/sdnr/wt/odlux/framework/package.json b/sdnr/wt/odlux/framework/package.json
index 3ecd34c23..345fc8b4c 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 3f9ecbee6..9d648b52d 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 23ae2fbc9..2d913be1b 100644
--- a/sdnr/wt/odlux/framework/src/app.tsx
+++ b/sdnr/wt/odlux/framework/src/app.tsx
@@ -68,6 +68,10 @@ export const runApplication = () => {
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 @@ export const runApplication = () => {
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 7d4633bc6..c74fd1a38 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 { EnhancedTableHead } from './tableHead';
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 styles = (theme: Theme) => createStyles({
}
});
+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 @@ type MaterialTableComponentBaseProps<TData> = WithStyles<typeof styles> & {
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 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
<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 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
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 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
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 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
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 3b2f8e0a8..f7de0a062 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 @@ interface ITableToolbarComponentProps extends WithStyles<typeof styles> {
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 @@ class TableToolbarComponent extends React.Component<ITableToolbarComponentProps,
{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 07ffe2ff5..544e14e01 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 { Dispatch } from '../../flux/store';
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 @@ export interface IExternalTableState<TData> {
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 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
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 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
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 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
}
- }).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 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
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 b5c1ee7b1..06df6709f 100644
--- a/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts
+++ b/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts
@@ -58,7 +58,7 @@ const applicationStateInit: IApplicationState = {
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 30091b574..5625b1f55 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,81 +25,95 @@ let userLoggedOut = false;
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;
- }
+ if (newScopesToSubscribe.length === 0) {
+ return true;
+ }
+ return false;
+}
- return true;
+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> {
- 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;
- }
- });
-
+ removeScope(scope, callback);
+ return socketReady && socketReady.then((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));
- return true;
- }
- return false;
- });
+ return setCurrentSubscriptions(notificationSocket);
+ }) || true;
}
export const startNotificationService = (store: ApplicationStore) => {
@@ -111,24 +124,24 @@ const connect = (): Promise<WebSocket> => {
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 @@ const connect = (): Promise<WebSocket> => {
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 @@ const connect = (): Promise<WebSocket> => {
}
-
-
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 f05c7b89f..c7b122449 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 @@ export const formEncode = (params: { [key: string]: string | number }) => Object
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 f97d6ffb3..5d2257a3f 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 marked from 'marked';
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 @@ interface AboutState {
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 @@ class AboutComponent extends React.Component<any, AboutState> {
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 d801f7c8e..cb36bc81a 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 5d0d8fc9a..b5d31c262 100644
--- a/sdnr/wt/odlux/framework/webpack.config.js
+++ b/sdnr/wt/odlux/framework/webpack.config.js
@@ -201,55 +201,55 @@ module.exports = (env) => {
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