Merge "SDN-R add updated featureaggregator"
authorKAPIL SINGAL <ks220y@att.com>
Sun, 2 Feb 2020 19:28:14 +0000 (19:28 +0000)
committerGerrit Code Review <gerrit@onap.org>
Sun, 2 Feb 2020 19:28:14 +0000 (19:28 +0000)
63 files changed:
sdnr/wt/odlux/README.md
sdnr/wt/odlux/apps/apiDemo/pom.xml
sdnr/wt/odlux/apps/app-feature/pom.xml
sdnr/wt/odlux/apps/configurationApp/pom.xml
sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts
sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/uiElementReference.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/components/verifyer.ts [new file with mode: 0644]
sdnr/wt/odlux/apps/configurationApp/src/handlers/configurationAppRootHandler.ts
sdnr/wt/odlux/apps/configurationApp/src/handlers/connectedNetworkElementsHandler.ts
sdnr/wt/odlux/apps/configurationApp/src/handlers/deviceDescriptionHandler.ts
sdnr/wt/odlux/apps/configurationApp/src/handlers/valueSelectorHandler.ts
sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts
sdnr/wt/odlux/apps/configurationApp/src/models/networkElementConnection.ts
sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts
sdnr/wt/odlux/apps/configurationApp/src/models/yang.ts
sdnr/wt/odlux/apps/configurationApp/src/pluginConfiguration.tsx
sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts
sdnr/wt/odlux/apps/configurationApp/src/services/yangService.ts
sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
sdnr/wt/odlux/apps/configurationApp/src/views/networkElementSelector.tsx
sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts
sdnr/wt/odlux/apps/configurationApp/tsconfig.json
sdnr/wt/odlux/apps/connectApp/pom.xml
sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
sdnr/wt/odlux/apps/connectApp/src/actions/networkElementsActions.ts
sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts
sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
sdnr/wt/odlux/apps/connectApp/src/models/panelId.ts
sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts
sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
sdnr/wt/odlux/apps/connectApp/webpack.config.js
sdnr/wt/odlux/apps/demoApp/pom.xml
sdnr/wt/odlux/apps/eventLogApp/pom.xml
sdnr/wt/odlux/apps/faultApp/pom.xml
sdnr/wt/odlux/apps/helpApp/pom.xml
sdnr/wt/odlux/apps/inventoryApp/pom.xml
sdnr/wt/odlux/apps/maintenanceApp/pom.xml
sdnr/wt/odlux/apps/mediatorApp/pom.xml
sdnr/wt/odlux/apps/minimumApp/pom.xml
sdnr/wt/odlux/apps/performanceHistoryApp/pom.xml
sdnr/wt/odlux/core/features/pom.xml
sdnr/wt/odlux/core/installer/pom.xml
sdnr/wt/odlux/core/pom.xml
sdnr/wt/odlux/core/provider/pom.xml
sdnr/wt/odlux/framework/pom.xml
sdnr/wt/odlux/framework/src/app.css
sdnr/wt/odlux/framework/src/components/material-table/index.tsx
sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
sdnr/wt/odlux/framework/src/views/about.tsx
sdnr/wt/odlux/framework/webpack.config.js
sdnr/wt/odlux/pom.xml
sdnr/wt/odlux/yarn.lock

index 6e02db0..6e5d596 100644 (file)
@@ -1,15 +1,22 @@
 # Developing a ODLUX application
 
+## Introduction
+
+ODLUX bundle contains the Browser based Grapical User Interface for SDN-R.
+ODLUX is available as OSGi bundle that is running in Opendaylight Karaf environment, using the configured jetty server of Opendaylight.
+Since ONAP Frankfurt a second WEB Server setup "sdncweb" is available, that extracts the JavaScrip files.
+
 ## Prerequisites
 
-* Node: 8.10 or higher
-* Yarn: 1.12.3 or higher
-* Lerna: 3.10.7 or higher
+Actual version in framework pom.xml in the frontend-maven-plugin definition.
+  * Node
+  * Yarn
+  * Lerna
 
 You can install these globally or let it be installed by maven due "mvn clean install"
 
 * Maven: 3 or higher
-* Java: 8 or higher
+* Java: 8
 
 ## Dev-Environment Installation
 
@@ -25,7 +32,7 @@ You can install these globally or let it be installed by maven due "mvn clean in
   |-framework
 
  ```
- * go to features/sdnr/wt/odlux/apps and create your app: 
+ * go to features/sdnr/wt/odlux/apps and create your app:
  ```
  mvn archetype:generate -DarchetypeGroupId=org.onap.ccsdk.features.sdnr.wt \
   -DarchetypeArtifactId=odlux-app-archetype \
@@ -40,7 +47,7 @@ You can install these globally or let it be installed by maven due "mvn clean in
  * with ```yarn start``` you can run your application due runtime in your application folder
  * by default this will run on http://localhost:3100/index.html
  * if you have added new dependencies you have to run ```lerna bootstrap``` in odlux/
- * build your app for development version you can use ```yarn run build``` or ```yarn run build:dev``` 
+ * build your app for development version you can use ```yarn run build``` or ```yarn run build:dev```
  * build for karaf with ```mvn clean install```
 
 
@@ -63,19 +70,19 @@ You can install these globally or let it be installed by maven due "mvn clean in
 ### Default menu positions
 
  * from 0 for top to 999 for bottom.
+
 ```
-0      Connect
-10     Fault
-20     Maintenance
-30     Configuration
-40     Protection
-50     Performance
-60     Security
-70     Inventory
-80     Topology
-90     Mediator
-100    Help
+0    Connect
+10    Fault
+20    Maintenance
+30    Configuration
+40    Protection
+50    Performance
+60    Security
+70    Inventory
+80    Topology
+90    Mediator
+100    Help
 ```
 
 ### blueprint.xml
@@ -99,162 +106,6 @@ You can install these globally or let it be installed by maven due "mvn clean in
 
 ### pom.xml
 
-```
-<?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-demoApp</artifactId>
-    <version>0.4.1-SNAPSHOT</version>
-    <packaging>bundle</packaging>
-    <name>sdnr-wt-odlux-app-demoApp</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>
-                    </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>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>
-            <resource>
-                <directory>src2/test/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>
-your
-```
-
-* a modified frontend-maven-plugin installs node, yarn and (optionally lerna) to compile the typescript sources to javascript. These will be build into the dist folder.
-
+ * The pom.xml in the framework subdirectory is the reference for ODLUX creation. [framework pom](framework/pom.xml)
+ * The node and yarn versions are specified
+ * A specific variant of "frontend-maven-plugin" is used to create the environment to compile to javascript. This modified frontend-maven-plugin installs node, yarn and (optionally lerna) to compile the typescript sources to javascript. These will be build into the dist folder.
index c59a842..5b6cfa3 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-apiDemo</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index 8888a75..d951016 100644 (file)
@@ -26,7 +26,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>feature</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>ccsdk-features :: ${project.artifactId} :: feature</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
index 305630d..9681555 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-configurationApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index fc06653..5b4498d 100644 (file)
@@ -202,7 +202,7 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch:
 
       if (ind === 0) { defaultNS = namespace };
 
