summaryrefslogtreecommitdiffstats
path: root/sdnr/wt-odlux/odlux/apps/mediatorApp
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt-odlux/odlux/apps/mediatorApp')
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/.babelrc17
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/package.json44
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/pom.xml105
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/avaliableMediatorServersActions.ts58
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorConfigActions.ts154
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorServerActions.ts114
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/assets/icons/mediatorAppIcon.svg49
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorConfigDialog.tsx399
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorServerDialog.tsx221
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/refreshMediatorDialog.tsx117
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/showMeditaorInfoDialog.tsx107
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/avaliableMediatorServersHandler.ts36
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorAppRootHandler.ts43
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorServerHandler.ts120
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/index.html29
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/models/mediatorServer.ts77
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/plugin.tsx83
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/services/mediatorService.ts204
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx291
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx193
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/tsconfig.json38
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/tslint.json4
-rw-r--r--sdnr/wt-odlux/odlux/apps/mediatorApp/webpack.config.js158
23 files changed, 2661 insertions, 0 deletions
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/.babelrc b/sdnr/wt-odlux/odlux/apps/mediatorApp/.babelrc
new file mode 100644
index 000000000..3d8cd1260
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/.babelrc
@@ -0,0 +1,17 @@
+{
+ "presets": [
+ ["@babel/preset-react"],
+ ["@babel/preset-env", {
+ "targets": {
+ "chrome": "66"
+ },
+ "spec": true,
+ "loose": false,
+ "modules": false,
+ "debug": false,
+ "useBuiltIns": "usage",
+ "forceAllTransforms": true
+ }]
+ ],
+ "plugins": []
+}
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/package.json b/sdnr/wt-odlux/odlux/apps/mediatorApp/package.json
new file mode 100644
index 000000000..867a8790d
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "@odlux/mediator-app",
+ "version": "0.1.0",
+ "description": "A react based modular UI to demo the mediator possible app.",
+ "main": "index.js",
+ "scripts": {
+ "start": "webpack-dev-server --env debug",
+ "build": "webpack --env release --config webpack.config.js",
+ "build:dev": "webpack --env debug --config webpack.config.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://git.mfico.de/highstreet-technologies/odlux.git"
+ },
+ "keywords": [
+ "reactjs",
+ "redux",
+ "ui",
+ "framework"
+ ],
+ "author": "Matthias Fischer",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@emotion/react": "^11.7.0",
+ "@emotion/styled": "^11.6.0",
+ "@mui/icons-material": "^5.2.0",
+ "@mui/material": "^5.2.2",
+ "@mui/styles": "^5.2.2",
+ "@odlux/framework": "*"
+ },
+ "peerDependencies": {
+ "@fortawesome/free-solid-svg-icons": "5.6.3",
+ "@types/classnames": "2.2.6",
+ "@types/flux": "3.1.8",
+ "@types/jquery": "3.3.10",
+ "@types/react": "17.0.37",
+ "@types/react-dom": "17.0.11",
+ "@types/react-router-dom": "5.1.7",
+ "jquery": "3.3.1",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-router-dom": "5.2.0"
+ }
+}
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/pom.xml b/sdnr/wt-odlux/odlux/apps/mediatorApp/pom.xml
new file mode 100644
index 000000000..547c91e92
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ ONAP : SDNR ODLUX
+ ~ ================================================================================
+ ~ Copyright (C) 2020 AT&T 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=======================================================
+ ~
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.onap.ccsdk.features.sdnr.odlux</groupId>
+ <artifactId>sdnr-odlux-app-mediatorApp</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>SDNR ODLUX :: ${project.artifactId}</name>
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+ </license>
+ </licenses>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>dist</directory>
+ <targetPath>odlux</targetPath>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>dist</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>node</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>node_modules</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>../node_modules</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <!-- eclipse bug build bin folder in basedir -->
+ <fileset>
+ <directory>bin</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>de.jacks-it-lab</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.7.2</version>
+ <executions>
+ <execution>
+ <id>install node and yarn</id>
+ <goals>
+ <goal>install-node-and-yarn</goal>
+ </goals>
+ <!-- optional: default phase is "generate-resources" -->
+ <phase>initialize</phase>
+ <configuration>
+ <nodeVersion>v16.17.0</nodeVersion>
+ <yarnVersion>v1.22.19</yarnVersion>
+ </configuration>
+ </execution>
+ <execution>
+ <id>yarn build</id>
+ <goals>
+ <goal>yarn</goal>
+ </goals>
+ <configuration>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/avaliableMediatorServersActions.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/avaliableMediatorServersActions.ts
new file mode 100644
index 000000000..3f56b05e1
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/avaliableMediatorServersActions.ts
@@ -0,0 +1,58 @@
+/**
+ * ============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 { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+import { AddSnackbarNotification } from '../../../../framework/src/actions/snackbarActions';
+
+import { MediatorServer } from '../models/mediatorServer';
+import { avaliableMediatorServersReloadAction } from '../handlers/avaliableMediatorServersHandler';
+import mediatorService from '../services/mediatorService';
+
+/** Represents the base action. */
+export class BaseAction extends Action { }
+
+/** Represents an async thunk action that will add a server to the avaliable mediator servers. */
+export const addAvaliableMediatorServerAsyncActionCreator = (server: MediatorServer) => (dispatch: Dispatch) => {
+ mediatorService.insertMediatorServer(server).then(_ => {
+ window.setTimeout(() => {
+ dispatch(avaliableMediatorServersReloadAction);
+ dispatch(new AddSnackbarNotification({ message: `Successfully added [${ server.name }]`, options: { variant: 'success' } }));
+ }, 900);
+ });
+ };
+
+ /** Represents an async thunk action that will add a server to the avaliable mediator servers. */
+export const updateAvaliableMediatorServerAsyncActionCreator = (server: MediatorServer) => (dispatch: Dispatch) => {
+ mediatorService.updateMediatorServer(server).then(_ => {
+ window.setTimeout(() => {
+ dispatch(avaliableMediatorServersReloadAction);
+ dispatch(new AddSnackbarNotification({ message: `Successfully updated [${ server.name }]`, options: { variant: 'success' } }));
+ }, 900);
+ });
+};
+
+ /** Represents an async thunk action that will delete a server from the avaliable mediator servers. */
+ export const removeAvaliableMediatorServerAsyncActionCreator = (server: MediatorServer) => (dispatch: Dispatch) => {
+ mediatorService.deleteMediatorServer(server).then(_ => {
+ window.setTimeout(() => {
+ dispatch(avaliableMediatorServersReloadAction);
+ dispatch(new AddSnackbarNotification({ message: `Successfully removed [${ server.name }]`, options: { variant: 'success' } }));
+ }, 900);
+ });
+ };
+ \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorConfigActions.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorConfigActions.ts
new file mode 100644
index 000000000..516515ab2
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorConfigActions.ts
@@ -0,0 +1,154 @@
+/**
+ * ============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 { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+
+import { AddSnackbarNotification } from '../../../../framework/src/actions/snackbarActions';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+import mediatorService from '../services/mediatorService';
+import { MediatorConfig, MediatorConfigResponse } from '../models/mediatorServer';
+
+/** Represents the base action. */
+export class BaseAction extends Action { }
+
+export class SetMediatorBusyByName extends BaseAction {
+ constructor(public name: string, public isBusy: boolean) {
+ super();
+ }
+}
+
+export class AddMediatorConfig extends BaseAction {
+ constructor(public mediatorConfig: MediatorConfigResponse) {
+ super();
+ }
+}
+
+export class UpdateMediatorConfig extends BaseAction {
+ constructor(public name: string, public mediatorConfig: MediatorConfigResponse) {
+ super();
+ }
+}
+
+export class RemoveMediatorConfig extends BaseAction {
+ constructor(public name: string) {
+ super();
+ }
+}
+
+
+export const startMediatorByNameAsyncActionCreator = (name: string) => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+ dispatch(new SetMediatorBusyByName(name, true));
+ const { mediator: { mediatorServerState: { id } } } = getState();
+ if (id) {
+ mediatorService.startMediatorByName(id, name).then(msg => {
+ dispatch(new AddSnackbarNotification({ message: msg + ' ' + name, options: { variant: 'info' } }));
+ // since there is no notification, a timeout will be need here
+ window.setTimeout(() => {
+ mediatorService.getMediatorServerConfigByName(id, name).then(config => {
+ if (config) {
+ dispatch(new UpdateMediatorConfig(name, config));
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: reading mediator config for ${name}.`, options: { variant: 'error' } }));
+ }
+ dispatch(new SetMediatorBusyByName(name, false));
+ });
+ }, 2100);
+ });
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: currently no mediator server selected.`, options: { variant: 'error' } }));
+ dispatch(new SetMediatorBusyByName(name, false));
+ }
+};
+
+export const stopMediatorByNameAsyncActionCreator = (name: string) => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+ dispatch(new SetMediatorBusyByName(name, true));
+ const { mediator: { mediatorServerState: { id } } } = getState();
+ if (id) {
+ mediatorService.stopMediatorByName(id, name).then(msg => {
+ dispatch(new AddSnackbarNotification({ message: msg + ' ' + name, options: { variant: 'info' } }));
+ // since there is no notification, a timeout will be need here
+ window.setTimeout(() => {
+ mediatorService.getMediatorServerConfigByName(id, name).then(config => {
+ if (config) {
+ dispatch(new UpdateMediatorConfig(name, config));
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: reading mediator config for ${name}.`, options: { variant: 'error' } }));
+ }
+ dispatch(new SetMediatorBusyByName(name, false));
+ });
+ }, 2100);
+ });
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: currently no mediator server selected.`, options: { variant: 'error' } }));
+ dispatch(new SetMediatorBusyByName(name, false));
+ }
+};
+
+export const addMediatorConfigAsyncActionCreator = (config: MediatorConfig) => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+ const { Name: name } = config;
+ const { mediator: { mediatorServerState: { id } } } = getState();
+ if (id) {
+ mediatorService.createMediatorConfig(id, config).then(msg => {
+ dispatch(new AddSnackbarNotification({ message: msg + ' ' + name, options: { variant: 'info' } }));
+ // since there is no notification, a timeout will be need here
+ window.setTimeout(() => {
+ mediatorService.getMediatorServerConfigByName(id, name).then(config => {
+ if (config) {
+ dispatch(new AddMediatorConfig(config));
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: reading mediator config for ${name}.`, options: { variant: 'error' } }));
+ }
+ });
+ }, 2100);
+ });
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: currently no mediator server selected.`, options: { variant: 'error' } }));
+ }
+};
+
+export const updateMediatorConfigAsyncActionCreator = (config: MediatorConfig) => (dispatch: Dispatch) => {
+ // currently not supported be backend
+};
+
+export const removeMediatorConfigAsyncActionCreator = (config: MediatorConfig) => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+ const { Name: name } = config;
+ const { mediator: { mediatorServerState: { id } } } = getState();
+ if (id) {
+ mediatorService.deleteMediatorConfigByName(id, name).then(msg => {
+ dispatch(new AddSnackbarNotification({ message: msg + ' ' + name, options: { variant: 'info' } }));
+ // since there is no notification, a timeout will be need here
+ window.setTimeout(() => {
+ mediatorService.getMediatorServerConfigByName(id, config.Name).then(config => {
+ if (!config) {
+ dispatch(new RemoveMediatorConfig(name));
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: deleting mediator config for ${name}.`, options: { variant: 'error' } }));
+ }
+ });
+ }, 2100);
+ });
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Error: currently no mediator server selected.`, options: { variant: 'error' } }));
+ dispatch(new SetMediatorBusyByName(name, false));
+ }
+};
+
+
+
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorServerActions.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorServerActions.ts
new file mode 100644
index 000000000..79e46df0e
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/actions/mediatorServerActions.ts
@@ -0,0 +1,114 @@
+/**
+ * ============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 { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+
+import { MediatorServerVersionInfo, MediatorConfig, MediatorConfigResponse, MediatorServerDevice } from '../models/mediatorServer';
+import mediatorService from '../services/mediatorService';
+import { AddSnackbarNotification } from '../../../../framework/src/actions/snackbarActions';
+import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+/** Represents the base action. */
+export class BaseAction extends Action { }
+
+export class SetMediatorServerBusy extends BaseAction {
+ constructor(public isBusy: boolean) {
+ super();
+ }
+}
+
+export class SetMediatorServerInfo extends BaseAction {
+ /**
+ * Initializes a new instance of this class.
+ */
+ constructor(public id: string | null, public name: string | null, public url: string | null) {
+ super();
+
+ }
+}
+
+export class SetMediatorServerVersion extends BaseAction {
+ /**
+ * Initializes a new instance of this class.
+ */
+ constructor(public versionInfo: MediatorServerVersionInfo | null) {
+ super();
+
+ }
+}
+
+export class SetAllMediatorServerConfigurations extends BaseAction {
+ /**
+ * Initializes a new instance of this class.
+ */
+ constructor(public allConfigurations: MediatorConfigResponse[] | null) {
+ super();
+
+ }
+}
+
+export class SetMediatorServerSupportedDevices extends BaseAction {
+ /**
+ * Initializes a new instance of this class.
+ */
+ constructor(public devices: MediatorServerDevice[] | null) {
+ super();
+
+ }
+}
+
+export class SetMediatorServerReachable extends BaseAction {
+ constructor(public isReachable: boolean) {
+ super();
+ }
+}
+
+export const initializeMediatorServerAsyncActionCreator = (serverId: string) => (dispatch: Dispatch) => {
+ dispatch(new SetMediatorServerBusy(true));
+ mediatorService.getMediatorServerById(serverId).then(mediatorServer => {
+ if (!mediatorServer) {
+ dispatch(new SetMediatorServerBusy(false));
+ dispatch(new AddSnackbarNotification({ message: `Error loading mediator server [${serverId}]`, options: { variant: 'error' } }));
+ dispatch(new NavigateToApplication("mediator"));
+ return;
+ }
+
+ dispatch(new SetMediatorServerInfo(mediatorServer.id, mediatorServer.name, mediatorServer.url));
+
+ Promise.all([
+ mediatorService.getMediatorServerAllConfigs(mediatorServer.id),
+ mediatorService.getMediatorServerSupportedDevices(mediatorServer.id),
+ mediatorService.getMediatorServerVersion(mediatorServer.id)
+ ]).then(([configurations, supportedDevices, versionInfo]) => {
+ if (configurations === null && supportedDevices === null && versionInfo === null) {
+ dispatch(new SetMediatorServerReachable(false));
+ } else {
+ dispatch(new SetMediatorServerReachable(true));
+ }
+ dispatch(new SetAllMediatorServerConfigurations(configurations));
+ dispatch(new SetMediatorServerSupportedDevices(supportedDevices));
+ dispatch(new SetMediatorServerVersion(versionInfo));
+ dispatch(new SetMediatorServerBusy(false));
+ }).catch(error => {
+ dispatch(new SetMediatorServerReachable(false));
+ dispatch(new SetMediatorServerBusy(false));
+ });
+ });
+};
+
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/assets/icons/mediatorAppIcon.svg b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/assets/icons/mediatorAppIcon.svg
new file mode 100644
index 000000000..b819aa610
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/assets/icons/mediatorAppIcon.svg
@@ -0,0 +1,49 @@
+<!-- highstreet technologies GmbH colour scheme
+ Grey #565656
+ LBlue #36A9E1
+ DBlue #246DA2
+ Green #003F2C / #006C4B
+ Yellw #C8D400
+ Red #D81036
+-->
+
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 980 980">
+
+<g transform="translate(0.000000,890.000000) scale(0.100000,-0.100000)">
+
+<path fill="#36A9E1" d="M4704 7791 c-314 -180 -1992 -1183 -1993 -1191 -2 -12 2183 -1311
+2198 -1307 20 5 1595 947 1856 1109 198 123 295 193 295 210 0 7 -22 26 -48
+42 -352 217 -2060 1224 -2103 1241 -9 3 -94 -40 -205 -104z"/>
+
+<path fill="#36A9E1" d="M2530 5147 l0 -1144 1098 -731 1097 -732 3 1217 c2 966 -1 1220 -10
+1229 -19 17 -2169 1304 -2179 1304 -5 0 -9 -475 -9 -1143z"/>
+
+<path fill="#36A9E1" d="M6163 5638 l-1093 -653 0 -1232 c0 -678 2 -1233 4 -1233 8 0 2161
+1293 2179 1308 16 14 17 62 16 761 -1 410 -5 961 -8 1224 l-6 477 -1092 -652z"/>
+
+<path fill="#565656" d="M7598 4488 c-3 -626 -6 -800 -17 -825 -16 -39 -136 -122 -486 -337
+-132 -81 -249 -154 -260 -162 -20 -15 -19 -16 20 -50 44 -39 414 -264 517
+-315 l66 -32 109 63 c107 62 414 243 838 493 383 226 1199 715 1219 730 19 14
+16 17 -50 59 -97 62 -1941 1168 -1948 1168 -3 0 -6 -357 -8 -792z"/>
+
+<path fill="#565656" d="M1280 4736 c-1071 -644 -1095 -659 -1093 -671 0 -5 492 -303 1092
+-661 l1091 -653 400 197 c219 108 399 199 399 202 0 3 -102 73 -226 155 -333
+220 -653 442 -691 479 -24 24 -35 45 -42 86 -6 30 -13 358 -16 728 -5 477 -10
+672 -18 671 -6 0 -409 -240 -896 -533z"/>
+
+<path fill="#565656" d="M0 2612 l0 -1149 872 -578 c1051 -697 1292 -855 1307 -855 8 0 11
+333 11 1213 l0 1212 -1063 637 c-584 350 -1077 643 -1094 652 l-33 17 0 -1149z"/>
+
+<path fill="#565656" d="M9380 3514 c-217 -129 -704 -420 -1082 -647 l-688 -412 0 -1228 0
+-1228 28 15 c56 29 810 476 1692 1003 l465 278 3 1228 c2 978 0 1227 -10 1227
+-7 0 -191 -106 -408 -236z"/>
+
+<path fill="#565656" d="M3019 2685 l-484 -243 2 -1124 c2 -1073 6 -1308 22 -1308 11 0 1943
+1147 2134 1267 l37 23 0 413 0 412 -378 250 c-331 219 -807 530 -838 548 -6 3
+-229 -103 -495 -238z"/>
+
+<path fill="#565656" d="M6249 2821 c-101 -60 -407 -244 -679 -408 l-495 -299 0 -409 0 -410
+440 -263 c1265 -755 1717 -1022 1733 -1022 9 0 12 292 12 1218 0 669 -4 1222
+-8 1228 -13 19 -788 474 -808 474 -6 0 -93 -49 -195 -109z"/>
+</g>
+</svg>
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorConfigDialog.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorConfigDialog.tsx
new file mode 100644
index 000000000..34ffc5e20
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorConfigDialog.tsx
@@ -0,0 +1,399 @@
+/**
+ * ============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 { Theme, Typography, FormControlLabel, Checkbox } from '@mui/material';
+
+import { WithStyles } from '@mui/styles';
+import createStyles from '@mui/styles/createStyles';
+import withStyles from '@mui/styles/withStyles';
+
+import Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
+import Select from '@mui/material/Select';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogContentText from '@mui/material/DialogContentText';
+import DialogTitle from '@mui/material/DialogTitle';
+
+import Tabs from '@mui/material/Tabs';
+import Tab from '@mui/material/Tab';
+
+import Fab from '@mui/material/Fab';
+import AddIcon from '@mui/icons-material/Add';
+import DeleteIcon from '@mui/icons-material/Delete';
+import IconButton from '@mui/material/IconButton';
+
+import { addMediatorConfigAsyncActionCreator, updateMediatorConfigAsyncActionCreator, removeMediatorConfigAsyncActionCreator } from '../actions/mediatorConfigActions';
+import { MediatorConfig, ODLConfig } from '../models/mediatorServer';
+import FormControl from '@mui/material/FormControl';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+
+import { Panel } from '../../../../framework/src/components/material-ui/panel';
+
+import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+
+const styles = (theme: Theme) => createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ flex: '1',
+ },
+ fab: {
+ position: 'absolute',
+ bottom: theme.spacing(1),
+ right: theme.spacing(1),
+ },
+ title: {
+ fontSize: 14,
+ },
+ center: {
+ flex: "1",
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ },
+ alignInOneLine: {
+ display: 'flex',
+ flexDirection: 'row'
+ },
+ left: {
+ marginRight: theme.spacing(1),
+ },
+ right: {
+ marginLeft: 0,
+ }
+});
+
+const TabContainer: React.SFC = ({ children }) => {
+ return (
+ <div style={{ width: "430px", height: "530px", position: "relative", display: 'flex', flexDirection: 'column' }}>
+ {children}
+ </div>
+ );
+}
+
+export enum EditMediatorConfigDialogMode {
+ None = "none",
+ AddMediatorConfig = "addMediatorConfig",
+ EditMediatorConfig = "editMediatorConfig",
+ RemoveMediatorConfig = "removeMediatorConfig",
+}
+
+const mapProps = (state: IApplicationStoreState) => ({
+ supportedDevices: state.mediator.mediatorServerState.supportedDevices
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ addMediatorConfig: (config: MediatorConfig) => {
+ dispatcher.dispatch(addMediatorConfigAsyncActionCreator(config));
+ },
+ updateMediatorConfig: (config: MediatorConfig) => {
+ dispatcher.dispatch(updateMediatorConfigAsyncActionCreator(config));
+ },
+ removeMediatorConfig: (config: MediatorConfig) => {
+ dispatcher.dispatch(removeMediatorConfigAsyncActionCreator(config));
+ },
+});
+
+type DialogSettings = {
+ dialogTitle: string;
+ dialogDescription: string;
+ applyButtonText: string;
+ cancelButtonText: string;
+ readonly: boolean;
+ readonlyName: boolean;
+};
+
+const settings: { [key: string]: DialogSettings } = {
+ [EditMediatorConfigDialogMode.None]: {
+ dialogTitle: "",
+ dialogDescription: "",
+ applyButtonText: "",
+ cancelButtonText: "",
+ readonly: true,
+ readonlyName: true,
+ },
+ [EditMediatorConfigDialogMode.AddMediatorConfig]: {
+ dialogTitle: "Add Mediator Configuration",
+ dialogDescription: "",
+ applyButtonText: "Add",
+ cancelButtonText: "Cancel",
+ readonly: false,
+ readonlyName: false,
+ },
+ [EditMediatorConfigDialogMode.EditMediatorConfig]: {
+ dialogTitle: "Edit Mediator Configuration",
+ dialogDescription: "",
+ applyButtonText: "Update",
+ cancelButtonText: "Cancel",
+ readonly: false,
+ readonlyName: true,
+ },
+ [EditMediatorConfigDialogMode.RemoveMediatorConfig]: {
+ dialogTitle: "Remove Mediator Configuration",
+ dialogDescription: "",
+ applyButtonText: "Remove",
+ cancelButtonText: "Cancel",
+ readonly: true,
+ readonlyName: true,
+ },
+};
+
+type EditMediatorConfigDialogComponentProps = WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch> & {
+ mode: EditMediatorConfigDialogMode;
+ mediatorConfig: MediatorConfig;
+ onClose: () => void;
+};
+
+type EditMediatorConfigDialogComponentState = MediatorConfig & { activeTab: number; activeOdlConfig: string, forceAddOdlConfig: boolean, isOdlConfigHostnameEmpty: boolean };
+
+class EditMediatorConfigDialogComponent extends React.Component<EditMediatorConfigDialogComponentProps, EditMediatorConfigDialogComponentState> {
+ constructor(props: EditMediatorConfigDialogComponentProps) {
+ super(props);
+
+ this.state = {
+ ...this.props.mediatorConfig,
+ activeTab: 0,
+ activeOdlConfig: "",
+ forceAddOdlConfig: false,
+ isOdlConfigHostnameEmpty: false
+ };
+ }
+
+ private odlConfigValueChangeHandlerCreator = <THtmlElement extends HTMLElement, TKey extends keyof ODLConfig>(index: number, property: TKey, mapValue: (event: React.ChangeEvent<THtmlElement>) => any) => (event: React.ChangeEvent<THtmlElement>) => {
+ event.stopPropagation();
+ event.preventDefault();
+ this.setState({
+ ODLConfig: [
+ ...this.state.ODLConfig.slice(0, index),
+ { ...this.state.ODLConfig[index], [property]: mapValue(event) },
+ ...this.state.ODLConfig.slice(index + 1)
+ ]
+ });
+ }
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ const { classes } = this.props;
+ return (
+ <Dialog open={this.props.mode !== EditMediatorConfigDialogMode.None}>
+ <DialogTitle id="form-dialog-title">{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ <Tabs value={this.state.activeTab} indicatorColor="secondary" textColor="secondary" onChange={(event, value) => this.setState({ activeTab: value })} >
+ <Tab label="Config" />
+ <Tab label="ODL AutoConnect" />
+ </Tabs>
+ {this.state.activeTab === 0 ? <TabContainer >
+ <TextField variant="standard" disabled={setting.readonly || setting.readonlyName} spellCheck={false} autoFocus margin="dense" id="name" label="Name" type="text" fullWidth value={this.state.Name} onChange={(event) => { this.setState({ Name: event.target.value }); }} />
+ <FormControl variant="standard" fullWidth disabled={setting.readonly}>
+ <InputLabel htmlFor="deviceType">Device</InputLabel>
+ <Select variant="standard" value={this.state.DeviceType} onChange={(event, value) => {
+ const device = this.props.supportedDevices.find(device => device.id === event.target.value);
+ if (device) {
+ this.setState({
+ DeviceType: device.id,
+ NeXMLFile: device.xml
+ });
+ } else {
+ this.setState({
+ DeviceType: -1,
+ NeXMLFile: ""
+ });
+ }
+ }} inputProps={{ name: 'deviceType', id: 'deviceType' }} fullWidth >
+ <MenuItem value={-1}><em>None</em></MenuItem>
+ {this.props.supportedDevices.map(device => (<MenuItem key={device.id} value={device.id} >{`${device.vendor} - ${device.device} (${device.version || '0.0.0'}) `}</MenuItem>))}
+ </Select>
+ </FormControl>
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ipAddress" label="Device IP" type="text" fullWidth value={this.state.DeviceIp} onChange={(event) => { this.setState({ DeviceIp: event.target.value }); }} />
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="devicePort" label="Device SNMP Port" type="number" fullWidth value={this.state.DevicePort || ""} onChange={(event) => { this.setState({ DevicePort: +event.target.value }); }} />
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="trapsPort" label="TrapsPort" type="number" fullWidth value={this.state.TrapPort || ""} onChange={(event) => { this.setState({ TrapPort: +event.target.value }); }} />
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ncUser" label="Netconf User" type="text" fullWidth value={this.state.NcUsername} onChange={(event) => { this.setState({ NcUsername: event.target.value }); }} />
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ncPassword" label="Netconf Password" type="password" fullWidth value={this.state.NcPassword} onChange={(event) => { this.setState({ NcPassword: event.target.value }); }} />
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} autoFocus margin="dense" id="ncPort" label="Netconf Port" type="number" fullWidth value={this.state.NcPort || ""} onChange={(event) => { this.setState({ NcPort: +event.target.value }); }} />
+ </TabContainer> : null}
+ {this.state.activeTab === 1 ? <TabContainer >
+ {this.state.ODLConfig && this.state.ODLConfig.length > 0
+ ? this.state.ODLConfig.map((cfg, ind) => {
+ const panelId = `panel-${ind}`;
+ const deleteButton = (<IconButton
+ onClick={() => {
+ this.setState({
+ ODLConfig: [
+ ...this.state.ODLConfig.slice(0, ind),
+ ...this.state.ODLConfig.slice(ind + 1)
+ ]
+ });
+ }}
+ size="large"><DeleteIcon /></IconButton>)
+ return (
+ <Panel title={cfg.Server && `${cfg.User ? `${cfg.User}@` : ''}${cfg.Protocol}://${cfg.Server}:${cfg.Port}` || "new odl config"} key={panelId} panelId={panelId} activePanel={this.state.activeOdlConfig} customActionButtons={[deleteButton]}
+ onToggle={(id) => { this.setState({ activeOdlConfig: (this.state.activeOdlConfig === id) ? "" : (id || "") }); console.log("activeOdlConfig " + id); this.hideHostnameErrormessage(id) }} >
+ <div className={classes.alignInOneLine}>
+ <FormControl variant="standard" className={classes.left} margin={"dense"} >
+ <InputLabel htmlFor={`protocol-${ind}`}>Protocoll</InputLabel>
+ <Select variant="standard" value={cfg.Protocol} onChange={(e, v) => this.odlConfigValueChangeHandlerCreator(ind, "Protocol", e => v)} inputProps={{ name: `protocol-${ind}`, id: `protocol-${ind}` }} fullWidth >
+ <MenuItem value={"http"}>http</MenuItem>
+ <MenuItem value={"https"}>https</MenuItem>
+ </Select>
+ </FormControl>
+ <TextField variant="standard" className={classes.left} spellCheck={false} margin="dense" id="hostname" label="Hostname" type="text" value={cfg.Server} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Server", e => e.target.value)} />
+ <TextField variant="standard" className={classes.right} style={{ maxWidth: "65px" }} spellCheck={false} margin="dense" id="port" label="Port" type="number" value={cfg.Port || ""} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Port", e => +e.target.value)} />
+ </div>
+ {
+ this.state.isOdlConfigHostnameEmpty &&
+ <Typography component={"div"} className={classes.left} color="error" gutterBottom>Please add a hostname.</Typography>
+ }
+ <div className={classes.alignInOneLine}>
+ <TextField variant="standard" className={classes.left} spellCheck={false} margin="dense" id="username" label="Username" type="text" value={cfg.User} onChange={this.odlConfigValueChangeHandlerCreator(ind, "User", e => e.target.value)} />
+ <TextField variant="standard" className={classes.right} spellCheck={false} margin="dense" id="password" label="Password" type="password" value={cfg.Password} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Password", e => e.target.value)} />
+ </div>
+ <div className={classes.alignInOneLine}>
+ <FormControlLabel className={classes.right} control={<Checkbox checked={cfg.Trustall} onChange={this.odlConfigValueChangeHandlerCreator(ind, "Trustall", e => e.target.checked)} />} label="Trustall" />
+ </div>
+ </Panel>
+ );
+ })
+ : (this.state.forceAddOdlConfig ?
+ <div className={classes.center} >
+ <Typography component={"div"} className={classes.title} color="error" gutterBottom>Please add at least one ODL auto connect configuration.</Typography>
+ </div>
+ :
+ <div className={classes.center} >
+ <Typography component={"div"} className={classes.title} color="textSecondary" gutterBottom>Please add an ODL auto connect configuration.</Typography>
+ </div>
+ )
+ }
+ <Fab className={classes.fab} color="primary" aria-label="Add" onClick={() => this.setState({
+ ODLConfig: [...this.state.ODLConfig, { Server: '', Port: 8181, Protocol: 'https', User: 'admin', Password: 'admin', Trustall: false }]
+ })} > <AddIcon /> </Fab>
+
+ </TabContainer> : null}
+
+ </DialogContent>
+ <DialogActions>
+ <Button color="inherit" onClick={(event) => { this.addConfig(event) }} > {setting.applyButtonText} </Button>
+ <Button onClick={(event) => {
+ this.onCancel();
+ event.preventDefault();
+ event.stopPropagation();
+ this.resetPanel();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ );
+ }
+
+ private addConfig = (event: any) => {
+ event.preventDefault();
+ event.stopPropagation();
+
+ if (this.state.ODLConfig.length === 0) {
+ this.setState({ activeTab: 1, forceAddOdlConfig: true });
+ }
+ else
+ if (this.state.ODLConfig.length > 0) {
+ for (let i = 0; i <= this.state.ODLConfig.length; i++) {
+ if (this.isHostnameEmpty(i)) {
+ this.setState({ activeOdlConfig: 'panel-' + i })
+ this.setState({ isOdlConfigHostnameEmpty: true })
+ return;
+ }
+ }
+
+ this.onApply(Object.keys(this.state).reduce<MediatorConfig & { [kex: string]: any }>((acc, key) => {
+ // do not copy additional state properties
+ if (key !== "activeTab" && key !== "activeOdlConfig" && key !== "isOdlConfigHostnameEmpty"
+ && key !== "forceAddOdlConfig" && key !== "_initialMediatorConfig") acc[key] = (this.state as any)[key];
+ return acc;
+ }, {} as MediatorConfig));
+ this.resetPanel();
+ }
+ }
+
+ private resetPanel = () => {
+ this.setState({ forceAddOdlConfig: false, isOdlConfigHostnameEmpty: false, activeTab: 0 });
+ }
+
+
+ private hideHostnameErrormessage = (panelId: string | null) => {
+
+ if (panelId) {
+ let id = Number(panelId.split('-')[1]);
+ if (!this.isHostnameEmpty(id)) {
+ this.setState({ isOdlConfigHostnameEmpty: false })
+ }
+ }
+ }
+
+ private isHostnameEmpty = (id: number) => {
+
+ const element = this.state.ODLConfig[id];
+ if (element) {
+ if (!element.Server) {
+ return true;
+ }
+ else {
+ return false
+ }
+
+ } else {
+ return null;
+ }
+ }
+
+ private onApply = (config: MediatorConfig) => {
+ this.props.onClose && this.props.onClose();
+ switch (this.props.mode) {
+ case EditMediatorConfigDialogMode.AddMediatorConfig:
+ config && this.props.addMediatorConfig(config);
+ break;
+ case EditMediatorConfigDialogMode.EditMediatorConfig:
+ config && this.props.updateMediatorConfig(config);
+ break;
+ case EditMediatorConfigDialogMode.RemoveMediatorConfig:
+ config && this.props.removeMediatorConfig(config);
+ break;
+ }
+ };
+
+ private onCancel = () => {
+ this.props.onClose && this.props.onClose();
+ }
+
+ static getDerivedStateFromProps(props: EditMediatorConfigDialogComponentProps, state: EditMediatorConfigDialogComponentState & { _initialMediatorConfig: MediatorConfig }): EditMediatorConfigDialogComponentState & { _initialMediatorConfig: MediatorConfig } {
+ if (props.mediatorConfig !== state._initialMediatorConfig) {
+ state = {
+ ...state,
+ ...props.mediatorConfig,
+ _initialMediatorConfig: props.mediatorConfig,
+ };
+ }
+ return state;
+ }
+}
+
+export const EditMediatorConfigDialog = withStyles(styles)(connect(mapProps, mapDispatch)(EditMediatorConfigDialogComponent));
+export default EditMediatorConfigDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorServerDialog.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorServerDialog.tsx
new file mode 100644
index 000000000..c8b158749
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/editMediatorServerDialog.tsx
@@ -0,0 +1,221 @@
+/**
+ * ============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 Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogContentText from '@mui/material/DialogContentText';
+import DialogTitle from '@mui/material/DialogTitle';
+
+import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
+
+import { addAvaliableMediatorServerAsyncActionCreator, removeAvaliableMediatorServerAsyncActionCreator, updateAvaliableMediatorServerAsyncActionCreator } from '../actions/avaliableMediatorServersActions';
+import { MediatorServer } from '../models/mediatorServer';
+import { Typography } from '@mui/material';
+
+export enum EditMediatorServerDialogMode {
+ None = "none",
+ AddMediatorServer = "addMediatorServer",
+ EditMediatorServer = "editMediatorServer",
+ RemoveMediatorServer = "removeMediatorServer",
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ addMediatorServer: (element: MediatorServer) => {
+ dispatcher.dispatch(addAvaliableMediatorServerAsyncActionCreator(element));
+ },
+ updateMediatorServer: (element: MediatorServer) => {
+ dispatcher.dispatch(updateAvaliableMediatorServerAsyncActionCreator(element));
+ },
+ removeMediatorServer: (element: MediatorServer) => {
+ dispatcher.dispatch(removeAvaliableMediatorServerAsyncActionCreator(element));
+ },
+});
+
+type DialogSettings = {
+ dialogTitle: string;
+ dialogDescription: string;
+ applyButtonText: string;
+ cancelButtonText: string;
+ readonly: boolean;
+};
+
+const settings: { [key: string]: DialogSettings } = {
+ [EditMediatorServerDialogMode.None]: {
+ dialogTitle: "",
+ dialogDescription: "",
+ applyButtonText: "",
+ cancelButtonText: "",
+ readonly: true,
+ },
+ [EditMediatorServerDialogMode.AddMediatorServer]: {
+ dialogTitle: "Add Mediator Server",
+ dialogDescription: "",
+ applyButtonText: "Add",
+ cancelButtonText: "Cancel",
+ readonly: false,
+ },
+ [EditMediatorServerDialogMode.EditMediatorServer]: {
+ dialogTitle: "Edit Mediator Server",
+ dialogDescription: "",
+ applyButtonText: "Update",
+ cancelButtonText: "Cancel",
+ readonly: false,
+ },
+ [EditMediatorServerDialogMode.RemoveMediatorServer]: {
+ dialogTitle: "Remove Mediator Server",
+ dialogDescription: "",
+ applyButtonText: "Remove",
+ cancelButtonText: "Cancel",
+ readonly: true,
+ },
+};
+
+type EditMediatorServerDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: EditMediatorServerDialogMode;
+ mediatorServer: MediatorServer;
+ onClose: () => void;
+};
+
+const urlRegex = RegExp("^https?://");
+
+type EditMediatorServerDialogComponentState = MediatorServer & { errorMessage: string[] };
+
+class EditMediatorServerDialogComponent extends React.Component<EditMediatorServerDialogComponentProps, EditMediatorServerDialogComponentState> {
+ constructor(props: EditMediatorServerDialogComponentProps) {
+ super(props);
+
+ this.state = {
+ ...this.props.mediatorServer,
+ errorMessage: []
+ };
+ }
+
+ areFieldsValid = () => {
+ return this.state.name.trim().length > 0 && this.state.url.trim().length > 0 && urlRegex.test(this.state.url);
+ }
+
+ createErrorMessages = () => {
+
+ let messages = [];
+ if (this.state.name.trim().length === 0 && this.state.url.trim().length === 0) {
+ messages.push("The server name and the url must not be empty.")
+ }
+ else
+ if (this.state.url.trim().length === 0) {
+ messages.push("The server url must not be empty.")
+
+ } else if (this.state.name.trim().length === 0) {
+ messages.push("The server name must not be empty.")
+ }
+
+ if (!urlRegex.test(this.state.url)) {
+ if (messages.length > 0) {
+ return messages.concat(["The server url must start with 'http(s)://'."])
+ } else {
+ return ["The server url must start with 'http(s)://'."]
+ }
+ }
+
+ return messages;
+ }
+
+
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+
+ return (
+ <Dialog open={this.props.mode !== EditMediatorServerDialogMode.None}>
+ <DialogTitle id="form-dialog-title">{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ {/* <TextField disabled spellCheck={false} autoFocus margin="dense" id="id" label="Id" type="text" fullWidth value={ this.state._id } onChange={(event)=>{ this.setState({_id: event.target.value}); } } /> */}
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} margin="dense" id="name" label="Name" type="text" fullWidth value={this.state.name} onChange={(event) => { this.setState({ name: event.target.value }); }} />
+ <TextField variant="standard" disabled={setting.readonly} spellCheck={false} margin="dense" id="url" label="Url" type="text" fullWidth value={this.state.url} onChange={(event) => { this.setState({ url: event.target.value }); }} />
+
+ <Typography id="errorMessage" component={"div"} color="error">{this.state.errorMessage.map((error, index) => <div key={index}>{error}</div>)}</Typography>
+
+ </DialogContent>
+ <DialogActions>
+ <Button onClick={(event) => {
+
+ if (this.areFieldsValid()) {
+ this.setState({ errorMessage: [] });
+ this.onApply({
+ id: this.state.id,
+ name: this.state.name,
+ url: this.state.url
+ });
+ } else {
+ const errorMessage = this.createErrorMessages()
+ this.setState({ errorMessage: errorMessage })
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+ }} color="inherit" > {setting.applyButtonText} </Button>
+ <Button onClick={(event) => {
+ this.onCancel();
+ this.setState({ errorMessage: [] });
+ event.preventDefault();
+ event.stopPropagation();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ )
+ }
+
+ private onApply = (element: MediatorServer) => {
+ this.props.onClose && this.props.onClose();
+ switch (this.props.mode) {
+ case EditMediatorServerDialogMode.AddMediatorServer:
+ element && this.props.addMediatorServer(element);
+ break;
+ case EditMediatorServerDialogMode.EditMediatorServer:
+ element && this.props.updateMediatorServer(element);
+ break;
+ case EditMediatorServerDialogMode.RemoveMediatorServer:
+ element && this.props.removeMediatorServer(element);
+ break;
+ }
+ };
+
+ private onCancel = () => {
+ this.props.onClose && this.props.onClose();
+ }
+
+ static getDerivedStateFromProps(props: EditMediatorServerDialogComponentProps, state: EditMediatorServerDialogComponentState & { _initialMediatorServer: MediatorServer }): EditMediatorServerDialogComponentState & { _initialMediatorServer: MediatorServer } {
+ if (props.mediatorServer !== state._initialMediatorServer) {
+ state = {
+ ...state,
+ ...props.mediatorServer,
+ _initialMediatorServer: props.mediatorServer,
+ };
+ }
+ return state;
+ }
+}
+
+export const EditMediatorServerDialog = connect(undefined, mapDispatch)(EditMediatorServerDialogComponent);
+export default EditMediatorServerDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/refreshMediatorDialog.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/refreshMediatorDialog.tsx
new file mode 100644
index 000000000..db1ef8771
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/refreshMediatorDialog.tsx
@@ -0,0 +1,117 @@
+/**
+ * ============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 Button from '@mui/material/Button';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogContentText from '@mui/material/DialogContentText';
+import DialogTitle from '@mui/material/DialogTitle';
+
+import { avaliableMediatorServersReloadAction } from '../handlers/avaliableMediatorServersHandler';
+import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
+
+import { MediatorServer } from '../models/mediatorServer';
+
+export enum RefreshMediatorDialogMode {
+ None = "none",
+ RefreshMediatorTable = "RefreshMediatorTable",
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ refreshMediator: () => dispatcher.dispatch(avaliableMediatorServersReloadAction)
+});
+
+type DialogSettings = {
+ dialogTitle: string,
+ dialogDescription: string,
+ applyButtonText: string,
+ cancelButtonText: string,
+ enableMountIdEditor: boolean,
+ enableUsernameEditor: boolean,
+ enableExtendedEditor: boolean,
+}
+
+const settings: { [key: string]: DialogSettings } = {
+ [RefreshMediatorDialogMode.None]: {
+ dialogTitle: "",
+ dialogDescription: "",
+ applyButtonText: "",
+ cancelButtonText: "",
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [RefreshMediatorDialogMode.RefreshMediatorTable]: {
+ dialogTitle: "Do you want to refresh the Mediator table?",
+ dialogDescription: "",
+ applyButtonText: "Yes",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ }
+}
+
+type RefreshMediatorDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: RefreshMediatorDialogMode;
+ onClose: () => void;
+};
+
+type RefreshMediatorDialogComponentState = MediatorServer & { isNameValid: boolean, isHostSet: boolean };
+
+class RefreshMediatorDialogComponent extends React.Component<RefreshMediatorDialogComponentProps, RefreshMediatorDialogComponentState> {
+ constructor(props: RefreshMediatorDialogComponentProps) {
+ super(props);
+ }
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ return (
+ <Dialog open={this.props.mode !== RefreshMediatorDialogMode.None}>
+ <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, "-").toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ </DialogContent>
+ <DialogActions>
+ <Button aria-label="dialog-confirm-button" onClick={(event) => {
+ this.onRefresh();
+ }} color="inherit" > {setting.applyButtonText} </Button>
+ <Button aria-label="dialog-cancel-button" onClick={(event) => {
+ this.onCancel();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ );
+ }
+
+ private onRefresh = () => {
+ this.props.refreshMediator();
+ this.props.onClose();
+ };
+
+ private onCancel = () => {
+ this.props.onClose();
+ }
+}
+
+export const RefreshMediatorDialog = connect(undefined, mapDispatch)(RefreshMediatorDialogComponent);
+export default RefreshMediatorDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/showMeditaorInfoDialog.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/showMeditaorInfoDialog.tsx
new file mode 100644
index 000000000..f8691ab2f
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/components/showMeditaorInfoDialog.tsx
@@ -0,0 +1,107 @@
+/**
+ * ============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 React from 'react'
+import { Dialog, DialogTitle, DialogContent, DialogActions, TextField, DialogContentText, Checkbox, Button, FormControlLabel, FormGroup } from '@mui/material';
+import { IApplicationState } from '../../../../framework/src/handlers/applicationStateHandler';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { connect, Connect } from '../../../../framework/src/flux/connect';
+import { MediatorConfigResponse } from '../models/mediatorServer';
+import { Panel } from '../../../../framework/src/components/material-ui/panel';
+
+export enum MediatorInfoDialogMode {
+ None = "none",
+ ShowDetails = "showDetails"
+}
+
+const mapProps = (state: IApplicationStoreState) => ({ supportedDevices: state.mediator.mediatorServerState.supportedDevices })
+
+type ShowMediatorInfoDialogComponentProps = Connect<typeof mapProps, undefined> &
+{
+ config: MediatorConfigResponse,
+ mode: MediatorInfoDialogMode,
+ onClose: () => void
+}
+
+type ShowMediatorInfoDialogComponentState = {
+ status: string,
+ devicetype: string,
+ activeOdlConfig: string
+}
+
+/*
+Displays all values of a mediator server
+*/
+class ShowMediatorInfoDialogComponent extends React.Component<ShowMediatorInfoDialogComponentProps, ShowMediatorInfoDialogComponentState> {
+
+ constructor(props: ShowMediatorInfoDialogComponentProps) {
+ super(props);
+ if (this.props.config) {
+ let deviceType = props.supportedDevices.find(element => element.id === this.props.config.DeviceType)
+
+ this.state = {
+ status: props.config.pid > 0 ? "Running" : "Stopped",
+ devicetype: deviceType != undefined ? deviceType.device : 'none',
+ activeOdlConfig: ''
+ }
+ }
+ }
+
+ onClose = (event: React.MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.props.onClose();
+ }
+
+ render() {
+ return (
+ <Dialog open={this.props.mode !== MediatorInfoDialogMode.None} onBackdropClick={this.props.onClose} >
+ <DialogTitle>{this.props.config.Name}</DialogTitle>
+ <DialogContent>
+ <TextField variant="standard" disabled margin="dense" id="deviceIp" label="Device IP" fullWidth defaultValue={this.props.config.DeviceIp} />
+ <TextField variant="standard" disabled margin="dense" id="deviceport" label="Device Port" fullWidth defaultValue={this.props.config.DevicePort} />
+ <TextField variant="standard" disabled margin="dense" id="status" label="Status" fullWidth defaultValue={this.state.status} />
+ <TextField variant="standard" disabled margin="dense" id="deviceType" label="Device Type" fullWidth defaultValue={this.state.devicetype} />
+ <TextField variant="standard" disabled margin="dense" id="ncPort" label="Netconf Port" fullWidth defaultValue={this.props.config.NcPort} />
+ <FormGroup>
+ <FormControlLabel control={<Checkbox disabled defaultChecked={this.props.config.IsNCConnected}></Checkbox>} label="Netconf Connection" />
+ <FormControlLabel control={<Checkbox disabled defaultChecked={this.props.config.IsNeConnected}></Checkbox>} label="Network Element Connection" />
+ <FormControlLabel control={<Checkbox disabled defaultChecked={this.props.config.fwactive}></Checkbox>} label="Firewall active" />
+ </FormGroup>
+ {
+ this.props.config.ODLConfig.map((element, index) =>
+ <Panel title={"ODL config " + (this.props.config.ODLConfig.length > 1 ? index + 1 : '')} key={index} panelId={'panel-' + index} activePanel={this.state.activeOdlConfig} onToggle={(id: string) => { this.setState({ activeOdlConfig: (this.state.activeOdlConfig === id) ? "" : (id || "") }); }}>
+ <TextField variant="standard" disabled margin="dense" defaultValue={element.Protocol + '://' + element.Server} label="Server" />
+ <TextField variant="standard" disabled margin="dense" defaultValue={element.Port} label="Port" />
+ <FormControlLabel control={<Checkbox disabled checked={element.Trustall} />} label="Trustall" />
+ </Panel>
+ )
+ }
+
+ </DialogContent>
+ <DialogActions>
+ <Button onClick={this.onClose} color="inherit">Close</Button>
+ </DialogActions>
+ </Dialog>
+ )
+ }
+
+}
+
+export const ShowMediatorInfoDialog = connect(mapProps)(ShowMediatorInfoDialogComponent)
+export default ShowMediatorInfoDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/avaliableMediatorServersHandler.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/avaliableMediatorServersHandler.ts
new file mode 100644
index 000000000..c22252d20
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/avaliableMediatorServersHandler.ts
@@ -0,0 +1,36 @@
+/**
+ * ============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 { createExternal,IExternalTableState } from '../../../../framework/src/components/material-table/utilities';
+import { createSearchDataHandler } from '../../../../framework/src/utilities/elasticSearch';
+
+import { MediatorServer } from '../models/mediatorServer';
+import { mediatorServerResourcePath } from '../services/mediatorService';
+
+export interface IAvaliableMediatorServersState extends IExternalTableState<MediatorServer> { }
+
+// create eleactic search material data fetch handler
+const avaliableMediatorServersSearchHandler = createSearchDataHandler<MediatorServer>(mediatorServerResourcePath);
+
+export const {
+ actionHandler: avaliableMediatorServersActionHandler,
+ createActions: createAvaliableMediatorServersActions,
+ createProperties: createAvaliableMediatorServersProperties,
+ reloadAction: avaliableMediatorServersReloadAction,
+
+ // set value action, to change a value
+} = createExternal<MediatorServer>(avaliableMediatorServersSearchHandler, appState => appState.mediator.avaliableMediatorServers); \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorAppRootHandler.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorAppRootHandler.ts
new file mode 100644
index 000000000..2642ec8cd
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorAppRootHandler.ts
@@ -0,0 +1,43 @@
+/**
+ * ============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==========================================================================
+ */
+// main state handler
+
+import { combineActionHandler } from '../../../../framework/src/flux/middleware';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+import { IAvaliableMediatorServersState, avaliableMediatorServersActionHandler } from './avaliableMediatorServersHandler' ;
+import { MediatorServerState, mediatorServerHandler } from './mediatorServerHandler';
+
+export interface IMediatorAppStoreState {
+ avaliableMediatorServers: IAvaliableMediatorServersState,
+ mediatorServerState: MediatorServerState,
+}
+
+declare module '../../../../framework/src/store/applicationStore' {
+ interface IApplicationStoreState {
+ mediator: IMediatorAppStoreState
+ }
+}
+
+const actionHandlers = {
+ avaliableMediatorServers: avaliableMediatorServersActionHandler,
+ mediatorServerState: mediatorServerHandler,
+};
+
+export const mediatorAppRootHandler = combineActionHandler<IMediatorAppStoreState>(actionHandlers);
+export default mediatorAppRootHandler;
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorServerHandler.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorServerHandler.ts
new file mode 100644
index 000000000..246634cbe
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/handlers/mediatorServerHandler.ts
@@ -0,0 +1,120 @@
+/**
+ * ============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 { XmlFileInfo, MediatorConfig, BusySymbol, MediatorConfigResponse, MediatorServerDevice } from "../models/mediatorServer";
+import { IActionHandler } from "../../../../framework/src/flux/action";
+import { SetMediatorServerVersion, SetMediatorServerInfo, SetAllMediatorServerConfigurations, SetMediatorServerBusy, SetMediatorServerSupportedDevices, SetMediatorServerReachable } from "../actions/mediatorServerActions";
+import { SetMediatorBusyByName, UpdateMediatorConfig, AddMediatorConfig, RemoveMediatorConfig } from "../actions/mediatorConfigActions";
+
+export type MediatorServerState = {
+ busy: boolean;
+ name: string | null;
+ url: string | null;
+ id: string | null;
+ serverVersion: string | null;
+ mediatorVersion: string | null;
+ nexmls: XmlFileInfo[];
+ configurations: MediatorConfigResponse[];
+ supportedDevices: MediatorServerDevice[];
+ isReachable: boolean;
+}
+
+const mediatorServerInit: MediatorServerState = {
+ busy: false,
+ name: null,
+ url: null,
+ id: null,
+ serverVersion: null,
+ mediatorVersion: null,
+ nexmls: [],
+ configurations: [],
+ supportedDevices: [],
+ isReachable: true
+}
+
+export const mediatorServerHandler: IActionHandler<MediatorServerState> = (state = mediatorServerInit, action) => {
+ if (action instanceof SetMediatorServerBusy) {
+ state = {
+ ...state,
+ busy: action.isBusy
+ };
+ } else if (action instanceof SetMediatorServerInfo) {
+ state = {
+ ...state,
+ name: action.name,
+ url: action.url,
+ id: action.id,
+ };
+ } else if (action instanceof SetMediatorServerVersion) {
+ state = {
+ ...state,
+ serverVersion: action.versionInfo && action.versionInfo.server,
+ mediatorVersion: action.versionInfo && action.versionInfo.mediator,
+ nexmls: action.versionInfo && [...action.versionInfo.nexmls] || [],
+ };
+ } else if (action instanceof SetAllMediatorServerConfigurations) {
+ state = {
+ ...state,
+ configurations: action.allConfigurations && action.allConfigurations.map(config => ({ ...config, busy: false })) || [],
+ };
+ } else if (action instanceof SetMediatorServerSupportedDevices) {
+ state = {
+ ...state,
+ supportedDevices: action.devices || [],
+ };
+ } else if (action instanceof SetMediatorBusyByName) {
+ const index = state.configurations.findIndex(config => config.Name === action.name);
+ if (index > -1) state = {
+ ...state,
+ configurations: [
+ ...state.configurations.slice(0, index),
+ { ...state.configurations[index], [BusySymbol]: action.isBusy },
+ ...state.configurations.slice(index + 1)
+ ]
+ };
+ } else if (action instanceof AddMediatorConfig) {
+ state = {
+ ...state,
+ configurations: [
+ ...state.configurations,
+ action.mediatorConfig
+ ]
+ };
+ } else if (action instanceof UpdateMediatorConfig) {
+ const index = state.configurations.findIndex(config => config.Name === action.name);
+ if (index > -1) state = {
+ ...state,
+ configurations: [
+ ...state.configurations.slice(0, index),
+ { ...action.mediatorConfig, [BusySymbol]: state.configurations[index][BusySymbol] },
+ ...state.configurations.slice(index + 1)
+ ]
+ };
+ } else if (action instanceof RemoveMediatorConfig) {
+ const index = state.configurations.findIndex(config => config.Name === action.name);
+ if (index > -1) state = {
+ ...state,
+ configurations: [
+ ...state.configurations.slice(0, index),
+ ...state.configurations.slice(index + 1)
+ ]
+ };
+ } else if( action instanceof SetMediatorServerReachable){
+ state = {...state, isReachable: action.isReachable}
+ }
+ return state;
+} \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/index.html b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/index.html
new file mode 100644
index 000000000..95bf9ec6b
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/index.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <!-- <link rel="stylesheet" href="./vendor.css"> -->
+ <title>Mediator App</title>
+</head>
+
+<body>
+ <div id="app"></div>
+ <script type="text/javascript" src="./require.js"></script>
+ <script type="text/javascript" src="./config.js"></script>
+ <script>
+ // run the application
+ require(["app", "mediatorApp" ,"connectApp","inventoryApp","faultApp","helpApp"], function (app, mediatorApp, connectApp,inventoryApp,faultApp,helpApp) {
+ mediatorApp.register();
+ connectApp.register();
+ inventoryApp.register();
+ faultApp.register();
+ helpApp.register();
+ app("./app.tsx").runApplication();
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/models/mediatorServer.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/models/mediatorServer.ts
new file mode 100644
index 000000000..6ab6db8b3
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/models/mediatorServer.ts
@@ -0,0 +1,77 @@
+/**
+ * ============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==========================================================================
+ */
+export type MediatorServer = {
+ id: string;
+ name: string;
+ url: string;
+}
+
+export type XmlFileInfo = {
+ filename: string;
+ version: string;
+}
+
+export type MediatorServerVersionInfo = {
+ mediator: string;
+ server: string;
+ nexmls: XmlFileInfo[];
+}
+
+export type ODLConfig = {
+ User: string;
+ Password: string;
+ Port: number;
+ Protocol: "http" | "https";
+ Server: string;
+ Trustall: boolean;
+};
+
+export const BusySymbol = Symbol("Busy");
+
+export type MediatorConfig = {
+ Name: string;
+ DeviceIp: string;
+ DevicePort: number;
+ DeviceType: number;
+ TrapPort: number;
+ NcUsername: string;
+ NcPassword: string;
+ NcPort: number;
+ NeXMLFile: string;
+ ODLConfig: ODLConfig[];
+}
+
+export type MediatorConfigResponse = MediatorConfig & {
+ IsNCConnected: boolean;
+ IsNeConnected: boolean;
+ autorun: boolean;
+ fwactive: boolean;
+ islocked: boolean;
+ ncconnections:{}[];
+ pid: number;
+ // extended properties
+ [BusySymbol]: boolean;
+}
+
+export type MediatorServerDevice = {
+ id: number; // DeviceType
+ device: string;
+ vendor: string;
+ version: string;
+ xml: string; // NeXMLFile
+} \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/plugin.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/plugin.tsx
new file mode 100644
index 000000000..1c30cfc54
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/plugin.tsx
@@ -0,0 +1,83 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+// app configuration and main entry point for the app
+
+import React from "react";
+import { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-router-dom';
+
+import applicationManager from '../../../framework/src/services/applicationManager';
+
+import { connect, Connect, IDispatcher } from '../../../framework/src/flux/connect';
+
+import { mediatorAppRootHandler } from './handlers/mediatorAppRootHandler';
+import { avaliableMediatorServersReloadAction } from "./handlers/avaliableMediatorServersHandler";
+
+import { MediatorApplication } from "./views/mediatorApplication";
+import { MediatorServerSelection } from "./views/mediatorServerSelection";
+import { initializeMediatorServerAsyncActionCreator } from "./actions/mediatorServerActions";
+
+const appIcon = require('./assets/icons/mediatorAppIcon.svg'); // select app icon
+
+let currentMediatorServerId: string | undefined = undefined;
+
+const mapDisp = (dispatcher: IDispatcher) => ({
+ loadMediatorServer : (mediatorServerId: string) => dispatcher.dispatch(initializeMediatorServerAsyncActionCreator(mediatorServerId)),
+});
+
+const MediatorServerRouteAdapter = connect(undefined, mapDisp)((props: RouteComponentProps<{ mediatorServerId: string }> & Connect<undefined, typeof mapDisp>) => {
+ if (currentMediatorServerId !== props.match.params.mediatorServerId) {
+ // route parameter has changed
+ currentMediatorServerId = props.match.params.mediatorServerId || undefined;
+ // Hint: This timeout is need, since it is not recommended to change the state while rendering is in progress !
+ window.setTimeout(() => {
+ if (currentMediatorServerId) {
+ props.loadMediatorServer(currentMediatorServerId);
+ }
+ });
+ }
+ return (
+ <MediatorApplication />
+ )
+});
+
+type AppProps = RouteComponentProps & Connect;
+
+const App = (props: AppProps) => (
+ <Switch>
+ <Route exact path={ `${ props.match.path }` } component={ MediatorServerSelection } />
+ <Route path={ `${ props.match.path }/:mediatorServerId` } component={ MediatorServerRouteAdapter } />
+ <Redirect to={ `${ props.match.path }` } />
+ </Switch>
+);
+
+const FinalApp = withRouter(connect()(App));
+
+export function register() {
+ const applicationApi = applicationManager.registerApplication({
+ name: "mediator",
+ icon: appIcon,
+ rootComponent: FinalApp,
+ rootActionHandler: mediatorAppRootHandler,
+ menuEntry: "Mediator"
+ });
+
+ // prefetch all available mediator servers
+ applicationApi.applicationStoreInitialized.then(applicationStore => {
+ applicationStore.dispatch(avaliableMediatorServersReloadAction)
+ });
+};
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/services/mediatorService.ts b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/services/mediatorService.ts
new file mode 100644
index 000000000..ede681776
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/services/mediatorService.ts
@@ -0,0 +1,204 @@
+/**
+ * ============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 $ from 'jquery';
+
+import { requestRest, formEncode } from '../../../../framework/src/services/restService';
+import { MediatorServer, MediatorServerVersionInfo, MediatorConfig, MediatorServerDevice, MediatorConfigResponse } from '../models/mediatorServer';
+import { PostResponse, DeleteResponse, Result } from '../../../../framework/src/models';
+
+export const mediatorServerResourcePath = "mediator-server";
+
+type MediatorServerResponse<TData> = { code: number, data: TData };
+type IndexableMediatorServer = MediatorServer & { [key: string]: any; };
+
+/**
+ * Represents a web api accessor service for all mediator server actions.
+ */
+class MediatorService {
+ /**
+ * Inserts data into the mediator servers table.
+ */
+ public async insertMediatorServer(server: IndexableMediatorServer): Promise<PostResponse | null> {
+ const path = `/restconf/operations/data-provider:create-mediator-server`;
+
+ const data = {
+ "url": server.url,
+ "name": server.name
+ }
+
+ const result = await requestRest<PostResponse>(path, { method: "POST", body: JSON.stringify({ input: data }) });
+ return result || null;
+ }
+
+ /**
+ * Updates data into the mediator servers table.
+ */
+ public async updateMediatorServer(server: IndexableMediatorServer): Promise<PostResponse | null> {
+ const path = `/restconf/operations/data-provider:update-mediator-server`;
+
+ const data = {
+ "id": server.id,
+ "url": server.url,
+ "name": server.name
+ }
+
+ const result = await requestRest<PostResponse>(path, { method: "POST", body: JSON.stringify({ input: data }) });
+ return result || null;
+ }
+
+ /**
+ * Deletes data from the mediator servers table.
+ */
+ public async deleteMediatorServer(server: MediatorServer): Promise<DeleteResponse | null> {
+ const path = `/restconf/operations/data-provider:delete-mediator-server`;
+
+ const data = {
+ "id": server.id,
+ }
+
+ const result = await requestRest<DeleteResponse>(path, { method: "POST", body: JSON.stringify({ input: data }) });
+ return result || null;
+ }
+
+ public async getMediatorServerById(serverId: string): Promise<MediatorServer | null> {
+ const path = `/restconf/operations/data-provider:read-mediator-server-list`;
+
+ const data = { "filter": [{ "property": "id", "filtervalue": serverId }] }
+
+
+ const result = await requestRest<Result<MediatorServer>>(path, { method: "POST", body: JSON.stringify({ input: data }) });
+
+ if (result && result["data-provider:output"].data[0]) {
+ const firstResult = result["data-provider:output"].data[0];
+
+ return {
+ id: firstResult.id,
+ name: firstResult.name,
+ url: firstResult.url
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ // https://cloud-highstreet-technologies.com/wiki/doku.php?id=att:ms:api
+
+ private async accassMediatorServer<TData = {}>(mediatorServerId: string, task: string, data?: {}): Promise<MediatorServerResponse<TData> | null> {
+ const path = `ms/${mediatorServerId}/api/'?task=${task}`;
+ const result = (await requestRest<string>(path, {
+ method: data ? "POST" : "GET",
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ },
+ body: data ? formEncode({
+ ...data,
+ ...{ task: task }
+ }) : null
+ }, true)) || null;
+
+ return result ? JSON.parse(result) as { code: number, data: TData } : null;
+ }
+ /*
+ private accassMediatorServer<TData = {}>(mediatorServerId: string, task: string, data?: {}): Promise<MediatorServerResponse<TData> | null> {
+ const path = `ms/${mediatorServerId}/api/?task=${task}`;
+ return new Promise<{ code: number, data: TData }>((resolve, reject) => {
+ $.ajax({
+ method: data ? 'POST' : 'GET',
+ url: path,
+ data: { ...{ task: task }, ...data },
+ //contentType: 'application/json'
+ }).then((result: any) => {
+ if (typeof result === "string") {
+ resolve(JSON.parse(result));
+ } else {
+ resolve(result);
+ };
+ });
+ });
+ }*/
+
+ public async getMediatorServerVersion(mediatorServerId: string): Promise<MediatorServerVersionInfo | null> {
+ const result = await this.accassMediatorServer<MediatorServerVersionInfo>(mediatorServerId, 'version');
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async getMediatorServerAllConfigs(mediatorServerId: string): Promise<MediatorConfigResponse[] | null> {
+ const result = await this.accassMediatorServer<MediatorConfigResponse[]>(mediatorServerId, 'getconfig');
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async getMediatorServerConfigByName(mediatorServerId: string, name: string): Promise<MediatorConfigResponse | null> {
+ const result = await this.accassMediatorServer<MediatorConfigResponse[]>(mediatorServerId, `getconfig&name=${name}`);
+ if (result && result.code === 1 && result.data && result.data.length === 1) return result.data[0];
+ return null;
+ }
+
+ public async getMediatorServerSupportedDevices(mediatorServerId: string): Promise<MediatorServerDevice[] | null> {
+ const result = await this.accassMediatorServer<MediatorServerDevice[]>(mediatorServerId, 'getdevices');
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async startMediatorByName(mediatorServerId: string, name: string): Promise<string | null> {
+ const result = await this.accassMediatorServer<string>(mediatorServerId, `start&name=${name}`);
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async stopMediatorByName(mediatorServerId: string, name: string): Promise<string | null> {
+ const result = await this.accassMediatorServer<string>(mediatorServerId, `stop&name=${name}`);
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async createMediatorConfig(mediatorServerId: string, config: MediatorConfig): Promise<string | null> {
+ const result = await this.accassMediatorServer<string>(mediatorServerId, 'create', { config: JSON.stringify(config) });
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async updateMediatorConfigByName(mediatorServerId: string, config: MediatorConfig): Promise<string | null> {
+ const result = await this.accassMediatorServer<string>(mediatorServerId, 'update', { config: JSON.stringify(config) });
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async deleteMediatorConfigByName(mediatorServerId: string, name: string): Promise<string | null> {
+ const result = await this.accassMediatorServer<string>(mediatorServerId, `delete&name=${name}`);
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async getMediatorServerFreeNcPorts(mediatorServerId: string, limit?: number): Promise<number[] | null> {
+ const result = await this.accassMediatorServer<number[]>(mediatorServerId, 'getncports', { limit });
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+
+ public async getMediatorServerFreeSnmpPorts(mediatorServerId: string, limit?: number): Promise<number[] | null> {
+ const result = await this.accassMediatorServer<number[]>(mediatorServerId, 'getsnmpports', { limit });
+ if (result && result.code === 1) return result.data;
+ return null;
+ }
+}
+
+export const mediatorService = new MediatorService;
+export default mediatorService; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx
new file mode 100644
index 000000000..03ce4532e
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx
@@ -0,0 +1,291 @@
+/**
+ * ============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 React from 'react';
+import { Theme, Tooltip } from '@mui/material';
+
+import { WithStyles } from '@mui/styles';
+import createStyles from '@mui/styles/createStyles';
+import withStyles from '@mui/styles/withStyles';
+
+import AddIcon from '@mui/icons-material/Add';
+import IconButton from '@mui/material/IconButton';
+import EditIcon from '@mui/icons-material/Edit';
+import DeleteIcon from '@mui/icons-material/Delete';
+import InfoIcon from '@mui/icons-material/Info';
+import StartIcon from '@mui/icons-material/PlayArrow';
+import StopIcon from '@mui/icons-material/Stop';
+
+import CircularProgress from '@mui/material/CircularProgress'
+
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import MaterialTable, { MaterialTableCtorType, ColumnType } from '../../../../framework/src/components/material-table';
+
+import { MediatorConfig, BusySymbol, MediatorConfigResponse } from '../models/mediatorServer';
+import EditMediatorConfigDialog, { EditMediatorConfigDialogMode } from '../components/editMediatorConfigDialog';
+import { startMediatorByNameAsyncActionCreator, stopMediatorByNameAsyncActionCreator } from '../actions/mediatorConfigActions';
+import mediatorService from '../services/mediatorService';
+import { ShowMediatorInfoDialog, MediatorInfoDialogMode } from '../components/showMeditaorInfoDialog'
+
+const styles = (theme: Theme) => createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ flex: '1',
+ },
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 300,
+ },
+ button: {
+ margin: 0,
+ padding: "6px 6px",
+ minWidth: 'unset'
+ },
+ spacer: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ display: "inline"
+ },
+ progress: {
+ flex: '1 1 100%',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ pointerEvents: 'none'
+ }
+});
+
+const mapProps = (state: IApplicationStoreState) => ({
+ serverName: state.mediator.mediatorServerState.name,
+ serverUrl: state.mediator.mediatorServerState.url,
+ serverId: state.mediator.mediatorServerState.id,
+ serverVersion: state.mediator.mediatorServerState.serverVersion,
+ mediatorVersion: state.mediator.mediatorServerState.mediatorVersion,
+ configurations: state.mediator.mediatorServerState.configurations,
+ supportedDevices: state.mediator.mediatorServerState.supportedDevices,
+ busy: state.mediator.mediatorServerState.busy,
+ isReachable: state.mediator.mediatorServerState.isReachable
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ startMediator: (name: string) => dispatcher.dispatch(startMediatorByNameAsyncActionCreator(name)),
+ stopMediator: (name: string) => dispatcher.dispatch(stopMediatorByNameAsyncActionCreator(name)),
+});
+
+const emptyMediatorConfig: MediatorConfig = {
+ Name: "",
+ DeviceIp: "127.0.0.1",
+ DevicePort: 161,
+ NcUsername: "admin",
+ NcPassword: "admin",
+ DeviceType: -1,
+ NcPort: 4020,
+ TrapPort: 10020,
+ NeXMLFile: "",
+ ODLConfig: []
+};
+
+const MediatorServerConfigurationsTable = MaterialTable as MaterialTableCtorType<MediatorConfigResponse>;
+const MediatorServerUnreachableTable = MaterialTable as MaterialTableCtorType<{ Name: string, status: string, ipAdress: string, device: string, actions: string }>
+
+type MediatorApplicationComponentProps = Connect<typeof mapProps, typeof mapDispatch> & WithStyles<typeof styles>;
+
+type MediatorServerSelectionComponentState = {
+ busy: boolean,
+ mediatorConfigToEdit: MediatorConfig,
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode,
+ mediatorShowInfoMode: MediatorInfoDialogMode,
+ mediatorConfigToDisplay: MediatorConfigResponse | null
+}
+
+class MediatorApplicationComponent extends React.Component<MediatorApplicationComponentProps, MediatorServerSelectionComponentState> {
+
+ constructor(props: MediatorApplicationComponentProps) {
+ super(props);
+
+ this.state = {
+ busy: false,
+ mediatorConfigToEdit: emptyMediatorConfig,
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode.None,
+ mediatorShowInfoMode: MediatorInfoDialogMode.None,
+ mediatorConfigToDisplay: null
+ }
+ }
+
+ render() {
+ const { classes } = this.props;
+
+ const renderActions = (rowData: MediatorConfigResponse) => (
+ <>
+ <div className={classes.spacer}>
+ <Tooltip disableInteractive title={"Start"} >
+ <IconButton disabled={rowData[BusySymbol]} className={classes.button} size="large">
+ <StartIcon onClick={(event) => { event.preventDefault(); event.stopPropagation(); this.props.startMediator(rowData.Name); }} />
+ </IconButton>
+ </Tooltip>
+ <Tooltip disableInteractive title={"Stop"} >
+ <IconButton disabled={rowData[BusySymbol]} className={classes.button} size="large">
+ <StopIcon onClick={(event) => { event.preventDefault(); event.stopPropagation(); this.props.stopMediator(rowData.Name); }} />
+ </IconButton>
+ </Tooltip>
+ </div>
+ <div className={classes.spacer}>
+ <Tooltip disableInteractive title={"Info"} ><IconButton
+ className={classes.button}
+ onClick={(event) => { this.onOpenInfoDialog(event, rowData) }}
+ size="large"><InfoIcon /></IconButton></Tooltip>
+ </div>
+ <div className={classes.spacer}>
+ {process.env.NODE_ENV === "development" ? <Tooltip disableInteractive title={"Edit"} ><IconButton
+ disabled={rowData[BusySymbol]}
+ className={classes.button}
+ onClick={event => this.onOpenEditConfigurationDialog(event, rowData)}
+ size="large"><EditIcon /></IconButton></Tooltip> : null}
+ <Tooltip disableInteractive title={"Remove"} ><IconButton
+ disabled={rowData[BusySymbol]}
+ className={classes.button}
+ onClick={event => this.onOpenRemoveConfigutationDialog(event, rowData)}
+ size="large"><DeleteIcon /></IconButton></Tooltip>
+ </div>
+ </>
+ );
+
+ const addMediatorConfigAction = { icon: AddIcon, tooltip: 'Add', ariaLabel: 'add-element', onClick: this.onOpenAddConfigurationDialog };
+
+ return (
+ <div className={classes.root}>
+ {this.props.busy || this.state.busy
+ ? <div className={classes.progress}> <CircularProgress color={"secondary"} size={48} /> </div>
+ :
+
+ this.props.isReachable ?
+
+ <MediatorServerConfigurationsTable defaultSortColumn={"Name"} tableId={null} defaultSortOrder="asc" stickyHeader title={this.props.serverName || ''} customActionButtons={[addMediatorConfigAction]} idProperty={"Name"} rows={this.props.configurations} asynchronus columns={[
+ { property: "Name", title: "Mediator", type: ColumnType.text },
+ { property: "Status", title: "Status", type: ColumnType.custom, customControl: ({ rowData }) => rowData.pid ? (<span>Running</span>) : (<span>Stopped</span>) },
+ { property: "DeviceIp", title: "IP Adress", type: ColumnType.text },
+ {
+ property: "Device", title: "Device", type: ColumnType.custom, customControl: ({ rowData }) => {
+ const dev = this.props.supportedDevices && this.props.supportedDevices.find(dev => dev.id === rowData.DeviceType);
+ return (
+ <span> {dev && `${dev.vendor} - ${dev.device} (${dev.version || '0.0.0'})`} </span>
+ )
+ }
+ },
+ { property: "actions", title: "Actions", type: ColumnType.custom, customControl: ({ rowData }) => renderActions(rowData) },
+ ]} />
+ :
+ <MediatorServerUnreachableTable title={this.props.serverName || ''} tableId={null} idProperty={"Name"} disableFilter={true} disableSorting={true} enableSelection={false} rows={[{ Name: '', status: "Mediator server not found.", ipAdress: '', device: '', actions: '' }]} columns={[
+ { property: "Name", title: "Mediator", type: ColumnType.text },
+ { property: "status", title: "Status", type: ColumnType.text },
+ { property: "ipAdress", title: "IP Adress", type: ColumnType.text },
+ { property: "device", title: "Device", type: ColumnType.text },
+ { property: "actions", title: "Actions", type: ColumnType.text },
+
+ ]} />
+ }
+
+ <EditMediatorConfigDialog
+ mediatorConfig={this.state.mediatorConfigToEdit}
+ mode={this.state.mediatorConfigEditorMode}
+ onClose={this.onCloseEditMediatorConfigDialog} />
+
+ {
+
+ this.state.mediatorShowInfoMode != MediatorInfoDialogMode.None &&
+ <ShowMediatorInfoDialog
+ config={this.state.mediatorConfigToDisplay as MediatorConfigResponse}
+ mode={this.state.mediatorShowInfoMode}
+ onClose={this.onCloseInfoDialog} />
+ }
+ </div>
+ );
+ }
+
+ private onOpenInfoDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfigResponse) => {
+ event.stopPropagation();
+ event.preventDefault();
+ this.setState({ mediatorShowInfoMode: MediatorInfoDialogMode.ShowDetails, mediatorConfigToDisplay: configEntry })
+ }
+
+ private onCloseInfoDialog = () => {
+ this.setState({ mediatorShowInfoMode: MediatorInfoDialogMode.None, mediatorConfigToDisplay: null })
+ }
+
+ private onOpenAddConfigurationDialog = () => {
+ // Tries to determine a free port for netconf listener and snpm listener
+ // it it could not determine free ports the dialog will open any way
+ // those ports should not be configured from the fontend, furthermore
+ // the backend should auto configure them and tell the user the result
+ // after the creation process.
+ this.setState({
+ busy: true,
+ });
+ this.props.serverId && Promise.all([
+ mediatorService.getMediatorServerFreeNcPorts(this.props.serverId, 1),
+ mediatorService.getMediatorServerFreeSnmpPorts(this.props.serverId, 1),
+ ]).then(([freeNcPorts, freeSnmpPorts]) => {
+ if (freeNcPorts && freeSnmpPorts && freeNcPorts.length > 0 && freeSnmpPorts.length > 0) {
+ this.setState({
+ busy: false,
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode.AddMediatorConfig,
+ mediatorConfigToEdit: {
+ ...emptyMediatorConfig,
+ NcPort: freeNcPorts[0],
+ TrapPort: freeSnmpPorts[0],
+ },
+ });
+ } else {
+ this.setState({
+ busy: false,
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode.AddMediatorConfig,
+ mediatorConfigToEdit: { ...emptyMediatorConfig },
+ });
+ }
+ })
+
+ }
+
+ private onOpenEditConfigurationDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfig) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.setState({
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode.EditMediatorConfig,
+ mediatorConfigToEdit: configEntry,
+ });
+ }
+
+ private onOpenRemoveConfigutationDialog = (event: React.MouseEvent<HTMLElement>, configEntry: MediatorConfig) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.setState({
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode.RemoveMediatorConfig,
+ mediatorConfigToEdit: configEntry,
+ });
+ }
+
+ private onCloseEditMediatorConfigDialog = () => {
+ this.setState({
+ mediatorConfigEditorMode: EditMediatorConfigDialogMode.None,
+ mediatorConfigToEdit: emptyMediatorConfig,
+ });
+ }
+}
+
+export const MediatorApplication = withStyles(styles)(connect(mapProps, mapDispatch)(MediatorApplicationComponent));
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx
new file mode 100644
index 000000000..fb12f2608
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx
@@ -0,0 +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 React from 'react';
+import { Theme, Tooltip } from '@mui/material';
+
+import { WithStyles } from '@mui/styles';
+import withStyles from '@mui/styles/withStyles';
+import createStyles from '@mui/styles/createStyles';
+
+import AddIcon from '@mui/icons-material/Add';
+import IconButton from '@mui/material/IconButton';
+import EditIcon from '@mui/icons-material/Edit';
+import DeleteIcon from '@mui/icons-material/Delete';
+import Refresh from '@mui/icons-material/Refresh';
+
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { connect, IDispatcher, Connect } from '../../../../framework/src/flux/connect';
+import MaterialTable, { MaterialTableCtorType, ColumnType } from '../../../../framework/src/components/material-table';
+
+import { createAvaliableMediatorServersProperties, createAvaliableMediatorServersActions } from '../handlers/avaliableMediatorServersHandler';
+
+import { MediatorServer } from '../models/mediatorServer';
+import EditMediatorServerDialog, { EditMediatorServerDialogMode } from '../components/editMediatorServerDialog';
+import RefreshMediatorDialog, { RefreshMediatorDialogMode } from '../components/refreshMediatorDialog';
+import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions';
+
+const MediatorServersTable = MaterialTable as MaterialTableCtorType<MediatorServer>;
+
+const styles = (theme: Theme) => createStyles({
+ button: {
+ margin: 0,
+ padding: "6px 6px",
+ minWidth: 'unset',
+ },
+ spacer: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ display: "inline",
+ },
+});
+
+const mapProps = (state: IApplicationStoreState) => ({
+ mediatorServersProperties: createAvaliableMediatorServersProperties(state),
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ mediatorServersActions: createAvaliableMediatorServersActions(dispatcher.dispatch),
+ selectMediatorServer: (mediatorServerId: string) => mediatorServerId && dispatcher.dispatch(new NavigateToApplication("mediator", mediatorServerId)),
+});
+
+const emptyMediatorServer: MediatorServer = {
+ id: "",
+ name: "",
+ url: ""
+};
+
+type MediatorServerSelectionComponentProps = Connect<typeof mapProps, typeof mapDispatch> & WithStyles<typeof styles>;
+
+type MediatorServerSelectionComponentState = {
+ mediatorServerToEdit: MediatorServer,
+ mediatorServerEditorMode: EditMediatorServerDialogMode,
+ refreshMediatorEditorMode: RefreshMediatorDialogMode
+}
+
+let initialSorted = false;
+
+class MediatorServerSelectionComponent extends React.Component<MediatorServerSelectionComponentProps, MediatorServerSelectionComponentState> {
+
+ constructor(props: MediatorServerSelectionComponentProps) {
+ super(props);
+
+ this.state = {
+ mediatorServerEditorMode: EditMediatorServerDialogMode.None,
+ mediatorServerToEdit: emptyMediatorServer,
+ refreshMediatorEditorMode: RefreshMediatorDialogMode.None
+ }
+ }
+
+ render() {
+ const { classes } = this.props;
+ const refreshMediatorAction = {
+ icon: Refresh, tooltip: 'Refresh Mediator Server Table', ariaLabel:'refresh', onClick: () => {
+ this.setState({
+ refreshMediatorEditorMode: RefreshMediatorDialogMode.RefreshMediatorTable
+ });
+ }
+ };
+
+ const addMediatorServerActionButton = {
+ icon: AddIcon, tooltip: 'Add', ariaLabel:'add-element', onClick: () => {
+ this.setState({
+ mediatorServerEditorMode: EditMediatorServerDialogMode.AddMediatorServer,
+ mediatorServerToEdit: emptyMediatorServer,
+ });
+ }
+ };
+ return <>
+ <MediatorServersTable stickyHeader title={"Mediator"} tableId={null} customActionButtons={[refreshMediatorAction, addMediatorServerActionButton]} idProperty={"id"}
+ {...this.props.mediatorServersActions} {...this.props.mediatorServersProperties} columns={[
+ { property: "name", title: "Name", type: ColumnType.text },
+ { property: "url", title: "Url", type: ColumnType.text },
+ {
+ property: "actions", title: "Actions", type: ColumnType.custom, customControl: ({ rowData }) => (
+ <div className={classes.spacer}>
+ <Tooltip disableInteractive title={"Edit"} ><IconButton
+ className={classes.button}
+ onClick={event => { this.onEditMediatorServer(event, rowData); }}
+ size="large"><EditIcon /></IconButton></Tooltip>
+ <Tooltip disableInteractive title={"Remove"} ><IconButton
+ className={classes.button}
+ onClick={event => { this.onRemoveMediatorServer(event, rowData); }}
+ size="large"><DeleteIcon /></IconButton></Tooltip>
+ </div>
+ )
+ }
+ ]} onHandleClick={this.onSelectMediatorServer} />
+ <EditMediatorServerDialog
+ mediatorServer={this.state.mediatorServerToEdit}
+ mode={this.state.mediatorServerEditorMode}
+ onClose={this.onCloseEditMediatorServerDialog} />
+ <RefreshMediatorDialog
+ mode={this.state.refreshMediatorEditorMode}
+ onClose={this.onCloseRefreshMediatorDialog}
+ />
+ </>;
+ }
+
+ public componentDidMount() {
+
+ if (!initialSorted) {
+ initialSorted = true;
+ this.props.mediatorServersActions.onHandleRequestSort("name");
+ } else {
+ this.props.mediatorServersActions.onRefresh();
+ }
+ }
+
+ private onSelectMediatorServer = (event: React.MouseEvent<HTMLElement>, server: MediatorServer) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.props.selectMediatorServer(server && server.id);
+
+ }
+
+ private onEditMediatorServer = (event: React.MouseEvent<HTMLElement>, server: MediatorServer) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.setState({
+ mediatorServerEditorMode: EditMediatorServerDialogMode.EditMediatorServer,
+ mediatorServerToEdit: server,
+ });
+ }
+
+ private onRemoveMediatorServer = (event: React.MouseEvent<HTMLElement>, server: MediatorServer) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.setState({
+ mediatorServerEditorMode: EditMediatorServerDialogMode.RemoveMediatorServer,
+ mediatorServerToEdit: server,
+ });
+ }
+
+ private onCloseEditMediatorServerDialog = () => {
+ this.setState({
+ mediatorServerEditorMode: EditMediatorServerDialogMode.None,
+ mediatorServerToEdit: emptyMediatorServer,
+ });
+ }
+ private onCloseRefreshMediatorDialog = () => {
+ this.setState({
+ refreshMediatorEditorMode: RefreshMediatorDialogMode.None
+ });
+ }
+}
+
+
+export const MediatorServerSelection = withStyles(styles)(connect(mapProps, mapDispatch)(MediatorServerSelectionComponent));
+export default MediatorServerSelection; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/tsconfig.json b/sdnr/wt-odlux/odlux/apps/mediatorApp/tsconfig.json
new file mode 100644
index 000000000..c95005660
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/tsconfig.json
@@ -0,0 +1,38 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./src",
+ "outDir": "./dist",
+ "sourceMap": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowSyntheticDefaultImports": true,
+ "allowUnreachableCode": false,
+ "allowUnusedLabels": false,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "pretty": true,
+ "newLine": "LF",
+ "module": "es2015",
+ "target": "es2016",
+ "moduleResolution": "node",
+ "experimentalDecorators": true,
+ "jsx": "preserve",
+ "lib": [
+ "dom",
+ "es2015",
+ "es2016"
+ ],
+ "types": [
+ "node",
+ "prop-types",
+ "react",
+ "react-dom"
+ ]
+ },
+ "exclude": [
+ "dist",
+ "node_modules"
+ ]
+}
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/tslint.json b/sdnr/wt-odlux/odlux/apps/mediatorApp/tslint.json
new file mode 100644
index 000000000..b5143e92c
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/tslint.json
@@ -0,0 +1,4 @@
+{
+ "rules":{
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/mediatorApp/webpack.config.js b/sdnr/wt-odlux/odlux/apps/mediatorApp/webpack.config.js
new file mode 100644
index 000000000..813c28f37
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/mediatorApp/webpack.config.js
@@ -0,0 +1,158 @@
+/**
+ * Webpack 4 configuration file
+ * see https://webpack.js.org/configuration/
+ * see https://webpack.js.org/configuration/dev-server/
+ */
+
+"use strict";
+
+const path = require("path");
+const webpack = require("webpack");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const TerserPlugin = require('terser-webpack-plugin');
+
+// const __dirname = (path => path.replace(/^([a-z]\:)/, c => c.toUpperCase()))(process.__dirname());
+
+module.exports = (env) => {
+ const distPath = path.resolve(__dirname, env === "release" ? "." : "../..", "dist");
+ const frameworkPath = path.resolve(__dirname, env === "release" ? "../../framework" : "../..", "dist");
+ return [{
+ name: "App",
+
+ mode: "none", //disable default behavior
+
+ target: "web",
+
+ context: path.resolve(__dirname, "src"),
+
+ entry: {
+ mediatorApp: ["./plugin.tsx"]
+ },
+
+ devtool: env === "release" ? false : "source-map",
+
+ resolve: {
+ extensions: [".ts", ".tsx", ".js", ".jsx"]
+ },
+
+ output: {
+ path: distPath,
+ filename: "[name].js",
+ library: "[name]",
+ libraryTarget: "umd2",
+ chunkFilename: "[name].js"
+ },
+ module: {
+ rules: [{
+ test: /\.tsx?$/,
+ exclude: /node_modules/,
+ use: [{
+ loader: "babel-loader"
+ }, {
+ loader: "ts-loader"
+ }]
+ }, {
+ test: /\.jsx?$/,
+ exclude: /node_modules/,
+ use: [{
+ loader: "babel-loader"
+ }]
+ },{
+ //don't minify images
+ test: /\.(png|gif|jpg|svg)$/,
+ use: [{
+ loader: 'url-loader',
+ options: {
+ limit: 10,
+ name: './images/[name].[ext]'
+ }
+ }]
+ }]
+ },
+
+ optimization: {
+ noEmitOnErrors: true,
+ namedModules: env !== "release",
+ minimize: env === "release",
+ minimizer: env !== "release" ? [] : [new TerserPlugin({
+ terserOptions: {
+ warnings: false, // false, true, "verbose"
+ compress: {
+ drop_console: true,
+ drop_debugger: true,
+ }
+ }
+ })],
+ },
+
+ plugins: [
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, "../../framework/src"),
+ manifest: require(path.resolve(frameworkPath, "vendor-manifest.json")),
+ sourceType: "umd2"
+ }),
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, "../../framework/src"),
+ manifest: require(path.resolve(frameworkPath, "app-manifest.json")),
+ sourceType: "umd2"
+ }),
+ ...(env === "release" ? [
+ new webpack.DefinePlugin({
+ "process.env": {
+ NODE_ENV: "'production'",
+ VERSION: JSON.stringify(require("./package.json").version)
+ }
+ }),
+ ] : [
+ new webpack.DefinePlugin({
+ "process.env": {
+ NODE_ENV: "'development'",
+ VERSION: JSON.stringify(require("./package.json").version)
+ }
+ }),
+ new CopyWebpackPlugin([{
+ from: 'index.html',
+ to: distPath
+ }]),
+ ])
+ ],
+
+ devServer: {
+ public: "http://localhost:3100",
+ contentBase: frameworkPath,
+
+ compress: true,
+ headers: {
+ "Access-Control-Allow-Origin": "*"
+ },
+ host: "0.0.0.0",
+ port: 3100,
+ disableHostCheck: true,
+ historyApiFallback: true,
+ inline: true,
+ hot: false,
+ quiet: false,
+ stats: {
+ colors: true
+ },
+ proxy: {
+ "/oauth2/": {
+ target: "http://localhost:3000",
+ secure: false
+ },
+ "/database/": {
+ target: "http://localhost:3000",
+ secure: false
+ },
+ "/restconf/": {
+ target: "http://localhost:3000",
+ secure: false
+ },
+ "/help/": {
+ target: "http://localhost:3000",
+ secure: false
+ }
+ }
+ }
+ }];
+}