aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/apps/helpApp
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/apps/helpApp')
-rw-r--r--sdnr/wt/odlux/apps/helpApp/.babelrc17
-rw-r--r--sdnr/wt/odlux/apps/helpApp/package.json45
-rw-r--r--sdnr/wt/odlux/apps/helpApp/pom.xml110
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/actions/helpActions.ts61
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/components/markdown.tsx60
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/components/subMenuEntry.tsx37
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/handlers/helpAppRootHandler.ts58
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/index.html25
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts24
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/plugin.tsx69
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts47
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/utilities/path.ts62
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src/views/helpApplication.tsx53
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java68
-rw-r--r--sdnr/wt/odlux/apps/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml9
-rw-r--r--sdnr/wt/odlux/apps/helpApp/tsconfig.json37
-rw-r--r--sdnr/wt/odlux/apps/helpApp/webpack.config.js153
17 files changed, 935 insertions, 0 deletions
diff --git a/sdnr/wt/odlux/apps/helpApp/.babelrc b/sdnr/wt/odlux/apps/helpApp/.babelrc
new file mode 100644
index 000000000..3d8cd1260
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/.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/helpApp/package.json b/sdnr/wt/odlux/apps/helpApp/package.json
new file mode 100644
index 000000000..a1bcc39e7
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@odlux/help-app",
+ "version": "0.1.0",
+ "description": "A react based modular UI providing the help functionaliy.",
+ "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": "MIT",
+ "dependencies": {
+ "@odlux/framework": "*",
+ "marked" : "0.6.0",
+ "@types/marked": "0.6.0",
+ "highlight.js" : "9.13.1",
+ "@types/highlight.js": "9.12.3",
+ "github-markdown-css": "2.10.0"
+ },
+ "peerDependencies": {
+ "@types/react": "16.4.14",
+ "@types/react-dom": "16.0.8",
+ "@types/react-router-dom": "4.3.1",
+ "@material-ui/core": "3.8.3",
+ "@material-ui/icons": "3.0.2",
+ "@types/classnames": "2.2.6",
+ "@types/flux": "3.1.8",
+ "@types/jquery": "3.3.10",
+ "jquery": "3.3.1",
+ "react": "16.5.2",
+ "react-dom": "16.5.2",
+ "react-router-dom": "4.3.1"
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/pom.xml b/sdnr/wt/odlux/apps/helpApp/pom.xml
new file mode 100644
index 000000000..439e05a4c
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/pom.xml
@@ -0,0 +1,110 @@
+<?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.2.1-SNAPSHOT</version>
+ <relativePath />
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+ <artifactId>sdnr-wt-odlux-app-helpApp</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>sdnr-wt-odlux-app-helpApp</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>
+ </dependencies>
+ <build>
+ <sourceDirectory>src2/main/java</sourceDirectory>
+ <plugins>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>2.5</version>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>dist</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>com.github.eirslett</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.8-SNAPSHOT</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>v8.10.0</nodeVersion>
+ <yarnVersion>v1.12.3</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></Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ <resources>
+ <resource>
+ <directory>dist</directory>
+ <targetPath>odlux</targetPath>
+ </resource>
+ <resource>
+ <directory>src2/main/resources</directory>
+ </resource>
+ </resources>
+ </build>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>highstreet repo</id>
+ <url>https://cloud-highstreet-technologies.com/mvn/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+</project> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src/actions/helpActions.ts b/sdnr/wt/odlux/apps/helpApp/src/actions/helpActions.ts
new file mode 100644
index 000000000..ba8969a2c
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/actions/helpActions.ts
@@ -0,0 +1,61 @@
+import { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+
+import { TocTreeNode } from '../models/tocNode';
+import helpService from '../services/helpService';
+
+export class LoadTocAction extends Action {
+ constructor() {
+ super();
+
+ }
+}
+
+export class TocLoadedAction extends Action {
+ constructor(public toc?: TocTreeNode[], error?: string) {
+ super();
+
+ }
+}
+
+export const requestTocAsyncAction = async (dispatch: Dispatch) => {
+ dispatch(new LoadTocAction);
+ try {
+ const toc = await helpService.getTableOfContents();
+ if (toc) {
+ dispatch(new TocLoadedAction(toc));
+ } else {
+ dispatch(new TocLoadedAction(undefined, "Could not load TOC."));
+ }
+ } catch (err) {
+ dispatch(new TocLoadedAction(undefined, err));
+ }
+}
+
+export class LoadDocumentAction extends Action {
+ constructor() {
+ super();
+
+ }
+}
+
+export class DocumentLoadedAction extends Action {
+ constructor(public document?: string, public documentPath?: string, error?: string) {
+ super();
+
+ }
+}
+
+export const requestDocumentAsyncActionCreator = (path: string) => async (dispatch: Dispatch) => {
+ dispatch(new LoadDocumentAction);
+ try {
+ const doc = await helpService.getDocument(path);
+ if (doc) {
+ dispatch(new DocumentLoadedAction(doc, path));
+ } else {
+ dispatch(new DocumentLoadedAction(undefined, undefined, "Could not load document."));
+ }
+ } catch (err) {
+ dispatch(new DocumentLoadedAction(undefined, undefined, err));
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src/components/markdown.tsx b/sdnr/wt/odlux/apps/helpApp/src/components/markdown.tsx
new file mode 100644
index 000000000..ea272bc4d
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/components/markdown.tsx
@@ -0,0 +1,60 @@
+import * as React from 'react';
+
+import * as marked from 'marked';
+import * as hljs from 'highlight.js';
+
+type MarkdownComponentProps = {
+ text: string;
+ className?: string;
+ markedOptions?: marked.MarkedOptions;
+ style?: React.CSSProperties
+}
+
+const defaultRenderer = new marked.Renderer();
+defaultRenderer.link = (href, title, text) => (
+ `<a target="_blank" rel="noopener noreferrer" href="${ href }" title="${ title }">${ text }</a>`
+);
+
+
+class MarkdownComponent extends React.Component<MarkdownComponentProps> {
+ constructor(props: MarkdownComponentProps) {
+ super(props);
+
+ const markedOptions: marked.MarkedOptions = {
+ gfm: true,
+ tables: true,
+ breaks: false,
+ pedantic: false,
+ sanitize: true,
+ smartLists: true,
+ smartypants: false,
+ langPrefix: 'hljs ',
+ ...(this.props.markedOptions || {}),
+ highlight: (code, lang) => {
+ if (!!(lang && hljs.getLanguage(lang))) {
+ return hljs.highlight(lang, code).value;
+ }
+ return code;
+ }
+ };
+
+ marked.setOptions(markedOptions);
+ }
+ render() {
+ const { text, className, style } = this.props;
+
+
+ const html = (marked(text || '', { renderer: this.props.markedOptions && this.props.markedOptions.renderer || defaultRenderer }));
+
+ return (
+ <div
+ dangerouslySetInnerHTML={ { __html: html } }
+ className={ className }
+ style={ style }
+ />
+ );
+ }
+}
+
+export const Markdown = MarkdownComponent;
+
diff --git a/sdnr/wt/odlux/apps/helpApp/src/components/subMenuEntry.tsx b/sdnr/wt/odlux/apps/helpApp/src/components/subMenuEntry.tsx
new file mode 100644
index 000000000..72bb39e39
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/components/subMenuEntry.tsx
@@ -0,0 +1,37 @@
+import * as React from 'react';
+
+import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
+import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { TreeView, TreeViewCtorType } from '../../../../framework/src/components/material-ui/treeView';
+
+import { ListItemText } from '@material-ui/core';
+
+import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions';
+
+import { TocTreeNode } from '../models/tocNode';
+
+const TocTree = TreeView as any as TreeViewCtorType<TocTreeNode>;
+
+const mapProps = (state: IApplicationStoreState) => ({
+ helpToc: state.helpApp.toc,
+ helpBusy: state.helpApp.busy
+});
+
+const mapDisp = (dispatcher: IDispatcher) => ({
+ requestDocument: (node: TocTreeNode) => dispatcher.dispatch(new NavigateToApplication("helpApp", node.uri))
+});
+
+const SubMenuEntryComponent: React.SFC<Connect<typeof mapProps, typeof mapDisp>> = (props) => {
+ return props.helpToc
+ ? (
+ <TocTree items={ props.helpToc } contentProperty={ "label" } childrenProperty={ "nodes" } depthOffset={ 1 }
+ useFolderIcons={ false } enableSearchBar={ false } onItemClick={ props.requestDocument } />
+ )
+ : (
+ <ListItemText >Loading ...</ListItemText>
+ )
+};
+
+export const SubMenuEntry = connect(mapProps, mapDisp)(SubMenuEntryComponent);
+export default SubMenuEntry;
+
diff --git a/sdnr/wt/odlux/apps/helpApp/src/handlers/helpAppRootHandler.ts b/sdnr/wt/odlux/apps/helpApp/src/handlers/helpAppRootHandler.ts
new file mode 100644
index 000000000..efdc6e83d
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/handlers/helpAppRootHandler.ts
@@ -0,0 +1,58 @@
+// main state handler
+
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { TocTreeNode } from 'models/tocNode';
+import { IActionHandler } from '../../../../framework/src/flux/action';
+import { LoadTocAction, TocLoadedAction, LoadDocumentAction, DocumentLoadedAction } from '../actions/helpActions';
+
+export interface IHelpAppStoreState {
+ busy: boolean;
+ toc: TocTreeNode[] | undefined;
+ content: string | undefined;
+ currentPath: string | undefined;
+}
+
+declare module '../../../../framework/src/store/applicationStore' {
+ interface IApplicationStoreState {
+ helpApp: IHelpAppStoreState
+ }
+}
+
+const helpAppStoreStateInit: IHelpAppStoreState = {
+ busy: false,
+ toc: undefined,
+ content: undefined,
+ currentPath: undefined
+};
+
+export const helpAppRootHandler: IActionHandler<IHelpAppStoreState> = (state = helpAppStoreStateInit, action) => {
+ if (action instanceof LoadTocAction) {
+ state = {
+ ...state,
+ busy: true
+ };
+ } else if (action instanceof TocLoadedAction) {
+ state = {
+ ...state,
+ busy: false,
+ toc: action.toc
+ };
+ } else if (action instanceof LoadDocumentAction) {
+ state = {
+ ...state,
+ busy: true
+ };
+ } else if (action instanceof DocumentLoadedAction) {
+ state = {
+ ...state,
+ busy: false,
+ content: action.document,
+ currentPath: action.documentPath
+ };
+ }
+
+ return state;
+}
+
+
+export default helpAppRootHandler;
diff --git a/sdnr/wt/odlux/apps/helpApp/src/index.html b/sdnr/wt/odlux/apps/helpApp/src/index.html
new file mode 100644
index 000000000..2d20410e0
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/index.html
@@ -0,0 +1,25 @@
+<!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>Minimal App</title>
+</head>
+
+<body>
+ <div id="app"></div>
+ <script type="text/javascript" src="./require.js"></script>
+ <script type="text/javascript" src="./config.js"></script>
+ <script>
+ // run the application
+ require(["app", "helpApp"], function (app, helpApp) {
+ helpApp.register();
+ app("./app.tsx")
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts b/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts
new file mode 100644
index 000000000..ae73ec43d
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts
@@ -0,0 +1,24 @@
+export type VersionInfo = {
+ label: string,
+ path: string,
+ date: string
+}
+
+export type TocNode = {
+ label: string;
+ versions: {
+ [versionKey: string]: VersionInfo,
+ current: VersionInfo
+ };
+ nodes?: TocNodeCollection;
+}
+
+export type TocNodeCollection = { [tocNodeKey: string]: TocNode };
+
+
+export type TocTreeNode = {
+ label: string;
+ uri: string;
+ nodes?: TocTreeNode[];
+ disabled?: boolean;
+}
diff --git a/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx b/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx
new file mode 100644
index 000000000..d1cf80804
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx
@@ -0,0 +1,69 @@
+// app configuration and main entry point for the app
+
+import * as React from "react";
+import { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-router-dom';
+
+import { faFirstAid } from '@fortawesome/free-solid-svg-icons'; // select app icon
+
+import applicationManager from '../../../framework/src/services/applicationManager';
+import { IApplicationStoreState } from "../../../framework/src/store/applicationStore";
+import connect, { Connect, IDispatcher } from '../../../framework/src/flux/connect';
+
+import { requestTocAsyncAction, requestDocumentAsyncActionCreator } from "./actions/helpActions";
+import { helpAppRootHandler } from './handlers/helpAppRootHandler';
+
+import { HelpApplication } from './views/helpApplication';
+import { SubMenuEntry } from "./components/subMenuEntry";
+
+import '!style-loader!css-loader!highlight.js/styles/default.css';
+
+const mapProps = (state: IApplicationStoreState) => ({
+
+});
+
+const mapDisp = (dispatcher: IDispatcher) => ({
+ requestDocument: (path: string) => {
+ dispatcher.dispatch(requestDocumentAsyncActionCreator(path));
+ }
+});
+
+let currentHelpPath: string | undefined = undefined;
+
+const HelpApplicationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComponentProps<{ '0'?: string }> & Connect<typeof mapProps, typeof mapDisp>) => {
+ if (currentHelpPath !== props.match.params["0"]) {
+ // route parameter has changed
+ currentHelpPath = props.match.params["0"] || undefined;
+ // Hint: This timeout is need, since it is not recommended to change the state while rendering is in progress !
+ window.setTimeout(() => {
+ if (currentHelpPath) {
+ props.requestDocument(currentHelpPath);
+ }
+ });
+ }
+ return (
+ <HelpApplication />
+ )
+});
+
+const App = withRouter((props: RouteComponentProps) => (
+ <Switch>
+ <Route path={ `${ props.match.path }/*` } component={ HelpApplicationRouteAdapter } />
+ <Redirect to={ `${ props.match.path }` } />
+ </Switch>
+));
+
+export async function register() {
+ const applicationApi = applicationManager.registerApplication({
+ name: "helpApp",
+ icon: faFirstAid,
+ rootComponent: App,
+ rootActionHandler: helpAppRootHandler,
+ menuEntry: "Help",
+ subMenuEntry: SubMenuEntry
+ });
+
+ // start the initial toc request after the application store is initalized
+ const store = await applicationApi.applicationStoreInitialized;
+ store.dispatch(requestTocAsyncAction);
+
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts b/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts
new file mode 100644
index 000000000..480cdd04e
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts
@@ -0,0 +1,47 @@
+import { requestRest } from '../../../../framework/src/services/restService';
+import { TocTreeNode, TocNodeCollection } from '../models/tocNode';
+
+class HelpService {
+
+ private tocNodeCollection: TocTreeNode[] | null = null;
+ private documents: { [path: string]: string | null } = {};
+
+ public async getDocument(path: string): Promise<string | null> {
+ // check if the result is allready in the cache
+ if (this.documents[path]) return Promise.resolve(this.documents[path]);
+
+ // request the document
+ const result = await requestRest<string>(`/help/${ path }`.replace(/\/{2,}/i, '/'));
+ if (result) {
+ this.documents[path] = result;
+ }
+ return this.documents[path] || null;
+ }
+
+ public async getTableOfContents(): Promise<TocTreeNode[] | null> {
+ // check if the result is allready in the cache
+ if (this.tocNodeCollection) return Promise.resolve(this.tocNodeCollection);
+
+ // request the table of contents
+ const result = await requestRest<TocNodeCollection>('/help/?meta');
+ if (result !== false) {
+ const mapNodesCollection = (col: TocNodeCollection): TocTreeNode[] => {
+ return Object.keys(col).reduce <TocTreeNode[]>((acc, key) => {
+ const current = col[key];
+ acc.push({
+ label: current.label,
+ uri: current.versions.current.path,
+ nodes: current.nodes && mapNodesCollection(current.nodes) || undefined
+ });
+ return acc;
+ }, []);
+ }
+
+ this.tocNodeCollection = result && mapNodesCollection(result);
+ }
+ return this.tocNodeCollection || null;
+ }
+}
+
+export const helpService = new HelpService();
+export default helpService; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src/utilities/path.ts b/sdnr/wt/odlux/apps/helpApp/src/utilities/path.ts
new file mode 100644
index 000000000..3cc58a202
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/utilities/path.ts
@@ -0,0 +1,62 @@
+export const resolvePath = (...paths: string[]): string => {
+ function resolve(pathA: string, pathB: string) {
+ // ‘a’ => ['a']
+ // 'a/b' => ['a', 'b']
+ // '/a/b' => ['', 'a', 'b']
+ // '/a/b/' => ['', 'a', 'b', '']
+ const pathBParts = pathB.split('/');
+ if (pathBParts[0] === '') {
+ return pathBParts.join('/');
+ }
+ const pathAParts = pathA.split('/');
+ const aLastIndex = pathAParts.length - 1;
+ if (pathAParts[aLastIndex] !== '') {
+ pathAParts[aLastIndex] = '';
+ }
+
+ let part: string;
+ let i = 0;
+ while (typeof (part = pathBParts[i]) === 'string') {
+ switch (part) {
+ case '..':
+ pathAParts.pop();
+ pathAParts.pop();
+ pathAParts.push('');
+ break;
+ case '.':
+ pathAParts.pop();
+ pathAParts.push('');
+ break;
+ default:
+ pathAParts.pop();
+ pathAParts.push(part);
+ pathAParts.push('');
+ break;
+ }
+ i++;
+ }
+ if (pathBParts[pathBParts.length - 1] !== '') pathAParts.pop();
+ return pathAParts.join('/');
+ }
+
+ let i = 0;
+ let path: string;
+ let r = location.pathname;
+
+ const urlRegex = /^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i;
+ const multiSlashReg = /\/\/+/g;
+
+ while (typeof (path = paths[i]) === 'string') {
+ debugger;
+ const matches = path && path.match(urlRegex);
+ if (matches || !i) {
+ r = path;
+ } else {
+ path = path.replace(multiSlashReg, '/');
+ r = resolve(r, path);
+ }
+ i++;
+ }
+
+ return r;
+}; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src/views/helpApplication.tsx b/sdnr/wt/odlux/apps/helpApp/src/views/helpApplication.tsx
new file mode 100644
index 000000000..dedb93607
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/src/views/helpApplication.tsx
@@ -0,0 +1,53 @@
+import * as React from 'react';
+import * as marked from 'marked';
+
+import { resolvePath } from '../utilities/path';
+
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import connect, { Connect } from '../../../../framework/src/flux/connect';
+
+import { Markdown } from "../components/markdown";
+
+import '!style-loader!css-loader!github-markdown-css/github-markdown.css'
+
+const mapProps = (state: IApplicationStoreState) => ({
+ content: state.helpApp.content,
+ currentPath: state.helpApp.currentPath
+});
+
+type HelpApplicationComponentProps = Connect<typeof mapProps>;
+
+class HelpApplicationComponent extends React.Component<HelpApplicationComponentProps> {
+
+ /**
+ * Initializes a new instance.
+ */
+ constructor(props: HelpApplicationComponentProps) {
+ super(props);
+
+ this.renderer = new marked.Renderer();
+
+ this.renderer.link = (href: string, title: string, text: string) => {
+ // check if href is rel or abs
+ const absUrlMatch = href.trim().match(/^https?:\/\//i);
+ return `<a href="${ absUrlMatch ? href : resolvePath('#/helpApp/', this.props.currentPath || '/', href) }" title="${ title }" >${ text }</a>`
+ };
+
+ this.renderer.image = (href: string, title: string) => {
+ return `<img src="${ resolvePath('/help/', this.props.currentPath || '/', href) }" alt="${ title }" />`
+ };
+
+ }
+
+ render(): JSX.Element {
+ return this.props.content ? (
+ <Markdown text={ this.props.content } markedOptions={ { renderer: this.renderer } } className="markdown-body"
+ style={{ maxWidth: "960px", margin: "1.5em auto" }} />
+ ) : (<h2>Loading ...</h2>)
+ }
+
+ private renderer: marked.Renderer;
+}
+
+export const HelpApplication = connect(mapProps)(HelpApplicationComponent);
+export default HelpApplication; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java b/sdnr/wt/odlux/apps/helpApp/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/helpApp/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/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wt/odlux/apps/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 000000000..a0e3dac11
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/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="helpApp"/>
+ <property name="index" value="100"/>
+ </bean>
+</blueprint> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/helpApp/tsconfig.json b/sdnr/wt/odlux/apps/helpApp/tsconfig.json
new file mode 100644
index 000000000..a66b5d828
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/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/helpApp/webpack.config.js b/sdnr/wt/odlux/apps/helpApp/webpack.config.js
new file mode 100644
index 000000000..fdae7d957
--- /dev/null
+++ b/sdnr/wt/odlux/apps/helpApp/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 autoprefixer = require('autoprefixer');
+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: {
+ helpApp: ["./plugin.tsx"]
+ },
+
+ devtool: env === "release" ? false : "source-map",
+
+ resolve: {
+ extensions: [".ts", ".tsx", ".js", ".jsx"]
+ },
+
+ output: {
+ path: distPath,
+ filename: "[name].js",
+ library: "[name]",
+ libraryTarget: "umd2",
+ chunkFilename: "[name].js"
+ },
+ module: {
+ rules: [{
+ test: /\.tsx?$/,
+ exclude: /node_modules/,
+ use: [{
+ loader: "babel-loader"
+ }, {
+ loader: "ts-loader"
+ }]
+ }, {
+ test: /\.jsx?$/,
+ exclude: /node_modules/,
+ use: [{
+ loader: "babel-loader"
+ }]
+ }, {
+ test: /\.css$/,
+ use: [{
+ loader: 'style-loader'
+ }, {
+ loader: 'css-loader',
+ options: {
+ modules: true,
+ localIdentName: env !== "release" ? '[name]_[local]_[hash:base64:5]' : '[hash]'
+ }
+ }, {
+ loader: 'postcss-loader',
+ options: {
+ plugins: () => [autoprefixer]
+ }
+ }]
+ }]
+ },
+
+ 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: {
+ "/help": {
+ target: "http://localhost:8181",
+ secure: false
+ }
+ }
+ }
+ }];
+}