-      viewElement = viewSpecification.elements[property];
+      viewElement = viewSpecification.elements[property] || viewSpecification.elements[`${namespace}:${property}`];
       if (!viewElement) throw Error("Property [" + property + "] does not exist.");
 
       if (viewElement.isList && !key) {
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts b/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts
new file mode 100644 (file)
index 0000000..ec49191
--- /dev/null
@@ -0,0 +1,21 @@
+/**
+ * ============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 { ViewElement } from "../models/uiModels";
+
+export type baseProps = { value: ViewElement, inputValue: string, readOnly: boolean, disabled: boolean, onChange(newValue: string): void };
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx
new file mode 100644 (file)
index 0000000..6735888
--- /dev/null
@@ -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 { ViewElementBase } from "models/uiModels";
+import { TextField, InputAdornment, Input, Tooltip, Divider, IconButton, InputBase, Paper, makeStyles, Theme, createStyles, FormControl, InputLabel, FormHelperText } from "@material-ui/core";
+import * as React from 'react';
+import { faAdjust } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { InputProps } from "@material-ui/core/Input";
+
+const useStyles = makeStyles((theme: Theme) =>
+    createStyles({
+        iconDark: {
+            color: '#ff8800'
+        },
+        iconLight: {
+            color: 'orange'
+        },
+        padding: {
+            paddingLeft: 10,
+            paddingRight: 10
+        },
+    }),
+);
+
+type ifwhenProps = { element: ViewElementBase, id: any, label: any, style: any, helperText: string, error: boolean, toogleTooltip(value: boolean): void, [x: string]: any };
+
+export const IfWhenTextInput = (props: ifwhenProps) => {
+
+    const { element, toogleTooltip, id, label, helperText: errorText, error, style, ...otherProps } = props;
+    const classes = useStyles();
+
+
+    const ifFeature = element.ifFeature ? <Tooltip onMouseMove={e => props.toogleTooltip(false)} onMouseOut={e => props.toogleTooltip(true)} title={element.ifFeature}><InputAdornment position="start"><FontAwesomeIcon icon={faAdjust} className={classes.iconDark}></FontAwesomeIcon></InputAdornment></Tooltip> : null;
+    const whenFeature = element.when ? (<Tooltip className={classes.padding} onMouseMove={e => props.toogleTooltip(false)} onMouseOut={e => props.toogleTooltip(true)} title={element.when}>
+        <InputAdornment className={classes.padding} position="end"><FontAwesomeIcon icon={faAdjust} className={classes.iconLight}></FontAwesomeIcon></InputAdornment></Tooltip>) : null;
+
+    return (
+        <FormControl error={error} style={style}>
+            <InputLabel htmlFor={id} >{label}</InputLabel>
+            <Input  {...otherProps} id={id} endAdornment={<div>{ifFeature}{whenFeature}</div>} />
+            <FormHelperText>{errorText}</FormHelperText>
+        </FormControl>
+
+    );
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx
new file mode 100644 (file)
index 0000000..cc141ee
--- /dev/null
@@ -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 { ViewElementBoolean } from "../models/uiModels";
+import * as React from "react"
+import { MenuItem, FormHelperText, Select, FormControl, InputLabel } from "@material-ui/core";
+import { baseProps } from "./baseProps";
+
+type booleanInputProps = baseProps;
+
+export const UiElementBoolean = (props: booleanInputProps) => {
+
+    const element = props.value as ViewElementBoolean;
+
+    let error = "";
+    const value = String(props.inputValue).toLowerCase();
+    if (element.mandatory && value !== "true" && value !== "false") {
+        error = "Error";
+    }
+    return (!props.readOnly || element.id != null
+        ? (<FormControl style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
+            <InputLabel htmlFor={`select-${element.id}`} >{element.label}</InputLabel>
+            <Select
+                required={!!element.mandatory}
+                error={!!error}
+                onChange={(e) => { props.onChange(e.target.value as any) }}
+                readOnly={props.readOnly}
+                disabled={props.disabled}
+                value={value}
+                inputProps={{
+                    name: element.id,
+                    id: `select-${element.id}`,
+                }}
+            >
+                <MenuItem value={'true'}>{element.trueValue || 'True'}</MenuItem>
+                <MenuItem value={'false'}>{element.falseValue || 'False'}</MenuItem>
+
+            </Select>
+            <FormHelperText>{error}</FormHelperText>
+        </FormControl>)
+        : null
+    );
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx
new file mode 100644 (file)
index 0000000..cf46205
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { ViewElementNumber } from "models/uiModels";
+import { Tooltip, InputAdornment } from "@material-ui/core";
+import * as React from 'react';
+import { baseProps } from "./baseProps";
+import { IfWhenTextInput } from "./ifWhenTextInput";
+import { checkRange } from "./verifyer";
+
+type numberInputProps = baseProps;
+
+export const UiElementNumber = (props: numberInputProps) => {
+
+
+    const [error, setError] = React.useState(false);
+    const [helperText, setHelperText] = React.useState("");
+    const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
+
+    const element = props.value as ViewElementNumber;
+
+    const verifyValue = (data: string) => {
+
+        if (data.trim().length > 0) {
+            const num = Number(data);
+            if (!isNaN(num)) {
+                const result = checkRange(element, num);
+                if (result.length > 0) {
+                    setError(true);
+                    setHelperText(result);
+                } else {
+                    setError(false);
+                    setHelperText("");
+                }
+            } else {
+                setError(true);
+                setHelperText("Input is not a number.");
+            }
+        } else {
+            setError(false);
+            setHelperText("");
+        }
+
+        props.onChange(data);
+    }
+
+    return (
+        <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
+            <IfWhenTextInput element={element} toogleTooltip={(val: boolean) => setTooltipVisibility(val)}
+                spellCheck={false} autoFocus margin="dense"
+                id={element.id} label={element.label} type="text" value={props.inputValue}
+                style={{ width: 485, marginLeft: 20, marginRight: 20 }}
+                onChange={(e: any) => { verifyValue(e.target.value) }}
+                error={error}
+                readOnly={props.readOnly}
+                disabled={props.disabled}
+                helperText={helperText}
+                startAdornment={element.units != null ? <InputAdornment position="start">{element.units}</InputAdornment> : undefined}
+            />
+        </Tooltip>
+    );
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementReference.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementReference.tsx
new file mode 100644 (file)
index 0000000..2760eee
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import React from 'react';
+import { Tooltip, Button, FormControl, Theme, createStyles, makeStyles } from '@material-ui/core';
+
+import { ViewElement } from '../models/uiModels';
+
+const useStyles = makeStyles((theme: Theme) => createStyles({
+  button: {
+    "justifyContent": "left"
+  },
+}));
+
+type UIElementReferenceProps = {
+  element: ViewElement;
+  disabled: boolean;
+  onOpenReference(element: ViewElement): void;
+};
+
+export const UIElementReference: React.FC<UIElementReferenceProps> = (props) => {
+  const classes = useStyles();
+  const { element } = props;
+  return (
+    <FormControl key={element.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
+      <Tooltip title={element.description || ''}>
+        <Button className={classes.button} color="secondary" disabled={props.disabled} onClick={() => {
+          props.onOpenReference(element);
+        }}>{element.label}</Button>
+      </Tooltip>
+    </FormControl>
+  );
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx
new file mode 100644 (file)
index 0000000..d460763
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import * as React from 'react';
+import { baseProps } from './baseProps';
+import { ViewElementSelection } from '../models/uiModels'
+import { FormControl, InputLabel, Select, FormHelperText, MenuItem } from '@material-ui/core';
+
+
+
+type selectionProps = baseProps;
+
+export const UiElementSelection = (props: selectionProps) => {
+
+    const element = props.value as ViewElementSelection;
+
+    let error = "";
+    const value = String(props.inputValue).toLowerCase();
+    if (element.mandatory && !!value) {
+        error = "Error";
+    }
+
+    return (props.readOnly || props.inputValue != null
+        ? (<FormControl style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
+            <InputLabel htmlFor={`select-${element.id}`} >{element.label}</InputLabel>
+            <Select
+                required={!!element.mandatory}
+                error={!!error}
+                onChange={(e) => { props.onChange(e.target.value as string) }}
+                readOnly={props.readOnly}
+                disabled={props.disabled}
+                value={value.toString().toLowerCase()}
+                inputProps={{
+                    name: element.id,
+                    id: `select-${element.id}`,
+                }}
+            >
+                {element.options.map(option => (<MenuItem key={option.key} title={option.description} value={option.key}>{option.key}</MenuItem>))}
+            </Select>
+            <FormHelperText>{error}</FormHelperText>
+        </FormControl>)
+        : null
+    );
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx
new file mode 100644 (file)
index 0000000..43c60b5
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * ============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 { Tooltip, TextField } from "@material-ui/core";
+import { ViewElementString } from "../models/uiModels";
+import * as React from "react"
+import { baseProps } from "./baseProps";
+import { IfWhenTextInput } from "./ifWhenTextInput";
+import { checkRange, checkPattern } from "./verifyer";
+
+type stringEntryProps = baseProps & { isKey: boolean };
+
+export const UiElementString = (props: stringEntryProps) => {
+
+    const [isError, setError] = React.useState(false);
+    const [helperText, setHelperText] = React.useState("");
+    const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
+
+    const element = props.value as ViewElementString;
+
+    const verifyValues = (data: string) => {
+
+        if (data.trim().length > 0) {
+
+            let errorMessage = "";
+            const result = checkRange(element, data.length);
+
+            if (result.length > 0)
+                errorMessage += result;
+
+
+            const patternResult = checkPattern(element.pattern, data)
+
+            if (patternResult.error) {
+                errorMessage += patternResult.error;
+            }
+
+            if (errorMessage.length > 0) {
+                setError(true);
+                setHelperText(errorMessage);
+            } else {
+                setError(false);
+                setHelperText("");
+            }
+        } else {
+            setError(false);
+            setHelperText("");
+        }
+
+
+        props.onChange(data);
+
+    }
+
+    return (
+        <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
+            <IfWhenTextInput element={element} toogleTooltip={(val: boolean) => setTooltipVisibility(val)}
+                spellCheck={false} autoFocus margin="dense"
+                id={element.id} label={props.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue}
+                style={{ width: 485, marginLeft: 20, marginRight: 20 }}
+                onChange={(e: any) => { verifyValues(e.target.value) }}
+                error={isError}
+                readOnly={props.readOnly}
+                disabled={props.disabled}
+                helperText={helperText}
+            />
+        </Tooltip>
+    );
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx
new file mode 100644 (file)
index 0000000..dc158c0
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * ============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 { baseProps } from './baseProps';
+import { Tooltip } from '@material-ui/core';
+import { IfWhenTextInput } from './ifWhenTextInput';
+import { ViewElementUnion, isViewElementString, isViewElementNumber, isViewElementObject, ViewElementNumber } from '../models/uiModels';
+import { checkRange, checkPattern } from './verifyer';
+
+type UiElementUnionProps = { isKey: boolean } & baseProps;
+
+export const UIElementUnion = (props: UiElementUnionProps) => {
+
+    const [isError, setError] = React.useState(false);
+    const [helperText, setHelperText] = React.useState("");
+    const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
+
+    const element = props.value as ViewElementUnion;
+
+    const verifyValues = (data: string) => {
+
+        debugger;
+        let foundObjectElements = 0;
+        let errorMessage = "";
+        let isPatternCorrect = null;
+
+        for (let i = 0; i < element.elements.length; i++) {
+            const unionElement = element.elements[i];
+
+            if (isViewElementNumber(unionElement)) {
+
+                errorMessage = checkRange(unionElement, Number(data));
+
+            } else if (isViewElementString(unionElement)) {
+                errorMessage += checkRange(unionElement, data.length);
+                isPatternCorrect = checkPattern(unionElement.pattern, data).isValid;
+
+
+            } else if (isViewElementObject(unionElement)) {
+                foundObjectElements++;
+            }
+
+            if (isPatternCorrect || errorMessage.length === 0) {
+                break;
+            }
+        }
+
+        if (errorMessage.length > 0 || isPatternCorrect !== null && !isPatternCorrect) {
+            setError(true);
+            setHelperText("Input is wrong.");
+        } else {
+            setError(false);
+            setHelperText("");
+        }
+
+        if (foundObjectElements > 0 && foundObjectElements != element.elements.length) {
+            throw new Error(`The union element ${element.id} can't be changed.`);
+
+        } else {
+            props.onChange(data);
+        }
+    };
+
+
+
+    return <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
+        <IfWhenTextInput element={element} toogleTooltip={(val: boolean) => setTooltipVisibility(val)}
+            spellCheck={false} autoFocus margin="dense"
+            id={element.id} label={props.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue}
+            onChange={(e: any) => { verifyValues(e.target.value) }}
+            error={isError}
+            style={{ width: 485, marginLeft: 20, marginRight: 20 }}
+            readOnly={props.readOnly}
+            disabled={props.disabled}
+            helperText={helperText}
+        />
+    </Tooltip>;
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/verifyer.ts b/sdnr/wt/odlux/apps/configurationApp/src/components/verifyer.ts
new file mode 100644 (file)
index 0000000..0a95cd8
--- /dev/null
@@ -0,0 +1,280 @@
+/**
+ * ============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 { Expression, YangRange, Operator, ViewElementNumber, ViewElementString, isViewElementNumber, isViewElementString } from '../models/uiModels';
+
+export type validated = { isValid: boolean, error?: string }
+
+export type validatedRange = { isValid: boolean, error?: string };
+
+
+const rangeErrorStartNumber = "The entered number must be";
+const rangeErrorinnerMinTextNumber = "greater or equals than";
+const rangeErrorinnerMaxTextNumber = "less or equals than";
+const rangeErrorEndTextNumber = ".";
+
+const rangeErrorStartString = "The entered text must have";
+const rangeErrorinnerMinTextString = "no more than";
+const rangeErrorinnerMaxTextString = "less than";
+const rangeErrorEndTextString = " characters.";
+
+let errorMessageStart = "";
+let errorMessageMiddleMinPart = "";
+let errorMessageMiddleMaxPart = "";
+let errorMessageEnd = "";
+
+
+export function checkRange(element: ViewElementNumber | ViewElementString, data: number): string {
+
+    //let test1: Operator<YangRange> = { operation: "AND", arguments: [{ operation: "OR", arguments: [{ operation: "AND", arguments: [new RegExp("^z", "g"), new RegExp("z$", "g")] }, new RegExp("^abc", "g"), new RegExp("^123", "g")] }, new RegExp("^def", "g"), new RegExp("^ppp", "g"), new RegExp("^aaa", "g")] };
+    //let test1: Operator<YangRange> = { operation: "AND", arguments: [{ operation: "OR", arguments: [{ operation: "AND", arguments: [{ min: -5, max: 10 }, { min: -30, max: -20 }] }, { min: 8, max: 15 }] }] };
+    //let test1: Operator<YangRange> = { operation: "OR", arguments: [{ operation: "OR", arguments: [{ min: -50, max: -40 }] }, { min: -30, max: -20 }, { min: 8, max: 15 }] };
+    //let test1: Operator<YangRange> = { operation: "AND", arguments: [{ operation: "OR", arguments: [{ min: -5, max: 10 }, { min: 17, max: 23 }] }] };
+
+    const number = data;
+
+    var expression = undefined;
+
+    if (isViewElementString(element)) {
+        expression = element.length;
+
+        errorMessageStart = rangeErrorStartString;
+        errorMessageMiddleMaxPart = rangeErrorinnerMaxTextString;
+        errorMessageMiddleMinPart = rangeErrorinnerMinTextString;
+        errorMessageEnd = rangeErrorEndTextString;
+
+    } else if (isViewElementNumber(element)) {
+        expression = element.range;
+
+        errorMessageStart = rangeErrorStartNumber;
+        errorMessageMiddleMaxPart = rangeErrorinnerMaxTextNumber;
+        errorMessageMiddleMinPart = rangeErrorinnerMinTextNumber;
+        errorMessageEnd = rangeErrorEndTextNumber;
+    }
+
+    if (expression) {
+        if (isYangOperator(expression)) {
+
+            const errorMessage = getRangeErrorMessages(expression, data);
+            return errorMessage;
+
+        } else
+            if (isYangRange(expression)) {
+
+                if (!isNaN(expression.min)) {
+                    if (number < expression.min) {
+                        return `${errorMessageStart} ${errorMessageMiddleMinPart} ${expression.min}${errorMessageEnd}`;
+                    }
+                }
+
+                if (!isNaN(expression.max)) {
+                    if (number > expression.max) {
+                        return `${errorMessageStart} ${errorMessageMiddleMaxPart} ${expression.max}${errorMessageEnd}`;
+                    }
+                }
+            }
+    }
+
+
+    return "";
+}
+
+function isYangRange(val: YangRange | Operator<YangRange>): val is YangRange {
+    return (val as YangRange).min !== undefined;
+}
+
+function isYangOperator(val: YangRange | Operator<YangRange>): val is Operator<YangRange> {
+    return (val as Operator<YangRange>).operation !== undefined;
+}
+
+function getRangeErrorMessagesRecursively(value: Operator<YangRange>, data: number): string[] {
+    let currentItteration: string[] = [];
+    console.log(value);
+
+    // itterate over all elements
+    for (let i = 0; i < value.arguments.length; i++) {
+        const element = value.arguments[i];
+
+        let min = undefined;
+        let max = undefined;
+
+        let isNumberCorrect = false;
+
+        if (isYangRange(element)) {
+
+            //check found min values
+            if (!isNaN(element.min)) {
+                if (data < element.min) {
+                    min = element.min;
+                } else {
+                    isNumberCorrect = true;
+                }
+            }
+
+            // check found max values
+            if (!isNaN(element.max)) {
+                if (data > element.max) {
+                    max = element.max;
+                } else {
+                    isNumberCorrect = true;
+                }
+            }
+
+            // construct error messages
+            if (min != undefined) {
+                currentItteration.push(`${value.operation.toLocaleLowerCase()} ${errorMessageMiddleMinPart} ${min}`);
+            } else if (max != undefined) {
+                currentItteration.push(`${value.operation.toLocaleLowerCase()} ${errorMessageMiddleMaxPart} ${max}`);
+
+            }
+
+        } else if (isYangOperator(element)) {
+
+            //get errormessages from expression
+            const result = getRangeErrorMessagesRecursively(element, data);
+            if (result.length === 0) {
+                isNumberCorrect = true;
+            }
+            currentItteration = currentItteration.concat(result);
+        }
+
+        // if its an OR operation, the number has been checked and min/max are empty (thus not violated)
+        // delete everything found (because at least one found is correct, therefore all are correct) and break from loop
+        if (min === undefined && max === undefined && isNumberCorrect && value.operation === "OR") {
+
+            currentItteration.splice(0, currentItteration.length);
+            break;
+        }
+    }
+
+    return currentItteration;
+}
+
+function getRangeErrorMessages(value: Operator<YangRange>, data: number): string {
+
+    const currentItteration = getRangeErrorMessagesRecursively(value, data);
+
+    // build complete error message from found parts
+    let errormessage = "";
+    if (currentItteration.length > 1) {
+
+        currentItteration.forEach((element, index) => {
+            if (index === 0) {
+                errormessage = createStartMessage(element);
+            } else if (index === currentItteration.length - 1) {
+                errormessage += ` ${element}${errorMessageEnd}`;
+            } else {
+                errormessage += `, ${element}`
+            }
+        });
+    } else if (currentItteration.length == 1) {
+        errormessage = `${createStartMessage(currentItteration[0])}${errorMessageEnd}`;
+    }
+
+    return errormessage;
+}
+
+function createStartMessage(element: string) {
+
+    //remove leading or or and from text
+    if (element.startsWith("and"))
+        element = element.replace("and", "");
+    else if (element.startsWith("or"))
+        element = element.replace("or", "");
+
+    return `${errorMessageStart} ${element}`;
+}
+
+export const checkPattern = (expression: RegExp | Operator<RegExp> | undefined, data: string): validated => {
+
+    if (expression) {
+        if (isRegExp(expression)) {
+            const isValid = expression.test(data);
+            if (!isValid)
+                return { isValid: isValid, error: "The input is in a wrong format." };
+
+        } else if (isRegExpOperator(expression)) {
+            const result = isPatternValid(expression, data);
+
+            if (!result) {
+                return { isValid: false, error: "The input is in a wrong format." };
+            }
+        }
+    }
+
+    return { isValid: true }
+}
+
+function getRegexRecursively(value: Operator<RegExp>, data: string): boolean[] {
+    let currentItteration: boolean[] = [];
+    for (let i = 0; i < value.arguments.length; i++) {
+        const element = value.arguments[i];
+        if (isRegExp(element)) {
+            // if regex is found, add it to list
+            currentItteration.push(element.test(data))
+        } else if (isRegExpOperator(element)) {
+            //if RegexExpression is found, try to get regex from it
+            currentItteration = currentItteration.concat(getRegexRecursively(element, data));
+        }
+    }
+
+    if (value.operation === "OR") {
+        // if one is true, all are true, all found items can be discarded
+        let result = currentItteration.find(element => element);
+        if (result) {
+            return [];
+        }
+    }
+    return currentItteration;
+}
+
+function isPatternValid(value: Operator<RegExp>, data: string): boolean {
+
+
+    // get all regex
+    const result = getRegexRecursively(value, data);
+    console.log(value);
+
+
+    if (value.operation === "AND") {
+        // if AND operation is executed...
+        // no element can be false
+        const check = result.find(element => element !== true);
+        if (check)
+            return false;
+        else
+            return true;
+    } else {
+        // if OR operation is executed...
+        // ... just one element must be true
+        const check = result.find(element => element === true);
+        if (check)
+            return true;
+        else
+            return false;
+
+    }
+}
+
+function isRegExp(val: RegExp | Operator<RegExp>): val is RegExp {
+    return (val as RegExp).source !== undefined;
+}
+
+function isRegExpOperator(val: RegExp | Operator<RegExp>): val is Operator<RegExp> {
+    return (val as Operator<RegExp>).operation !== undefined;
+}
\ No newline at end of file
index 04b63d3..1af699a 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { combineActionHandler } from '../../../../framework/src/flux/middleware';
 
 import { IConnectedNetworkElementsState, connectedNetworkElementsActionHandler } from './connectedNetworkElementsHandler';
index 6a68242..e6b808b 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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';
 
@@ -16,4 +34,3 @@ export const {
 
   // set value action, to change a value
 } = createExternal<NetworkElementConnection>(connectedNetworkElementsSearchHandler, appState => appState.configuration.connectedNetworkElements);
\ No newline at end of file
index 3cc27aa..408399d 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { Module } from "../models/yang";
 import { ViewSpecification } from "../models/uiModels";
 import { IActionHandler } from "../../../../framework/src/flux/action";
@@ -25,6 +43,6 @@ export const deviceDescriptionHandler: IActionHandler<IDeviceDescriptionState> =
       modules: action.modules,
       views: action.views
     };
-  } 
+  }
   return state;
 };
index c9e7dd2..9af640f 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { ViewSpecification } from "../models/uiModels";
 import { EnableValueSelector, SetSelectedValue, UpdateDeviceDescription, SetCollectingSelectionData, UpdatViewDescription } from "../actions/deviceActions";
@@ -23,7 +41,7 @@ export const valueSelectorHandler: IActionHandler<IValueSelectorState> = (state
   if (action instanceof SetCollectingSelectionData) {
     state = {
       ...state,
-     collectingData: action.busy,
+      collectingData: action.busy,
     };
   } else if (action instanceof EnableValueSelector) {
     state = {
index 48155ee..c1b3350 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { UpdatViewDescription } from "../actions/deviceActions";
index 2575500..88f7018 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
 export type NetworkElementConnection = {
   id?: string;
   nodeId: string;
index 441d128..7b41c38 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 ViewElementBase = {
   "id": string;
   "label": string;
@@ -15,7 +33,7 @@ export type ViewElementBase = {
 // https://tools.ietf.org/html/rfc7950#section-9.8
 export type ViewElementBinary = ViewElementBase & {
   "uiType": "binary";
-  "length"?: number;  // number of octets
+  "length"?: Expression<YangRange>;  // number of octets
 }
 
 // https://tools.ietf.org/html/rfc7950#section-9.7.4
@@ -29,16 +47,17 @@ export type ViewElementBits = ViewElementBase & {
 // https://tools.ietf.org/html/rfc7950#section-9
 export type ViewElementString = ViewElementBase & {
   "uiType": "string";
-  "pattern"?: string[];
-  "length"?: string;
+  "pattern"?: Expression<RegExp>;
+  "length"?: Expression<YangRange>;
   "invertMatch"?: true;
 }
 
 // https://tools.ietf.org/html/rfc7950#section-9.3
 export type ViewElementNumber = ViewElementBase & {
   "uiType": "number";
-  "min"?: number;
-  "max"?: number;
+  "min": number;
+  "max": number;
+  "range"?: Expression<YangRange>;
   "units"?: string;
   "format"?: string;
   "fDigits"?: number;
@@ -85,6 +104,16 @@ export type ViewElementReference = ViewElementBase & {
   "ref": (currentPath: string) => ViewElement | null;
 }
 
+export type ViewElementUnion = ViewElementBase & {
+  "uiType": "union";
+  "elements": ViewElement[];
+}
+
+export type ViewElementChoise = ViewElementBase & {
+  "uiType": "choise";
+  "cases": { [name: string]: { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } } };
+}
+
 export type ViewElement =
   | ViewElementBits
   | ViewElementBinary
@@ -94,14 +123,16 @@ export type ViewElement =
   | ViewElementObject
   | ViewElementList
   | ViewElementSelection
-  | ViewElementReference;
+  | ViewElementReference
+  | ViewElementUnion
+  | ViewElementChoise;
 
 export const isViewElementString = (viewElement: ViewElement): viewElement is ViewElementString => {
   return viewElement && viewElement.uiType === "string";
 }
 
 export const isViewElementNumber = (viewElement: ViewElement): viewElement is ViewElementNumber => {
-  return viewElement && viewElement.uiType === "number" ;
+  return viewElement && viewElement.uiType === "number";
 }
 
 export const isViewElementBoolean = (viewElement: ViewElement): viewElement is ViewElementBoolean => {
@@ -128,6 +159,15 @@ export const isViewElementReference = (viewElement: ViewElement): viewElement is
   return viewElement && viewElement.uiType === "reference";
 }
 
+export const isViewElementUnion = (viewElement: ViewElement): viewElement is ViewElementUnion => {
+  return viewElement && viewElement.uiType === "union";
+}
+
+export const isViewElementChoise = (viewElement: ViewElement): viewElement is ViewElementChoise => {
+  return viewElement && viewElement.uiType === "choise";
+}
+
+
 export type ViewSpecification = {
   "id": string;
   "name": string;
@@ -140,3 +180,17 @@ export type ViewSpecification = {
   "elements": { [name: string]: ViewElement };
   readonly "canEdit": boolean;
 }
+
+export type YangRange = {
+  min: number,
+  max: number,
+}
+
+export type Expression<T> =
+  | T
+  | Operator<T>;
+
+export type Operator<T> = {
+  operation: "AND" | "OR";
+  arguments: Expression<T>[];
+}
\ No newline at end of file
index 57edf80..11eb44d 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { ViewElement, ViewSpecification } from "./uiModels";
 
 export type Token = {
@@ -33,7 +51,7 @@ export type Module = {
   namespace?: string;
   prefix?: string;
   identities: { [name: string]: Identity };
-  revisions: { [version: string]: Revision } ;
+  revisions: { [version: string]: Revision };
   imports: { [prefix: string]: string };
   features: { [feature: string]: { description?: string } };
   typedefs: { [type: string]: ViewElement };
index 7fd3a97..0cab7b7 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-router-dom';
 
@@ -32,7 +50,7 @@ const ConfigurationApplicationRouteAdapter = connect(mapProps, mapDisp)((props:
       currentNodeId = undefined;
       currentVirtualPath = undefined;
     }
-  },[]);
+  }, []);
   if (props.location.pathname !== lastUrl) {
     // ensure the asynchronus update will only be called once per path
     lastUrl = props.location.pathname;
@@ -59,9 +77,9 @@ const ConfigurationApplicationRouteAdapter = connect(mapProps, mapDisp)((props:
 
 const App = withRouter((props: RouteComponentProps) => (
   <Switch>
-    <Route path={`${props.match.url}/:nodeId/*`} component={ ConfigurationApplicationRouteAdapter } />
-    <Route path={`${props.match.url}/:nodeId`} component={ ConfigurationApplicationRouteAdapter } />
-    <Route path={`${props.match.url}`} component={ NetworkElementSelector } />
+    <Route path={`${props.match.url}/:nodeId/*`} component={ConfigurationApplicationRouteAdapter} />
+    <Route path={`${props.match.url}/:nodeId`} component={ConfigurationApplicationRouteAdapter} />
+    <Route path={`${props.match.url}`} component={NetworkElementSelector} />
     <Redirect to={`${props.match.url}`} />
   </Switch>
 ));
index 061be05..d0ed03a 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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, requestRestExt } from "../../../../framework/src/services/restService";
 import { convertPropertyNames, replaceHyphen } from "../../../../framework/src/utilities/yangHelper";
 
@@ -32,7 +50,7 @@ class RestService {
   public setConfigData(path: string, data: any) {
     return requestRestExt<{ [key: string]: any }>(path, { method: "PUT", body: JSON.stringify(data) });
   }
- }
+}
 
 export const restService = new RestService();
 export default restService;
\ No newline at end of file
index 17a4e43..3dc3a86 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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==========================================================================
+ */
+
 type YangInfo = [string, (string | null | undefined)];
 
 const cache: { [path: string]: string } = {
index 24a4af8..9c92ceb 100644 (file)
@@ -16,7 +16,7 @@
  * ============LICENSE_END==========================================================================
  */
 
-import * as React from 'react';
+import React from 'react';
 import { RouteComponentProps, withRouter } from 'react-router-dom';
 
 import { WithStyles, withStyles, createStyles, Theme } from '@material-ui/core/styles';
@@ -26,11 +26,12 @@ import { IApplicationStoreState } from "../../../../framework/src/store/applicat
 import MaterialTable, { ColumnModel, ColumnType, MaterialTableCtorType } from "../../../../framework/src/components/material-table";
 import { Loader } from "../../../../framework/src/components/material-ui/loader";
 
-import { SetSelectedValue, splitVPath, updateDataActionAsyncCreator } from "../actions/deviceActions";
-import { ViewSpecification, isViewElementString, isViewElementNumber, isViewElementBoolean, isViewElementObjectOrList, isViewElementSelection } from "../models/uiModels";
+import { SetSelectedValue, splitVPath, updateDataActionAsyncCreator, updateViewActionAsyncCreator } from "../actions/deviceActions";
+import { ViewSpecification, isViewElementString, isViewElementNumber, isViewElementBoolean, isViewElementObjectOrList, isViewElementSelection, isViewElementChoise, ViewElement, ViewElementChoise, isViewElementUnion } from "../models/uiModels";
 
 import Fab from '@material-ui/core/Fab';
 import AddIcon from '@material-ui/icons/Add';
+import ArrowBack from '@material-ui/icons/ArrowBack';
 import RemoveIcon from '@material-ui/icons/RemoveCircleOutline';
 import SaveIcon from '@material-ui/icons/Save';
 import EditIcon from '@material-ui/icons/Edit';
@@ -38,7 +39,7 @@ import Tooltip from "@material-ui/core/Tooltip";
 import TextField from "@material-ui/core/TextField";
 import FormControl from "@material-ui/core/FormControl";
 import IconButton from "@material-ui/core/IconButton";
-import Button from "@material-ui/core/Button";
+
 import InputAdornment from "@material-ui/core/InputAdornment";
 import InputLabel from "@material-ui/core/InputLabel";
 import Select from "@material-ui/core/Select";
@@ -47,6 +48,13 @@ import Breadcrumbs from "@material-ui/core/Breadcrumbs";
 import Link from "@material-ui/core/Link";
 import FormHelperText from '@material-ui/core/FormHelperText';
 
+import { UIElementReference } from '../components/uiElementReference';
+import { UiElementNumber } from '../components/uiElementNumber';
+import { UiElementString } from '../components/uiElementString';
+import { UiElementBoolean } from '../components/uiElementBoolean';
+import { UiElementSelection } from '../components/uiElementSelection';
+import { UIElementUnion } from '../components/uiElementUnion';
+
 const styles = (theme: Theme) => createStyles({
   header: {
     "display": "flex",
@@ -97,6 +105,16 @@ const styles = (theme: Theme) => createStyles({
       },
     },
   },
+  section: {
+    padding: "15px",
+    borderBottom: `2px solid ${theme.palette.divider}`,
+  },
+  viewElements: {
+    width: 485, marginLeft: 20, marginRight: 20
+  },
+  verificationElements: {
+    width: 485, marginLeft: 20, marginRight: 20
+  }
 });
 
 const mapProps = (state: IApplicationStoreState) => ({
@@ -115,6 +133,7 @@ const mapProps = (state: IApplicationStoreState) => ({
 const mapDispatch = (dispatcher: IDispatcher) => ({
   onValueSelected: (value: any) => dispatcher.dispatch(new SetSelectedValue(value)),
   onUpdateData: (vPath: string, data: any) => dispatcher.dispatch(updateDataActionAsyncCreator(vPath, data)),
+  reloadView: (vPath: string) => dispatcher.dispatch(updateViewActionAsyncCreator(vPath)),
 });
 
 const SelectElementTable = MaterialTable as MaterialTableCtorType<{ [key: string]: any }>;
@@ -126,6 +145,7 @@ type ConfigurationApplicationComponentState = {
   editMode: boolean;
   canEdit: boolean;
   viewData: { [key: string]: any } | null;
+  choises: { [path: string]: { selectedCase: string, data: { [property: string]: any } } };
 }
 
 const OldProps = Symbol("OldProps");
@@ -134,27 +154,61 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
   /**
    *
    */
-  constructor (props: ConfigurationApplicationComponentProps) {
+  constructor(props: ConfigurationApplicationComponentProps) {
     super(props);
 
     this.state = {
       isNew: false,
       canEdit: false,
       editMode: false,
-      viewData: null
+      viewData: null,
+      choises: {},
     }
   }
 
-  static getDerivedStateFromProps(nextProps: ConfigurationApplicationComponentProps, prevState: ConfigurationApplicationComponentState & { [OldProps]: ConfigurationApplicationComponentProps  }) {
+  static getDerivedStateFromProps(nextProps: ConfigurationApplicationComponentProps, prevState: ConfigurationApplicationComponentState & { [OldProps]: ConfigurationApplicationComponentProps }) {
 
     if (!prevState || !prevState[OldProps] || (prevState[OldProps].viewData !== nextProps.viewData)) {
-      const isNew: boolean = nextProps.vPath?.endsWith("[]") || false;
+      const isNew: boolean = nextProps.vPath ?.endsWith("[]") || false;
       const state = {
         ...prevState,
         isNew: isNew,
         editMode: isNew,
         viewData: nextProps.viewData || null,
         [OldProps]: nextProps,
+        choises: nextProps.viewSpecification && Object.keys(nextProps.viewSpecification.elements).reduce((acc, cur) => {
+          const elm = nextProps.viewSpecification.elements[cur];
+          if (isViewElementChoise(elm)) {
+            const caseKeys = Object.keys(elm.cases);
+
+            // find the right case for this choise, use the first one with data, at least use index 0
+            const selectedCase = caseKeys.find(key => {
+              const caseElm = elm.cases[key];
+              return Object.keys(caseElm.elements).some(caseElmKey => {
+                const caseElmElm = caseElm.elements[caseElmKey];
+                return nextProps.viewData[caseElmElm.label] != null || nextProps.viewData[caseElmElm.id] != null;
+              });
+            }) || caseKeys[0];
+
+            // extract all data of the active case
+            const caseElements = elm.cases[selectedCase].elements;
+            const data = Object.keys(caseElements).reduce((dataAcc, dataCur) => {
+              const dataElm = caseElements[dataCur];
+              if (nextProps.viewData[dataElm.label] !== undefined) {
+                dataAcc[dataElm.label] = nextProps.viewData[dataElm.label];
+              } else if (nextProps.viewData[dataElm.id] !== undefined) {
+                dataAcc[dataElm.id] = nextProps.viewData[dataElm.id];
+              }
+              return dataAcc;
+            }, {} as { [name: string]: any });
+
+            acc[elm.id] = {
+              selectedCase,
+              data,
+            };
+          }
+          return acc;
+        }, {} as { [path: string]: { selectedCase: string, data: { [property: string]: any } } }) || {}
       }
       return state;
     }
@@ -174,123 +228,203 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
     });
   }
 
-  private renderUIElement = (viewSpecification: ViewSpecification, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
-    const elements = viewSpecification.elements;
-    return (
-      Object.keys(elements).sort((a, b) => {
-        const vsA = elements[a];
-        const vsB = elements[b];
-        if (keyProperty) {
-          // if (vsA.label === vsB.label) return 0;
-          if (vsA.label === keyProperty) return -1;
-          if (vsB.label === keyProperty) return +1;
-        }
+  private renderUIElement = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
+    const isKey = (uiElement.label === keyProperty);
+    const canEdit = editMode && (isNew || (uiElement.config && !isKey));
+    if (isViewElementSelection(uiElement)) {
+
+      return <UiElementSelection
+        key={uiElement.id}
+        inputValue={viewData[uiElement.id] || ''}
+        value={uiElement}
+        readOnly={!canEdit}
+        disabled={editMode && !canEdit}
+        onChange={(e) => { this.changeValueFor(uiElement.id, e) }}
+      />
+
+    } else if (isViewElementBoolean(uiElement)) {
+      return <UiElementBoolean
+        key={uiElement.id}
+        inputValue={viewData[uiElement.id] || ''}
+        value={uiElement}
+        readOnly={!canEdit}
+        disabled={editMode && !canEdit}
+        onChange={(e) => { this.changeValueFor(uiElement.id, e) }} />
+
+    } else if (isViewElementString(uiElement)) {
+      return <UiElementString
+        key={uiElement.id}
+        inputValue={viewData[uiElement.id] || ''}
+        value={uiElement}
+        isKey={isKey}
+        readOnly={!canEdit}
+        disabled={editMode && !canEdit}
+        onChange={(e) => { this.changeValueFor(uiElement.id, e) }} />
+
+    } else if (isViewElementNumber(uiElement)) {
+      return <UiElementNumber
+        key={uiElement.id}
+        value={uiElement}
+        inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]}
+        readOnly={!canEdit}
+        disabled={editMode && !canEdit}
+        onChange={(e) => { this.changeValueFor(uiElement.id, e) }} />
+    } else if (isViewElementUnion(uiElement)) {
+      return <UIElementUnion
+        key={uiElement.id}
+        isKey={false}
+        value={uiElement}
+        inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]}
+        readOnly={!canEdit}
+        disabled={editMode && !canEdit}
+        onChange={(e) => { this.changeValueFor(uiElement.id, e) }} />
+    }
+    else {
+      if (process.env.NODE_ENV !== "production") {
+        console.error(`Unknown element type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
+      }
+      return null;
+    }
+  };
 
-        if (vsA.uiType === vsB.uiType) return 0;
-        if (vsA.uiType !== "object" && vsB.uiType !== "object") return 0;
-        if (vsA.uiType === "object") return +1;
-        return -1;
-      }).map(key => {
-        const uiElement = elements[key];
-        const isKey = (uiElement.label === keyProperty);
-        const canEdit = editMode && (isNew || (uiElement.config && !isKey));
-        if (isViewElementSelection(uiElement)) {
-          let error = ""
-          const value = String(viewData[uiElement.id]).toLowerCase();
-          if (uiElement.mandatory && !!value) {
-            error = "Error";
-          }
-          return (canEdit || viewData[uiElement.id] != null
-            ? (<FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
-              <InputLabel htmlFor={`select-${uiElement.id}`} >{uiElement.label}</InputLabel>
-              <Select
-                required={!!uiElement.mandatory}
-                error={!!error}
-                onChange={(e) => { this.changeValueFor(uiElement.id, e.target.value) }}
-                readOnly={!canEdit}
-                disabled={editMode && !canEdit}
-                value={(viewData[uiElement.id] || '').toString().toLowerCase()}
-                inputProps={{
-                  name: uiElement.id,
-                  id: `select-${uiElement.id}`,
-                }}
-              >
-                {uiElement.options.map(option => (<MenuItem key={option.key} title={option.description} value={option.value}>{option.key}</MenuItem>))}
-              </Select>
-              <FormHelperText>{error}</FormHelperText>
-            </FormControl>)
-            : null
-          );
-        } else if (isViewElementBoolean(uiElement)) {
-          let error = ""
-          const value = String(viewData[uiElement.id]).toLowerCase();
-          if (uiElement.mandatory && value !== "true" && value !== "false") {
-            error = "Error";
-          }
-          return (canEdit || viewData[uiElement.id] != null
-            ? (<FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
-              <InputLabel htmlFor={`select-${uiElement.id}`} >{uiElement.label}</InputLabel>
-              <Select
-                required={!!uiElement.mandatory}
-                error={!!error}
-                onChange={(e) => { this.changeValueFor(uiElement.id, e.target.value) }}
-                readOnly={!canEdit}
-                disabled={editMode && !canEdit}
-                value={value}
-                inputProps={{
-                  name: uiElement.id,
-                  id: `select-${uiElement.id}`,
-                }}
-              >
-                <MenuItem value={'true'}>{uiElement.trueValue || 'True'}</MenuItem>
-                <MenuItem value={'false'}>{uiElement.falseValue || 'False'}</MenuItem>
-
-              </Select>
-              <FormHelperText>{error}</FormHelperText>
-            </FormControl>)
-            : null
-          );
-        } else if (isViewElementString(uiElement)) {
-          return (
-            <Tooltip key={uiElement.id} title={uiElement.description || ''}>
-              <TextField InputProps={{ readOnly: !canEdit, disabled: editMode && !canEdit }} spellCheck={false} autoFocus margin="dense"
-                id={uiElement.id} label={isKey ? "🔑 " + uiElement.label : uiElement.label} type="text" value={viewData[uiElement.id] || ''}
-                style={{ width: 485, marginLeft: 20, marginRight: 20 }}
-                onChange={(e) => { this.changeValueFor(uiElement.id, e.target.value) }}
-              />
-            </Tooltip>
-          );
-        } else if (isViewElementNumber(uiElement)) {
-          return (
-            <Tooltip key={uiElement.id} title={uiElement.description || ''}>
-              <TextField InputProps={{ readOnly: !canEdit, disabled: editMode && !canEdit, startAdornment: uiElement.units != null ? <InputAdornment position="start">{uiElement.units}</InputAdornment> : undefined }} spellCheck={false} autoFocus margin="dense"
-                id={uiElement.id} label={uiElement.label} type="text" value={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]}
-                style={{ width: 485, marginLeft: 20, marginRight: 20 }}
-                onChange={(e) => { this.changeValueFor(uiElement.id, e.target.value) }}
-              />
-            </Tooltip>
-          );
-        } else if (isViewElementObjectOrList(uiElement)) {
-          return (
-            <FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
-              <Tooltip title={uiElement.description || ''}>
-                <Button className={this.props.classes.leftButton} color="secondary" disabled={this.state.editMode} onClick={() => {
-                  this.navigate(`/${uiElement.id}`);
-                }}>{uiElement.label}</Button>
-              </Tooltip>
-            </FormControl>
-          );
-        } else {
-          if (process.env.NODE_ENV !== "production") {
-            console.error(`Unknown type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
+  // private renderUIReference = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
+  //   const isKey = (uiElement.label === keyProperty);
+  //   const canEdit = editMode && (isNew || (uiElement.config && !isKey));
+  //   if (isViewElementObjectOrList(uiElement)) {
+  //     return (
+  //       <FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
+  //         <Tooltip title={uiElement.description || ''}>
+  //           <Button className={this.props.classes.leftButton} color="secondary" disabled={this.state.editMode} onClick={() => {
+  //             this.navigate(`/${uiElement.id}`);
+  //           }}>{uiElement.label}</Button>
+  //         </Tooltip>
+  //       </FormControl>
+  //     );
+  //   } else {
+  //     if (process.env.NODE_ENV !== "production") {
+  //       console.error(`Unknown reference type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
+  //     }
+  //     return null;
+  //   }
+  // };
+
+  private renderUIChoise = (uiElement: ViewElementChoise, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
+    const isKey = (uiElement.label === keyProperty);
+
+    const currentChoise = this.state.choises[uiElement.id];
+    const currentCase = currentChoise && uiElement.cases[currentChoise.selectedCase];
+
+    const canEdit = editMode && (isNew || (uiElement.config && !isKey));
+    if (isViewElementChoise(uiElement)) {
+      const subElements = currentCase ?.elements;
+      return (
+        <>
+          <FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
+            <InputLabel htmlFor={`select-${uiElement.id}`} >{uiElement.label}</InputLabel>
+            <Select
+              required={!!uiElement.mandatory}
+              onChange={(e) => {
+                if (currentChoise.selectedCase === e.target.value) {
+                  return; // nothing changed
+                }
+                this.setState({ choises: { ...this.state.choises, [uiElement.id]: { ...this.state.choises[uiElement.id], selectedCase: e.target.value as string } } });
+              }}
+              readOnly={!canEdit}
+              disabled={editMode && !canEdit}
+              value={this.state.choises[uiElement.id].selectedCase}
+              inputProps={{
+                name: uiElement.id,
+                id: `select-${uiElement.id}`,
+              }}
+            >
+              {
+                Object.keys(uiElement.cases).map(caseKey => {
+                  const caseElm = uiElement.cases[caseKey];
+                  return (
+                    <MenuItem key={caseElm.id} title={caseElm.description} value={caseKey}>{caseElm.label}</MenuItem>
+                  );
+                })
+              }
+            </Select>
+          </FormControl>
+          {subElements
+            ? Object.keys(subElements).map(elmKey => {
+              const elm = subElements[elmKey];
+              return this.renderUIElement(elm, viewData, keyProperty, editMode, isNew);
+            })
+            : <h3>Invalid Choise</h3>
           }
-          return null;
+        </>
+      );
+    } else {
+      if (process.env.NODE_ENV !== "production") {
+        console.error(`Unknown type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
+      }
+      return null;
+    }
+  };
+
+  private renderUIView = (viewSpecification: ViewSpecification, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
+    const { classes } = this.props;
+
+    const orderFunc = (vsA: ViewElement, vsB: ViewElement) => {
+      if (keyProperty) {
+        // if (vsA.label === vsB.label) return 0;
+        if (vsA.label === keyProperty) return -1;
+        if (vsB.label === keyProperty) return +1;
+      }
+
+      // if (vsA.uiType === vsB.uiType) return 0;
+      // if (vsA.uiType !== "object" && vsB.uiType !== "object") return 0;
+      // if (vsA.uiType === "object") return +1;
+      return -1;
+    };
+
+    const sections = Object.keys(viewSpecification.elements).reduce((acc, cur) => {
+      const elm = viewSpecification.elements[cur];
+      if (isViewElementObjectOrList(elm)) {
+        acc.references.push(elm);
+      } else if (isViewElementChoise(elm)) {
+        acc.choises.push(elm);
+      } else {
+        acc.elements.push(elm);
+      }
+      return acc;
+    }, { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[] });
+
+    sections.elements = sections.elements.sort(orderFunc);
+
+    return (
+      <>
+        <div className={classes.section} />
+        {sections.elements.length > 0
+          ? (
+            <div className={classes.section}>
+              {sections.elements.map(element => this.renderUIElement(element, viewData, keyProperty, editMode, isNew))}
+            </div>
+          ) : null
+        }
+        {sections.references.length > 0
+          ? (
+            <div className={classes.section}>
+              {sections.references.map(element => (
+                <UIElementReference key={element.id} element={element} disabled={editMode} onOpenReference={(elm) => { this.navigate(`/${elm.id}`) }} />
+              ))}
+            </div>
+          ) : null
         }
-      })
+        {sections.choises.length > 0
+          ? (
+            <div className={classes.section}>
+              {sections.choises.map(element => this.renderUIChoise(element, viewData, keyProperty, editMode, isNew))}
+            </div>
+          ) : null
+        }
+      </>
     );
   };
 
-  private renderUIElementList(listSpecification: ViewSpecification, listKeyProperty: string, listData: { [key: string]: any }[]) {
+  private renderUIViewList(listSpecification: ViewSpecification, listKeyProperty: string, listData: { [key: string]: any }[]) {
     const listElements = listSpecification.elements;
 
     const navigate = (path: string) => {
@@ -381,11 +515,41 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
             }
           </Breadcrumbs>
         </div>
+        {this.state.editMode && (
+          <Fab color="secondary" aria-label="edit" className={this.props.classes.fab} onClick={async () => {
+            this.props.vPath && await this.props.reloadView(this.props.vPath);
+            this.setState({ editMode: false });
+          }} ><ArrowBack /></Fab>
+        ) || null}
         { /* do not show edit if this is a list or it can't be edited */
           !displayAsList && viewSpecification.canEdit && (<div>
             <Fab color="secondary" aria-label="edit" className={this.props.classes.fab} onClick={() => {
               if (this.state.editMode) {
-                this.props.onUpdateData(this.props.vPath!, this.state.viewData);
+
+                // ensure only active choises will be contained
+                const choiseKeys = Object.keys(viewSpecification.elements).filter(elmKey => isViewElementChoise(viewSpecification.elements[elmKey]));
+                const elementsToRemove = choiseKeys.reduce((acc, cur) => {
+                  const choise = viewSpecification.elements[cur] as ViewElementChoise;
+                  const selectedCase = this.state.choises[cur].selectedCase;
+                  Object.keys(choise.cases).forEach(caseKey => {
+                    if (caseKey === selectedCase) return;
+                    const caseElements = choise.cases[caseKey].elements;
+                    Object.keys(caseElements).forEach(caseElementKey => {
+                      acc.push(caseElements[caseElementKey]);
+                    });
+                  });
+                  return acc;
+                }, [] as ViewElement[]);
+
+                const viewData = this.state.viewData;
+                const resultingViewData = viewData && Object.keys(viewData).reduce((acc, cur) => {
+                  if (!elementsToRemove.some(elm => elm.label === cur || elm.id === cur)) {
+                    acc[cur] = viewData[cur];
+                  }
+                  return acc;
+                }, {} as { [key: string]: any });
+
+                this.props.onUpdateData(this.props.vPath!, resultingViewData);
               }
               this.setState({ editMode: !editMode });
             }}>
@@ -431,10 +595,10 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
 
     return (
       <div>
-        { this.renderBreadCrumps() }
-        { displayAsList && viewData instanceof Array
-            ? this.renderUIElementList(viewSpecification, keyProperty!, viewData)
-            : this.renderUIElement(viewSpecification, viewData!, keyProperty, editMode, isNew)
+        {this.renderBreadCrumps()}
+        {displayAsList && viewData instanceof Array
+          ? this.renderUIViewList(viewSpecification, keyProperty!, viewData)
+          : this.renderUIView(viewSpecification, viewData!, keyProperty, editMode, isNew)
         }
       </div >
     );
index 6fd5c8c..8155bec 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============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 { RouteComponentProps, withRouter } from 'react-router-dom';
 
@@ -29,7 +47,7 @@ class NetworkElementSelectorComponent extends React.Component<NetworkElementSele
 
   render() {
     return (
-      <ConnectedElementTable onHandleClick={(e, row) => { this.props.history.push(`${ this.props.match.path }/${row.nodeId}`) }} columns={[
+      <ConnectedElementTable onHandleClick={(e, row) => { this.props.history.push(`${this.props.match.path}/${row.nodeId}`) }} columns={[
         { property: "nodeId", title: "Name", type: ColumnType.text },
         { property: "isRequired", title: "Required ?", type: ColumnType.boolean },
         { property: "host", title: "Host", type: ColumnType.text },
index c7ab5e4..49c2b9b 100644 (file)
@@ -1,6 +1,24 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
 
 import { Token, Statement, Module, Identity } from "../models/yang";
-import { ViewSpecification, ViewElement, isViewElementObjectOrList, ViewElementBase, isViewElementReference } from "../models/uiModels";
+import { ViewSpecification, ViewElement, isViewElementObjectOrList, ViewElementBase, isViewElementReference, ViewElementChoise, ViewElementBinary, ViewElementString, isViewElementString, isViewElementNumber, ViewElementNumber, Expression, YangRange, ViewElementUnion } from "../models/uiModels";
 import { yangService } from "../services/yangService";
 
 export const splitVPath = (vPath: string, vPathParser: RegExp): RegExpMatchArray[] => {
@@ -238,6 +256,8 @@ class YangLexer {
 export class YangParser {
   private _groupingsToResolve: (() => void)[] = [];
   private _identityToResolve: (() => void)[] = [];
+  private _unionsToResolve: (() => void)[] = [];
+
 
   private _modules: { [name: string]: Module } = {};
   private _views: ViewSpecification[] = [{
@@ -248,7 +268,9 @@ export class YangParser {
     parentView: "0",
     title: "root",
     elements: {},
-   }];
+  }];
+
+  public static ResolveStack = Symbol("ResolveStack");
 
   constructor() {
 
@@ -311,12 +333,12 @@ export class YangParser {
     const revisions = this.extractNodes(rootStatement, "revision");
     module.revisions = {
       ...module.revisions,
-      ...revisions.reduce<{ [version: string]: { }}>((acc, version) => {
+      ...revisions.reduce<{ [version: string]: {}>((acc, version) => {
         if (!version.arg) {
           throw new Error(`Module [${module.name}] has a version w/o version number.`);
         }
         const description = this.extractValue(version, "description");
-        const reference = this.extractValue(version,"reference");
+        const reference = this.extractValue(version, "reference");
         acc[version.arg] = {
           description,
           reference,
@@ -345,10 +367,10 @@ export class YangParser {
     const imports = this.extractNodes(rootStatement, "import");
     module.imports = {
       ...module.imports,
-      ...imports.reduce < { [key: string]: string }>((acc, imp) => {
+      ...imports.reduce<{ [key: string]: string }>((acc, imp) => {
         const prefix = imp.sub && imp.sub.filter(s => s.key === "prefix");
         if (!imp.arg) {
-           throw new Error(`Module [${module.name}] has an import with neither name nor prefix.`);
+          throw new Error(`Module [${module.name}] has an import with neither name nor prefix.`);
         }
         acc[prefix && prefix.length === 1 && prefix[0].arg || imp.arg] = imp.arg;
         return acc;
@@ -389,8 +411,15 @@ export class YangParser {
   }
 
   public postProcess() {
-    // process all groupings
+
     // execute all post processes like resolving in propper order
+    this._unionsToResolve.forEach(cb => {
+      try { cb(); } catch (error) {
+        console.warn(error.message);
+      }
+    });
+
+    // process all groupings
     this._groupingsToResolve.forEach(cb => {
       try { cb(); } catch (error) {
         console.warn(`Error resolving: [${error.message}]`);
@@ -418,7 +447,7 @@ export class YangParser {
     });
 
     // process Identities
-    const traverseIdentity = (identities : Identity[]) => {
+    const traverseIdentity = (identities: Identity[]) => {
       const result: Identity[] = [];
       for (let identity of identities) {
         if (identity.children && identity.children.length > 0) {
@@ -438,7 +467,7 @@ export class YangParser {
         const identity = module.identities[idKey];
         if (identity.base != null) {
           const base = this.resolveIdentity(identity.base, module);
-          base.children?.push(identity);
+          base.children ?.push(identity);
         } else {
           baseIdentites.push(identity);
         }
@@ -455,7 +484,6 @@ export class YangParser {
     });
   };
 
-
   private _nextId = 1;
   private get nextId() {
     return this._nextId++;
@@ -478,7 +506,7 @@ export class YangParser {
   private extractTypeDefinitions(statement: Statement, module: Module, currentPath: string): void {
     const typedefs = this.extractNodes(statement, "typedef");
     typedefs && typedefs.forEach(def => {
-      if (! def.arg) {
+      if (!def.arg) {
         throw new Error(`Module: [${module.name}]. Found typefed without name.`);
       }
       module.typedefs[def.arg] = this.getViewElement(def, module, 0, currentPath, false);
@@ -562,13 +590,14 @@ export class YangParser {
     // extract conditions
     const ifFeature = this.extractValue(statement, "if-feature");
     const whenCondition = this.extractValue(statement, "when");
+    if (whenCondition) console.warn("Found in [" + module.name + "]" + currentPath + " when: " + whenCondition);
 
     // extract all container
     const container = this.extractNodes(statement, "container");
     if (container && container.length > 0) {
       subViews.push(...container.reduce<ViewSpecification[]>((acc, cur) => {
         if (!cur.arg) {
-          throw new Error(`Module: [${module.name}]. Found container without name.`);
+          throw new Error(`Module: [${module.name}]${currentPath}. Found container without name.`);
         }
         const [currentView, subViews] = this.extractSubViews(cur, currentId, module, `${currentPath}/${module.name}:${cur.arg}`);
         elements.push({
@@ -589,11 +618,11 @@ export class YangParser {
     if (lists && lists.length > 0) {
       subViews.push(...lists.reduce<ViewSpecification[]>((acc, cur) => {
         if (!cur.arg) {
-          throw new Error(`Module: [${module.name}]. Found list without name.`);
+          throw new Error(`Module: [${module.name}]${currentPath}. Found list without name.`);
         }
         const key = this.extractValue(cur, "key") || undefined;
         if (config && !key) {
-          throw new Error(`Module: [${module.name}]. Found configurable list without key.`);
+          throw new Error(`Module: [${module.name}]${currentPath}. Found configurable list without key.`);
         }
         const [currentView, subViews] = this.extractSubViews(cur, currentId, module, `${currentPath}/${module.name}:${cur.arg}`);
         elements.push({
@@ -635,10 +664,70 @@ export class YangParser {
 
     const choiceStms = this.extractNodes(statement, "choice");
     if (choiceStms && choiceStms.length > 0) {
-      for (let i = 0; i < choiceStms.length; ++i) {
-        const cases = this.extractNodes(choiceStms[i], "case");
-        console.warn(`Choice found ${choiceStms[i].arg}::${cases.map(c => c.arg).join(";")}`, choiceStms[i]);
-      }
+      elements.push(...choiceStms.reduce<ViewElementChoise[]>((accChoise, curChoise) => {
+        if (!curChoise.arg) {
+          throw new Error(`Module: [${module.name}]${currentPath}. Found choise without name.`);
+        }
+        // extract all cases like containers
+        const cases: { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } }[] = [];
+        const caseStms = this.extractNodes(curChoise, "case");
+        if (caseStms && caseStms.length > 0) {
+          cases.push(...caseStms.reduce((accCase, curCase) => {
+            if (!curCase.arg) {
+              throw new Error(`Module: [${module.name}]${currentPath}/${curChoise.arg}. Found case without name.`);
+            }
+            const description = this.extractValue(curCase, "description") || undefined;
+            const [caseView, caseSubViews] = this.extractSubViews(curCase, parentId, module, `${currentPath}/${module.name}:${curChoise.arg}`);
+            subViews.push(caseView, ...caseSubViews);
+
+            const caseDef: { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } } = {
+              id: parentId === 0 ? `${module.name}:${curCase.arg}` : curCase.arg,
+              label: curCase.arg,
+              description: description,
+              elements: caseView.elements
+            };
+            accCase.push(caseDef);
+            return accCase;
+          }, [] as { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } }[]));
+        }
+
+        // extract all simple cases (one case per leaf, container, etc.)
+        const [choiseView, choiseSubViews] = this.extractSubViews(curChoise, parentId, module, `${currentPath}/${module.name}:${curChoise.arg}`);
+        subViews.push(choiseView, ...choiseSubViews);
+        cases.push(...Object.keys(choiseView.elements).reduce((accElm, curElm) => {
+          const elm = choiseView.elements[curElm];
+          const caseDef: { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } } = {
+            id: elm.id,
+            label: elm.label,
+            description: elm.description,
+            elements: { [elm.id]: elm }
+          };
+          accElm.push(caseDef);
+          return accElm;
+        }, [] as { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } }[]));
+
+        const description = this.extractValue(curChoise, "description") || undefined;
+        const configValue = this.extractValue(curChoise, "config");
+        const config = configValue == null ? true : configValue.toLocaleLowerCase() !== "false";
+
+        const mandatory = this.extractValue(curChoise, "mandatory") === "true" || false;
+
+        const element: ViewElementChoise = {
+          uiType: "choise",
+          id: parentId === 0 ? `${module.name}:${curChoise.arg}` : curChoise.arg,
+          label: curChoise.arg,
+          config: config,
+          mandatory: mandatory,
+          description: description,
+          cases: cases.reduce((acc, cur) => {
+            acc[cur.id] = cur;
+            return acc;
+          }, {} as { [name: string]: { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } } })
+        };
+
+        accChoise.push(element);
+        return accChoise;
+      }, []));
     }
 
     const rpcs = this.extractNodes(statement, "rpc");
@@ -707,17 +796,74 @@ export class YangParser {
     return [viewSpec, subViews];
   }
 
+  // https://tools.ietf.org/html/rfc7950#section-9.3.4
+  private static decimalRange = [
+    { min: -9223372036854775808, max: 9223372036854775807 },
+    { min: -922337203685477580.8, max: 922337203685477580.7 },
+    { min: -92233720368547758.08, max: 92233720368547758.07 },
+    { min: -9223372036854775.808, max: 9223372036854775.807 },
+    { min: -922337203685477.5808, max: 922337203685477.5807 },
+    { min: -92233720368547.75808, max: 92233720368547.75807 },
+    { min: -9223372036854.775808, max: 9223372036854.775807 },
+    { min: -922337203685.4775808, max: 922337203685.4775807 },
+    { min: -92233720368.54775808, max: 92233720368.54775807 },
+    { min: -9223372036.854775808, max: 9223372036.854775807 },
+    { min: -922337203.6854775808, max: 922337203.6854775807 },
+    { min: -92233720.36854775808, max: 92233720.36854775807 },
+    { min: -9223372.036854775808, max: 9223372.036854775807 },
+    { min: -922337.2036854775808, max: 922337.2036854775807 },
+    { min: -92233.72036854775808, max: 92233.72036854775807 },
+    { min: -9223.372036854775808, max: 9223.372036854775807 },
+    { min: -922.3372036854775808, max: 922.3372036854775807 },
+    { min: -92.23372036854775808, max: 92.23372036854775807 },
+    { min: -9.223372036854775808, max: 9.223372036854775807 },
+  ];
+
   /** Extracts the UI View from the type in the cur statement. */
   private getViewElement(cur: Statement, module: Module, parentId: number, currentPath: string, isList: boolean): ViewElement {
 
     const type = this.extractValue(cur, "type");
     const defaultVal = this.extractValue(cur, "default") || undefined;
     const description = this.extractValue(cur, "description") || undefined;
-    const rangeMatch = this.extractValue(cur, "range", /^(\d+)\.\.(\d+)/) || undefined;
 
     const configValue = this.extractValue(cur, "config");
     const config = configValue == null ? true : configValue.toLocaleLowerCase() !== "false";
 
+    const extractRange = (min: number, max: number, property: string = "range"): { expression: Expression<YangRange> | undefined, min: number, max: number } => {
+      const ranges = this.extractValue(this.extractNodes(cur, "type")[0]!, property) || undefined;
+      const range = ranges ?.replace(/min/i, String(min)).replace(/max/i, String(max)).split("|").map(r => {
+        const [minStr, maxStr] = r.split('..');
+        const minValue = Number(minStr);
+        const maxValue = Number(maxStr);
+
+        if (minValue > min) min = minValue;
+        if (maxValue < max) max = maxValue;
+
+        return {
+          min: minValue,
+          max: maxValue
+        };
+      });
+      return {
+        min: min,
+        max: max,
+        expression: range && range.length === 1
+          ? range[0]
+          : range && range.length > 1
+            ? { operation: "OR", arguments: range }
+            : undefined
+      }
+    };
+
+    const extractPattern = (): Expression<RegExp> | undefined => {
+      const pattern = this.extractNodes(this.extractNodes(cur, "type")[0]!, "pattern").map(p => p.arg!).filter(p => !!p).map(p => `^${p}$`);
+      return pattern && pattern.length == 1
+        ? new RegExp(pattern[0])
+        : pattern && pattern.length > 1
+          ? { operation: "AND", arguments: pattern.map(p => new RegExp(p)) }
+          : undefined;
+    }
+
     const mandatory = this.extractValue(cur, "mandatory") === "true" || false;
 
     if (!cur.arg) {
@@ -729,7 +875,7 @@ export class YangParser {
     }
 
     const element: ViewElementBase = {
-      id: parentId === 0 ? `${module.name}:${cur.arg}`: cur.arg,
+      id: parentId === 0 ? `${module.name}:${cur.arg}` : cur.arg,
       label: cur.arg,
       config: config,
       mandatory: mandatory,
@@ -739,10 +885,12 @@ export class YangParser {
     };
 
     if (type === "string") {
+      const length = extractRange(0, +18446744073709551615, "length");
       return ({
         ...element,
         uiType: "string",
-        pattern: this.extractNodes(this.extractNodes(cur, "type")[0]!, "pattern").map(p => p.arg!).filter(p => !!p),
+        length: length.expression,
+        pattern: extractPattern(),
       });
     } else if (type === "boolean") {
       return ({
@@ -750,106 +898,109 @@ export class YangParser {
         uiType: "boolean"
       });
     } else if (type === "uint8") {
+      const range = extractRange(0, +255);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +255,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "uint16") {
+      const range = extractRange(0, +65535);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +65535,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "uint32") {
+      const range = extractRange(0, +4294967295);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +4294967295,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "uint64") {
+      const range = extractRange(0, +18446744073709551615);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +18446744073709551615,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "int8") {
+      const range = extractRange(-128, +127);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : -128,
-        max: rangeMatch ? Number(rangeMatch[1]) : +127,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "int16") {
+      const range = extractRange(-32768, +32767);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : -32768,
-        max: rangeMatch ? Number(rangeMatch[1]) : +32767,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "int32") {
+      const range = extractRange(-2147483648, +2147483647);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : -2147483648,
-        max: rangeMatch ? Number(rangeMatch[1]) : +2147483647,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
       });
     } else if (type === "int64") {
+      const range = extractRange(-9223372036854775808, +9223372036854775807);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +18446744073709551615,
-        units: this.extractValue(cur, "units") || undefined,
-        format: this.extractValue(cur, "format") || undefined,
-      });
-    } else if (type === "decimal16") {
-      return ({
-        ...element,
-        uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +18446744073709551615,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
-        fDigits: Number(this.extractValue(this.extractNodes(cur, "type")[0]!, "fraction-digits")) || -1
-      });
-    } else if (type === "decimal32") {
-      return ({
-        ...element,
-        uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +18446744073709551615,
-        units: this.extractValue(cur, "units") || undefined,
-        format: this.extractValue(cur, "format") || undefined,
-        fDigits: Number(this.extractValue(this.extractNodes(cur, "type")[0]!, "fraction-digits")) || -1
       });
     } else if (type === "decimal64") {
+      // decimalRange
+      const fDigits = Number(this.extractValue(this.extractNodes(cur, "type")[0]!, "fraction-digits")) || -1;
+      if (fDigits === -1) {
+        throw new Error(`Module: [${module.name}][${currentPath}][${cur.arg}]. Found decimal64 with invalid fraction-digits.`);
+      }
+      const range = extractRange(YangParser.decimalRange[fDigits].min, YangParser.decimalRange[fDigits].max);
       return ({
         ...element,
         uiType: "number",
-        min: rangeMatch ? Number(rangeMatch[0]) : 0,
-        max: rangeMatch ? Number(rangeMatch[1]) : +18446744073709551615,
+        fDigits: fDigits,
+        range: range.expression,
+        min: range.min,
+        max: range.max,
         units: this.extractValue(cur, "units") || undefined,
         format: this.extractValue(cur, "format") || undefined,
-        fDigits: Number(this.extractValue(this.extractNodes(cur, "type")[0]!, "fraction-digits")) || -1
       });
     } else if (type === "enumeration") {
       const typeNode = this.extractNodes(cur, "type")[0]!;
@@ -881,7 +1032,7 @@ export class YangParser {
       }
       const refPath = this.resolveReferencePath(vPath, module);
       const resolve = this.resolveReference.bind(this);
-      const res : ViewElement = {
+      const res: ViewElement = {
         ...element,
         uiType: "reference",
         referencePath: refPath,
@@ -912,7 +1063,7 @@ export class YangParser {
         options: []
       };
       this._identityToResolve.push(() => {
-        const identity : Identity = this.resolveIdentity(base, module);
+        const identity: Identity = this.resolveIdentity(base, module);
         if (!identity) {
           throw new Error(`Module: [${module.name}][${currentPath}][${cur.arg}]. Could not resolve identity [${base}].`);
         }
@@ -925,7 +1076,7 @@ export class YangParser {
           description: val.description
         }));
       });
-      return res ;
+      return res;
     } else if (type === "empty") {
       // todo: ❗ handle empty ⚡
       /*  9.11.  The empty Built-In Type
@@ -939,18 +1090,41 @@ export class YangParser {
     } else if (type === "union") {
       // todo: ❗ handle union ⚡
       /* 9.12.  The union Built-In Type */
-      console.warn(`found type: union in [${module.name}][${currentPath}][${element.label}]`);
-      return {
+      const typeNode = this.extractNodes(cur, "type")[0]!;
+      const typeNodes = this.extractNodes(typeNode, "type");
+
+      const resultingElement = {
         ...element,
-        uiType: "string",
+        uiType: "union",
+        elements: []
+      } as ViewElementUnion;
+
+      const resolveUnion = () => {
+        resultingElement.elements.push(...typeNodes.map(node => {
+          const stm: Statement = {
+            ...cur,
+            sub: [
+              ...(cur.sub ?.filter(s => s.key !== "type") || []),
+              node
+            ]
+          };
+          return {
+            ...this.getViewElement(stm, module, parentId, currentPath, isList),
+            id: node.arg!
+          };
+        }));
       };
+
+      this._unionsToResolve.push(resolveUnion);
+
+      return resultingElement;
     } else if (type === "bits") {
       const typeNode = this.extractNodes(cur, "type")[0]!;
       const bitNodes = this.extractNodes(typeNode, "bit");
       return {
         ...element,
         uiType: "bits",
-        flags: bitNodes.reduce<{[name: string]: number | undefined; }>((acc, bitNode) => {
+        flags: bitNodes.reduce<{ [name: string]: number | undefined; }>((acc, bitNode) => {
           if (!bitNode.arg) {
             throw new Error(`Module: [${module.name}][${currentPath}][${cur.arg}]. Found bit without name.`);
           }
@@ -961,25 +1135,60 @@ export class YangParser {
         }, {})
       };
     } else if (type === "binary") {
-      const typeNode = this.extractNodes(cur, "type")[0]!;
-      const length = Number(this.extractValue(typeNode, "length"));
       return {
         ...element,
         uiType: "binary",
-        length: length === length ? length : undefined
+        length: extractRange(0, +18446744073709551615, "length"),
       };
     } else {
       // not a build in type, have to resolve type
-      const typeRef = this.resolveType(type, module);
+      let typeRef = this.resolveType(type, module);
       if (typeRef == null) console.error(new Error(`Could not resolve type ${type} in [${module.name}][${currentPath}].`));
+
+      if (isViewElementString(typeRef)) {
+        typeRef = this.resolveStringType(typeRef, extractPattern(), extractRange(0, +18446744073709551615));
+
+      } else if (isViewElementNumber(typeRef)) {
+        typeRef = this.resolveNumberType(typeRef, extractRange(typeRef.min, typeRef.max));
+      }
+
       return ({
         ...typeRef,
         ...element,
-        description: description
+        description: description,
       }) as ViewElement;
     }
   }
 
+  private resolveStringType(parentElement: ViewElementString, pattern: Expression<RegExp> | undefined, length: { expression: Expression<YangRange> | undefined, min: number, max: number }) {
+    return {
+      ...parentElement,
+      pattern: pattern != null && parentElement.pattern
+        ? { operation: "AND", arguments: [pattern, parentElement.pattern] }
+        : parentElement.pattern
+          ? parentElement.pattern
+          : pattern,
+      length: length.expression != null && parentElement.length
+        ? { operation: "AND", arguments: [length.expression, parentElement.length] }
+        : parentElement.length
+          ? parentElement.length
+          : length ?.expression,
+    } as ViewElementString;
+  }
+
+  private resolveNumberType(parentElement: ViewElementNumber, range: { expression: Expression<YangRange> | undefined, min: number, max: number }) {
+    return {
+      ...parentElement,
+      range: range.expression != null && parentElement.range
+        ? { operation: "AND", arguments: [range.expression, parentElement.range] }
+        : parentElement.range
+          ? parentElement.range
+          : range,
+      min: range.min,
+      max: range.max,
+    } as ViewElementNumber;
+  }
+
   private resolveReferencePath(vPath: string, module: Module) {
     const vPathParser = /(?:(?:([^\/\:]+):)?([^\/]+))/g // 1 = opt: namespace / 2 = property
     return vPath.replace(vPathParser, (_, ns, property) => {
@@ -988,10 +1197,9 @@ export class YangParser {
     });
   }
 
-
   private resolveReference(vPath: string, currentPath: string) {
     const vPathParser = /(?:(?:([^\/\[\]\:]+):)?([^\/\[\]]+)(\[[^\]]+\])?)/g // 1 = opt: namespace / 2 = property / 3 = opt: indexPath
-    let element : ViewElement | null = null;
+    let element: ViewElement | null = null;
     let moduleName = "";
 
     const vPathParts = splitVPath(vPath, vPathParser).map(p => ({ ns: p[1], property: p[2], ind: p[3] }));
@@ -999,7 +1207,7 @@ export class YangParser {
       ? splitVPath(currentPath, vPathParser).map(p => ({ ns: p[1], property: p[2], ind: p[3] }))
       : [];
 
-    for (let i = 0; i < vPathParts.length; ++i){
+    for (let i = 0; i < vPathParts.length; ++i) {
       const vPathPart = vPathParts[i];
       if (vPathPart.property === "..") {
         resultPathParts.pop();
@@ -1009,26 +1217,26 @@ export class YangParser {
     }
 
     // resolve element by path
-    for (let j = 0; j < resultPathParts.length;++j){
+    for (let j = 0; j < resultPathParts.length; ++j) {
       const pathPart = resultPathParts[j];
-        if (j===0) {
+      if (j === 0) {
+        moduleName = pathPart.ns;
+        const rootModule = this._modules[moduleName];
+        if (!rootModule) throw new Error("Could not resolve module [" + moduleName + "].\r\n" + vPath);
+        element = rootModule.elements[`${pathPart.ns}:${pathPart.property}`];
+      } else if (element && isViewElementObjectOrList(element)) {
+        const view: ViewSpecification = this._views[+element.viewId];
+        if (moduleName !== pathPart.ns) {
           moduleName = pathPart.ns;
-          const rootModule = this._modules[moduleName];
-          if (!rootModule) throw new Error("Could not resolve module [" + moduleName +"].\r\n" + vPath);
-          element = rootModule.elements[`${pathPart.ns}:${pathPart.property}`];
-        } else if (element && isViewElementObjectOrList(element)) {
-          const view: ViewSpecification = this._views[+element.viewId];
-          if (moduleName !== pathPart.ns) {
-            moduleName = pathPart.ns;
-            element = view.elements[`${moduleName}:${pathPart.property}`];
-          } else {
-            element = view.elements[pathPart.property] || view.elements[`${moduleName}:${pathPart.property}`];
-          }
+          element = view.elements[`${moduleName}:${pathPart.property}`];
         } else {
-          throw new Error("Could not resolve reference.\r\n" + vPath);
+          element = view.elements[pathPart.property] || view.elements[`${moduleName}:${pathPart.property}`];
         }
-        if (!element) throw new Error("Could not resolve path [" + pathPart.property + "] in ["+ currentPath +"] \r\n" + vPath);
+      } else {
+        throw new Error("Could not resolve reference.\r\n" + vPath);
       }
+      if (!element) throw new Error("Could not resolve path [" + pathPart.property + "] in [" + currentPath + "] \r\n" + vPath);
+    }
 
     return element;
   }
index b0c9b42..c950056 100644 (file)
@@ -4,7 +4,7 @@
     "outDir": "./dist",
     "sourceMap": true,
     "forceConsistentCasingInFileNames": true,
-    "allowSyntheticDefaultImports": false,
+    "allowSyntheticDefaultImports": true,
     "allowUnreachableCode": false,
     "allowUnusedLabels": false,
     "noFallthroughCasesInSwitch": true,
index cfc7720..619c02a 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-connectApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index bf4778b..a6d81c1 100644 (file)
@@ -23,7 +23,7 @@ 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 { networkElementsReloadAction, networkElementsReloadActionAsync } from '../handlers/networkElementsHandler';
 import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
 
 import { PanelId } from '../models/panelId';
@@ -38,7 +38,7 @@ export class SetPanelAction extends Action {
 }
 
 export class AddWebUriList extends Action {
-  constructor(public element: guiCutThrough[], public knownElements: string[]) {
+  constructor(public searchedElements: guiCutThrough[], public notSearchedElements: string[], public newlySearchedElements?: string[]) {
     super();
   }
 }
@@ -53,58 +53,65 @@ export const removeWebUriAction = (nodeId: string) => {
   return new RemoveWebUri(nodeId);
 }
 
+export class SetWeburiSearchBusy extends Action {
+  constructor(public isbusy: boolean) {
+    super();
+  }
+}
+
 let isBusy = false;
-export const findWebUrisForGuiCutThroughAsyncAction = (dispatcher: Dispatch) => (networkElements: NetworkElementConnection[], knownElements: string[]) => {
+export const findWebUrisForGuiCutThroughAsyncAction = (networkElements: NetworkElementConnection[]) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) => {
 
   // keep method from executing simultanously; state not used because change of iu isn't needed
   if (isBusy)
     return;
   isBusy = true;
 
-  const nodeIds = networkElements.map(element => { return element.id as string });
+  const { connect: { guiCutThrough } } = getState();
 
-  if (knownElements.length > 0) {
+  let notConnectedElements: string[] = [];
+  let elementsToSearch: string[] = [];
+  let prevFoundElements: string[] = [];
 
-    let elementsToSearch: string[] = [];
 
-    nodeIds.forEach(element => {
-      // find index of nodeId
-      const index = knownElements.indexOf(element);
+  networkElements.forEach(item => {
+    const id = item.id as string;
+    if (item.status === "Connected") {
 
-      // if element dosen't exist, add it to list
-      if (index === -1) {
-        elementsToSearch.push(element)
+      // element is connected and is added to search list, if it doesn't exist already
+      const exists = guiCutThrough.searchedElements.filter(element => element.nodeId === id).length > 0;
+      if (!exists) {
+        elementsToSearch.push(id);
+
+        //element was found previously, but not searched for a weburi
+        if (guiCutThrough.notSearchedElements.length > 0 && guiCutThrough.notSearchedElements.includes(id)) {
+          prevFoundElements.push(id);
+        }
+      }
+    }
+    else {
+      // element isn't connected and cannot be searched for a weburi
+      if (!guiCutThrough.notSearchedElements.includes(id)) {
+        notConnectedElements.push(item.id as string);
       }
-    });
-
-    // 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;
-    })
+  if (elementsToSearch.length > 0 || notConnectedElements.length > 0) {
+    const result = await connectService.getAllWebUriExtensionsForNetworkElementListAsync(elementsToSearch);
+    dispatcher(new AddWebUriList(result, notConnectedElements, prevFoundElements));
   }
+  isBusy = false;
 }
 
 export const setPanelAction = (panelId: PanelId) => {
   return new SetPanelAction(panelId);
 }
 
-export const updateCurrentViewAsyncAction = () => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+export const updateCurrentViewAsyncAction = () => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
   const { connect: { currentOpenPanel } } = getState();
   if (currentOpenPanel === "NetworkElements") {
-    return dispatch(networkElementsReloadAction);
+    return await dispatch(networkElementsReloadActionAsync);
   }
   else {
     return dispatch(connectionStatusLogReloadAction);
index 1a86f94..1e569a1 100644 (file)
@@ -43,7 +43,7 @@ export const editNetworkElementAsyncActionCreator = (element: UpdateNetworkEleme
     const res = await connectService.deleteNetworkElement(element);
   }
   else {
-      const res = await connectService.updateNetworkElement(element);
+    const res = await connectService.updateNetworkElement(element);
   }
   dispatch(updateCurrentViewAsyncAction());
   dispatch(new AddSnackbarNotification({ message: `Successfully modified [${element.id}]`, options: { variant: 'success' } }));
@@ -54,7 +54,7 @@ export const editNetworkElementAsyncActionCreator = (element: UpdateNetworkEleme
 export const removeNetworkElementAsyncActionCreator = (element: UpdateNetworkElement) => async (dispatch: Dispatch) => {
   const res = await connectService.deleteNetworkElement(element);
   await dispatch(unmountNetworkElementAsyncActionCreator(element && element.id));
-  dispatch(updateCurrentViewAsyncAction());
+  await dispatch(updateCurrentViewAsyncAction());
 };
 
 
index 1e1f115..ce7f48c 100644 (file)
@@ -60,8 +60,8 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
     await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
     await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement));
   },
-  removeNetworkElement: (element: UpdateNetworkElement) => {
-    dispatcher.dispatch(removeNetworkElementAsyncActionCreator(element));
+  removeNetworkElement: async (element: UpdateNetworkElement) => {
+    await dispatcher.dispatch(removeNetworkElementAsyncActionCreator(element));
     dispatcher.dispatch(removeWebUriAction(element.id));
   }
 });
@@ -158,7 +158,7 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
     const setting = settings[this.props.mode];
     return (
       <Dialog open={this.props.mode !== EditNetworkElementDialogMode.None}>
-        <DialogTitle id="form-dialog-title">{setting.dialogTitle}</DialogTitle>
+        <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, "-").toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle>
         <DialogContent>
           <DialogContentText>
             {setting.dialogDescription}
@@ -179,7 +179,7 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
           </FormControl>
         </DialogContent>
         <DialogActions>
-          <Button onClick={(event) => {
+          <Button aria-label="dialog-confirm-button" onClick={(event) => {
             this.onApply({
               isRequired: this.state.isRequired,
               id: this.state.nodeId,
@@ -192,7 +192,7 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
             event.preventDefault();
             event.stopPropagation();
           }} > {setting.applyButtonText} </Button>
-          <Button onClick={(event) => {
+          <Button aria-label="dialog-cancel-button" onClick={(event) => {
             this.onCancel();
             event.preventDefault();
             event.stopPropagation();
index 1440599..23a8014 100644 (file)
@@ -21,7 +21,7 @@ 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 { SetPanelAction, AddWebUriList, RemoveWebUri, SetWeburiSearchBusy } from '../actions/commonNetworkElementsActions';
 import { PanelId } from '../models/panelId';
 import { guiCutThrough } from '../models/guiCutTrough';
 
@@ -41,26 +41,33 @@ const currentOpenPanelHandler: IActionHandler<PanelId> = (state = null, action)
 }
 
 interface guiCutThroughState {
-  availableWebUris: guiCutThrough[];
-  knownElements: string[];
+  searchedElements: guiCutThrough[];
+  notSearchedElements: string[];
 }
 
-const guiCutThroughHandler: IActionHandler<guiCutThroughState> = (state = { availableWebUris: [], knownElements: [] }, action) => {
+const guiCutThroughHandler: IActionHandler<guiCutThroughState> = (state = { searchedElements: [], notSearchedElements: [] }, action) => {
   if (action instanceof AddWebUriList) {
-    let knownElements: string[];
-    let availableWebUris: guiCutThrough[];
+    let notSearchedElements: string[];
+    let searchedElements: guiCutThrough[];
 
-    knownElements = state.knownElements.concat(action.knownElements);
+    notSearchedElements = state.notSearchedElements.concat(action.notSearchedElements);
 
-    availableWebUris = state.availableWebUris.concat(action.element);
+    //remove elements, which were just searched
+    if (action.newlySearchedElements) {
+      action.newlySearchedElements.forEach(item => {
+        notSearchedElements = notSearchedElements.filter(id => id !== item);
+      })
+    }
 
-    state = { availableWebUris: availableWebUris, knownElements: knownElements }
+    searchedElements = state.searchedElements.concat(action.searchedElements);
+
+    state = { searchedElements: searchedElements, notSearchedElements: notSearchedElements }
 
   } 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 };
+    const webUris = state.searchedElements.filter(item => item.nodeId !== nodeId);
+    const knownElements = state.notSearchedElements.filter(item => item !== nodeId);
+    state = { notSearchedElements: knownElements, searchedElements: webUris };
   }
   return state;
 }
index 78c7000..4fe858c 100644 (file)
@@ -31,11 +31,13 @@ export const {
   createActions: createNetworkElementsActions,
   createProperties: createNetworkElementsProperties,
   reloadAction: networkElementsReloadAction,
+  reloadActionAsync: networkElementsReloadActionAsync
 
   // set value action, to change a value
 } = createExternal<NetworkElementConnection>(networkElementsSearchHandler, appState => {
 
-  const webUris = appState.connect.guiCutThrough.availableWebUris;
+  const webUris = appState.connect.guiCutThrough.searchedElements;
+  // add weburi links, if element is connected & weburi available
   if (appState.connect.networkElements.rows && webUris.length > 0) {
 
     appState.connect.networkElements.rows.forEach(element => {
index 4b443ba..d44eea6 100644 (file)
@@ -1 +1,19 @@
-export type guiCutThrough = { webUri: string, nodeId: string }
\ No newline at end of file
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+export type guiCutThrough = { webUri?: string, nodeId: string }
\ No newline at end of file
index 4c2dc9b..f58dc58 100644 (file)
@@ -1,3 +1,21 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
 export type NetworkElementConnection = {
   id?: string;
   nodeId: string;
index b514120..2000d94 100644 (file)
@@ -1 +1,19 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
 export type PanelId = null | "NetworkElements" | "ConnectionStatusLog";
\ No newline at end of file
index 7a410f4..41449e8 100644 (file)
@@ -188,14 +188,20 @@ class ConnectService {
       promises.push(requestRest<any>(path, { method: "GET" })
         .then(result => {
 
-          if (result['network-element'] && result['network-element'].extension) {
+          if (result != null && 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 });
+            } else {
+              webUris.push({ webUri: undefined, nodeId: nodeId });
             }
+          } else {
+            webUris.push({ webUri: undefined, nodeId: nodeId });
           }
         })
-        .catch(error => console.log("network element is unreachable: " + error)))
+        .catch(error => {
+          webUris.push({ webUri: undefined, nodeId: nodeId });
+        }))
 
     })
 
index aa3391c..f8c0f3a 100644 (file)
@@ -25,7 +25,7 @@ import { connectionStatusLogReloadAction, createConnectionStatusLogActions } fro
 
 import { NetworkElementsList } from '../components/networkElements';
 import { ConnectionStatusLog } from '../components/connectionStatusLog';
-import { setPanelAction, findWebUrisForGuiCutThroughAsyncAction } from '../actions/commonNetworkElementsActions';
+import { setPanelAction, findWebUrisForGuiCutThroughAsyncAction, SetWeburiSearchBusy } from '../actions/commonNetworkElementsActions';
 import { PanelId } from '../models/panelId';
 import { NetworkElementConnection } from 'models/networkElementConnection';
 
@@ -42,7 +42,8 @@ const mapDispatcher = (dispatcher: IDispatcher) => ({
   onLoadNetworkElements: () => {
     dispatcher.dispatch(networkElementsReloadAction);
   },
-  loadWebUris: findWebUrisForGuiCutThroughAsyncAction(dispatcher.dispatch),
+  loadWebUris: async (networkElements: NetworkElementConnection[]) => { await dispatcher.dispatch(findWebUrisForGuiCutThroughAsyncAction(networkElements)) },
+  isBusy: (busy: boolean) => dispatcher.dispatch(new SetWeburiSearchBusy(busy)),
   onLoadConnectionStatusLog: () => {
     dispatcher.dispatch(connectionStatusLogReloadAction);
   },
@@ -55,13 +56,12 @@ type ConnectApplicationComponentProps = Connect<typeof mapProps, typeof mapDispa
 
 class ConnectApplicationComponent extends React.Component<ConnectApplicationComponentProps>{
 
-  componentDidUpdate = () => {
+  componentDidUpdate = async () => {
     // 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);
+    if (networkElements.rows.length > 0) {
+      await this.props.loadWebUris(networkElements.rows);
     }
   }
 
index 6d70b04..aa3acf0 100644 (file)
@@ -126,23 +126,23 @@ module.exports = (env) => {
       },
       proxy: {
         "/oauth2/": {
-          target: "http://10.20.6.29:28181",
+          target: "http://10.20.6.29:48181",
           secure: false
         },
         "/database/": {
-          target: "http://10.20.6.29:28181",
+          target: "http://10.20.6.29:48181",
           secure: false
         },
         "/restconf/": {
-          target: "http://10.20.6.29:28181",
+          target: "http://10.20.6.29:48181",
           secure: false
         },
         "/help/": {
-          target: "http://10.20.6.29:28181",
+          target: "http://10.20.6.29:48181",
           secure: false
         },
         "/websocket": {
-          target: "http://10.20.6.29:28181",
+          target: "http://10.20.6.29:48181",
           ws: true,
           changeOrigin: true,
           secure: false
index 92ef685..9e96cf4 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-demoApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index d84a106..e5ac653 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-eventLogApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index 119d636..63825dd 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-faultApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index b40de2f..760049c 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-helpApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index aad75ca..9420b6c 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-inventoryApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index 0d51219..0196e39 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-maintenanceApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index 038761a..5a3b802 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-mediatorApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index f1eb06a..81af1fb 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-minimumApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index 5968721..e60a6c1 100644 (file)
@@ -14,7 +14,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>sdnr-wt-odlux-app-performanceHistoryApp</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
                     <execution>
                         <id>install node and yarn</id>
                         <goals>
index b4ded60..c29104e 100644 (file)
@@ -26,7 +26,7 @@
     <version>0.7.1-SNAPSHOT</version>
     <packaging>feature</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>ccsdk-features :: ${project.artifactId} :: feature</name>
     <licenses>
         <license>
             <name>Apache License, Version 2.0</name>
index 3f99719..cf00a49 100755 (executable)
 <?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">
-    <modelVersion>4.0.0</modelVersion>
+       <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>org.onap.ccsdk.parent</groupId>
-        <artifactId>odlparent-lite</artifactId>
-        <version>1.5.2-SNAPSHOT</version>
-        <relativePath/>
-    </parent>
+       <parent>
+               <groupId>org.onap.ccsdk.parent</groupId>
+               <artifactId>odlparent-lite</artifactId>
+               <version>1.5.2-SNAPSHOT</version>
+               <relativePath/>
+       </parent>
 
-    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-    <artifactId>sdnr-wt-odlux-core-installer</artifactId>
-    <version>0.7.1-SNAPSHOT</version>
-    <packaging>pom</packaging>
+       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+       <artifactId>sdnr-wt-odlux-core-installer</artifactId>
+       <version>0.7.1-SNAPSHOT</version>
+       <packaging>pom</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
-    <licenses>
-        <license>
-            <name>Apache License, Version 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
-        </license>
-    </licenses>
+       <name>ccsdk-features :: ${project.artifactId}</name>
+       <licenses>
+               <license>
+                       <name>Apache License, Version 2.0</name>
+                       <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+               </license>
+       </licenses>
 
-    <properties>
-        <application.name>sdnr-wt-odlux-core</application.name>
-        <include.transitive.dependencies>false</include.transitive.dependencies>
-    </properties>
+       <properties>
+               <application.name>sdnr-wt-odlux-core</application.name>
+               <include.transitive.dependencies>false</include.transitive.dependencies>
+       </properties>
 
-    <dependencies>
-        <dependency>
-            <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-            <artifactId>${application.name}-feature</artifactId>
-            <version>${project.version}</version>
-            <type>xml</type>
-            <classifier>features</classifier>
-            <exclusions>
-                <exclusion>
-                    <groupId>*</groupId>
-                    <artifactId>*</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-            <artifactId>${application.name}-provider</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
+       <dependencies>
+               <dependency>
+                       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+                       <artifactId>${application.name}-feature</artifactId>
+                       <version>${project.version}</version>
+                       <type>xml</type>
+                       <classifier>features</classifier>
+                       <exclusions>
+                               <exclusion>
+                                       <groupId>*</groupId>
+                                       <artifactId>*</artifactId>
+                               </exclusion>
+                       </exclusions>
+               </dependency>
+               <dependency>
+                       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+                       <artifactId>${application.name}-provider</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+       </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>maven-repo-zip</id>
-                        <goals>
-                            <goal>single</goal>
-                        </goals>
-                        <phase>package</phase>
-                        <configuration>
-                            <attach>true</attach>
-                            <finalName>stage/${application.name}-${project.version}</finalName>
-                            <descriptors>
-                                <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor>
-                            </descriptors>
-                            <appendAssemblyId>true</appendAssemblyId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-dependency-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>copy-nested-dependencies</id>
-                        <goals>
-                            <goal>copy-dependencies</goal>
-                        </goals>
-                        <phase>prepare-package</phase>
-                        <configuration>
-                            <transitive>true</transitive>
-                            <outputDirectory>${project.build.directory}/assembly/system</outputDirectory>
-                            <overWriteReleases>false</overWriteReleases>
-                            <overWriteSnapshots>true</overWriteSnapshots>
-                            <overWriteIfNewer>true</overWriteIfNewer>
-                            <useRepositoryLayout>true</useRepositoryLayout>
-                            <addParentPoms>false</addParentPoms>
-                            <copyPom>false</copyPom>
-                            <!--<includeArtifactIds>sdnr-wt-apigateway-provider,${application.name}</includeArtifactIds> -->
-                            <!--<scope>provided</scope> -->
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+       <build>
+               <plugins>
+                       <plugin>
+                               <artifactId>maven-assembly-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>maven-repo-zip</id>
+                                               <goals>
+                                                       <goal>single</goal>
+                                               </goals>
+                                               <phase>package</phase>
+                                               <configuration>
+                                                       <attach>true</attach>
+                                                       <finalName>stage/${application.name}-${project.version}</finalName>
+                                                       <descriptors>
+                                                               <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor>
+                                                       </descriptors>
+                                                       <appendAssemblyId>true</appendAssemblyId>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-dependency-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>copy-nested-dependencies</id>
+                                               <goals>
+                                                       <goal>copy-dependencies</goal>
+                                               </goals>
+                                               <phase>prepare-package</phase>
+                                               <configuration>
+                                                       <transitive>true</transitive>
+                                                       <outputDirectory>${project.build.directory}/assembly/system</outputDirectory>
+                                                       <overWriteReleases>false</overWriteReleases>
+                                                       <overWriteSnapshots>true</overWriteSnapshots>
+                                                       <overWriteIfNewer>true</overWriteIfNewer>
+                                                       <useRepositoryLayout>true</useRepositoryLayout>
+                                                       <addParentPoms>false</addParentPoms>
+                                                       <copyPom>false</copyPom>
+                                                       <!--<includeArtifactIds>sdnr-wt-apigateway-provider,${application.name}</includeArtifactIds> -->
+                                                       <!--<scope>provided</scope> -->
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
 </project>
index dafa88b..9840177 100644 (file)
@@ -1,35 +1,35 @@
 <?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">
-    <modelVersion>4.0.0</modelVersion>
+       <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>org.onap.ccsdk.parent</groupId>
-        <artifactId>odlparent-lite</artifactId>
-        <version>1.5.2-SNAPSHOT</version>
-        <relativePath/>
-    </parent>
+       <parent>
+               <groupId>org.onap.ccsdk.parent</groupId>
+               <artifactId>odlparent-lite</artifactId>
+               <version>1.5.2-SNAPSHOT</version>
+               <relativePath/>
+       </parent>
 
-    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-    <artifactId>sdnr-wt-odlux-core-top</artifactId>
-    <version>0.7.1-SNAPSHOT</version>
-    <packaging>pom</packaging>
+       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+       <artifactId>sdnr-wt-odlux-core-top</artifactId>
+       <version>0.7.1-SNAPSHOT</version>
+       <packaging>pom</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
-    <licenses>
-        <license>
-            <name>Apache License, Version 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
-        </license>
-    </licenses>
+       <name>odlux-core</name>
+       <licenses>
+               <license>
+                       <name>Apache License, Version 2.0</name>
+                       <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+               </license>
+       </licenses>
 
-    <modules>
-        <module>model</module>
-        <module>provider</module>
-        <module>features</module>
-        <module>installer</module>
-    </modules>
+       <modules>
+               <module>model</module>
+               <module>provider</module>
+               <module>features</module>
+               <module>installer</module>
+       </modules>
 
-    <properties>
-        <feature-name>sdnr-wt-odlux-core</feature-name>
-    </properties>
+       <properties>
+               <feature-name>sdnr-wt-odlux-core</feature-name>
+       </properties>
 </project>
index 2b36c31..09b26f0 100644 (file)
 <?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">
-    <modelVersion>4.0.0</modelVersion>
+       <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>org.onap.ccsdk.parent</groupId>
-        <artifactId>binding-parent</artifactId>
-        <version>1.5.2-SNAPSHOT</version>
-        <relativePath/>
-    </parent>
+       <parent>
+               <groupId>org.onap.ccsdk.parent</groupId>
+               <artifactId>binding-parent</artifactId>
+               <version>1.5.2-SNAPSHOT</version>
+               <relativePath/>
+       </parent>
 
-    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-    <artifactId>sdnr-wt-odlux-core-provider</artifactId>
-    <version>0.7.1-SNAPSHOT</version>
-    <packaging>bundle</packaging>
+       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+       <artifactId>sdnr-wt-odlux-core-provider</artifactId>
+       <version>0.7.1-SNAPSHOT</version>
+       <packaging>bundle</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
-    <licenses>
-        <license>
-            <name>Apache License, Version 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
-        </license>
-    </licenses>
+       <name>ccsdk-features :: ${project.artifactId}</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>org.onap.ccsdk.features.sdnr.wt</groupId>
-            <artifactId>sdnr-wt-odlux-core-model</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>sdnr-wt-odlux-framework</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <scope>test</scope>
-        </dependency>
+       <dependencies>
+               <dependency>
+                       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+                       <artifactId>sdnr-wt-odlux-core-model</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>sdnr-wt-odlux-framework</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.eclipse.jetty</groupId>
+                       <artifactId>jetty-server</artifactId>
+                       <scope>test</scope>
+               </dependency>
 
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.compendium</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>com.google.guava</groupId>
+                       <artifactId>guava</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>javax.servlet</groupId>
+                       <artifactId>javax.servlet-api</artifactId>
+               </dependency>
+                               <dependency>
+                       <groupId>org.mockito</groupId>
+                       <artifactId>mockito-core</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-simple</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>1.8</source>
-                    <target>1.8</target>
-                </configuration>
-            </plugin>
-            <plugin>
-                <artifactId>maven-checkstyle-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
-            </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.*;resolution:=optional,*;
-                        </Import-Package>
-                        <Embed-Dependency>sdnr-wt-odlux-framework;inline=true</Embed-Dependency>
-                        <Embed-Transitive>true</Embed-Transitive>
-                        <Export-Package>${project.groupId}.*</Export-Package>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.8</source>
+                                       <target>1.8</target>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <artifactId>maven-checkstyle-plugin</artifactId>
+                               <configuration>
+                                       <skip>true</skip>
+                               </configuration>
+                       </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.*;resolution:=optional,*;
+                                               </Import-Package>
+                                               <Embed-Dependency>sdnr-wt-odlux-framework;inline=true</Embed-Dependency>
+                                               <Embed-Transitive>true</Embed-Transitive>
+                                               <Export-Package>${project.groupId}.*</Export-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
 </project>
index fc7a532..78349e4 100644 (file)
 <?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">
-    <modelVersion>4.0.0</modelVersion>
+       <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>org.onap.ccsdk.parent</groupId>
-        <artifactId>odlparent</artifactId>
-        <version>1.5.2-SNAPSHOT</version>
-        <relativePath/>
-    </parent>
+       <parent>
+               <groupId>org.onap.ccsdk.parent</groupId>
+               <artifactId>odlparent</artifactId>
+               <version>1.5.2-SNAPSHOT</version>
+               <relativePath/>
+       </parent>
 
-    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-    <artifactId>sdnr-wt-odlux-framework</artifactId>
-    <version>0.7.1-SNAPSHOT</version>
-    <packaging>jar</packaging>
+       <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+       <artifactId>sdnr-wt-odlux-framework</artifactId>
+       <version>0.7.1-SNAPSHOT</version>
+       <packaging>jar</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
-    <licenses>
-        <license>
-            <name>Apache License, Version 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
-        </license>
-    </licenses>
+       <name>sdnr-wt-odlux-framework</name>
+       <licenses>
+               <license>
+                       <name>Apache License, Version 2.0</name>
+                       <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+               </license>
+       </licenses>
 
-    <properties>
-        <buildtime>${maven.build.timestamp}</buildtime>
-        <distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion>
-        <buildno>36.1a30021(19/12/12)</buildno>
-        <odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version>
-    </properties>
+       <properties>
+               <buildtime>${maven.build.timestamp}</buildtime>
+               <distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion>
+               <buildno>39.0e1988b(20/01/12)</buildno>
+               <odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version>
+       </properties>
 
-    <build>
-        <resources>
-            <resource>
-                <directory>dist</directory>
-                <targetPath>odlux</targetPath>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <artifactId>maven-clean-plugin</artifactId>
-                <configuration>
-                    <filesets>
-                        <fileset>
-                            <directory>dist</directory>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>node</directory>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>node_modules</directory>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <fileset>
-                            <directory>../node_modules</directory>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                        <!-- eclipse bug build bin folder in basedir -->
-                        <fileset>
-                            <directory>bin</directory>
-                            <followSymlinks>false</followSymlinks>
-                        </fileset>
-                    </filesets>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>de.jacks-it-lab</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.7.2</version>
-                <executions>
-                    <execution>
-                        <id>install node and yarn</id>
-                        <goals>
-                            <goal>install-node-and-yarn</goal>
-                        </goals>
-                        <!-- optional: default phase is "generate-resources" -->
-                        <phase>initialize</phase>
-                        <configuration>
-                            <nodeVersion>v10.16.3</nodeVersion>
-                            <yarnVersion>v1.19.0</yarnVersion>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>clear cache</id>
-                        <goals>
-                            <goal>yarn</goal>
-                        </goals>
-                        <phase>initialize</phase>
-                        <configuration>
-                            <arguments>cache clean</arguments>
-                            <installDirectory>${project.basedir}</installDirectory>
-                            <workingDirectory>${project.basedir}/../</workingDirectory>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>install lerna</id>
-                        <goals>
-                            <goal>yarn</goal>
-                        </goals>
-                        <phase>initialize</phase>
-                        <configuration>
-                            <arguments>add lerna@3.13.1 -W --exact</arguments>
-                            <installDirectory>${project.basedir}</installDirectory>
-                            <workingDirectory>${project.basedir}/../</workingDirectory>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>exec lerna bootstrap</id>
-                        <goals>
-                            <goal>lerna</goal>
-                        </goals>
-                        <phase>initialize</phase>
-                        <configuration>
-                            <lernaInheritsProxyConfigFromMaven>false</lernaInheritsProxyConfigFromMaven>
-                            <arguments>bootstrap</arguments>
-                            <installDirectory>${project.basedir}</installDirectory>
-                            <workingDirectory>${project.basedir}/../</workingDirectory>
-                        </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>com.google.code.maven-replacer-plugin</groupId>
-                <artifactId>replacer</artifactId>
-                <version>1.5.2</version>
-                <executions>
-                    <execution>
-                        <id>replace version</id>
-                        <phase>prepare-package</phase>
-                        <goals>
-                            <goal>replace</goal>
-                        </goals>
-                    </execution>
-                </executions>
-                <configuration>
-                    <basedir>${project.build.directory}/classes/odlux</basedir>
-                    <includes>
-                        <include>app.js</include>
-                    </includes>
-                    <replacements>
-                        <replacement>
-                            <token>##odlux.version##</token>
-                            <value>${odlux.version}</value>
-                        </replacement>
-                    </replacements>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+       <build>
+               <resources>
+                       <resource>
+                               <directory>dist</directory>
+                               <targetPath>odlux</targetPath>
+                       </resource>
+               </resources>
+               <plugins>
+                       <plugin>
+                               <artifactId>maven-clean-plugin</artifactId>
+                               <configuration>
+                                       <filesets>
+                                               <fileset>
+                                                       <directory>dist</directory>
+                                                       <followSymlinks>false</followSymlinks>
+                                               </fileset>
+                                               <fileset>
+                                                       <directory>node</directory>
+                                                       <followSymlinks>false</followSymlinks>
+                                               </fileset>
+                                               <fileset>
+                                                       <directory>node_modules</directory>
+                                                       <followSymlinks>false</followSymlinks>
+                                               </fileset>
+                                               <fileset>
+                                                       <directory>../node_modules</directory>
+                                                       <followSymlinks>false</followSymlinks>
+                                               </fileset>
+                                               <!-- eclipse bug build bin folder in basedir -->
+                                               <fileset>
+                                                       <directory>bin</directory>
+                                                       <followSymlinks>false</followSymlinks>
+                                               </fileset>
+                                       </filesets>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>de.jacks-it-lab</groupId>
+                               <artifactId>frontend-maven-plugin</artifactId>
+                               <version>1.7.2</version>
+                               <executions>
+                                       <execution>
+                                               <id>install node and yarn</id>
+                                               <goals>
+                                                       <goal>install-node-and-yarn</goal>
+                                               </goals>
+                                               <!-- optional: default phase is "generate-resources" -->
+                                               <phase>initialize</phase>
+                                               <configuration>
+                                                       <nodeVersion>v10.16.3</nodeVersion>
+                                                       <yarnVersion>v1.19.0</yarnVersion>
+                                               </configuration>
+                                       </execution>
+                                       <execution>
+                                               <id>clear cache</id>
+                                               <goals>
+                                                       <goal>yarn</goal>
+                                               </goals>
+                                               <phase>initialize</phase>
+                                               <configuration>
+                                                       <arguments>cache clean</arguments>
+                                                       <installDirectory>${project.basedir}</installDirectory>
+                                                       <workingDirectory>${project.basedir}/../</workingDirectory>
+                                               </configuration>
+                                       </execution>
+                                       <execution>
+                                               <id>install lerna</id>
+                                               <goals>
+                                                       <goal>yarn</goal>
+                                               </goals>
+                                               <phase>initialize</phase>
+                                               <configuration>
+                                                       <arguments>add lerna@3.13.1 -W --exact</arguments>
+                                                       <installDirectory>${project.basedir}</installDirectory>
+                                                       <workingDirectory>${project.basedir}/../</workingDirectory>
+                                               </configuration>
+                                       </execution>
+                                       <execution>
+                                               <id>exec lerna bootstrap</id>
+                                               <goals>
+                                                       <goal>lerna</goal>
+                                               </goals>
+                                               <phase>initialize</phase>
+                                               <configuration>
+                                                       <lernaInheritsProxyConfigFromMaven>false</lernaInheritsProxyConfigFromMaven>
+                                                       <arguments>bootstrap</arguments>
+                                                       <installDirectory>${project.basedir}</installDirectory>
+                                                       <workingDirectory>${project.basedir}/../</workingDirectory>
+                                               </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>com.google.code.maven-replacer-plugin</groupId>
+                               <artifactId>replacer</artifactId>
+                               <version>1.5.2</version>
+                               <executions>
+                                       <execution>
+                                               <id>replace version</id>
+                                               <phase>prepare-package</phase>
+                                               <goals>
+                                                       <goal>replace</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       <basedir>${project.build.directory}/classes/odlux</basedir>
+                                       <includes>
+                                               <include>app.js</include>
+                                       </includes>
+                                       <replacements>
+                                               <replacement>
+                                                       <token>##odlux.version##</token>
+                                                       <value>${odlux.version}</value>
+                                               </replacement>
+                                       </replacements>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
 </project>
index 356f36d..f70fbc0 100644 (file)
@@ -3,4 +3,14 @@ html, body, #app {
   padding: 0px;
   margin: 0px;
   font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+.about-table td{
+  padding:0.5rem 1rem;
+  border-bottom: 1px solid #DDD;
+}
+.about-table pre {
+  background:#FFF;
+  border:1px solid #CCC;
+  padding:1rem;
+  margin: 1rem 0;
 }
\ No newline at end of file
index 3e31c5e..5206744 100644 (file)
@@ -179,7 +179,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
         <TableToolbar tableId={this.props.tableId} numSelected={selected && selected.length} title={this.props.title} customActionButtons={this.props.customActionButtons} onExportToCsv={this.exportToCsv}
           onToggleFilter={toggleFilter} />
         <div className={classes.tableWrapper}>
-          <Table className={classes.table} aria-labelledby="tableTitle">
+          <Table className={classes.table} aria-label={this.props.tableId ? this.props.tableId : 'tableTitle'}>
             <EnhancedTableHead
               columns={columns}
               numSelected={selected && selected.length}
@@ -193,7 +193,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
             <TableBody>
               {showFilter && <EnhancedTableFilter columns={columns} filter={filter} onFilterChanged={this.onFilterChanged} enableSelection={this.props.enableSelection} /> || null}
               {rows // may need ordering here
-                .map((entry: TData & { [key: string]: any }) => {
+                .map((entry: TData & { [key: string]: any }, index) => {
                   const entryId = getId(entry);
                   const isSelected = this.isSelected(entryId);
                   return (
@@ -202,6 +202,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
                       onClick={event => this.handleClick(event, entry, entryId)}
                       role="checkbox"
                       aria-checked={isSelected}
+                      aria-label={`${(this.props.tableId ? this.props.tableId : 'table')}-row-${(index + 1)}`}
                       tabIndex={-1}
                       key={entryId}
                       selected={isSelected}
index 737ea85..2075e05 100644 (file)
@@ -69,14 +69,14 @@ class EnhancedTableFilterComponent extends React.Component<IEnhancedTableFilterC
               {col.disableFilter || (col.type === ColumnType.custom)
                 ? null
                 : (col.type === ColumnType.boolean)
-                  ? <Select className={classes.input} value={filter[col.property] !== undefined ? filter[col.property] : ''} onChange={this.createFilterHandler(col.property)} inputProps={{ name: `${col.property}-bool`, id: `${col.property}-bool` }} >
-                    <MenuItem value={undefined}>
+                  ? <Select className={classes.input} aria-label={(col.title as string).toLowerCase() + ' filter'} value={filter[col.property] !== undefined ? filter[col.property] : ''} onChange={this.createFilterHandler(col.property)} inputProps={{ name: `${col.property}-bool`, id: `${col.property}-bool` }} >
+                    <MenuItem value={undefined} >
                       <em>None</em>
                     </MenuItem>
                     <MenuItem value={true as any as string}>{col.labels ? col.labels["true"] : "true"}</MenuItem>
                     <MenuItem value={false as any as string}>{col.labels ? col.labels["false"] : "false"}</MenuItem>
                   </Select>
-                  : <Input className={classes.input} inputProps={{ 'aria-label': 'Filter' }} value={filter[col.property] || ''} onChange={this.createFilterHandler(col.property)} />}
+                  : <Input className={classes.input} inputProps={{ 'aria-label': (col.title as string).toLowerCase() + ' filter' }} value={filter[col.property] || ''} onChange={this.createFilterHandler(col.property)} />}
             </TableCell>
           );
         }, this)}
index 6e8902c..74682cd 100644 (file)
@@ -196,6 +196,29 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
     }).catch(error => new AddErrorInfoAction(error));
   };
 
+  const reloadActionAsync = async (dispatch: Dispatch, getAppState: () => IApplicationStoreState) => {
+    dispatch(new RefreshAction());
+    const ownState = selectState(getAppState());
+    const filter = { ...ownState.preFilter, ...(ownState.showFilter && ownState.filter || {}) };
+
+    try {
+      const result = await Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter));
+
+
+      if (ownState.page > 0 && ownState.rowsPerPage * ownState.page > result.total) { //if result is smaller than the currently shown page, new search and repaginate
+
+        let newPage = Math.floor(result.total / ownState.rowsPerPage);
+
+        const repaginationResult = await Promise.resolve(callback(newPage, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter));
+        dispatch(new SetResultAction(repaginationResult));
+      } else {
+        dispatch(new SetResultAction(result));
+      }
+    } catch (error) {
+      new AddErrorInfoAction(error);
+    }
+  };
+
   const createPreActions = (dispatch: Dispatch, skipRefresh: boolean = false) => {
     return {
       onPreFilterChanged: (preFilter: { [key: string]: string }) => {
@@ -258,6 +281,7 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
     createActions: createActions,
     createProperties: createProperties,
     createPreActions: createPreActions,
-    actionHandler: externalTableStateActionHandler
+    actionHandler: externalTableStateActionHandler,
+    reloadActionAsync: reloadActionAsync,
   }
 }
\ No newline at end of file
index d47e09c..59a7151 100644 (file)
  * the License.
  * ============LICENSE_END==========================================================================
  */
-import * as React from 'react';\r
-\r
-const AboutComponent = () => {\r
-\r
-  return (\r
-    <div>\r
-      <h2>About</h2>\r
-      <div style={{ margin: "0 auto" }}>##odlux.version##</div>\r
-    </div>\r
-  );\r
-};\r
-\r
-export const About = AboutComponent;\r
+import * as React from 'react';
+import * as marked from 'marked';
+import * as hljs from 'highlight.js';
+import { requestRestExt } from '../services/restService';
+const defaultRenderer = new marked.Renderer();
+defaultRenderer.link = (href, title, text) => (
+  `<a target="_blank" rel="noopener noreferrer" href="${href}" title="${title}">${text}</a>`
+);
+interface AboutState {
+  content: string | null;
+}
+
+class AboutComponent extends React.Component<any, AboutState> {
+
+
+  constructor(props: any) {
+    super(props);
+    this.state = { content: null }
+    this.loadAboutContent();
+  }
+  private loadAboutContent(): void {
+    requestRestExt<string>('/about').then((response) => {
+      this.setState({ content: response.status == 200 ? response.data : `${response.status} ${response.message}` || "Server error" })
+    }).catch((error) => {
+      this.setState({ content: error })
+    })
+  }
+  render() {
+
+    const markedOptions: marked.MarkedOptions = {
+      gfm: true,
+      breaks: false,
+      pedantic: false,
+      sanitize: true,
+      smartLists: true,
+      smartypants: false,
+      langPrefix: 'hljs ',
+      ...({}),
+      highlight: (code, lang) => {
+        if (!!(lang && hljs.getLanguage(lang))) {
+          return hljs.highlight(lang, code).value;
+        }
+        return code;
+      }
+    };
+
+
+    const className = "about-table"
+    const style: React.CSSProperties = {};
+
+    const html = (marked(this.state.content || 'loading', { renderer: markedOptions && markedOptions.renderer || defaultRenderer }));
+
+    return (
+      <div
+        dangerouslySetInnerHTML={{ __html: html }}
+        className={className}
+        style={style}
+      />
+
+    );
+  }
+};
+
+export const About = AboutComponent;
 export default About;
\ No newline at end of file
index 578a0ae..93b748d 100644 (file)
@@ -191,7 +191,11 @@ module.exports = (env) => {
       },\r
       proxy: {\r
         "/oauth2/**/*": {\r
-          target: "http://10.20.6.29:48181",\r
+          target: "http://172.18.0.3:8181",\r
+          secure: false\r
+        },\r
+        "/about": {\r
+          target: "http://172.18.0.3:8181",\r
           secure: false\r
         }\r
       }\r
index cac9817..df71097 100644 (file)
     </parent>
 
     <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
-    <artifactId>sdnr-wt-odlux-top</artifactId>
+    <artifactId>odlux-top</artifactId>
     <version>0.7.1-SNAPSHOT</version>
     <packaging>pom</packaging>
 
-    <name>ccsdk-features :: ${project.artifactId}</name>
+    <name>odlux</name>
 
     <modules>
         <module>framework</module>
         <module>apps/maintenanceApp</module>
         <module>apps/minimumApp</module>
         <module>apps/performanceHistoryApp</module>
-        <module>apps/eventLogApp</module>
+         <module>apps/eventLogApp</module>
         <module>apps/configurationApp</module>
         <module>apps/app-feature</module>
         <module>apps/app-installer</module>
     </modules>
 
     <build>
-        <plugins>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>exec-maven-plugin</artifactId>
-                <executions>
-                    <execution><!-- Run our version calculation script -->
-                        <id>Clean node and node_modules</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>exec</goal>
-                        </goals>
-                        <configuration>
-                            <executable>rm</executable>
-                            <arguments>
-                                <argument>-r</argument>
-                                <argument>node_modules</argument>
-                            </arguments>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.codehaus.mojo</groupId>
+                               <artifactId>exec-maven-plugin</artifactId>
+                               <executions>
+                                       <execution><!-- Run our version calculation script -->
+                                               <id>Clean node and node_modules</id>
+                                               <phase>package</phase>
+                                               <goals>
+                                                       <goal>exec</goal>
+                                               </goals>
+                                               <configuration>
+                                                       <executable>rm</executable>
+                                                        <arguments>
+                                                               <argument>-r</argument>
+                                                               <argument>node_modules</argument>
+                                                       </arguments>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
 </project>
index 9ce3e4b..e828763 100644 (file)
     universal-user-agent "^4.0.0"
 
 "@octokit/rest@^16.16.0":
-  version "16.35.0"
-  resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.35.0.tgz#7ccc1f802f407d5b8eb21768c6deca44e7b4c0d8"
-  integrity sha512-9ShFqYWo0CLoGYhA1FdtdykJuMzS/9H6vSbbQWDX4pWr4p9v+15MsH/wpd/3fIU+tSxylaNO48+PIHqOkBRx3w==
+  version "16.36.0"
+  resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.36.0.tgz#99892c57ba632c2a7b21845584004387b56c2cb7"
+  integrity sha512-zoZj7Ya4vWBK4fjTwK2Cnmu7XBB1p9ygSvTk2TthN6DVJXM4hQZQoAiknWFLJWSTix4dnA3vuHtjPZbExYoCZA==
   dependencies:
     "@octokit/request" "^5.2.0"
     "@octokit/request-error" "^1.0.2"
   integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==
 
 "@types/node@>= 8":
-  version "12.12.17"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.17.tgz#191b71e7f4c325ee0fb23bc4a996477d92b8c39b"
-  integrity sha512-Is+l3mcHvs47sKy+afn2O1rV4ldZFU7W8101cNlOd+MRbjM4Onida8jSZnJdTe/0Pcf25g9BNIUsuugmE6puHA==
+  version "13.1.6"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.6.tgz#076028d0b0400be8105b89a0a55550c86684ffec"
+  integrity sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg==
 
 "@types/prop-types@*":
   version "15.7.3"
@@ -4877,9 +4877,9 @@ handlebars@^4.0.3:
     uglify-js "^3.1.4"
 
 handlebars@^4.4.0:
-  version "4.5.3"
-  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
-  integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
+  version "4.7.1"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.1.tgz#052bd2618964dcb8aebad0940bfeb2d8d1cfbfde"
+  integrity sha512-2dd6soo60cwKNJ90VewNLIzdZPR/E2YhszOTgHpN9V0YuwZk7x33/iZoIBnASwDFVHMY7iJ6NPL8d9f/DWYCTA==
   dependencies:
     neo-async "^2.6.0"
     optimist "^0.6.1"
@@ -7974,9 +7974,9 @@ p-waterfall@^1.0.0:
     p-reduce "^1.0.0"
 
 pacote@^9.5.0:
-  version "9.5.11"
-  resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.11.tgz#524152077cb392c47b1fbe198aa28f778bef7ee1"
-  integrity sha512-DMDPvFKCjCg6zMS4IfzZyvT57O/bX8XGG00eEoy4K/S4Wj+qiN8KbnmKpsTvfS6OL9r5TAicxMKWbj1yV2Yh4g==
+  version "9.5.12"
+  resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.12.tgz#1e11dd7a8d736bcc36b375a9804d41bb0377bf66"
+  integrity sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==
   dependencies:
     bluebird "^3.5.3"
     cacache "^12.0.2"
@@ -9140,9 +9140,9 @@ run-queue@^1.0.0, run-queue@^1.0.3:
     aproba "^1.1.1"
 
 rxjs@^6.4.0:
-  version "6.5.3"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
-  integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
+  version "6.5.4"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
+  integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
   dependencies:
     tslib "^1.9.0"