aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt-odlux/odlux/apps/connectApp
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt-odlux/odlux/apps/connectApp')
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/.babelrc17
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/package.json44
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/policies.json12
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/pom.xml109
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts141
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts82
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts60
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/actions/networkElementsActions.ts60
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/actions/tlsKeyActions.ts59
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/assets/icons/connectAppIcon.svg22
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx99
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx425
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx160
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx314
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx114
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx114
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts100
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts36
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.ts92
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts64
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/tlsKeyHandler.ts55
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/index.html28
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/connectionStatusLog.ts27
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/guiCutTrough.ts22
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementBase.ts22
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnection.ts69
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts25
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/panelId.ts19
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/topologyNetconf.ts59
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts24
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/pluginConnect.tsx109
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/services/connectService.ts305
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/src/views/connectView.tsx102
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/tsconfig.json6
-rw-r--r--sdnr/wt-odlux/odlux/apps/connectApp/webpack.config.js202
35 files changed, 3198 insertions, 0 deletions
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/.babelrc b/sdnr/wt-odlux/odlux/apps/connectApp/.babelrc
new file mode 100644
index 000000000..3d8cd1260
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/.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/connectApp/package.json b/sdnr/wt-odlux/odlux/apps/connectApp/package.json
new file mode 100644
index 000000000..9a3c35baa
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "@odlux/connect-app",
+ "version": "0.1.1",
+ "description": "A react based modular UI to display network element/node connect data from a database.",
+ "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/connectApp/policies.json b/sdnr/wt-odlux/odlux/apps/connectApp/policies.json
new file mode 100644
index 000000000..2ec73612e
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/policies.json
@@ -0,0 +1,12 @@
+[
+ {
+ "path": "/rests/**/node=Sim2230**",
+ "methods": {
+ "get": true,
+ "post": false,
+ "put": false,
+ "delete": false,
+ "patch": false
+ }
+ }
+] \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/pom.xml b/sdnr/wt-odlux/odlux/apps/connectApp/pom.xml
new file mode 100644
index 000000000..12df827e0
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/pom.xml
@@ -0,0 +1,109 @@
+<?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-connectApp</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>
+
+ <properties>
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ </properties>
+
+ <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/connectApp/src/actions/commonNetworkElementsActions.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
new file mode 100644
index 000000000..948f2aada
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
@@ -0,0 +1,141 @@
+
+/**
+ * ============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==========================================================================
+ */
+
+/**
+ * Create an update action that can distinguish whether one or the other view is currently active and update it.
+ * This action is then used for each update in the other actions and when notifications arrive.
+ * create an update action that can distinguish whether one or the other view is currently active and update it.
+ * This action is then used for each update in the other actions and when notifications arrive.
+ */
+
+import { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
+import { networkElementsReloadAction } from '../handlers/networkElementsHandler';
+import { guiCutThrough } from '../models/guiCutTrough';
+import { PanelId } from '../models/panelId';
+import { connectService } from '../services/connectService';
+
+
+export class SetPanelAction extends Action {
+ constructor(public panelId: PanelId) {
+ super();
+ }
+}
+
+export class AddWebUriList extends Action {
+ constructor(public searchedElements: guiCutThrough[], public notSearchedElements: string[], public unsupportedElements: string[], public newlySearchedElements?: string[]) {
+ super();
+ }
+}
+
+export class RemoveWebUri extends Action {
+ constructor(public element: string) {
+ super();
+ }
+}
+
+export const removeWebUriAction = (nodeId: string) => {
+ return new RemoveWebUri(nodeId);
+};
+
+export class SetWeburiSearchBusy extends Action {
+ constructor(public isbusy: boolean) {
+ super();
+ }
+}
+
+let isBusy = false;
+export const findWebUrisForGuiCutThroughAsyncAction = (networkElementIds: string[]) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) => {
+
+ // keep method from executing simultanously; state not used because change of iu isn't needed
+
+ if (isBusy)
+ return;
+ isBusy = true;
+
+ const { connect: { guiCutThrough: guiCutThrough2, networkElements } } = getState();
+
+ let notConnectedElements: string[] = [];
+ let elementsToSearch: string[] = [];
+ let prevFoundElements: string[] = [];
+ let unsupportedElements: string[] = [];
+
+ networkElementIds.forEach(id => {
+ const item = networkElements.rows.find((ne) => ne.id === id);
+ if (item) {
+ if (item.status === 'Connected') {
+
+ // if (item.coreModelCapability !== "Unsupported") {
+ // element is connected and is added to search list, if it doesn't exist already
+ const exists = guiCutThrough2.searchedElements.filter(element => element.id === id).length > 0;
+ if (!exists) {
+ elementsToSearch.push(id);
+
+ //element was found previously, but wasn't connected
+ if (guiCutThrough2.notSearchedElements.length > 0 && guiCutThrough2.notSearchedElements.includes(id)) {
+ prevFoundElements.push(id);
+ }
+ }
+ // } else {
+ // // element does not support core model and must not be searched for a weburi
+ // const id = item.id as string;
+ // const exists = guiCutThrough.unsupportedElements.filter(element => element === id).length > 0;
+ // if (!exists) {
+ // unsupportedElements.push(id);
+
+ // //element was found previously, but wasn't connected
+ // if (guiCutThrough.notSearchedElements.length > 0 && guiCutThrough.notSearchedElements.includes(id)) {
+ // prevFoundElements.push(id);
+ // }
+ // }
+ // }
+ } else {
+ // element isn't connected and cannot be searched for a weburi
+ if (!guiCutThrough2.notSearchedElements.includes(id)) {
+ notConnectedElements.push(item.id as string);
+ }
+ }
+ }
+ });
+
+
+ if (elementsToSearch.length > 0 || notConnectedElements.length > 0 || unsupportedElements.length > 0) {
+ const result = await connectService.getAllWebUriExtensionsForNetworkElementListAsync(elementsToSearch);
+ dispatcher(new AddWebUriList(result, notConnectedElements, unsupportedElements, prevFoundElements));
+ }
+ isBusy = false;
+
+};
+
+export const setPanelAction = (panelId: PanelId) => {
+ return new SetPanelAction(panelId);
+};
+
+export const updateCurrentViewAsyncAction = () => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+ const { connect: { currentOpenPanel } } = getState();
+ if (currentOpenPanel === 'NetworkElements') {
+ return dispatch(networkElementsReloadAction);
+ } else {
+ return dispatch(connectionStatusLogReloadAction);
+ }
+};
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts
new file mode 100644
index 000000000..120f9916f
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts
@@ -0,0 +1,82 @@
+/**
+ * ============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 { Module, TopologyNode } from '../models/topologyNetconf';
+import { connectService } from '../services/connectService';
+
+/**
+ * Represents the base action.
+ */
+export class BaseAction extends Action { }
+
+/**
+ * Represents an action causing the store to load all element Yang capabilities.
+ */
+export class LoadAllElementInfoAction extends BaseAction { }
+
+/**
+ * Represents an action causing the store to update element Yang capabilities.
+ */
+export class AllElementInfoLoadedAction extends BaseAction {
+ /**
+ * Initialize this instance.
+ * @param elementInfo The information of the element which is returned.
+ */
+ constructor(public elementInfo: TopologyNode | null, public error?: string) {
+ super();
+ }
+}
+
+/**
+ * Represents an action causing the store to update element Yang capabilities Module Features.
+ */
+export class AllElementInfoFeatureLoadedAction extends BaseAction {
+ /**
+ * Initialize this instance.
+ * @param elementFeatureInfo The information of the element which is returned.
+ */
+ constructor(public elementFeatureInfo: Module[] | null | undefined, public error?: string) {
+ super();
+ }
+}
+
+/**
+ * Represents an asynchronous thunk action to load all yang capabilities.
+ */
+export const loadAllInfoElementAsync = (nodeId: string) => (dispatch: Dispatch) => {
+ dispatch(new LoadAllElementInfoAction());
+ connectService.infoNetworkElement(nodeId).then(info => {
+ dispatch(new AllElementInfoLoadedAction(info));
+ }, error => {
+ dispatch(new AllElementInfoLoadedAction(null, error));
+ });
+};
+
+/**
+ * Represents an asynchronous thunk action to load all yang features.
+ */
+export const loadAllInfoElementFeaturesAsync = (nodeId: string) => (dispatch: Dispatch) => {
+ dispatch(new LoadAllElementInfoAction());
+ connectService.infoNetworkElementFeatures(nodeId).then(infoFeatures => {
+ dispatch(new AllElementInfoFeatureLoadedAction(infoFeatures));
+ }, error => {
+ dispatch(new AllElementInfoFeatureLoadedAction(null, error));
+ });
+}; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts
new file mode 100644
index 000000000..11bac10e4
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts
@@ -0,0 +1,60 @@
+/**
+ * ============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 { connectService } from '../services/connectService';
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import { AddSnackbarNotification } from '../../../../framework/src/actions/snackbarActions';
+import { updateCurrentViewAsyncAction } from './commonNetworkElementsActions';
+
+/** Represents the base action. */
+export class BaseAction extends Action { }
+
+/** Represents an action creator for a async thunk action to mount a network element/node. */
+export const mountNetworkElementAsyncActionCreator = (networkElement: NetworkElementConnection) => (dispatch: Dispatch) => {
+ return connectService.mountNetworkElement(networkElement).then((success) => {
+ if (success) {
+ dispatch(updateCurrentViewAsyncAction());
+ dispatch(new AddSnackbarNotification({ message: `Requesting mount [${networkElement.nodeId}]`, options: { variant: 'info' } }));
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Failed to mount [${networkElement.nodeId}]`, options: { variant: 'warning' } }));
+ }
+ }).catch(error => {
+ dispatch(new AddSnackbarNotification({ message: `Failed to mount [${networkElement.nodeId}]`, options: { variant: 'error' } }));
+ console.error(error);
+ });
+};
+
+/** Represents an action creator for a async thunk action to unmount a network element/node. */
+export const unmountNetworkElementAsyncActionCreator = (nodeId: string) => (dispatch: Dispatch) => {
+ return connectService.unmountNetworkElement(nodeId).then((success) => {
+ if (success) {
+ dispatch(updateCurrentViewAsyncAction());
+ dispatch(new AddSnackbarNotification({ message: `Requesting unmount [${nodeId}]`, options: { variant: 'info' } }));
+ } else {
+ dispatch(new AddSnackbarNotification({ message: `Failed to unmount [${nodeId}]`, options: { variant: 'warning' } }));
+ }
+ }).catch(error => {
+ dispatch(new AddSnackbarNotification({ message: `Failed to unmount [${nodeId}]`, options: { variant: 'error' } }));
+ console.error(error);
+ });
+};
+
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/networkElementsActions.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/networkElementsActions.ts
new file mode 100644
index 000000000..d22a6c645
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/networkElementsActions.ts
@@ -0,0 +1,60 @@
+/**
+ * ============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 { NetworkElementConnection, ConnectionStatus, UpdateNetworkElement } from '../models/networkElementConnection';
+import { connectService } from '../services/connectService';
+import { updateCurrentViewAsyncAction } from './commonNetworkElementsActions';
+import { unmountNetworkElementAsyncActionCreator } from './mountedNetworkElementsActions';
+
+/** Represents the base action. */
+export class BaseAction extends Action { }
+
+/** Represents an async thunk action creator to add an element to the network elements/nodes. */
+export const addNewNetworkElementAsyncActionCreator = (element: NetworkElementConnection) => async (dispatch: Dispatch) => {
+ await connectService.createNetworkElement({ ...element });
+ dispatch(updateCurrentViewAsyncAction());
+ dispatch(new AddSnackbarNotification({ message: `Successfully added [${element.nodeId}]`, options: { variant: 'success' } }));
+};
+
+/** Represents an async thunk action creator to edit network element/node. */
+export const editNetworkElementAsyncActionCreator = (element: UpdateNetworkElement) => async (dispatch: Dispatch) => {
+ const connectionStatus: ConnectionStatus[] = (await connectService.getNetworkElementConnectionStatus(element.id).then(ne => (ne))) || [];
+ const currentConnectionStatus = connectionStatus[0].status;
+ if (currentConnectionStatus === 'Disconnected') {
+ await connectService.deleteNetworkElement(element);
+ } else {
+ await connectService.updateNetworkElement(element);
+ }
+ dispatch(updateCurrentViewAsyncAction());
+ dispatch(new AddSnackbarNotification({ message: `Successfully modified [${element.id}]`, options: { variant: 'success' } }));
+};
+
+
+/** Represents an async thunk action creator to delete an element from network elements/nodes. */
+export const removeNetworkElementAsyncActionCreator = (element: UpdateNetworkElement) => async (dispatch: Dispatch) => {
+ await connectService.deleteNetworkElement(element);
+ await dispatch(unmountNetworkElementAsyncActionCreator(element && element.id));
+ await dispatch(updateCurrentViewAsyncAction());
+};
+
+
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/tlsKeyActions.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/tlsKeyActions.ts
new file mode 100644
index 000000000..65d23c439
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/actions/tlsKeyActions.ts
@@ -0,0 +1,59 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+import { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+
+import { TlsKeys } from '../models/networkElementConnection';
+import { connectService } from '../services/connectService';
+
+/**
+ * Represents the base action.
+ */
+export class BaseAction extends Action { }
+
+/**
+ * Represents an action causing the store to load all TLS Keys.
+ */
+export class LoadAllTlsKeyListAction extends BaseAction { }
+
+/**
+ * Represents an action causing the store to get all TLS Keys.
+ */
+export class AllTlsKeyListLoadedAction extends BaseAction {
+ /**
+ * Initialize this instance.
+ *
+ * @param gets all the tlsKey list from the database.
+ */
+ constructor(public tlsList: TlsKeys[] | null, public error?: string) {
+ super();
+ }
+}
+
+/**
+ * Represents an asynchronous thunk action to load all tlsKeys
+ */
+
+export const loadAllTlsKeyListAsync = () => async (dispatch: Dispatch) => {
+ dispatch(new LoadAllTlsKeyListAction());
+ connectService.getTlsKeys().then(TlsKeyList => {
+ dispatch(new AllTlsKeyListLoadedAction(TlsKeyList));
+ }).catch(error => {
+ dispatch(new AllTlsKeyListLoadedAction(null, error));
+ });
+};
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/assets/icons/connectAppIcon.svg b/sdnr/wt-odlux/odlux/apps/connectApp/src/assets/icons/connectAppIcon.svg
new file mode 100644
index 000000000..5aca4fae7
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/assets/icons/connectAppIcon.svg
@@ -0,0 +1,22 @@
+<!-- highstreet technologies GmbH colour scheme
+ Grey #565656
+ LBlue #36A9E1
+ DBlue #246DA2
+ Green #003F2C / #006C4B
+ Yellw #C8D400
+ Red #D81036
+-->
+
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 650 650">
+
+<g transform="translate(20,0) scale(1,1)">
+
+<path fill="#C8D400" d="M 121.5 10 c -11.5 4.1 -19.6 12.1 -23.6 23.5 c -1.8 5 -1.9 9.2 -1.9 73.9 l 0 48.5 l 37.5 0 l 37.5 0 l 0 -45.9 c 0 -40.3 -0.4 -67.9 -1 -71.2 c -2.3 -11.9 -10.6 -22.5 -21.6 -27.6 c -7.9 -3.6 -18.8 -4.1 -26.9 -1.2 z"/>
+
+<path fill="#C8D400" d="M 347.9 10 c -11.5 4.1 -19.6 12.1 -23.6 23.5 c -1.8 5 -1.9 9.2 -1.9 73.9 l 0 48.5 l 37.5 0 l 37.5 0 l 0 -45.9 c 0 -40.3 -0.4 -67.9 -1 -71.2 c -2.3 -11.9 -10.6 -22.5 -21.6 -27.6 c -7.9 -3.6 -18.8 -4.1 -26.9 -1.2 z"/>
+
+<path fill="#565656" d="m 32.5 190 c -4.9 2.2 -9.1 6.9 -10.5 11.9 c -0.7 2.4 -1 11.9 -0.8 26.3 l 0.3 22.6 l 2.9 4.1 c 4.5 6.5 9.1 8.2 22.4 8.2 l 11.2 0 l 0 17.7 c 0 35.3 3.1 59 10.5 80.3 c 21.5 61.6 70.5 105.9 135.3 122 l 4.2 1.1 l 0 57.9 c 1 27.9 4 72.9 75 75 c 177 -5.1 344 -100.1 345 -204.1 l 1 -75 c -49 124 -165 214 -337 217.1 c -5 -0.1 -7 -3.1 -7 -7.1 l 0 -63.8 l 4.2 -1.1 c 17.1 -4.4 26.1 -7.6 39.6 -14 c 51.7 -24.6 90.3 -74.2 101.7 -130.5 c 3 -14.6 4.5 -33.9 4.5 -57.7 l 0 -17.6 l 12.3 -0.4 c 11.1 -0.3 12.7 -0.5 15.9 -2.7 c 1.9 -1.3 4.6 -4 5.9 -5.9 c 2.3 -3.5 2.4 -4.2 2.7 -26.1 c 0.2 -14.4 -0.1 -23.9 -0.8 -26.3 c -1.4 -5 -5.6 -9.7 -10.5 -11.9 c -3.8 -1.8 -12.4 -1.9 -213 -1.9 c -200.6 0 -209.2 0.1 -213 1.9 z"/>
+
+
+</g>
+</svg>
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
new file mode 100644
index 000000000..6a8c92438
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
@@ -0,0 +1,99 @@
+/**
+ * ============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 Refresh from '@mui/icons-material/Refresh';
+
+import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+import { createConnectionStatusLogActions, createConnectionStatusLogProperties } from '../handlers/connectionStatusLogHandler';
+import { NetworkElementConnectionLog } from '../models/networkElementConnectionLog';
+import RefreshConnectionStatusLogDialog, { RefreshConnectionStatusLogDialogMode } from './refreshConnectionStatusLogDialog';
+
+const mapProps = (state: IApplicationStoreState) => ({
+ connectionStatusLogProperties: createConnectionStatusLogProperties(state),
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ connectionStatusLogActions: createConnectionStatusLogActions(dispatcher.dispatch),
+});
+
+const ConnectionStatusTable = MaterialTable as MaterialTableCtorType<NetworkElementConnectionLog>;
+
+type ConnectionStatusLogComponentProps = Connect<typeof mapProps, typeof mapDispatch>;
+type ConnectionStatusLogComponentState = {
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode;
+};
+
+let initialSorted = false;
+
+
+class ConnectionStatusLogComponent extends React.Component<ConnectionStatusLogComponentProps, ConnectionStatusLogComponentState > {
+ constructor(props: ConnectionStatusLogComponentProps) {
+ super(props);
+
+ this.state = {
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.None,
+ };
+ }
+
+ render(): JSX.Element {
+ const refreshConnectionStatusLogAction = {
+ icon: Refresh, tooltip: 'Refresh Connection Status Log Table', ariaLabel:'refresh', onClick: () => {
+ this.setState({
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.RefreshConnectionStatusLogTable,
+ });
+ },
+ };
+
+ return (
+ <>
+ <ConnectionStatusTable stickyHeader tableId="connection-status-table" customActionButtons={[refreshConnectionStatusLogAction]} columns={[
+ { property: 'timestamp', title: 'Timestamp', type: ColumnType.text },
+ { property: 'nodeId', title: 'Node ID', type: ColumnType.text },
+ { property: 'status', title: 'Connection Status', type: ColumnType.text },
+ ]} idProperty="id" {...this.props.connectionStatusLogActions} {...this.props.connectionStatusLogProperties} >
+ </ConnectionStatusTable>
+ <RefreshConnectionStatusLogDialog
+ mode={ this.state.refreshConnectionStatusLogEditorMode }
+ onClose={ this.onCloseRefreshConnectionStatusLogDialog }
+ />
+ </>
+ );
+ }
+
+ private onCloseRefreshConnectionStatusLogDialog = () => {
+ this.setState({
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.None,
+ });
+ };
+
+ componentDidMount() {
+ if (!initialSorted) {
+ initialSorted = true;
+ this.props.connectionStatusLogActions.onHandleExplicitRequestSort('timestamp', 'desc');
+ } else {
+ this.props.connectionStatusLogActions.onRefresh();
+ }
+ }
+}
+
+export const ConnectionStatusLog = connect(mapProps, mapDispatch)(ConnectionStatusLogComponent);
+export default ConnectionStatusLog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
new file mode 100644
index 000000000..b0db63476
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
@@ -0,0 +1,425 @@
+/**
+ * ============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 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 FormControl from '@mui/material/FormControl';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import Radio from '@mui/material/Radio';
+import RadioGroup from '@mui/material/RadioGroup';
+import Select from '@mui/material/Select';
+import TextField from '@mui/material/TextField';
+import Typography from '@mui/material/Typography';
+
+import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+
+import { removeWebUriAction } from '../actions/commonNetworkElementsActions';
+import { mountNetworkElementAsyncActionCreator, unmountNetworkElementAsyncActionCreator } from '../actions/mountedNetworkElementsActions';
+import {
+ addNewNetworkElementAsyncActionCreator, editNetworkElementAsyncActionCreator, removeNetworkElementAsyncActionCreator,
+} from '../actions/networkElementsActions';
+import { loadAllTlsKeyListAsync } from '../actions/tlsKeyActions';
+import { NetworkElementConnection, propertyOf, UpdateNetworkElement } from '../models/networkElementConnection';
+
+export enum EditNetworkElementDialogMode {
+ None = 'none',
+ EditNetworkElement = 'editNetworkElement',
+ RemoveNetworkElement = 'removeNetworkElement',
+ AddNewNetworkElement = 'addNewNetworkElement',
+ MountNetworkElement = 'mountNetworkElement',
+ UnmountNetworkElement = 'unmountNetworkElement',
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ addNewNetworkElement: async (element: NetworkElementConnection) => {
+ await dispatcher.dispatch(addNewNetworkElementAsyncActionCreator(element));
+ await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(element));
+ },
+ mountNetworkElement: (element: NetworkElementConnection) => dispatcher.dispatch(mountNetworkElementAsyncActionCreator(element)),
+ unmountNetworkElement: (element: NetworkElementConnection) => {
+ dispatcher.dispatch(unmountNetworkElementAsyncActionCreator(element && element.nodeId));
+ },
+ editNetworkElement: async (element: UpdateNetworkElement, mountElement: NetworkElementConnection) => {
+
+ const values = Object.keys(element);
+ console.log('edit element');
+ console.log(values);
+
+ //make sure properties are there in case they get renamed
+ const idProperty = propertyOf<UpdateNetworkElement>('id');
+ const isRequiredProperty = propertyOf<UpdateNetworkElement>('isRequired');
+
+
+ if (values.length === 2 && values.includes(idProperty as string) && values.includes(isRequiredProperty as string)) {
+ // do not mount network element/node, if only isRequired is changed
+ await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
+
+ } else if (!(values.length === 1 && values.includes(idProperty as string))) { //do not edit or mount network element/node , if only id was saved into object (no changes made!)
+ await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
+ await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement));
+ }
+ },
+ removeNetworkElement: async (element: UpdateNetworkElement) => {
+ await dispatcher.dispatch(removeNetworkElementAsyncActionCreator(element));
+ dispatcher.dispatch(removeWebUriAction(element.id));
+ },
+ getAvailableTlsKeys: async () => dispatcher.dispatch(loadAllTlsKeyListAsync()),
+});
+
+type DialogSettings = {
+ dialogTitle: string;
+ dialogDescription: string;
+ applyButtonText: string;
+ cancelButtonText: string;
+ enableMountIdEditor: boolean;
+ enableUsernameEditor: boolean;
+ enableExtendedEditor: boolean;
+};
+
+const settings: { [key: string]: DialogSettings } = {
+ [EditNetworkElementDialogMode.None]: {
+ dialogTitle: '',
+ dialogDescription: '',
+ applyButtonText: '',
+ cancelButtonText: '',
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+
+ [EditNetworkElementDialogMode.AddNewNetworkElement]: {
+ dialogTitle: 'Add New Node',
+ dialogDescription: 'Add this new node:',
+ applyButtonText: 'Add node',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ },
+ [EditNetworkElementDialogMode.MountNetworkElement]: {
+ dialogTitle: 'Mount Node',
+ dialogDescription: 'Mount this node:',
+ applyButtonText: 'Mount node',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [EditNetworkElementDialogMode.UnmountNetworkElement]: {
+ dialogTitle: 'Unmount Node',
+ dialogDescription: 'Unmount this node:',
+ applyButtonText: 'Unmount node',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [EditNetworkElementDialogMode.EditNetworkElement]: {
+ dialogTitle: 'Modify Node',
+ dialogDescription: 'Modify this node',
+ applyButtonText: 'Modify',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: false,
+ enableUsernameEditor: true,
+ enableExtendedEditor: false,
+ },
+ [EditNetworkElementDialogMode.RemoveNetworkElement]: {
+ dialogTitle: 'Remove Node',
+ dialogDescription: 'Do you really want to remove this node?',
+ applyButtonText: 'Remove node',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+};
+
+type EditNetworkElementDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: EditNetworkElementDialogMode;
+ initialNetworkElement: NetworkElementConnection;
+ onClose: () => void;
+ radioChecked: string;
+};
+
+type EditNetworkElementDialogComponentState = NetworkElementConnection & {
+ isNameValid: boolean;
+ isHostSet: boolean;
+ isPasswordSelected: boolean;
+ isTlsSelected: boolean;
+ radioSelected: string;
+ showPasswordTextField: boolean;
+ showTlsDropdown: boolean;
+};
+
+class EditNetworkElementDialogComponent extends React.Component<EditNetworkElementDialogComponentProps, EditNetworkElementDialogComponentState> {
+ constructor(props: EditNetworkElementDialogComponentProps) {
+ super(props);
+ this.handleRadioChange = this.handleRadioChange.bind(this);
+ // Initialization of state is partly overwritten by update via react getDerivedStateFromProps() below.
+ // Change initialization values in parent "networkElements.tsx" in "const emptyRequireNetworkElement"
+ this.state = {
+ nodeId: this.props.initialNetworkElement.nodeId,
+ isRequired: this.props.initialNetworkElement.isRequired,
+ host: this.props.initialNetworkElement.host,
+ port: this.props.initialNetworkElement.port,
+ isNameValid: true,
+ isHostSet: true,
+ isPasswordSelected: true,
+ isTlsSelected: false,
+ radioSelected: '',
+ showPasswordTextField: true,
+ showTlsDropdown: false,
+ };
+ }
+
+ public handleRadioChange = (event: any) => {
+ this.setState({
+ radioSelected: event.target.value,
+ showPasswordTextField: event.target.value === 'password',
+ showTlsDropdown: event.target.value === 'tlsKey',
+ });
+ };
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ let { showPasswordTextField, showTlsDropdown, radioSelected } = this.state;
+ radioSelected = this.state.radioSelected.length > 0 ? this.state.radioSelected : this.props.radioChecked;
+
+ if (radioSelected === 'password') {
+ radioSelected = 'password';
+ showPasswordTextField = true;
+ showTlsDropdown = false;
+ } else if (radioSelected === 'tlsKey') {
+ radioSelected = 'tlsKey';
+ showPasswordTextField = false;
+ showTlsDropdown = true;
+ }
+
+ let tlsKeysList = this.props.state.connect.availableTlsKeys ? this.props.state.connect.availableTlsKeys.tlsKeysList ? this.props.state.connect.availableTlsKeys.tlsKeysList : [] : [];
+
+ return (
+ <Dialog open={this.props.mode !== EditNetworkElementDialogMode.None}>
+ <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, '-').toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ <TextField variant="standard" disabled={!setting.enableMountIdEditor} spellCheck={false} autoFocus margin="dense"
+ id="name" label="Node ID" aria-label="name" type="text" fullWidth value={this.state.nodeId} onChange={(event) => { this.setState({ nodeId: event.target.value }); }} />
+ {!this.state.isNameValid && <Typography variant="body1" color="error">Node ID cannot be empty.</Typography>}
+ <TextField variant="standard" disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense"
+ id="ipaddress" label="Host/IP address" aria-label="ip adress" type="text" fullWidth value={this.state.host} onChange={(event) => { this.setState({ host: event.target.value }); }} />
+ {!this.state.isHostSet && <Typography variant="body1" color="error">Host/IP address cannot be empty.</Typography>}
+
+ <TextField variant="standard" disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense"
+ id="netconfport" label="NETCONF port" aria-label="netconf port" type="number" fullWidth value={this.state.port.toString()}
+ onChange={(event) => { this.setState({ port: +event.target.value }); }} />
+ {setting.enableUsernameEditor && <TextField variant="standard" disabled={!setting.enableUsernameEditor} spellCheck={false} margin="dense"
+ id="username" label="Username" aria-label="username" type="text" fullWidth value={this.state.username} onChange={(event) => { this.setState({ username: event.target.value }); }} /> || null}
+
+ {setting.enableUsernameEditor &&
+ <RadioGroup row aria-label="password-tls-key" name="password-tls-key" value={radioSelected}
+ onChange={this.handleRadioChange} >
+ <FormControlLabel aria-label="passwordSelection" value='password' control={<Radio color="secondary" />} label="Password" onChange={this.onRadioSelect} />
+ <FormControlLabel aria-label="tlsKeySelection" value='tlsKey' control={<Radio color="secondary" />} label="TlsKey" onChange={this.onRadioSelect} />
+ </RadioGroup> || null}
+
+ {setting.enableUsernameEditor && showPasswordTextField &&
+ <TextField variant="standard" disabled={!setting.enableUsernameEditor || !showPasswordTextField} spellCheck={false} margin="dense"
+ id="password" aria-label="password" type="password" fullWidth value={this.state.password}
+ onChange={(event) => { this.setState({ password: event.target.value }); }}
+ /> || null}
+
+ <FormControl variant="standard" fullWidth disabled={!setting.enableUsernameEditor}>
+ {setting.enableUsernameEditor && showTlsDropdown &&
+ <div>
+ <InputLabel htmlFor="pass">--Select tls-key--</InputLabel>
+ <Select variant="standard" disabled={!setting.enableUsernameEditor || !showTlsDropdown}
+ id="tlsKey" aria-label="tlsKey" value={this.state.tlsKey} fullWidth // displayEmpty
+ onChange={(event) => { this.setState({ tlsKey: event.target.value as any }); }}
+ inputProps={{ name: 'tlsKey', id: 'tlsKey' }} >
+ <MenuItem value={''} disabled >--Select tls-key--</MenuItem>
+ {tlsKeysList.map(tlsKey =>
+ (<MenuItem value={tlsKey.key} key={tlsKey.key} aria-label={tlsKey.key} >{tlsKey.key}</MenuItem>))}
+ </Select>
+ </div>
+ }
+ </FormControl>
+
+ <FormControl variant="standard" fullWidth disabled={!setting.enableUsernameEditor}>
+ <InputLabel htmlFor="active">Required</InputLabel>
+ <Select variant="standard" aria-label="required-selection" value={this.state.isRequired || false} onChange={(event) => {
+ this.setState({ isRequired: event.target.value as any as boolean });
+ }} inputProps={{ name: 'required', id: 'required' }} fullWidth >
+ <MenuItem value={true as any as string} aria-label="true">True</MenuItem>
+ <MenuItem value={false as any as string} aria-label="false">False</MenuItem>
+ </Select>
+ </FormControl>
+ </DialogContent>
+ <DialogActions>
+ <Button aria-label="dialog-confirm-button" onClick={(event) => {
+
+ if (this.areRequieredFieldsValid()) {
+ this.onApply({
+ isRequired: this.state.isRequired,
+ id: this.state.nodeId,
+ nodeId: this.state.nodeId,
+ host: this.state.host,
+ port: this.state.port,
+ username: this.state.username,
+ password: this.state.password,
+ tlsKey: this.state.tlsKey,
+ });
+ }
+ event.preventDefault();
+ event.stopPropagation();
+ }} color="inherit" > {setting.applyButtonText} </Button>
+ <Button aria-label="dialog-cancel-button" onClick={(event) => {
+ this.onCancel();
+ event.preventDefault();
+ event.stopPropagation();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ );
+ }
+
+ public renderTlsKeys = () => {
+ try {
+ this.props.getAvailableTlsKeys();
+ } catch (err) {
+ console.log(err);
+ }
+ };
+
+ public componentDidMount() {
+ this.renderTlsKeys();
+ }
+
+ public onRadioSelect = (e: any) => {
+ if (e.target.value == 'password') {
+ this.setState({ isPasswordSelected: true, isTlsSelected: false });
+ } else if (e.target.value == 'tlsKey') {
+ this.setState({ isPasswordSelected: false, isTlsSelected: true });
+ }
+ };
+
+ private onApply = (element: NetworkElementConnection) => {
+ if (this.props.onClose) this.props.onClose();
+ let updateElement: UpdateNetworkElement = {
+ id: this.state.nodeId,
+ };
+ if (this.state.isPasswordSelected) {
+ element.tlsKey = '';
+ } else if (this.state.isTlsSelected) { //check here
+ element.password = '';
+ }
+
+ switch (this.props.mode) {
+ case EditNetworkElementDialogMode.AddNewNetworkElement:
+ if (element) this.props.addNewNetworkElement(element);
+ this.setState({
+ radioSelected: '',
+ isPasswordSelected: true,
+ });
+ break;
+ case EditNetworkElementDialogMode.MountNetworkElement:
+ if (element) this.props.mountNetworkElement(element);
+ break;
+ case EditNetworkElementDialogMode.UnmountNetworkElement:
+ if (element) this.props.unmountNetworkElement(element);
+ break;
+ case EditNetworkElementDialogMode.EditNetworkElement:
+ if (this.props.initialNetworkElement.isRequired !== this.state.isRequired)
+ updateElement.isRequired = this.state.isRequired;
+ if (this.props.initialNetworkElement.username !== this.state.username)
+ updateElement.username = this.state.username;
+ if (this.props.initialNetworkElement.password !== this.state.password && this.state.isPasswordSelected) {
+ updateElement.password = this.state.password;
+ updateElement.tlsKey = '';
+ }
+ if (this.props.initialNetworkElement.tlsKey !== this.state.tlsKey && this.state.isTlsSelected) {
+ updateElement.tlsKey = this.state.tlsKey;
+ updateElement.password = '';
+ }
+ if (element) this.props.editNetworkElement(updateElement, element);
+ this.setState({
+ radioSelected: '',
+ });
+ break;
+ case EditNetworkElementDialogMode.RemoveNetworkElement:
+ if (element) this.props.removeNetworkElement(updateElement);
+ break;
+ }
+
+ this.setState({ password: '', username: '', tlsKey: '' });
+ this.resetRequieredFields();
+ };
+
+ private onCancel = () => {
+ if (this.props.onClose) this.props.onClose();
+ this.setState({ password: '', username: '', tlsKey: '', radioSelected: '' });
+ this.resetRequieredFields();
+ };
+
+ private resetRequieredFields() {
+ this.setState({ isNameValid: true, isHostSet: true });
+ }
+
+ private areRequieredFieldsValid() {
+ let areFieldsValid = true;
+
+ if (this.state.nodeId == undefined || this.state.nodeId.trim().length === 0) {
+ this.setState({ isNameValid: false });
+ areFieldsValid = false;
+ } else {
+ this.setState({ isNameValid: true });
+ }
+
+ if (this.state.host == undefined || this.state.host.trim().length === 0) {
+ this.setState({ isHostSet: false });
+ areFieldsValid = false;
+ } else {
+ this.setState({ isHostSet: true });
+ }
+
+ return areFieldsValid;
+ }
+
+ static getDerivedStateFromProps(props: EditNetworkElementDialogComponentProps, state: EditNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection }): EditNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection } {
+ let returnState = state;
+ if (props.initialNetworkElement !== state.initialNetworkElement) {
+ returnState = {
+ ...state,
+ ...props.initialNetworkElement,
+ initialNetworkElement: props.initialNetworkElement,
+ };
+ }
+ return returnState;
+ }
+}
+
+export const EditNetworkElementDialog = connect(undefined, mapDispatch)(EditNetworkElementDialogComponent);
+export default EditNetworkElementDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx
new file mode 100644
index 000000000..4841b9389
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx
@@ -0,0 +1,160 @@
+/**
+ * ============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 DialogTitle from '@mui/material/DialogTitle';
+
+import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import { connect, Connect } from '../../../../framework/src/flux/connect';
+
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import { AvailableCapabilities } from '../models/yangCapabilitiesType';
+
+export enum InfoNetworkElementDialogMode {
+ None = 'none',
+ InfoNetworkElement = 'infoNetworkElement',
+}
+
+const mapDispatch = () => ({
+});
+
+const InfoElementTable = MaterialTable as MaterialTableCtorType<AvailableCapabilities>;
+
+type DialogSettings = {
+ dialogTitle: string;
+ dialogDescription: string;
+ cancelButtonText: string;
+};
+
+const settings: { [key: string]: DialogSettings } = {
+ [InfoNetworkElementDialogMode.None]: {
+ dialogTitle: '',
+ dialogDescription: '',
+ cancelButtonText: '',
+ },
+ [InfoNetworkElementDialogMode.InfoNetworkElement]: {
+ dialogTitle: 'YANG Capabilities of the Node',
+ dialogDescription: '',
+ cancelButtonText: 'OK',
+ },
+};
+
+type InfoNetworkElementDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: InfoNetworkElementDialogMode;
+ initialNetworkElement: NetworkElementConnection;
+ onClose: () => void;
+};
+
+type InfoNetworkElementDialogComponentState = NetworkElementConnection;
+
+class InfoNetworkElementDialogComponent extends React.Component<InfoNetworkElementDialogComponentProps, InfoNetworkElementDialogComponentState> {
+ constructor(props: InfoNetworkElementDialogComponentProps) {
+ super(props);
+
+ this.state = {
+ nodeId: this.props.initialNetworkElement.nodeId,
+ isRequired: false,
+ host: this.props.initialNetworkElement.host,
+ port: this.props.initialNetworkElement.port,
+ };
+ }
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ const availableCapabilities = this.props.state.connect.elementInfo.elementInfo['netconf-node-topology:available-capabilities']['available-capability'];
+ let yangFeatures = this.props.state.connect.elementFeatureInfo.elementFeatureInfo;
+ let yangCapabilities: AvailableCapabilities[] = [];
+
+ availableCapabilities.forEach(value => {
+ const capabilty = value.capability;
+ const indexRevision = capabilty.indexOf('revision=');
+ const indexModule = capabilty.indexOf(')', indexRevision);
+ if (indexRevision > 0 && indexModule > 0) {
+ let moduleName = capabilty.substring(indexModule + 1);
+ let ModuleFeaturesList;
+ for (let index = 0; index < yangFeatures.length; index++) {
+ if (yangFeatures[index].name == moduleName) {
+ ModuleFeaturesList = yangFeatures[index].feature ? yangFeatures[index].feature : null;
+ break;
+ }
+ }
+ const featuresListCommaSeparated = ModuleFeaturesList ? ModuleFeaturesList.toString() : '';
+ let featuresList = featuresListCommaSeparated.replace(',', ', ');
+
+ yangCapabilities.push({
+ module: moduleName,
+ revision: capabilty.substring(indexRevision + 9, indexRevision + 19),
+ features: featuresList,
+ });
+ }
+ });
+
+ yangCapabilities = yangCapabilities.sort((a, b) => a.module === b.module ? 0 : a.module > b.module ? 1 : -1);
+
+ return (
+ <>
+ <Dialog open={this.props.mode !== InfoNetworkElementDialogMode.None} >
+ <DialogTitle id="form-dialog-title">{`${setting.dialogTitle}: "${this.state.nodeId}"`}</DialogTitle>
+ <InfoElementTable stickyHeader isPopup tableId="info-element-table" asynchronus columns={[
+ { property: 'module', title: 'YANG Capability', type: ColumnType.text, width: 900 },
+ {
+ property: 'revision', title: 'Revision', type: ColumnType.custom, customControl: ({ rowData }) => {
+ return (
+ <div>
+ <a href={`/yang-schema/${rowData.module}/${rowData.revision}`} target="_blank" > {rowData.revision} </a>
+ </div>
+ );
+ },
+ },
+ { property: 'features', title: 'Features', type: ColumnType.text, width: 500 },
+ ]} idProperty="id" rows={yangCapabilities} >
+ </InfoElementTable>
+ <DialogActions>
+ <Button aria-label="ok-button" onClick={(event) => {
+ this.onCancel();
+ event.preventDefault();
+ event.stopPropagation();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ </>
+ );
+ }
+
+ private onCancel = () => {
+ this.props.onClose();
+ };
+
+ static getDerivedStateFromProps(props: InfoNetworkElementDialogComponentProps, state: InfoNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection }): InfoNetworkElementDialogComponentState & { initialNetworkElement: NetworkElementConnection } {
+ let returnState = state;
+ if (props.initialNetworkElement !== state.initialNetworkElement) {
+ returnState = {
+ ...state,
+ ...props.initialNetworkElement,
+ initialNetworkElement: props.initialNetworkElement,
+ };
+ }
+ return returnState;
+ }
+}
+
+export const InfoNetworkElementDialog = connect(undefined, mapDispatch)(InfoNetworkElementDialogComponent);
+export default InfoNetworkElementDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx
new file mode 100644
index 000000000..1ce8f0c3b
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/networkElements.tsx
@@ -0,0 +1,314 @@
+/**
+* ============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 AddIcon from '@mui/icons-material/Add';
+import ComputerIcon from '@mui/icons-material/Computer';
+import EditIcon from '@mui/icons-material/Edit';
+import Info from '@mui/icons-material/Info';
+import LinkIcon from '@mui/icons-material/Link';
+import LinkOffIcon from '@mui/icons-material/LinkOff';
+import Refresh from '@mui/icons-material/Refresh';
+import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
+import { Divider, MenuItem, Typography } from '@mui/material';
+import { Theme } from '@mui/material/styles';
+import { WithStyles } from '@mui/styles';
+import createStyles from '@mui/styles/createStyles';
+import withStyles from '@mui/styles/withStyles';
+
+import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions';
+import { ColumnType, MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { getAccessPolicyByUrl } from '../../../../framework/src/services/restService';
+
+import { loadAllInfoElementAsync, loadAllInfoElementFeaturesAsync } from '../actions/infoNetworkElementActions';
+import { createNetworkElementsActions, createNetworkElementsProperties } from '../handlers/networkElementsHandler';
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import { ModuleSet, TopologyNode } from '../models/topologyNetconf';
+import { connectService } from '../services/connectService';
+
+import EditNetworkElementDialog, { EditNetworkElementDialogMode } from './editNetworkElementDialog';
+import InfoNetworkElementDialog, { InfoNetworkElementDialogMode } from './infoNetworkElementDialog';
+import RefreshNetworkElementsDialog, { RefreshNetworkElementsDialogMode } from './refreshNetworkElementsDialog';
+
+const styles = (theme: Theme) => createStyles({
+ connectionStatusConnected: {
+ color: 'darkgreen',
+ },
+ connectionStatusConnecting: {
+ color: 'blue',
+ },
+ connectionStatusDisconnected: {
+ color: 'red',
+ },
+ button: {
+ margin: 0,
+ padding: '6px 6px',
+ minWidth: 'unset',
+ },
+ spacer: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ display: 'inline',
+ },
+});
+
+type GetStatelessComponentProps<T> = T extends (props: infer P & { children?: React.ReactNode }) => any ? P : any;
+const MenuItemExt: React.FC<GetStatelessComponentProps<typeof MenuItem>> = (props) => {
+ const [disabled, setDisabled] = React.useState(true);
+ const onMouseDown = (ev: React.MouseEvent<HTMLElement>) => {
+ if (ev.button === 1) {
+ setDisabled(!disabled);
+ ev.preventDefault();
+ }
+ };
+ return (
+ <div onMouseDown={onMouseDown} >
+ <MenuItem {...{ ...props, disabled: props.disabled && disabled }} />
+ </div>
+ );
+};
+
+const mapProps = (state: IApplicationStoreState) => ({
+ networkElementsProperties: createNetworkElementsProperties(state),
+ applicationState: state,
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ networkElementsActions: createNetworkElementsActions(dispatcher.dispatch),
+ navigateToApplication: (applicationName: string, path?: string) => dispatcher.dispatch(new NavigateToApplication(applicationName, path)),
+ networkElementInfo: async (nodeId: string) => dispatcher.dispatch(loadAllInfoElementAsync(nodeId)),
+ networkElementFeaturesInfo: async (nodeId: string) => dispatcher.dispatch(loadAllInfoElementFeaturesAsync(nodeId)),
+});
+
+type NetworkElementsListComponentProps = WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>;
+type NetworkElementsListComponentState = {
+ networkElementToEdit: NetworkElementConnection;
+ networkElementEditorMode: EditNetworkElementDialogMode;
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode;
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode;
+ elementInfo: TopologyNode | null;
+ elementInfoFeature: ModuleSet | null;
+};
+
+const emptyRequireNetworkElement: NetworkElementConnection = { id: '', nodeId: '', host: '', port: 830, status: 'Disconnected', isRequired: true };
+let initialSorted = false;
+const NetworkElementTable = MaterialTable as MaterialTableCtorType<NetworkElementConnection>;
+
+export class NetworkElementsListComponent extends React.Component<NetworkElementsListComponentProps, NetworkElementsListComponentState> {
+
+ constructor(props: NetworkElementsListComponentProps) {
+ super(props);
+
+ this.state = {
+ networkElementToEdit: emptyRequireNetworkElement,
+ networkElementEditorMode: EditNetworkElementDialogMode.None,
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None,
+ elementInfo: null,
+ elementInfoFeature: null,
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None,
+ };
+ }
+
+ getContextMenu(rowData: NetworkElementConnection): JSX.Element[] {
+ const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id);
+ const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri);
+ const canMount = mountPolicy && mountPolicy.POST || false;
+
+ const { configuration } = this.props.applicationState as any;
+ const buttonArray = [
+ <MenuItemExt aria-label={'mount-button'} onClick={event => this.onOpenMountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkIcon /><Typography>Mount</Typography></MenuItemExt>,
+ <MenuItemExt aria-label={'unmount-button'} onClick={event => this.onOpenUnmountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkOffIcon /><Typography>Unmount</Typography></MenuItemExt>,
+ <Divider />,
+ <MenuItem aria-label={'info-button'} onClick={event => this.onOpenInfoNetworkElementDialog(event, rowData)} disabled={rowData.status !== 'Connected'} ><Info /><Typography>Info</Typography></MenuItem>,
+ <MenuItem aria-label={'edit-button'} onClick={event => this.onOpenEditNetworkElementDialog(event, rowData)}><EditIcon /><Typography>Edit</Typography></MenuItem>,
+ <MenuItem aria-label={'remove-button'} onClick={event => this.onOpenRemoveNetworkElementDialog(event, rowData)} ><RemoveIcon /><Typography>Remove</Typography></MenuItem>,
+ <Divider />,
+ <MenuItem aria-label={'inventory-button'} onClick={() => this.props.navigateToApplication('inventory', rowData.nodeId)}><Typography>Inventory</Typography></MenuItem>,
+ <Divider />,
+ <MenuItem aria-label={'fault-button'} onClick={() => this.props.navigateToApplication('fault', rowData.nodeId)} ><Typography>Fault</Typography></MenuItem>,
+ <MenuItem aria-label={'configure-button'} onClick={() => this.props.navigateToApplication('configuration', rowData.nodeId)} disabled={rowData.status === 'Connecting' || rowData.status === 'Disconnected' || !configuration}><Typography>Configure</Typography></MenuItem>,
+ <MenuItem onClick={() => this.props.navigateToApplication('accounting', rowData.nodeId)} disabled={true}><Typography>Accounting</Typography></MenuItem>,
+ <MenuItem aria-label={'performance-button'} onClick={() => this.props.navigateToApplication('performanceHistory', rowData.nodeId)}><Typography>Performance</Typography></MenuItem>,
+ <MenuItem onClick={() => this.props.navigateToApplication('security', rowData.nodeId)} disabled={true} ><Typography>Security</Typography></MenuItem>,
+ ];
+
+ if (rowData.weburi) {
+ // add an icon for gui cuttrough, if weburi is available
+ return [<MenuItem aria-label={'web-client-button'} onClick={() => window.open(rowData.weburi, '_blank')} ><ComputerIcon /><Typography>Web Client</Typography></MenuItem>].concat(buttonArray);
+ } else {
+ return buttonArray;
+ }
+ }
+
+ // private navigationCreator
+
+ render(): JSX.Element {
+ //const { classes } = this.props;
+ const { networkElementToEdit } = this.state;
+ let savedRadio = 'password';
+ if (this.state.networkElementToEdit.password && this.state.networkElementToEdit.password.length > 0) {
+ savedRadio = 'password';
+ } else if (this.state.networkElementToEdit.tlsKey && this.state.networkElementToEdit.tlsKey.length > 0) {
+ savedRadio = 'tlsKey';
+ }
+
+ // const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id);
+ // const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri);
+ // const canAdd = mountPolicy && mountPolicy.POST || false;
+ const canAdd = true;
+
+ const addRequireNetworkElementAction = {
+ icon: AddIcon, tooltip: 'Add node', ariaLabel: 'add-element', onClick: () => {
+ this.setState({
+ networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement,
+ networkElementToEdit: emptyRequireNetworkElement,
+ });
+ },
+ };
+
+ const refreshNetworkElementsAction = {
+ icon: Refresh, tooltip: 'Refresh table', ariaLabel: 'refresh', onClick: () => {
+ this.setState({
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable,
+ });
+ },
+ };
+
+ return <>
+ <NetworkElementTable stickyHeader tableId="network-element-table" customActionButtons={[refreshNetworkElementsAction, ...(canAdd ? [addRequireNetworkElementAction] : [])]} columns={[
+ { property: 'nodeId', title: 'Node ID', type: ColumnType.text },
+ { property: 'status', title: 'Connection Status', type: ColumnType.text, width:'15%' },
+ { property: 'host', title: 'Host', type: ColumnType.text },
+ { property: 'port', title: 'Port', type: ColumnType.numeric },
+ { property: 'isRequired', title: 'Required', type: ColumnType.boolean },
+ { property: 'deviceType', title: 'Type', type: ColumnType.text },
+ // { property: "coreModelCapability", title: "Core Model", type: ColumnType.text },
+ { property: 'deviceFunction', title: 'Function', type: ColumnType.text, width: '25%' },
+ ]} idProperty="id" {...this.props.networkElementsActions} {...this.props.networkElementsProperties} asynchronus createContextMenu={rowData => {
+
+ return this.getContextMenu(rowData);
+ }} >
+ </NetworkElementTable>
+ <EditNetworkElementDialog
+ initialNetworkElement={networkElementToEdit}
+ mode={this.state.networkElementEditorMode}
+ onClose={this.onCloseEditNetworkElementDialog}
+ radioChecked={savedRadio}
+ />
+ <RefreshNetworkElementsDialog
+ mode={this.state.refreshNetworkElementsEditorMode}
+ onClose={this.onCloseRefreshNetworkElementsDialog}
+ />
+ <InfoNetworkElementDialog
+ initialNetworkElement={networkElementToEdit}
+ mode={this.state.infoNetworkElementEditorMode}
+ onClose={this.onCloseInfoNetworkElementDialog}
+ />
+ </>;
+ }
+
+ public componentDidMount() {
+ if (!initialSorted) {
+ initialSorted = true;
+ this.props.networkElementsActions.onHandleRequestSort('node-id');
+ } else {
+ this.props.networkElementsActions.onRefresh();
+ }
+ }
+
+ private onOpenAddNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement,
+ });
+ };
+
+ private onOpenRemoveNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.RemoveNetworkElement,
+ });
+ };
+
+ private onOpenEditNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ //let radioSaved;
+ //if (element.password && element.password.length > 0)
+ // radioSaved = 'password';
+ //else if (element.tlsKey && element.tlsKey.length > 0)
+ // radioSaved = 'tlsKey';
+ this.setState({
+ networkElementToEdit: {
+ nodeId: element.nodeId,
+ isRequired: element.isRequired,
+ host: element.host,
+ port: element.port,
+ username: element.username,
+ password: element.password,
+ tlsKey: element.tlsKey,
+ },
+ networkElementEditorMode: EditNetworkElementDialogMode.EditNetworkElement,
+ });
+ };
+
+ private onOpenUnmountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.UnmountNetworkElement,
+ });
+ };
+
+ private onOpenMountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.MountNetworkElement,
+ });
+ };
+
+ private onOpenInfoNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.props.networkElementInfo(element.nodeId);
+ this.props.networkElementFeaturesInfo(element.nodeId);
+ this.setState({
+ networkElementToEdit: element,
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode.InfoNetworkElement,
+ });
+ };
+
+ private onCloseEditNetworkElementDialog = () => {
+ this.setState({
+ networkElementEditorMode: EditNetworkElementDialogMode.None,
+ networkElementToEdit: emptyRequireNetworkElement,
+ });
+ };
+
+ private onCloseInfoNetworkElementDialog = () => {
+ this.setState({
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None,
+ networkElementToEdit: emptyRequireNetworkElement,
+ });
+ };
+
+ private onCloseRefreshNetworkElementsDialog = () => {
+ this.setState({
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None,
+ });
+ };
+}
+
+export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent));
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx
new file mode 100644
index 000000000..a4aea7f82
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx
@@ -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 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 { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+
+import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
+import { ConnectionStatusLogType } from '../models/connectionStatusLog';
+
+export enum RefreshConnectionStatusLogDialogMode {
+ None = 'none',
+ RefreshConnectionStatusLogTable = 'RefreshConnectionStatusLogTable',
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ refreshConnectionStatusLog: () => dispatcher.dispatch(connectionStatusLogReloadAction),
+});
+
+type DialogSettings = {
+ dialogTitle: string;
+ dialogDescription: string;
+ applyButtonText: string;
+ cancelButtonText: string;
+ enableMountIdEditor: boolean;
+ enableUsernameEditor: boolean;
+ enableExtendedEditor: boolean;
+};
+
+const settings: { [key: string]: DialogSettings } = {
+ [RefreshConnectionStatusLogDialogMode.None]: {
+ dialogTitle: '',
+ dialogDescription: '',
+ applyButtonText: '',
+ cancelButtonText: '',
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [RefreshConnectionStatusLogDialogMode.RefreshConnectionStatusLogTable]: {
+ dialogTitle: 'Do you want to refresh the Connection Status Log table?',
+ dialogDescription: '',
+ applyButtonText: 'Yes',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ },
+};
+
+type RefreshConnectionStatusLogDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: RefreshConnectionStatusLogDialogMode;
+ onClose: () => void;
+};
+
+type RefreshConnectionStatusLogDialogComponentState = ConnectionStatusLogType & { isNameValid: boolean; isHostSet: boolean };
+
+class RefreshConnectionStatusLogDialogComponent extends React.Component<RefreshConnectionStatusLogDialogComponentProps, RefreshConnectionStatusLogDialogComponentState> {
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ return (
+ <Dialog open={this.props.mode !== RefreshConnectionStatusLogDialogMode.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={() => {
+ this.onRefresh();
+ }} color="inherit" > {setting.applyButtonText} </Button>
+ <Button aria-label="dialog-cancel-button" onClick={() => {
+ this.onCancel();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ );
+ }
+
+ private onRefresh = () => {
+ this.props.refreshConnectionStatusLog();
+ this.props.onClose();
+ };
+
+ private onCancel = () => {
+ this.props.onClose();
+ };
+}
+
+export const RefreshConnectionStatusLogDialog = connect(undefined, mapDispatch)(RefreshConnectionStatusLogDialogComponent);
+export default RefreshConnectionStatusLogDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx
new file mode 100644
index 000000000..e41fd27aa
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx
@@ -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 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 { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+
+import { networkElementsReloadAction } from '../handlers/networkElementsHandler';
+import { NetworkElementConnection } from '../models/networkElementConnection';
+
+export enum RefreshNetworkElementsDialogMode {
+ None = 'none',
+ RefreshNetworkElementsTable = 'RefreshNetworkElementsTable',
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ refreshNetworkElement: () => dispatcher.dispatch(networkElementsReloadAction),
+});
+
+type DialogSettings = {
+ dialogTitle: string;
+ dialogDescription: string;
+ applyButtonText: string;
+ cancelButtonText: string;
+ enableMountIdEditor: boolean;
+ enableUsernameEditor: boolean;
+ enableExtendedEditor: boolean;
+};
+
+const settings: { [key: string]: DialogSettings } = {
+ [RefreshNetworkElementsDialogMode.None]: {
+ dialogTitle: '',
+ dialogDescription: '',
+ applyButtonText: '',
+ cancelButtonText: '',
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable]: {
+ dialogTitle: 'Do you want to refresh the nodes table?',
+ dialogDescription: '',
+ applyButtonText: 'Yes',
+ cancelButtonText: 'Cancel',
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ },
+};
+
+type RefreshNetworkElementsDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: RefreshNetworkElementsDialogMode;
+ onClose: () => void;
+};
+
+type RefreshNetworkElementsDialogComponentState = NetworkElementConnection & { isNameValid: boolean; isHostSet: boolean };
+
+class RefreshNetworkElementsDialogComponent extends React.Component<RefreshNetworkElementsDialogComponentProps, RefreshNetworkElementsDialogComponentState> {
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ return (
+ <Dialog open={this.props.mode !== RefreshNetworkElementsDialogMode.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={() => {
+ this.onRefresh();
+ }} color="inherit" > {setting.applyButtonText} </Button>
+ <Button aria-label="dialog-cancel-button" onClick={() => {
+ this.onCancel();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ );
+ }
+
+ private onRefresh = () => {
+ this.props.refreshNetworkElement();
+ this.props.onClose();
+ };
+
+ private onCancel = () => {
+ this.props.onClose();
+ };
+}
+
+export const RefreshNetworkElementsDialog = connect(undefined, mapDispatch)(RefreshNetworkElementsDialogComponent);
+export default RefreshNetworkElementsDialog; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
new file mode 100644
index 000000000..b386dcdef
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
@@ -0,0 +1,100 @@
+/**
+ * ============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 { IActionHandler } from '../../../../framework/src/flux/action';
+import { combineActionHandler } from '../../../../framework/src/flux/middleware';
+
+import { AddWebUriList, RemoveWebUri, SetPanelAction } from '../actions/commonNetworkElementsActions';
+import { guiCutThrough } from '../models/guiCutTrough';
+import { PanelId } from '../models/panelId';
+import { connectionStatusLogActionHandler, IConnectionStatusLogState } from './connectionStatusLogHandler';
+import { IInfoNetworkElementFeaturesState, IInfoNetworkElementsState, infoNetworkElementFeaturesActionHandler, infoNetworkElementsActionHandler } from './infoNetworkElementHandler';
+import { INetworkElementsState, networkElementsActionHandler } from './networkElementsHandler';
+import { availableTlsKeysActionHandler, IAvailableTlsKeysState } from './tlsKeyHandler';
+
+export interface IConnectAppStoreState {
+ networkElements: INetworkElementsState;
+ connectionStatusLog: IConnectionStatusLogState;
+ currentOpenPanel: PanelId;
+ elementInfo: IInfoNetworkElementsState;
+ elementFeatureInfo: IInfoNetworkElementFeaturesState;
+ guiCutThrough: guiCutThroughState;
+ availableTlsKeys: IAvailableTlsKeysState;
+}
+
+const currentOpenPanelHandler: IActionHandler<PanelId> = (state = null, action) => {
+ if (action instanceof SetPanelAction) {
+ state = action.panelId;
+ }
+ return state;
+};
+
+interface guiCutThroughState {
+ searchedElements: guiCutThrough[];
+ notSearchedElements: string[];
+ unsupportedElements: string[];
+}
+
+const guiCutThroughHandler: IActionHandler<guiCutThroughState> = (state = { searchedElements: [], notSearchedElements: [], unsupportedElements: [] }, action) => {
+ if (action instanceof AddWebUriList) {
+ let notSearchedElements: string[];
+ let searchedElements: guiCutThrough[];
+ let unsupportedElements: string[];
+
+ notSearchedElements = state.notSearchedElements.concat(action.notSearchedElements);
+ unsupportedElements = state.unsupportedElements.concat(action.unsupportedElements);
+
+ //remove elements, which were just searched
+ if (action.newlySearchedElements) {
+ action.newlySearchedElements.forEach(item => {
+ notSearchedElements = notSearchedElements.filter(id => id !== item);
+ });
+ }
+
+ searchedElements = state.searchedElements.concat(action.searchedElements);
+
+ state = { searchedElements: searchedElements, notSearchedElements: notSearchedElements, unsupportedElements: unsupportedElements };
+
+ } else if (action instanceof RemoveWebUri) {
+ const nodeId = action.element;
+ const webUris = state.searchedElements.filter(item => item.id !== nodeId);
+ const knownElements = state.notSearchedElements.filter(item => item !== nodeId);
+ const unsupportedElement = state.unsupportedElements.filter(item => item != nodeId);
+ state = { notSearchedElements: knownElements, searchedElements: webUris, unsupportedElements: unsupportedElement };
+ }
+ return state;
+};
+
+declare module '../../../../framework/src/store/applicationStore' {
+ interface IApplicationStoreState {
+ connect: IConnectAppStoreState;
+ }
+}
+
+const actionHandlers = {
+ networkElements: networkElementsActionHandler,
+ connectionStatusLog: connectionStatusLogActionHandler,
+ currentOpenPanel: currentOpenPanelHandler,
+ elementInfo: infoNetworkElementsActionHandler,
+ elementFeatureInfo: infoNetworkElementFeaturesActionHandler,
+ guiCutThrough: guiCutThroughHandler,
+ availableTlsKeys: availableTlsKeysActionHandler,
+};
+
+export const connectAppRootHandler = combineActionHandler<IConnectAppStoreState>(actionHandlers);
+export default connectAppRootHandler;
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts
new file mode 100644
index 000000000..264b6c198
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.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 { NetworkElementConnectionLog } from '../models/networkElementConnectionLog';
+
+export interface IConnectionStatusLogState extends IExternalTableState<NetworkElementConnectionLog> { }
+
+// create eleactic search material data fetch handler
+const connectionStatusLogSearchHandler = createSearchDataHandler<NetworkElementConnectionLog>('connectionlog');
+
+export const {
+ actionHandler: connectionStatusLogActionHandler,
+ createActions: createConnectionStatusLogActions,
+ createProperties: createConnectionStatusLogProperties,
+ reloadAction: connectionStatusLogReloadAction,
+
+ // set value action, to change a value
+} = createExternal<NetworkElementConnectionLog>(connectionStatusLogSearchHandler, appState => appState.connect.connectionStatusLog);
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.ts
new file mode 100644
index 000000000..692e63a5c
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.ts
@@ -0,0 +1,92 @@
+/**
+ * ============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 { IActionHandler } from '../../../../framework/src/flux/action';
+
+import { AllElementInfoFeatureLoadedAction, AllElementInfoLoadedAction, LoadAllElementInfoAction } from '../actions/infoNetworkElementActions';
+import { Module, TopologyNode } from '../models/topologyNetconf';
+
+export interface IInfoNetworkElementsState {
+ elementInfo: TopologyNode;
+ busy: boolean;
+}
+
+export interface IInfoNetworkElementFeaturesState {
+ elementFeatureInfo: Module[];
+ busy: boolean;
+}
+
+const infoNetworkElementsStateInit: IInfoNetworkElementsState = {
+ elementInfo: {
+ 'node-id': '',
+ 'netconf-node-topology:available-capabilities': {
+ 'available-capability': [],
+ },
+ },
+ busy: false,
+};
+
+const infoNetworkElementFeaturesStateInit: IInfoNetworkElementFeaturesState = {
+ elementFeatureInfo: [],
+ busy: false,
+};
+
+export const infoNetworkElementsActionHandler: IActionHandler<IInfoNetworkElementsState> = (state = infoNetworkElementsStateInit, action) => {
+ if (action instanceof LoadAllElementInfoAction) {
+ state = {
+ ...state,
+ busy: true,
+ };
+ } else if (action instanceof AllElementInfoLoadedAction) {
+ if (!action.error && action.elementInfo) {
+ state = {
+ ...state,
+ elementInfo: action.elementInfo,
+ busy: false,
+ };
+ } else {
+ state = {
+ ...state,
+ busy: false,
+ };
+ }
+ }
+ return state;
+};
+
+export const infoNetworkElementFeaturesActionHandler: IActionHandler<IInfoNetworkElementFeaturesState> = (state = infoNetworkElementFeaturesStateInit, action) => {
+ if (action instanceof LoadAllElementInfoAction) {
+ state = {
+ ...state,
+ busy: true,
+ };
+ } else if (action instanceof AllElementInfoFeatureLoadedAction) {
+ if (!action.error && action.elementFeatureInfo) {
+ state = {
+ ...state,
+ elementFeatureInfo: action.elementFeatureInfo,
+ busy: false,
+ };
+ } else {
+ state = {
+ ...state,
+ busy: false,
+ };
+ }
+ }
+ return state;
+}; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
new file mode 100644
index 000000000..42d2824b9
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
@@ -0,0 +1,64 @@
+/**
+ * ============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 { getAccessPolicyByUrl } from '../../../../framework/src/services/restService';
+import { createSearchDataHandler } from '../../../../framework/src/utilities/elasticSearch';
+
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import { connectService } from '../services/connectService';
+
+export interface INetworkElementsState extends IExternalTableState<NetworkElementConnection> { }
+
+// create eleactic search material data fetch handler
+const networkElementsSearchHandler = createSearchDataHandler<NetworkElementConnection>('network-element-connection');
+
+export const {
+ actionHandler: networkElementsActionHandler,
+ createActions: createNetworkElementsActions,
+ createProperties: createNetworkElementsProperties,
+ reloadAction: networkElementsReloadAction,
+
+ // set value action, to change a value
+} = createExternal<NetworkElementConnection>(networkElementsSearchHandler, appState => {
+
+ const webUris = appState.connect.guiCutThrough.searchedElements;
+ // add weburi links, if element is connected & weburi available
+ if (appState.connect.networkElements.rows && webUris.length > 0) {
+
+ appState.connect.networkElements.rows.forEach(element => {
+
+ if (element.status === 'Connected') {
+ const webUri = webUris.find(item => item.id === element.id as string);
+ if (webUri) {
+ element.weburi = webUri.weburi;
+ element.isWebUriUnreachable = false;
+ } else {
+ element.isWebUriUnreachable = true;
+ }
+ }
+ });
+ }
+
+ return appState.connect.networkElements;
+}, (ne) => {
+ if (!ne || !ne.id) return true;
+ const neUrl = connectService.getNetworkElementUri(ne.id);
+ const policy = getAccessPolicyByUrl(neUrl);
+ return !(policy.GET || policy.POST);
+});
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/tlsKeyHandler.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/tlsKeyHandler.ts
new file mode 100644
index 000000000..20badcba0
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/handlers/tlsKeyHandler.ts
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+import { IActionHandler } from '../../../../framework/src/flux/action';
+
+import { AllTlsKeyListLoadedAction, LoadAllTlsKeyListAction } from '../actions/tlsKeyActions';
+import { TlsKeys } from '../models/networkElementConnection';
+
+export interface IAvailableTlsKeysState {
+ tlsKeysList: TlsKeys[];
+ busy: boolean;
+}
+
+const tlsKeysStateInit: IAvailableTlsKeysState = {
+ tlsKeysList: [],
+ busy: false,
+};
+
+export const availableTlsKeysActionHandler: IActionHandler<IAvailableTlsKeysState> = (state = tlsKeysStateInit, action) => {
+ if (action instanceof LoadAllTlsKeyListAction) {
+ state = {
+ ...state,
+ busy: true,
+ };
+
+ } else if (action instanceof AllTlsKeyListLoadedAction) {
+ if (!action.error && action.tlsList) {
+ state = {
+ ...state,
+ tlsKeysList: action.tlsList,
+ busy: false,
+ };
+ } else {
+ state = {
+ ...state,
+ busy: false,
+ };
+ }
+ }
+ return state;
+}; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/index.html b/sdnr/wt-odlux/odlux/apps/connectApp/src/index.html
new file mode 100644
index 000000000..1a16876c9
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/index.html
@@ -0,0 +1,28 @@
+<!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>connectApp</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", "connectApp", "faultApp", "inventoryApp", "configurationApp"], function (app, connectApp, faultApp, inventoryApp, configurationApp) {
+ connectApp.register();
+ faultApp.register();
+ inventoryApp.register();
+ app("./app.tsx").configureApplication({ authentication:"basic", enablePolicy: false, transportpceUrl:"http://test.de"});
+ app("./app.tsx").runApplication();
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/connectionStatusLog.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/connectionStatusLog.ts
new file mode 100644
index 000000000..82b49a081
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/connectionStatusLog.ts
@@ -0,0 +1,27 @@
+/**
+ * ============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 ConnectionStatusLogType = {
+ _id: string;
+ elementStatus: string;
+ timeStamp: string;
+ objectId: string;
+ type: string;
+ newValue: string;
+};
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/guiCutTrough.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/guiCutTrough.ts
new file mode 100644
index 000000000..0fd46a82d
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/guiCutTrough.ts
@@ -0,0 +1,22 @@
+/**
+ * ============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 guiCutThrough = {
+ id: string;
+ weburi?: string;
+}; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementBase.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementBase.ts
new file mode 100644
index 000000000..a46a30e2b
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementBase.ts
@@ -0,0 +1,22 @@
+/**
+ * ============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 NetworkElementBaseType = {
+ mountId: string;
+ host: string;
+ port: number;
+}; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnection.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnection.ts
new file mode 100644
index 000000000..bb076c720
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnection.ts
@@ -0,0 +1,69 @@
+/**
+ * ============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 NetworkElementConnection = {
+ id?: string;
+ nodeId: string;
+ isRequired: boolean;
+ host: string;
+ port: number;
+ username?: string;
+ password?: string;
+ tlsKey?: string;
+ weburi?: string;
+ isWebUriUnreachable?: boolean;
+ status?: 'Connected' | 'mounted' | 'unmounted' | 'Connecting' | 'Disconnected' | 'idle';
+ coreModelCapability?: string;
+ deviceType?: string;
+ deviceFunction?: string;
+ nodeDetails?: {
+ availableCapabilites: {
+ capabilityOrigin: string;
+ capability: string;
+ }[];
+ unavailableCapabilities: {
+ failureReason: string;
+ capability: string;
+ }[];
+ };
+};
+
+
+export type UpdateNetworkElement = {
+ id: string;
+ isRequired?: boolean;
+ username?: string;
+ password?: string;
+ tlsKey?: string;
+};
+
+export type ConnectionStatus = {
+ status: string;
+};
+
+export type TlsKeys = {
+ key: string;
+};
+
+
+/**
+ * Checks if a object has a given propertyname, if yes, the name is returned as string.
+ * @throws at compile time if property is not available
+ * @param name propertyname
+ */
+export const propertyOf = <TObj>(name: keyof TObj) => name; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts
new file mode 100644
index 000000000..4b4e28325
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts
@@ -0,0 +1,25 @@
+/**
+ * ============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 NetworkElementConnectionLog = {
+ id: string;
+ nodeId: string;
+ status: 'connected' | 'mounted' | 'unmounted' | 'connecting' | 'disconnected' | 'idle';
+ timestamp: string;
+};
+
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/panelId.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/panelId.ts
new file mode 100644
index 000000000..2861f107f
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/panelId.ts
@@ -0,0 +1,19 @@
+/**
+ * ============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 PanelId = null | 'NetworkElements' | 'ConnectionStatusLog'; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/topologyNetconf.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/topologyNetconf.ts
new file mode 100644
index 000000000..85a1a71fd
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/topologyNetconf.ts
@@ -0,0 +1,59 @@
+/**
+ * ============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 interface AvailableCapability {
+ 'capability-origin': string;
+ capability: string;
+}
+
+export interface NetconfNodeTopologyAvailableCapabilities {
+ 'available-capability': AvailableCapability[];
+}
+
+export interface TopologyNode {
+ 'node-id': string;
+ 'netconf-node-topology:available-capabilities': NetconfNodeTopologyAvailableCapabilities;
+}
+
+export interface Topology {
+ 'topology-id': string;
+ 'network-topology:node': TopologyNode[];
+}
+
+/**
+ * Represents the type of the features of the Module.
+ */
+export interface Module {
+ feature?: string[];
+ location?: string[];
+ name: string;
+ namespace?: string;
+ revision?: string;
+}
+
+export interface ModuleFeatures {
+ module: Module[];
+}
+
+export interface ModuleSet {
+ 'module-set': ModuleFeatures[];
+}
+
+export interface FeatureTopology {
+ 'ietf-yang-library:yang-library' : ModuleSet;
+}
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts
new file mode 100644
index 000000000..b69993f7d
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts
@@ -0,0 +1,24 @@
+/**
+ * ============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 AvailableCapabilities = {
+ id?: string;
+ module: string;
+ revision: string;
+ features: string;
+}; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/pluginConnect.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/pluginConnect.tsx
new file mode 100644
index 000000000..c2907166c
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/pluginConnect.tsx
@@ -0,0 +1,109 @@
+/**
+ * ============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 { Redirect, Route, RouteComponentProps, Switch, withRouter } from 'react-router-dom';
+
+import { AddSnackbarNotification } from '../../../framework/src/actions/snackbarActions';
+import { connect, Connect, IDispatcher } from '../../../framework/src/flux/connect';
+import applicationManager from '../../../framework/src/services/applicationManager';
+import { IFormatedMessage, subscribe } from '../../../framework/src/services/notificationService';
+import { IApplicationStoreState } from '../../../framework/src/store/applicationStore';
+
+import { findWebUrisForGuiCutThroughAsyncAction, SetPanelAction, updateCurrentViewAsyncAction } from './actions/commonNetworkElementsActions';
+import { NetworkElementsList } from './components/networkElements';
+import connectAppRootHandler from './handlers/connectAppRootHandler';
+import { createNetworkElementsActions, createNetworkElementsProperties, networkElementsReloadAction } from './handlers/networkElementsHandler';
+import { PanelId } from './models/panelId';
+import ConnectApplication from './views/connectView';
+
+const appIcon = require('./assets/icons/connectAppIcon.svg'); // select app icon
+
+let currentStatus: string | undefined = undefined;
+
+const mapProps = (state: IApplicationStoreState) => ({
+ networkElementDashboardProperties: createNetworkElementsProperties(state),
+});
+
+const mapDisp = (dispatcher: IDispatcher) => ({
+ networkElementsDashboardActions: createNetworkElementsActions(dispatcher.dispatch, true),
+ setCurrentPanel: (panelId: PanelId) => dispatcher.dispatch(new SetPanelAction(panelId)),
+});
+
+const ConnectApplicationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComponentProps<{ status?: string }> & Connect<typeof mapProps, typeof mapDisp>) => {
+
+ // TODO: move into useEffect!
+ if (currentStatus !== props.match.params.status) {
+ currentStatus = props.match.params.status || undefined;
+ window.setTimeout(() => {
+ if (currentStatus) {
+ props.setCurrentPanel('NetworkElements');
+ props.networkElementsDashboardActions.onFilterChanged('status', currentStatus);
+ if (!props.networkElementDashboardProperties.showFilter) {
+ props.networkElementsDashboardActions.onToggleFilter(false);
+ props.networkElementsDashboardActions.onRefresh();
+ } else
+ props.networkElementsDashboardActions.onRefresh();
+ }
+ });
+ }
+ return (
+ <NetworkElementsList />
+ );
+});
+
+
+const App = withRouter((props: RouteComponentProps) => (
+ <Switch>
+ <Route path={`${props.match.path}/connectionStatus/:status?`} component={ConnectApplicationRouteAdapter} />
+ <Route path={`${props.match.path}`} component={ConnectApplication} />
+ <Redirect to={`${props.match.path}`} />
+ </Switch>
+));
+
+export function register() {
+ const applicationApi = applicationManager.registerApplication({
+ name: 'connect',
+ icon: appIcon,
+ rootComponent: App,
+ rootActionHandler: connectAppRootHandler,
+ menuEntry: 'Connect',
+ });
+
+ // subscribe to the websocket notifications
+ subscribe<IFormatedMessage>(['object-creation-notification', 'object-deletion-notification', 'attribute-value-changed-notification'], (msg => {
+ const store = applicationApi.applicationStore;
+ if (msg && msg.type.type === 'object-creation-notification' && store) {
+ store.dispatch(new AddSnackbarNotification({ message: `Adding node [${msg.data['object-id-ref']}]`, options: { variant: 'info' } }));
+ } else if (msg && (msg.type.type === 'object-deletion-notification' || msg.type.type === 'attribute-value-changed-notification') && store) {
+ store.dispatch(new AddSnackbarNotification({ message: `Updating node [${msg.data['object-id-ref']}]`, options: { variant: 'info' } }));
+ }
+ if (store) {
+ store.dispatch(updateCurrentViewAsyncAction() as any).then(() => {
+ if (msg['node-id']) {
+ store.dispatch(findWebUrisForGuiCutThroughAsyncAction([msg['node-id']]));
+ }
+ });
+ }
+ }));
+
+ applicationApi.applicationStoreInitialized.then(store => {
+ store.dispatch(networkElementsReloadAction);
+ });
+
+} \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/services/connectService.ts b/sdnr/wt-odlux/odlux/apps/connectApp/src/services/connectService.ts
new file mode 100644
index 000000000..1d74f859a
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/services/connectService.ts
@@ -0,0 +1,305 @@
+/**
+ * ============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 { requestRest } from '../../../../framework/src/services/restService';
+import { NetworkElementConnection, ConnectionStatus, UpdateNetworkElement } from '../models/networkElementConnection';
+import { TlsKeys } from '../models/networkElementConnection';
+import { convertPropertyNames, replaceUpperCase } from '../../../../framework/src/utilities/yangHelper';
+import { Result } from '../../../../framework/src/models/elasticSearch';
+
+import { FeatureTopology, Topology, TopologyNode, Module } from '../models/topologyNetconf';
+import { guiCutThrough } from '../models/guiCutTrough';
+
+/**
+* Represents a web api accessor service for all network element/node actions.
+*/
+class ConnectService {
+ public getNetworkElementUri = (nodeId: string) => '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId;
+
+ public getNetworkElementConnectDataProviderUri = (operation: 'create' | 'update' | 'delete') => `/rests/operations/data-provider:${operation}-network-element-connection`;
+
+ public getAllWebUriExtensionsForNetworkElementListUri = (nodeId: string) => this.getNetworkElementUri(nodeId) + '/yang-ext:mount/core-model:network-element';
+
+ public getNetworkElementYangLibraryFeature = (nodeId: string) => '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId + '/yang-ext:mount/ietf-yang-library:yang-library?content=nonconfig';
+
+ /**
+ * Inserts a network element/node.
+ */
+ public async createNetworkElement(element: NetworkElementConnection): Promise<NetworkElementConnection | null> {
+ const path = this.getNetworkElementConnectDataProviderUri('create');
+ const result = await requestRest<NetworkElementConnection>(path, {
+ method: 'POST', body: JSON.stringify(convertPropertyNames({ 'data-provider:input': element }, replaceUpperCase)),
+ });
+ return result || null;
+ }
+
+ /**
+ * Updates a network element/node.
+ */
+ public async updateNetworkElement(element: UpdateNetworkElement): Promise<NetworkElementConnection | null> {
+ const path = this.getNetworkElementConnectDataProviderUri('update');
+ const result = await requestRest<NetworkElementConnection>(path, {
+ method: 'POST', body: JSON.stringify(convertPropertyNames({ 'data-provider:input': element }, replaceUpperCase)),
+ });
+ return result || null;
+ }
+
+ /**
+ * Deletes a network element/node.
+ */
+ public async deleteNetworkElement(element: UpdateNetworkElement): Promise<NetworkElementConnection | null> {
+ const query = {
+ 'id': element.id,
+ };
+ const path = this.getNetworkElementConnectDataProviderUri('delete');
+ const result = await requestRest<NetworkElementConnection>(path, {
+ method: 'POST', body: JSON.stringify(convertPropertyNames({ 'data-provider:input': query }, replaceUpperCase)),
+ });
+ return result || null;
+ }
+
+ /** Mounts network element/node */
+ public async mountNetworkElement(networkElement: NetworkElementConnection): Promise<boolean> {
+ const path = this.getNetworkElementUri(networkElement.nodeId);
+ const mountXml = [
+ '<node xmlns="urn:TBD:params:xml:ns:yang:network-topology">',
+ `<node-id>${networkElement.nodeId}</node-id>`,
+ `<host xmlns="urn:opendaylight:netconf-node-topology">${networkElement.host}</host>`,
+ `<port xmlns="urn:opendaylight:netconf-node-topology">${networkElement.port}</port>`,
+ `<username xmlns="urn:opendaylight:netconf-node-topology">${networkElement.username}</username>`,
+ `<password xmlns="urn:opendaylight:netconf-node-topology">${networkElement.password}</password>`,
+ ' <tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>',
+
+ ' <!-- non-mandatory fields with default values, you can safely remove these if you do not wish to override any of these values-->',
+ ' <reconnect-on-changed-schema xmlns="urn:opendaylight:netconf-node-topology">false</reconnect-on-changed-schema>',
+ ' <connection-timeout-millis xmlns="urn:opendaylight:netconf-node-topology">20000</connection-timeout-millis>',
+ ' <max-connection-attempts xmlns="urn:opendaylight:netconf-node-topology">100</max-connection-attempts>',
+ ' <between-attempts-timeout-millis xmlns="urn:opendaylight:netconf-node-topology">2000</between-attempts-timeout-millis>',
+ ' <sleep-factor xmlns="urn:opendaylight:netconf-node-topology">1.5</sleep-factor>',
+
+ ' <!-- keepalive-delay set to 0 turns off keepalives-->',
+ ' <keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">120</keepalive-delay>',
+ '</node>'].join('');
+
+ const tlsXml = [
+ '<node xmlns="urn:TBD:params:xml:ns:yang:network-topology">',
+ `<node-id>${networkElement.nodeId}</node-id>`,
+ '<key-based xmlns="urn:opendaylight:netconf-node-topology">',
+ `<key-id xmlns="urn:opendaylight:netconf-node-topology">${networkElement.tlsKey}</key-id>`,
+ `<username xmlns="urn:opendaylight:netconf-node-topology">${networkElement.username}</username>`,
+ '</key-based>',
+ `<host xmlns="urn:opendaylight:netconf-node-topology">${networkElement.host}</host>`,
+ `<port xmlns="urn:opendaylight:netconf-node-topology">${networkElement.port}</port>`,
+ '<tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>',
+ '<protocol xmlns="urn:opendaylight:netconf-node-topology">',
+ '<name xmlns="urn:opendaylight:netconf-node-topology">TLS</name>',
+ ' </protocol>',
+ '<max-connection-attempts xmlns="urn:opendaylight:netconf-node-topology">2</max-connection-attempts>',
+ '</node>'].join('');
+ let bodyXml;
+ if (networkElement.password) {
+ bodyXml = mountXml;
+ } else {
+ bodyXml = tlsXml;
+ }
+
+ try {
+ const result = await requestRest<string>(path, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/xml',
+ 'Accept': 'application/xml',
+ },
+ body: bodyXml,
+ });
+ // expect an empty answer
+ return result !== null;
+ } catch {
+ return false;
+ }
+ }
+
+ /** Unmounts a network element by its id. */
+ public async unmountNetworkElement(nodeId: string): Promise<boolean> {
+ const path = this.getNetworkElementUri(nodeId);
+
+ try {
+ const result = await requestRest<string>(path, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/xml',
+ 'Accept': 'application/xml',
+ },
+ });
+ // expect an empty answer
+ return result !== null;
+
+ } catch {
+ return false;
+ }
+ }
+
+ /** Yang capabilities of the selected network element/node */
+ public async infoNetworkElement(nodeId: string): Promise<TopologyNode | null> {
+ const path = this.getNetworkElementUri(nodeId);
+ const topologyRequestPomise = requestRest<Topology>(path, { method: 'GET' });
+
+ return topologyRequestPomise && topologyRequestPomise.then(result => {
+ return result && result['network-topology:node'] && result['network-topology:node'][0] || null;
+ });
+ }
+
+
+ /** Yang features of the selected network element/node module */
+ public async infoNetworkElementFeatures(nodeId: string): Promise<Module[] | null | undefined> {
+ const path = this.getNetworkElementYangLibraryFeature(nodeId);
+ const topologyRequestPomise = requestRest<FeatureTopology>(path, { method: 'GET' });
+
+ return topologyRequestPomise && topologyRequestPomise.then(result => {
+ const resultFinal = result && result['ietf-yang-library:yang-library']
+ && result['ietf-yang-library:yang-library']['module-set'] &&
+ result['ietf-yang-library:yang-library']['module-set'][0] &&
+ result['ietf-yang-library:yang-library']['module-set'][0].module || null;
+ return resultFinal;
+ });
+ }
+
+
+
+ /**
+ * Get the connection state of the network element/ node
+ */
+ public async getNetworkElementConnectionStatus(element: string): Promise<(ConnectionStatus)[] | null> {
+ const path = '/rests/operations/data-provider:read-network-element-connection-list';
+ const query = {
+ 'data-provider:input': {
+ 'filter': [{
+ 'property': 'node-id',
+ 'filtervalue': element,
+ }],
+ 'pagination': {
+ 'size': 20,
+ 'page': 1,
+ },
+ },
+ };
+ const result = await requestRest<Result<ConnectionStatus>>(path, { method: 'POST', body: JSON.stringify(query) });
+ return result && result['data-provider:output'] && result['data-provider:output'].data && result['data-provider:output'].data.map(ne => ({
+ status: ne.status,
+ })) || null;
+ }
+
+ /**
+ * Gets all available tlsKeys.
+ */
+
+ public async getTlsKeys(): Promise<(TlsKeys)[] | null> {
+ const path = '/rests/operations/data-provider:read-tls-key-entry';
+ const query = {
+ 'data-provider:input': {
+ 'filter': [],
+ 'sortorder': [],
+ 'pagination': {
+ 'size': 20,
+ 'page': 1,
+ },
+ },
+ };
+
+ const result = await requestRest<Result<string>>(path, { method: 'POST', body: JSON.stringify(query) });
+ return result && result['data-provider:output'] && result['data-provider:output'].data && result['data-provider:output'].data.map(ne => ({
+ key: ne,
+ })) || null;
+ }
+
+ public async getAllWebUriExtensionsForNetworkElementListAsync(neList: string[]): Promise<(guiCutThrough)[]> {
+ const path = '/rests/operations/data-provider:read-gui-cut-through-entry';
+ let webUriList: guiCutThrough[] = [];
+ const query = {
+ 'data-provider:input': {
+ 'filter': [{
+ 'property': 'id',
+ 'filtervalues': neList,
+ }],
+ 'pagination': {
+ 'size': 20,
+ 'page': 1,
+ },
+ },
+ };
+
+ const result = await requestRest<Result<guiCutThrough>>(path, { method: 'POST', body: JSON.stringify(query) });
+ const resultData = result && result['data-provider:output'] && result['data-provider:output'].data;
+ neList.forEach(nodeId => {
+ let entryNotFound = true;
+ if (resultData) {
+ try {
+ resultData.forEach(entry => {
+ if (entry.id == nodeId) {
+ entryNotFound = false;
+ if (entry.weburi) {
+ webUriList.push({ id: nodeId, weburi: entry.weburi });
+ } else {
+ webUriList.push({ id: nodeId, weburi: undefined });
+ }
+ throw new Error();
+ }
+ });
+ } catch (e) { }
+ }
+ if (entryNotFound)
+ webUriList.push({ id: nodeId, weburi: undefined });
+ });
+ return webUriList;
+ }
+
+ // public async getAllWebUriExtensionsForNetworkElementListAsync(ne: string[]): Promise<(guiCutThrough)[] | null> {
+
+ // let promises: any[] = [];
+ // let webUris: guiCutThrough[] = []
+
+ // ne.forEach(nodeId => {
+ // const path = this.getAllWebUriExtensionsForNetworkElementListUri(nodeId);
+
+ // // add search request to array
+ // promises.push(requestRest<any>(path, { method: "GET" })
+ // .then(result => {
+ // if (result != null && result['core-model:network-element'] && result['core-model:network-element'].extension) {
+ // const webUri = result['core-model:network-element'].extension.find((item: any) => item['value-name'] === "webUri")
+ // if (webUri) {
+ // webUris.push({ weburi: webUri.value, id: nodeId });
+ // } else {
+ // webUris.push({ weburi: undefined, id: nodeId });
+ // }
+ // } else {
+ // webUris.push({ weburi: undefined, id: nodeId });
+ // }
+ // })
+ // .catch(error => {
+ // webUris.push({ weburi: undefined, id: nodeId });
+ // }))
+ // })
+ // // wait until all promises are done and return weburis
+ // return Promise.all(promises).then(result => { return webUris });
+ // }
+
+}
+
+
+
+export const connectService = new ConnectService();
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/src/views/connectView.tsx b/sdnr/wt-odlux/odlux/apps/connectApp/src/views/connectView.tsx
new file mode 100644
index 000000000..a6fcb7c32
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/src/views/connectView.tsx
@@ -0,0 +1,102 @@
+/**
+ * ============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 { AppBar, Tab, Tabs } from '@mui/material';
+
+import { useApplicationDispatch, useSelectApplicationState } from '../../../../framework/src/flux/connect';
+
+import { findWebUrisForGuiCutThroughAsyncAction, setPanelAction } from '../actions/commonNetworkElementsActions';
+import { ConnectionStatusLog } from '../components/connectionStatusLog';
+import { NetworkElementsList } from '../components/networkElements';
+import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
+import { networkElementsReloadAction } from '../handlers/networkElementsHandler';
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import { PanelId } from '../models/panelId';
+
+const ConnectApplicationComponent: React.FC<{}> = () => {
+
+ const panelId = useSelectApplicationState(state => state.connect.currentOpenPanel);
+ const netWorkElements = useSelectApplicationState(state => state.connect.networkElements);
+
+ const dispatch = useApplicationDispatch();
+ const onLoadNetworkElements = () => dispatch(networkElementsReloadAction);
+ const loadWebUris = (networkElements: NetworkElementConnection[]) => dispatch(findWebUrisForGuiCutThroughAsyncAction(networkElements.map((ne) => ne.id!)));
+ const onLoadConnectionStatusLog = () => dispatch(connectionStatusLogReloadAction);
+ const switchActivePanel = (panelId2: PanelId) => dispatch(setPanelAction(panelId2));
+
+ const onTogglePanel = (panelId2: PanelId) => {
+ const nextActivePanel = panelId2;
+ switchActivePanel(nextActivePanel);
+
+ switch (nextActivePanel) {
+ case 'NetworkElements':
+ onLoadNetworkElements();
+ break;
+ case 'ConnectionStatusLog':
+ onLoadConnectionStatusLog();
+ break;
+ case null:
+ // do nothing if all panels are closed
+ break;
+ default:
+ console.warn('Unknown nextActivePanel [' + nextActivePanel + '] in connectView');
+ break;
+ }
+ };
+
+ const onHandleTabChange = (event: React.SyntheticEvent, newValue: PanelId) => {
+ switchActivePanel(newValue);
+ };
+
+ React.useEffect(()=>{
+ if (panelId === null) { //don't change tabs, if one is selected already
+ onTogglePanel('NetworkElements');
+ }
+ }, []);
+
+ React.useEffect(()=>{
+ const networkElements = netWorkElements;
+
+ if (networkElements.rows.length > 0) {
+ // Search for weburi client for all netWorkElements in case of table data changes.
+ // e.G: Pagination of the table data (there is no event)
+ loadWebUris(networkElements.rows);
+ }
+ }, [netWorkElements]);
+
+ return (
+ <>
+ <AppBar enableColorOnDark position="static">
+ <Tabs indicatorColor="secondary" textColor="inherit" value={panelId} onChange={onHandleTabChange} aria-label="connect-app-tabs">
+ <Tab aria-label="network-elements-list-tab" label="NODES" value="NetworkElements" />
+ <Tab aria-label="connection-status-log-tab" label="Connection Status Log" value="ConnectionStatusLog" />
+ </Tabs>
+ </AppBar>
+ {panelId === 'NetworkElements'
+ ? <NetworkElementsList />
+ : panelId === 'ConnectionStatusLog'
+ ? <ConnectionStatusLog />
+ : null
+ }
+ </>
+ );
+};
+
+export const ConnectApplication = ConnectApplicationComponent;
+export default ConnectApplication; \ No newline at end of file
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/tsconfig.json b/sdnr/wt-odlux/odlux/apps/connectApp/tsconfig.json
new file mode 100644
index 000000000..18956db7c
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ },
+}
diff --git a/sdnr/wt-odlux/odlux/apps/connectApp/webpack.config.js b/sdnr/wt-odlux/odlux/apps/connectApp/webpack.config.js
new file mode 100644
index 000000000..b7aebb9df
--- /dev/null
+++ b/sdnr/wt-odlux/odlux/apps/connectApp/webpack.config.js
@@ -0,0 +1,202 @@
+/**
+ * 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 policies = require('./policies.json');
+
+// 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: {
+ connectApp: ["./pluginConnect.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
+ },
+ before: function(app, server, compiler) {
+ app.get('/oauth/policies',(_, res) => res.json(policies));
+ },
+ proxy: {
+ "/about": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/yang-schema/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/oauth/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/database/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/restconf/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/rests/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/userdata": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/userdata/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/help/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/about/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/tree/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/websocket": {
+ target: "http://sdnr:8181",
+ ws: true,
+ changeOrigin: true,
+ secure: false
+ },
+ "/apidoc": {
+ target: "http://sdnr:8181",
+ ws: true,
+ changeOrigin: true,
+ secure: false
+ }
+ }
+ }
+ }];
+}