aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/apps/connectApp
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/apps/connectApp')
-rw-r--r--sdnr/wt/odlux/apps/connectApp/.babelrc17
-rw-r--r--sdnr/wt/odlux/apps/connectApp/package.json40
-rw-r--r--sdnr/wt/odlux/apps/connectApp/pom.xml147
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts113
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts57
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts60
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/actions/networkElementsActions.ts61
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx52
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx252
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx154
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx259
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts83
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts35
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.ts60
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts58
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/index.html27
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/connectionStatusLog.ts27
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts1
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/networkElementBase.ts22
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts36
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts25
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/panelId.ts1
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts36
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts22
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx56
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts208
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx111
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java68
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml9
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java45
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src2/test/resources/test.js5
-rw-r--r--sdnr/wt/odlux/apps/connectApp/tsconfig.json37
-rw-r--r--sdnr/wt/odlux/apps/connectApp/webpack.config.js153
33 files changed, 2337 insertions, 0 deletions
diff --git a/sdnr/wt/odlux/apps/connectApp/.babelrc b/sdnr/wt/odlux/apps/connectApp/.babelrc
new file mode 100644
index 000000000..3d8cd1260
--- /dev/null
+++ b/sdnr/wt/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/apps/connectApp/package.json b/sdnr/wt/odlux/apps/connectApp/package.json
new file mode 100644
index 000000000..04653d520
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@odlux/connect-app",
+ "version": "0.1.1",
+ "description": "A react based modular UI to display network 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": {
+ "@odlux/framework": "*"
+ },
+ "peerDependencies": {
+ "@types/react": "16.9.11",
+ "@types/react-dom": "16.9.4",
+ "@types/react-router-dom": "4.3.1",
+ "@material-ui/core": "4.6.1",
+ "@material-ui/icons": "4.5.1",
+ "@types/classnames": "2.2.6",
+ "@types/flux": "3.1.8",
+ "@types/jquery": "3.3.10",
+ "jquery": "3.3.1",
+ "react": "16.11.0",
+ "react-dom": "16.11.0",
+ "react-router-dom": "4.3.1"
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/pom.xml b/sdnr/wt/odlux/apps/connectApp/pom.xml
new file mode 100644
index 000000000..f52fa1111
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/pom.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+
+ <parent>
+ <groupId>org.onap.ccsdk.parent</groupId>
+ <artifactId>odlparent</artifactId>
+ <version>1.5.1-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+ <artifactId>sdnr-wt-odlux-app-connectApp</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>sdnr-wt-odlux-app-connectApp</name>
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+ </license>
+ </licenses>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-core-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-core-provider</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src2/main/java</sourceDirectory>
+ <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>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-test-source</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src2/test/java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>de.jacks-it-lab</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.7.1</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>v10.16.3</nodeVersion>
+ <yarnVersion>v1.19.0</yarnVersion>
+ </configuration>
+ </execution>
+ <execution>
+ <id>yarn build</id>
+ <goals>
+ <goal>yarn</goal>
+ </goals>
+ <configuration>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>org.onap.ccsdk.features.sdnr.wt.odlux.model.*,com.opensymphony.*</Import-Package>
+ <Private-Package/>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ <resources>
+ <resource>
+ <directory>dist</directory>
+ <targetPath>odlux</targetPath>
+ </resource>
+ <resource>
+ <directory>src2/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>src2/test/resources</directory>
+ </resource>
+ </resources>
+ </build>
+</project>
diff --git a/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts b/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
new file mode 100644
index 000000000..bf4778b5b
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
@@ -0,0 +1,113 @@
+// update action erstellen, die unterscheiden kann, ob die eine oder die andere Ansicht gerade aktive ist und diese katualisiert.
+// Diese action wird dann bei jeder aktualisierung in den anderen Actions und bei eintreffen von notifikationen verwendet.
+
+/**
+ * ============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 { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+import { networkElementsReloadAction } from '../handlers/networkElementsHandler';
+import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
+
+import { PanelId } from '../models/panelId';
+import { guiCutThrough } from '../models/guiCutTrough';
+import connectService from '../services/connectService';
+import { NetworkElementConnection } from '../models/networkElementConnection';
+
+export class SetPanelAction extends Action {
+ constructor(public panelId: PanelId) {
+ super();
+ }
+}
+
+export class AddWebUriList extends Action {
+ constructor(public element: guiCutThrough[], public knownElements: string[]) {
+ super();
+ }
+}
+
+export class RemoveWebUri extends Action {
+ constructor(public element: string) {
+ super();
+ }
+}
+
+export const removeWebUriAction = (nodeId: string) => {
+ return new RemoveWebUri(nodeId);
+}
+
+let isBusy = false;
+export const findWebUrisForGuiCutThroughAsyncAction = (dispatcher: Dispatch) => (networkElements: NetworkElementConnection[], knownElements: string[]) => {
+
+ // keep method from executing simultanously; state not used because change of iu isn't needed
+ if (isBusy)
+ return;
+ isBusy = true;
+
+ const nodeIds = networkElements.map(element => { return element.id as string });
+
+ if (knownElements.length > 0) {
+
+ let elementsToSearch: string[] = [];
+
+ nodeIds.forEach(element => {
+ // find index of nodeId
+ const index = knownElements.indexOf(element);
+
+ // if element dosen't exist, add it to list
+ if (index === -1) {
+ elementsToSearch.push(element)
+ }
+ });
+
+ // if new elements were found, search for weburi
+ if (elementsToSearch.length > 0) {
+ const foundWebUris = connectService.getAllWebUriExtensionsForNetworkElementListAsync(elementsToSearch);
+ foundWebUris.then(result => {
+ dispatcher(new AddWebUriList(result, elementsToSearch));
+ isBusy = false;
+ })
+
+ } else {
+ isBusy = false;
+ }
+
+ } else {
+ connectService.getAllWebUriExtensionsForNetworkElementListAsync(nodeIds).then(result => {
+ dispatcher(new AddWebUriList(result, nodeIds));
+ 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/apps/connectApp/src/actions/infoNetworkElementActions.ts b/sdnr/wt/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts
new file mode 100644
index 000000000..4ae28aab2
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/actions/infoNetworkElementActions.ts
@@ -0,0 +1,57 @@
+/**
+ * ============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 { 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 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));
+ });
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts b/sdnr/wt/odlux/apps/connectApp/src/actions/mountedNetworkElementsActions.ts
new file mode 100644
index 000000000..84e73ae5a
--- /dev/null
+++ b/sdnr/wt/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 crator for a async thunk action to mount a network element. */
+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 crator for a async thunk action to unmount a network element. */
+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/apps/connectApp/src/actions/networkElementsActions.ts b/sdnr/wt/odlux/apps/connectApp/src/actions/networkElementsActions.ts
new file mode 100644
index 000000000..1a86f94b1
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/actions/networkElementsActions.ts
@@ -0,0 +1,61 @@
+/**
+ * ============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. */
+export const addNewNetworkElementAsyncActionCreator = (element: NetworkElementConnection) => async (dispatch: Dispatch) => {
+ const res = 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. */
+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") {
+ const res = await connectService.deleteNetworkElement(element);
+ }
+ else {
+ const res = 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. */
+export const removeNetworkElementAsyncActionCreator = (element: UpdateNetworkElement) => async (dispatch: Dispatch) => {
+ const res = await connectService.deleteNetworkElement(element);
+ await dispatch(unmountNetworkElementAsyncActionCreator(element && element.id));
+ dispatch(updateCurrentViewAsyncAction());
+};
+
+
+
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
new file mode 100644
index 000000000..4e5ca65e1
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
@@ -0,0 +1,52 @@
+/**
+ * ============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 connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { MaterialTable, ColumnType, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+
+import { createConnectionStatusLogActions, createConnectionStatusLogProperties } from '../handlers/connectionStatusLogHandler';
+import { NetworkElementConnectionLog } from '../models/networkElementConnectionLog';
+
+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>;
+
+class ConnectionStatusLogComponent extends React.Component<ConnectionStatusLogComponentProps> {
+ render(): JSX.Element {
+ return (
+ <ConnectionStatusTable tableId="connection-status-table" columns={[
+ { property: "timestamp", title: "Time", type: ColumnType.text },
+ { property: "nodeId", title: "Node Name", type: ColumnType.text },
+ { property: "status", title: "Connection status", type: ColumnType.text },
+ ]} idProperty="id" {...this.props.connectionStatusLogActions} {...this.props.connectionStatusLogProperties} >
+ </ConnectionStatusTable>
+ );
+ };
+}
+
+export const ConnectionStatusLog = connect(mapProps, mapDispatch)(ConnectionStatusLogComponent);
+export default ConnectionStatusLog; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
new file mode 100644
index 000000000..1e1f11523
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
@@ -0,0 +1,252 @@
+/**
+ * ============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 '@material-ui/core/Button';
+import TextField from '@material-ui/core/TextField';
+import Dialog from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import { FormControl, InputLabel, Select, MenuItem } from '@material-ui/core';
+
+import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
+
+import {
+ editNetworkElementAsyncActionCreator,
+ addNewNetworkElementAsyncActionCreator,
+ removeNetworkElementAsyncActionCreator
+} from '../actions/networkElementsActions';
+
+import { unmountNetworkElementAsyncActionCreator, mountNetworkElementAsyncActionCreator } from '../actions/mountedNetworkElementsActions';
+import { NetworkElementConnection, UpdateNetworkElement } from '../models/networkElementConnection';
+import { removeWebUriAction } from '../actions/commonNetworkElementsActions';
+
+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) => {
+ await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
+ await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement));
+ },
+ removeNetworkElement: (element: UpdateNetworkElement) => {
+ dispatcher.dispatch(removeNetworkElementAsyncActionCreator(element));
+ dispatcher.dispatch(removeWebUriAction(element.id));
+ }
+});
+
+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 network element",
+ dialogDescription: "Add this new network element:",
+ applyButtonText: "Add network element",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ },
+ [EditNetworkElementDialogMode.MountNetworkElement]: {
+ dialogTitle: "Mount network element",
+ dialogDescription: "mount this network element:",
+ applyButtonText: "mount network element",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [EditNetworkElementDialogMode.UnmountNetworkElement]: {
+ dialogTitle: "Unmount network element",
+ dialogDescription: "unmount this network element:",
+ applyButtonText: "Unmount network element",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [EditNetworkElementDialogMode.EditNetworkElement]: {
+ dialogTitle: "Modify the network elements",
+ dialogDescription: "Modify this network element",
+ applyButtonText: "Modify",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: false,
+ enableUsernameEditor: true,
+ enableExtendedEditor: false,
+ },
+ [EditNetworkElementDialogMode.RemoveNetworkElement]: {
+ dialogTitle: "Remove network element",
+ dialogDescription: "Do you really want to remove this network element:",
+ applyButtonText: "Remove network element",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ }
+}
+
+type EditNetworkElementDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: EditNetworkElementDialogMode;
+ initialNetworkElement: NetworkElementConnection;
+ onClose: () => void;
+};
+
+type EditNetworkElementDialogComponentState = NetworkElementConnection;
+
+class EditNetworkElementDialogComponent extends React.Component<EditNetworkElementDialogComponentProps, EditNetworkElementDialogComponentState> {
+ constructor(props: EditNetworkElementDialogComponentProps) {
+ 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];
+ return (
+ <Dialog open={this.props.mode !== EditNetworkElementDialogMode.None}>
+ <DialogTitle id="form-dialog-title">{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ <TextField disabled={!setting.enableMountIdEditor} spellCheck={false} autoFocus margin="dense" id="name" label="Name" aria-label="name" type="text" fullWidth value={this.state.nodeId} onChange={(event) => { this.setState({ nodeId: event.target.value }); }} />
+ <TextField disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense" id="ipaddress" label="IP address" aria-label="ip adress" type="text" fullWidth value={this.state.host} onChange={(event) => { this.setState({ host: event.target.value }); }} />
+ <TextField 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 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 && <TextField disabled={!setting.enableUsernameEditor} spellCheck={false} margin="dense" id="password" label="Password" aria-label="password" type="password" fullWidth value={this.state.password} onChange={(event) => { this.setState({ password: event.target.value }); }} /> || null}
+ <FormControl fullWidth disabled={!setting.enableUsernameEditor}>
+ <InputLabel htmlFor="active">Required</InputLabel>
+ <Select 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} >True</MenuItem>
+ <MenuItem value={false as any as string} >False</MenuItem>
+ </Select>
+ </FormControl>
+ </DialogContent>
+ <DialogActions>
+ <Button onClick={(event) => {
+ 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,
+ });
+ event.preventDefault();
+ event.stopPropagation();
+ }} > {setting.applyButtonText} </Button>
+ <Button onClick={(event) => {
+ this.onCancel();
+ event.preventDefault();
+ event.stopPropagation();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ )
+ }
+
+ private onApply = (element: NetworkElementConnection) => {
+ this.props.onClose && this.props.onClose();
+ let updateElement: UpdateNetworkElement = {
+ id: this.state.nodeId
+ }
+ switch (this.props.mode) {
+ case EditNetworkElementDialogMode.AddNewNetworkElement:
+ element && this.props.addNewNetworkElement(element);
+ break;
+ case EditNetworkElementDialogMode.MountNetworkElement:
+ element && this.props.mountNetworkElement(element);
+ break;
+ case EditNetworkElementDialogMode.UnmountNetworkElement:
+ 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)
+ updateElement.password = this.state.password;
+ element && this.props.editNetworkElement(updateElement, element);
+ break;
+ case EditNetworkElementDialogMode.RemoveNetworkElement:
+ element && this.props.removeNetworkElement(updateElement);
+ break;
+ }
+ };
+
+ private onCancel = () => {
+ this.props.onClose && this.props.onClose();
+ }
+
+ static getDerivedStateFromProps(props: EditNetworkElementDialogComponentProps, state: EditNetworkElementDialogComponentState & { _initialNetworkElement: NetworkElementConnection }): EditNetworkElementDialogComponentState & { _initialNetworkElement: NetworkElementConnection } {
+ if (props.initialNetworkElement !== state._initialNetworkElement) {
+ state = {
+ ...state,
+ ...props.initialNetworkElement,
+ _initialNetworkElement: props.initialNetworkElement,
+ };
+ }
+ return state;
+ }
+}
+
+export const EditNetworkElementDialog = connect(undefined, mapDispatch)(EditNetworkElementDialogComponent);
+export default EditNetworkElementDialog; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx
new file mode 100644
index 000000000..ea9d419ec
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/infoNetworkElementDialog.tsx
@@ -0,0 +1,154 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+import * as React from 'react';
+
+import Button from '@material-ui/core/Button';
+import Dialog from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import { IDispatcher, 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 = (dispatcher: IDispatcher) => ({
+});
+
+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 network element",
+ dialogDescription: "Available capabilities of the network element",
+ cancelButtonText: "Cancel",
+ }
+}
+
+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 yangCapabilities: AvailableCapabilities[] = [];
+
+ availableCapabilities.forEach(value => {
+ const capabilty = value.capability;
+ const indexRevision = capabilty.indexOf("revision=");
+ const indexModule = capabilty.indexOf(")", indexRevision);
+ if (indexRevision > 0 && indexModule > 0) {
+ yangCapabilities.push({
+ module: capabilty.substr(indexModule + 1),
+ revision: capabilty.substr(indexRevision + 9, 10)
+ });
+ }
+ });
+
+ return (
+ <Dialog open={this.props.mode !== InfoNetworkElementDialogMode.None}>
+ <DialogTitle id="form-dialog-title">{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription + " " + this.state.nodeId}
+ </DialogContentText>
+ <Table >
+ <TableHead>
+ <TableRow>
+ <TableCell align="right">S.No</TableCell>
+ <TableCell >Module</TableCell>
+ <TableCell >Revision</TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {yangCapabilities.map((yang, index) => (
+ <TableRow>
+ <TableCell>{index + 1}</TableCell>
+ <TableCell>{yang.module}</TableCell>
+ <TableCell>{yang.revision}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </DialogContent>
+ <DialogActions>
+ <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 } {
+ if (props.initialNetworkElement !== state._initialNetworkElement) {
+ state = {
+ ...state,
+ ...props.initialNetworkElement,
+ _initialNetworkElement: props.initialNetworkElement,
+ };
+ }
+ return state;
+ }
+}
+
+export const InfoNetworkElementDialog = connect(undefined, mapDispatch)(InfoNetworkElementDialogComponent);
+export default InfoNetworkElementDialog; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
new file mode 100644
index 000000000..0f4b0e8ff
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
@@ -0,0 +1,259 @@
+/**
+* ============LICENSE_START========================================================================
+* ONAP : ccsdk feature sdnr wt odlux
+* =================================================================================================
+* Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+* =================================================================================================
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software distributed under the License
+* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+* or implied. See the License for the specific language governing permissions and limitations under
+* the License.
+* ============LICENSE_END==========================================================================
+*/
+import * as React from 'react';
+import { Theme, createStyles, withStyles, WithStyles } from '@material-ui/core/styles';
+
+import AddIcon from '@material-ui/icons/Add';
+import LinkIcon from '@material-ui/icons/Link';
+import LinkOffIcon from '@material-ui/icons/LinkOff';
+import RemoveIcon from '@material-ui/icons/RemoveCircleOutline';
+import EditIcon from '@material-ui/icons/Edit';
+import Info from '@material-ui/icons/Info';
+import ComputerIcon from '@material-ui/icons/Computer';
+
+import Button from '@material-ui/core/Button';
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
+
+import { MaterialTable, ColumnType, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { connect, Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions';
+
+import { createNetworkElementsActions, createNetworkElementsProperties } from '../handlers/networkElementsHandler';
+
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import EditNetworkElementDialog, { EditNetworkElementDialogMode } from './editNetworkElementDialog';
+
+import InfoNetworkElementDialog, { InfoNetworkElementDialogMode } from './infoNetworkElementDialog';
+import { loadAllInfoElementAsync } from '../actions/infoNetworkElementActions';
+import { TopologyNode } from '../models/topologyNetconf';
+
+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"
+ }
+});
+
+const mapProps = (state: IApplicationStoreState) => ({
+ networkElementsProperties: createNetworkElementsProperties(state),
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ networkElementsActions: createNetworkElementsActions(dispatcher.dispatch),
+ navigateToApplication: (applicationName: string, path?: string) => dispatcher.dispatch(new NavigateToApplication(applicationName, path)),
+ networkElementInfo: async (nodeId: string) => await dispatcher.dispatch(loadAllInfoElementAsync(nodeId)),
+});
+
+type NetworkElementsListComponentProps = WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>;
+type NetworkElementsListComponentState = {
+ networkElementToEdit: NetworkElementConnection,
+ networkElementEditorMode: EditNetworkElementDialogMode,
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode,
+ elementInfo: TopologyNode | null
+}
+
+const emptyRequireNetworkElement: NetworkElementConnection = { id: "", nodeId: "", host: "", port: 0, status: "Disconnected", isRequired: 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,
+ elementInfo: null,
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None
+ };
+ }
+
+ // private navigationCreator
+
+ render(): JSX.Element {
+ const { classes } = this.props;
+ const { networkElementToEdit } = this.state;
+ const addRequireNetworkElementAction = {
+ icon: AddIcon, tooltip: 'Add', onClick: () => {
+ this.setState({
+ networkElementEditorMode: EditNetworkElementDialogMode.AddNewNetworkElement,
+ networkElementToEdit: emptyRequireNetworkElement,
+ });
+ }
+ };
+ let counter = 0;
+ return (
+ <>
+ <NetworkElementTable tableId="network-element-table" customActionButtons={[addRequireNetworkElementAction]} columns={[
+ { property: "nodeId", title: "Node Name", type: ColumnType.text },
+ { property: "isRequired", title: "Required", type: ColumnType.boolean },
+ { property: "status", title: "Connection Status", type: ColumnType.text },
+ { property: "host", title: "Host", type: ColumnType.text },
+ { property: "port", title: "Port", type: ColumnType.numeric },
+ { property: "coreModelCapability", title: "Core Model", type: ColumnType.text },
+ { property: "deviceType", title: "Type", type: ColumnType.text },
+ {
+ property: "actions", title: "Actions", type: ColumnType.custom, customControl: ({ rowData }) => {
+ counter++;
+ return (
+ <>
+ <div className={classes.spacer}>
+ {
+ rowData.webUri && <Tooltip title={"Web Client"} ><IconButton aria-label={"web-client-button-" + counter} className={classes.button} onClick={event => { console.log(rowData); window.open(rowData.webUri, "_blank") }}><ComputerIcon /></IconButton></Tooltip>
+ }
+ <Tooltip title={"Mount"} >
+ <IconButton aria-label={"mount-button-" + counter} className={classes.button} onClick={event => this.onOpenMountdNetworkElementsDialog(event, rowData)} >
+ <LinkIcon /></IconButton>
+ </Tooltip>
+ <Tooltip title={"Unmount"} >
+ <IconButton aria-label={"unmount-button-" + counter} className={classes.button} onClick={event => this.onOpenUnmountdNetworkElementsDialog(event, rowData)} >
+ <LinkOffIcon /></IconButton>
+ </Tooltip>
+ <Tooltip title={"Info"} ><IconButton aria-label={"info-button-" + counter} className={classes.button} onClick={event => this.onOpenInfoNetworkElementDialog(event, rowData)} disabled={rowData.status === "Connecting" || rowData.status === "Disconnected"} >
+ <Info /></IconButton>
+ </Tooltip>
+ <Tooltip title={"Edit"} ><IconButton aria-label={"edit-button-" + counter} className={classes.button} onClick={event => this.onOpenEditNetworkElementDialog(event, rowData)} ><EditIcon /></IconButton></Tooltip>
+ <Tooltip title={"Remove"} ><IconButton aria-label={"remove-button-" + counter} className={classes.button} onClick={event => this.onOpenRemoveNetworkElementDialog(event, rowData)} ><RemoveIcon /></IconButton></Tooltip>
+ </div>
+ <div className={classes.spacer}>
+ <Tooltip title={"Inventory"} ><Button aria-label={"inventory-button-" + counter} className={classes.button} onClick={this.navigateToApplicationHandlerCreator("inventory", rowData)} >I</Button></Tooltip>
+ </div>
+ <div className={classes.spacer}>
+ <Tooltip title={"Fault"} ><Button aria-label={"fault-button-" + counter} className={classes.button} onClick={this.navigateToApplicationHandlerCreator("fault", rowData)} >F</Button></Tooltip>
+ <Tooltip title={"Configure"} ><Button aria-label={"configure-button-" + counter} className={classes.button} onClick={this.navigateToApplicationHandlerCreator("configuration", rowData)} >C</Button></Tooltip>
+ <Tooltip title={"Accounting "} ><Button className={classes.button} onClick={this.navigateToApplicationHandlerCreator("accounting", rowData)} disabled={true} >A</Button></Tooltip>
+ <Tooltip title={"Performance"} ><Button aria-label={"performance-button-" + counter} className={classes.button} onClick={this.navigateToApplicationHandlerCreator("performanceHistory", rowData)}>P</Button></Tooltip>
+ <Tooltip title={"Security"} ><Button className={classes.button} onClick={this.navigateToApplicationHandlerCreator("security", rowData)} disabled={true} >S</Button></Tooltip>
+ </div>
+ </>
+ )
+ }
+ },
+ ]} idProperty="id" {...this.props.networkElementsActions} {...this.props.networkElementsProperties} asynchronus >
+ </NetworkElementTable>
+ <EditNetworkElementDialog
+ initialNetworkElement={networkElementToEdit}
+ mode={this.state.networkElementEditorMode}
+ onClose={this.onCloseEditNetworkElementDialog}
+ />
+ <InfoNetworkElementDialog
+ initialNetworkElement={networkElementToEdit}
+ mode={this.state.infoNetworkElementEditorMode}
+ onClose={this.onCloseInfoNetworkElementDialog}
+ />
+ </>
+ );
+ };
+
+ public componentDidMount() {
+ this.props.networkElementsActions.onRefresh();
+ }
+
+ private onOpenRemoveNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.RemoveNetworkElement
+ });
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ private onOpenEditNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: {
+ nodeId: element.nodeId,
+ isRequired: element.isRequired,
+ host: element.host,
+ port: element.port,
+ username: element.username,
+ password: element.password,
+ },
+ networkElementEditorMode: EditNetworkElementDialogMode.EditNetworkElement
+ });
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ private onOpenUnmountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.UnmountNetworkElement
+ });
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ private onOpenMountdNetworkElementsDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.setState({
+ networkElementToEdit: element,
+ networkElementEditorMode: EditNetworkElementDialogMode.MountNetworkElement
+ });
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ private onOpenInfoNetworkElementDialog = (event: React.MouseEvent<HTMLElement>, element: NetworkElementConnection) => {
+ this.props.networkElementInfo(element.nodeId);
+ this.setState({
+ networkElementToEdit: element,
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode.InfoNetworkElement,
+ });
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ private onCloseEditNetworkElementDialog = () => {
+ this.setState({
+ networkElementEditorMode: EditNetworkElementDialogMode.None,
+ networkElementToEdit: emptyRequireNetworkElement,
+ });
+ }
+ private onCloseInfoNetworkElementDialog = () => {
+ this.setState({
+ infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None,
+ networkElementToEdit: emptyRequireNetworkElement,
+ });
+ }
+
+ private navigateToApplicationHandlerCreator = (applicationName: string, element: NetworkElementConnection) => (event: React.MouseEvent<HTMLElement>) => {
+ this.props.navigateToApplication(applicationName, element.nodeId);
+ event.preventDefault();
+ event.stopPropagation();
+ }
+}
+
+export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent));
+export default NetworkElementsList; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
new file mode 100644
index 000000000..1440599fd
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
@@ -0,0 +1,83 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { IActionHandler } from '../../../../framework/src/flux/action';
+import { combineActionHandler } from '../../../../framework/src/flux/middleware';
+import { INetworkElementsState, networkElementsActionHandler } from './networkElementsHandler';
+import { IConnectionStatusLogState, connectionStatusLogActionHandler } from './connectionStatusLogHandler';
+import { IInfoNetworkElementsState, infoNetworkElementsActionHandler } from './infoNetworkElementHandler';
+import { SetPanelAction, AddWebUriList, RemoveWebUri } from '../actions/commonNetworkElementsActions';
+import { PanelId } from '../models/panelId';
+import { guiCutThrough } from '../models/guiCutTrough';
+
+export interface IConnectAppStoreState {
+ networkElements: INetworkElementsState;
+ connectionStatusLog: IConnectionStatusLogState;
+ currentOpenPanel: PanelId;
+ elementInfo: IInfoNetworkElementsState;
+ guiCutThrough: guiCutThroughState;
+}
+
+const currentOpenPanelHandler: IActionHandler<PanelId> = (state = null, action) => {
+ if (action instanceof SetPanelAction) {
+ state = action.panelId;
+ }
+ return state;
+}
+
+interface guiCutThroughState {
+ availableWebUris: guiCutThrough[];
+ knownElements: string[];
+}
+
+const guiCutThroughHandler: IActionHandler<guiCutThroughState> = (state = { availableWebUris: [], knownElements: [] }, action) => {
+ if (action instanceof AddWebUriList) {
+ let knownElements: string[];
+ let availableWebUris: guiCutThrough[];
+
+ knownElements = state.knownElements.concat(action.knownElements);
+
+ availableWebUris = state.availableWebUris.concat(action.element);
+
+ state = { availableWebUris: availableWebUris, knownElements: knownElements }
+
+ } else if (action instanceof RemoveWebUri) {
+ const nodeId = action.element;
+ const webUris = state.availableWebUris.filter(item => item.nodeId !== nodeId);
+ const knownElements = state.knownElements.filter(item => item !== nodeId);
+ state = { knownElements: knownElements, availableWebUris: webUris };
+ }
+ return state;
+}
+
+declare module '../../../../framework/src/store/applicationStore' {
+ interface IApplicationStoreState {
+ connect: IConnectAppStoreState
+ }
+}
+
+const actionHandlers = {
+ networkElements: networkElementsActionHandler,
+ connectionStatusLog: connectionStatusLogActionHandler,
+ currentOpenPanel: currentOpenPanelHandler,
+ elementInfo: infoNetworkElementsActionHandler,
+ guiCutThrough: guiCutThroughHandler
+};
+
+export const connectAppRootHandler = combineActionHandler<IConnectAppStoreState>(actionHandlers);
+export default connectAppRootHandler;
diff --git a/sdnr/wt/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts
new file mode 100644
index 000000000..6863ec33b
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/connectionStatusLogHandler.ts
@@ -0,0 +1,35 @@
+/**
+ * ============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/apps/connectApp/src/handlers/infoNetworkElementHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.ts
new file mode 100644
index 000000000..d67a81ec4
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/infoNetworkElementHandler.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 { IActionHandler } from '../../../../framework/src/flux/action';
+
+import { AllElementInfoLoadedAction, LoadAllElementInfoAction } from '../actions/infoNetworkElementActions';
+
+import { TopologyNode } from '../models/topologyNetconf';
+
+export interface IInfoNetworkElementsState {
+ elementInfo: TopologyNode;
+ busy: boolean;
+}
+
+const infoNetworkElementsStateInit: IInfoNetworkElementsState = {
+ elementInfo: {
+ "node-id": "",
+ "netconf-node-topology:available-capabilities": {
+ "available-capability": []
+ }
+ },
+ 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;
+}; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
new file mode 100644
index 000000000..78c7000d2
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+import { createExternal, IExternalTableState } from '../../../../framework/src/components/material-table/utilities';
+import { createSearchDataHandler } from '../../../../framework/src/utilities/elasticSearch';
+
+import { NetworkElementConnection } from '../models/networkElementConnection';
+import connectService from '../services/connectService';
+import { requestRest } from '../../../../framework/src/services/restService';
+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.availableWebUris;
+ if (appState.connect.networkElements.rows && webUris.length > 0) {
+
+ appState.connect.networkElements.rows.forEach(element => {
+
+ if (element.status === "Connected") {
+ const webUri = webUris.find(item => item.nodeId === element.id as string);
+ if (webUri) {
+ element.webUri = webUri.webUri;
+ element.isWebUriUnreachable = false;
+ }
+ else {
+ element.isWebUriUnreachable = true
+ }
+ }
+ });
+ }
+
+ return appState.connect.networkElements
+});
+
diff --git a/sdnr/wt/odlux/apps/connectApp/src/index.html b/sdnr/wt/odlux/apps/connectApp/src/index.html
new file mode 100644
index 000000000..9c8a2063e
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/index.html
@@ -0,0 +1,27 @@
+<!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").runApplication();
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/connectionStatusLog.ts b/sdnr/wt/odlux/apps/connectApp/src/models/connectionStatusLog.ts
new file mode 100644
index 000000000..df43c217a
--- /dev/null
+++ b/sdnr/wt/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/apps/connectApp/src/models/guiCutTrough.ts b/sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts
new file mode 100644
index 000000000..4b443bac8
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts
@@ -0,0 +1 @@
+export type guiCutThrough = { webUri: string, nodeId: string } \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementBase.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementBase.ts
new file mode 100644
index 000000000..39278a8e1
--- /dev/null
+++ b/sdnr/wt/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/apps/connectApp/src/models/networkElementConnection.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
new file mode 100644
index 000000000..4c2dc9b09
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
@@ -0,0 +1,36 @@
+export type NetworkElementConnection = {
+ id?: string;
+ nodeId: string;
+ isRequired: boolean;
+ host: string;
+ port: number;
+ username?: string;
+ password?: string;
+ webUri?: string;
+ isWebUriUnreachable?: boolean;
+ status?: "Connected" | "mounted" | "unmounted" | "Connecting" | "Disconnected" | "idle";
+ coreModelCapability?: string;
+ deviceType?: string;
+ nodeDetails?: {
+ availableCapabilites: {
+ capabilityOrigin: string;
+ capability: string;
+ }[];
+ unavailableCapabilities: {
+ failureReason: string;
+ capability: string;
+ }[];
+ }
+}
+
+
+export type UpdateNetworkElement = {
+ id: string;
+ isRequired?: boolean;
+ username?: string;
+ password?: string;
+}
+
+export type ConnectionStatus = {
+ status: string
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnectionLog.ts
new file mode 100644
index 000000000..a1535cbe5
--- /dev/null
+++ b/sdnr/wt/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/apps/connectApp/src/models/panelId.ts b/sdnr/wt/odlux/apps/connectApp/src/models/panelId.ts
new file mode 100644
index 000000000..b51412055
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/panelId.ts
@@ -0,0 +1 @@
+export type PanelId = null | "NetworkElements" | "ConnectionStatusLog"; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts b/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts
new file mode 100644
index 000000000..694009d1b
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.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==========================================================================
+ */
+
+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;
+ node: TopologyNode[];
+}
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts b/sdnr/wt/odlux/apps/connectApp/src/models/yangCapabilitiesType.ts
new file mode 100644
index 000000000..230468287
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/yangCapabilitiesType.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 AvailableCapabilities = {
+ module: string,
+ revision: string
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx b/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx
new file mode 100644
index 000000000..f711c440c
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx
@@ -0,0 +1,56 @@
+/**
+ * ============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 { faPlug } from '@fortawesome/free-solid-svg-icons';
+
+import applicationManager from '../../../framework/src/services/applicationManager';
+import { subscribe, IFormatedMessage } from '../../../framework/src/services/notificationService';
+
+import connectAppRootHandler from './handlers/connectAppRootHandler';
+import ConnectApplication from './views/connectView';
+
+import { AddSnackbarNotification } from '../../../framework/src/actions/snackbarActions';
+import { updateCurrentViewAsyncAction } from './actions/commonNetworkElementsActions';
+
+type ObjectNotification = {
+ counter: string;
+ nodeName: string;
+ objectId: string;
+ timeStamp: string;
+}
+
+export function register() {
+ const applicationApi = applicationManager.registerApplication({
+ name: "connect",
+ icon: faPlug,
+ rootComponent: ConnectApplication,
+ rootActionHandler: connectAppRootHandler,
+ menuEntry: "Connect"
+ });
+
+ // subscribe to the websocket notifications
+ subscribe<ObjectNotification & IFormatedMessage>(["ObjectCreationNotification", "ObjectDeletionNotification", "AttributeValueChangedNotification"], (msg => {
+ const store = applicationApi.applicationStore;
+ if (msg && msg.notifType === "ObjectCreationNotification" && store) {
+ store.dispatch(new AddSnackbarNotification({ message: `Adding network element [${msg.objectId}]`, options: { variant: 'info' } }));
+ } else if (msg && (msg.notifType === "ObjectDeletionNotification" || msg.notifType === "AttributeValueChangedNotification") && store) {
+ store.dispatch(new AddSnackbarNotification({ message: `Updating network element [${msg.objectId}]`, options: { variant: 'info' } }));
+ }
+ store && store.dispatch(updateCurrentViewAsyncAction());
+ }));
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts b/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts
new file mode 100644
index 000000000..7a410f4ae
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts
@@ -0,0 +1,208 @@
+/**
+ * ============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 { convertPropertyNames, replaceUpperCase } from '../../../../framework/src/utilities/yangHelper';
+import { Result } from '../../../../framework/src/models/elasticSearch';
+
+import { Topology, TopologyNode } from '../models/topologyNetconf';
+import { guiCutThrough } from '../models/guiCutTrough';
+
+/**
+* Represents a web api accessor service for all Network Elements actions.
+*/
+class ConnectService {
+
+ /**
+ * Inserts a network elements.
+ */
+ public async createNetworkElement(element: NetworkElementConnection): Promise<NetworkElementConnection | null> {
+ const path = `/restconf/operations/data-provider:create-network-element-connection`;
+ const result = await requestRest<NetworkElementConnection>(path, {
+ method: "POST", body: JSON.stringify(convertPropertyNames({ input: element }, replaceUpperCase))
+ });
+ return result || null;
+ }
+
+ /**
+ * Updates a network element.
+ */
+ public async updateNetworkElement(element: UpdateNetworkElement): Promise<NetworkElementConnection | null> {
+ const path = `/restconf/operations/data-provider:update-network-element-connection`;
+ const result = await requestRest<NetworkElementConnection>(path, {
+ method: "POST", body: JSON.stringify(convertPropertyNames({ input: element }, replaceUpperCase))
+ });
+ return result || null;
+ }
+
+ /**
+ * Deletes a network element.
+ */
+ public async deleteNetworkElement(element: UpdateNetworkElement): Promise<NetworkElementConnection | null> {
+ const query = {
+ "id": element.id
+ };
+ const path = `/restconf/operations/data-provider:delete-network-element-connection`;
+ const result = await requestRest<NetworkElementConnection>(path, {
+ method: "POST", body: JSON.stringify(convertPropertyNames({ input: query }, replaceUpperCase))
+ });
+ return result || null;
+ }
+
+ /** Mounts network element. */
+ public async mountNetworkElement(networkElement: NetworkElementConnection): Promise<boolean> {
+ const path = 'restconf/config/network-topology:network-topology/topology/topology-netconf/node/' + 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('');
+
+ try {
+ const result = await requestRest<string>(path, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/xml',
+ 'Accept': 'application/xml'
+ },
+ body: mountXml
+ });
+ // 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 = 'restconf/config/network-topology:network-topology/topology/topology-netconf/node/' + 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 elements. */
+ public async infoNetworkElement(nodeId: string): Promise<TopologyNode | null> {
+ const path = 'restconf/operational/network-topology:network-topology/topology/topology-netconf/node/' + nodeId;
+ const topologyRequestPomise = requestRest<Topology>(path, { method: "GET" });
+
+ return topologyRequestPomise && topologyRequestPomise.then(result => {
+ return result && result.node && result.node[0] || null;
+ });
+ }
+
+ /**
+ * Get the connection state of the network element.
+ */
+ public async getNetworkElementConnectionStatus(element: string): Promise<(ConnectionStatus)[] | null> {
+ const path = `/restconf/operations/data-provider:read-network-element-connection-list`;
+ const query = {
+ "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.output && result.output.data && result.output.data.map(ne => ({
+ status: ne.status
+ })) || null;
+ }
+
+ public async getWebUriExtensionForNetworkElementAsync(ne: string) {
+ const path = 'restconf/config/network-topology:network-topology/topology/topology-netconf/node/' + ne + '/yang-ext:mount/core-model:network-element';
+ try {
+ const result = await requestRest<any>(path, { method: "GET" });
+
+ if (result['network-element'].extension) {
+ const webUri = result['network-element'].extension.find((item: any) => item['value-name'] === "webUri")
+ if (webUri) {
+ return webUri.value as string;
+ }
+ }
+ } catch (error) {
+ console.log(ne + ' unrechable: ' + error)
+ }
+
+ return undefined;
+
+ }
+
+ public getAllWebUriExtensionsForNetworkElementListAsync(ne: string[]) {
+
+ let promises: any[] = [];
+ let webUris: guiCutThrough[] = []
+
+ ne.forEach(nodeId => {
+ const path = 'restconf/config/network-topology:network-topology/topology/topology-netconf/node/' + nodeId + '/yang-ext:mount/core-model:network-element';
+
+ // add search request to array
+ promises.push(requestRest<any>(path, { method: "GET" })
+ .then(result => {
+
+ if (result['network-element'] && result['network-element'].extension) {
+ const webUri = result['network-element'].extension.find((item: any) => item['value-name'] === "webUri")
+ if (webUri) {
+ webUris.push({ webUri: webUri.value, nodeId: nodeId });
+ }
+ }
+ })
+ .catch(error => console.log("network element is unreachable: " + error)))
+
+ })
+
+ // wait until all promises are done and return weburis
+ return Promise.all(promises).then(result => { return webUris });
+ }
+
+}
+export const connectService = new ConnectService();
+export default connectService;
diff --git a/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx b/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
new file mode 100644
index 000000000..aa3391c47
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
@@ -0,0 +1,111 @@
+/**
+ * ============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 connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { Panel } from '../../../../framework/src/components/material-ui';
+import { networkElementsReloadAction, createNetworkElementsActions } from '../handlers/networkElementsHandler';
+import { connectionStatusLogReloadAction, createConnectionStatusLogActions } from '../handlers/connectionStatusLogHandler';
+
+import { NetworkElementsList } from '../components/networkElements';
+import { ConnectionStatusLog } from '../components/connectionStatusLog';
+import { setPanelAction, findWebUrisForGuiCutThroughAsyncAction } from '../actions/commonNetworkElementsActions';
+import { PanelId } from '../models/panelId';
+import { NetworkElementConnection } from 'models/networkElementConnection';
+
+const mapProps = (state: IApplicationStoreState) => ({
+ panelId: state.connect.currentOpenPanel,
+ user: state.framework.authenticationState.user,
+ netWorkElements: state.connect.networkElements,
+ availableGuiCutroughs: state.connect.guiCutThrough
+});
+
+const mapDispatcher = (dispatcher: IDispatcher) => ({
+ networkElementsActions: createNetworkElementsActions(dispatcher.dispatch),
+ connectionStatusLogActions: createConnectionStatusLogActions(dispatcher.dispatch),
+ onLoadNetworkElements: () => {
+ dispatcher.dispatch(networkElementsReloadAction);
+ },
+ loadWebUris: findWebUrisForGuiCutThroughAsyncAction(dispatcher.dispatch),
+ onLoadConnectionStatusLog: () => {
+ dispatcher.dispatch(connectionStatusLogReloadAction);
+ },
+ switchActivePanel: (panelId: PanelId) => {
+ dispatcher.dispatch(setPanelAction(panelId));
+ }
+});
+
+type ConnectApplicationComponentProps = Connect<typeof mapProps, typeof mapDispatcher>;
+
+class ConnectApplicationComponent extends React.Component<ConnectApplicationComponentProps>{
+
+ componentDidUpdate = () => {
+ // search for guicutthroughs after networkelements were found
+ const networkElements = this.props.netWorkElements;
+ const guiCuttrough = this.props.availableGuiCutroughs;
+
+ if (networkElements.rows.length > 0 && networkElements.total !== guiCuttrough.knownElements.length) {
+ this.props.loadWebUris(networkElements.rows, guiCuttrough.knownElements);
+ }
+ }
+
+ private onTogglePanel = (panelId: PanelId) => {
+ const nextActivePanel = panelId === this.props.panelId ? null : panelId;
+ this.props.switchActivePanel(nextActivePanel);
+
+ switch (nextActivePanel) {
+ case 'NetworkElements':
+ this.props.onLoadNetworkElements();
+ break;
+ case 'ConnectionStatusLog':
+ this.props.onLoadConnectionStatusLog();
+ break;
+ case null:
+ // do nothing if all panels are closed
+ break;
+ default:
+ console.warn("Unknown nextActivePanel [" + nextActivePanel + "] in connectView");
+ break;
+ }
+
+ };
+
+ render(): JSX.Element {
+ const { panelId } = this.props;
+
+ return (
+ <>
+ <Panel activePanel={panelId} panelId={'NetworkElements'} onToggle={this.onTogglePanel} title={"Network Elements"}>
+ <NetworkElementsList />
+ </Panel>
+ <Panel activePanel={panelId} panelId={'ConnectionStatusLog'} onToggle={this.onTogglePanel} title={"Connection Status Log"}>
+ <ConnectionStatusLog />
+ </Panel>
+ </>
+ );
+ };
+ public componentDidMount() {
+ this.onTogglePanel("NetworkElements");
+ this.props.networkElementsActions.onToggleFilter();
+ this.props.connectionStatusLogActions.onToggleFilter();
+ }
+}
+
+export const ConnectApplication = (connect(mapProps, mapDispatcher)(ConnectApplicationComponent));
+export default ConnectApplication; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java b/sdnr/wt/odlux/apps/connectApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java
new file mode 100644
index 000000000..1e882fc69
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * 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==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.odlux.bundles;
+
+import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundle;
+import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader;
+
+public class MyOdluxBundle extends OdluxBundle {
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ }
+
+ @Override
+ public void clean() {
+ super.clean();
+ }
+
+ @Override
+ public String getResourceFileContent(String filename) {
+ return super.getResourceFileContent(filename);
+ }
+
+ @Override
+ public boolean hasResource(String filename) {
+ return super.hasResource(filename);
+ }
+
+ @Override
+ public void setBundleName(String bundleName) {
+ super.setBundleName(bundleName);
+ }
+
+ @Override
+ public void setLoader(OdluxBundleLoader loader) {
+ super.setLoader(loader);
+ }
+
+ @Override
+ public String getBundleName() {
+ return super.getBundleName();
+ }
+
+ @Override
+ public OdluxBundleLoader getLoader() {
+ return super.getLoader();
+ }
+
+ public MyOdluxBundle() {
+ super();
+ }
+}
diff --git a/sdnr/wt/odlux/apps/connectApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wt/odlux/apps/connectApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 000000000..adc9b777b
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,9 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <reference id="loadersvc" availability="mandatory" activation="eager" interface="org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader"/>
+
+ <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.onap.ccsdk.features.sdnr.wt.odlux.bundles.MyOdluxBundle">
+ <property name="loader" ref="loadersvc"/>
+ <property name="bundleName" value="connectApp"/>
+ <property name="index" value="0"/>
+ </bean>
+</blueprint> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java b/sdnr/wt/odlux/apps/connectApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java
new file mode 100644
index 000000000..edf68e096
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * 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==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.odlux.bundles.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.odlux.OdluxBundleLoaderImpl;
+import org.onap.ccsdk.features.sdnr.wt.odlux.bundles.MyOdluxBundle;
+
+public class TestBundleRes {
+
+ @Test
+ public void test() {
+ OdluxBundleLoaderImpl loader = OdluxBundleLoaderImpl.getInstance();
+ MyOdluxBundle b = new MyOdluxBundle();
+ b.setLoader(loader);
+ b.setIndex(0);
+ b.setBundleName("abc");
+ b.initialize();
+ assertTrue(loader.getNumberOfBundles()==1);
+ assertNotNull(b.getLoader());
+ assertEquals("abc",b.getBundleName());
+ assertTrue(b.hasResource("test.js"));
+ assertNotNull(b.getResourceFileContent("test.js"));
+ b.clean();
+ assertTrue(loader.getNumberOfBundles()==0);
+ }
+
+}
diff --git a/sdnr/wt/odlux/apps/connectApp/src2/test/resources/test.js b/sdnr/wt/odlux/apps/connectApp/src2/test/resources/test.js
new file mode 100644
index 000000000..b47fdc39f
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src2/test/resources/test.js
@@ -0,0 +1,5 @@
+asdac sad
+as
+d
+sad
+ sadfa \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/tsconfig.json b/sdnr/wt/odlux/apps/connectApp/tsconfig.json
new file mode 100644
index 000000000..a66b5d828
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/tsconfig.json
@@ -0,0 +1,37 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./src",
+ "outDir": "./dist",
+ "sourceMap": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowSyntheticDefaultImports": false,
+ "allowUnreachableCode": false,
+ "allowUnusedLabels": false,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "pretty": true,
+ "newLine": "LF",
+ "module": "es2015",
+ "target": "es2016",
+ "moduleResolution": "node",
+ "experimentalDecorators": true,
+ "jsx": "preserve",
+ "lib": [
+ "dom",
+ "es2015",
+ "es2016"
+ ],
+ "types": [
+ "prop-types",
+ "react",
+ "react-dom"
+ ]
+ },
+ "exclude": [
+ "dist",
+ "node_modules"
+ ]
+}
diff --git a/sdnr/wt/odlux/apps/connectApp/webpack.config.js b/sdnr/wt/odlux/apps/connectApp/webpack.config.js
new file mode 100644
index 000000000..6d70b04b0
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/webpack.config.js
@@ -0,0 +1,153 @@
+/**
+ * Webpack 4 configuration file
+ * see https://webpack.js.org/configuration/
+ * see https://webpack.js.org/configuration/dev-server/
+ */
+
+"use strict";
+
+const path = require("path");
+const webpack = require("webpack");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const TerserPlugin = require('terser-webpack-plugin');
+
+// const __dirname = (path => path.replace(/^([a-z]\:)/, c => c.toUpperCase()))(process.__dirname());
+
+module.exports = (env) => {
+ const distPath = path.resolve(__dirname, env === "release" ? "." : "../..", "dist");
+ const frameworkPath = path.resolve(__dirname, env === "release" ? "../../framework" : "../..", "dist");
+ return [{
+ name: "App",
+
+ mode: "none", //disable default behavior
+
+ target: "web",
+
+ context: path.resolve(__dirname, "src"),
+
+ entry: {
+ 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"
+ }]
+ }]
+ },
+
+ optimization: {
+ noEmitOnErrors: true,
+ namedModules: env !== "release",
+ minimize: env === "release",
+ minimizer: env !== "release" ? [] : [new TerserPlugin({
+ terserOptions: {
+ warnings: false, // false, true, "verbose"
+ compress: {
+ drop_console: true,
+ drop_debugger: true,
+ }
+ }
+ })],
+ },
+ plugins: [
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, "../../framework/src"),
+ manifest: require(path.resolve(frameworkPath, "vendor-manifest.json")),
+ sourceType: "umd2"
+ }),
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, "../../framework/src"),
+ manifest: require(path.resolve(frameworkPath, "app-manifest.json")),
+ sourceType: "umd2"
+ }),
+ ...(env === "release") ? [
+ new webpack.DefinePlugin({
+ "process.env": {
+ NODE_ENV: "'production'",
+ VERSION: JSON.stringify(require("./package.json").version)
+ }
+ }),
+ ] : [
+ new webpack.DefinePlugin({
+ "process.env": {
+ NODE_ENV: "'development'",
+ VERSION: JSON.stringify(require("./package.json").version)
+ }
+ }),
+ new CopyWebpackPlugin([{
+ from: 'index.html',
+ to: distPath
+ }]),
+ ]
+ ],
+
+ devServer: {
+ public: "http://localhost:3100",
+ contentBase: frameworkPath,
+
+ compress: true,
+ headers: {
+ "Access-Control-Allow-Origin": "*"
+ },
+ host: "0.0.0.0",
+ port: 3100,
+ disableHostCheck: true,
+ historyApiFallback: true,
+ inline: true,
+ hot: false,
+ quiet: false,
+ stats: {
+ colors: true
+ },
+ proxy: {
+ "/oauth2/": {
+ target: "http://10.20.6.29:28181",
+ secure: false
+ },
+ "/database/": {
+ target: "http://10.20.6.29:28181",
+ secure: false
+ },
+ "/restconf/": {
+ target: "http://10.20.6.29:28181",
+ secure: false
+ },
+ "/help/": {
+ target: "http://10.20.6.29:28181",
+ secure: false
+ },
+ "/websocket": {
+ target: "http://10.20.6.29:28181",
+ ws: true,
+ changeOrigin: true,
+ secure: false
+ }
+ }
+ }
+ }];
+}