Add LISP user interface 33/25933/6
authorAlberto Montes <alm59321@gmail.com>
Tue, 25 Aug 2015 08:48:11 +0000 (10:48 +0200)
committerAlberto Montes <alm59321@gmail.com>
Wed, 26 Aug 2015 12:05:19 +0000 (14:05 +0200)
Add new menu option LISP UI, with two tabs, Keys and Mappings.

Change-Id: I30f855d686f159e8dd10534a46857f3414d9b470
Signed-off-by: Alberto Montes <al.montes.gomez@gmail.com>
25 files changed:
artifacts/pom.xml
commons/parent/pom.xml
features/pom.xml
features/src/main/features/features.xml
pom.xml
ui/bundle/pom.xml [new file with mode: 0644]
ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml [new file with mode: 0644]
ui/module/pom.xml [new file with mode: 0644]
ui/module/src/main/resources/lispui/assets/data/locale-en_US.json [new file with mode: 0644]
ui/module/src/main/resources/lispui/keys/key.create.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/keys/key.get.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/keys/key.table.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/keys/key.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/keys/lispui.key.controller.js [new file with mode: 0644]
ui/module/src/main/resources/lispui/lispui.controller.js [new file with mode: 0644]
ui/module/src/main/resources/lispui/lispui.module.js [new file with mode: 0644]
ui/module/src/main/resources/lispui/lispui.services.js [new file with mode: 0644]
ui/module/src/main/resources/lispui/lispui.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/mappings/lispui.mapping.controller.js [new file with mode: 0644]
ui/module/src/main/resources/lispui/mappings/mapping.create.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/mappings/mapping.get.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/mappings/mapping.table.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/mappings/mapping.tpl.html [new file with mode: 0644]
ui/module/src/main/resources/lispui/root.tpl.html [new file with mode: 0644]
ui/pom.xml [new file with mode: 0644]

index 10e974a2495b4c575d15874ee68cf9c15a57f41a..9c2682c66f884cc73db5a480f01b52af4b3668d0 100644 (file)
@@ -67,6 +67,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <artifactId>mappingservice.lisp-proto</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>lispflowmapping-ui-bundle</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>${project.groupId}</groupId>
         <artifactId>features-lispflowmapping</artifactId>
index 04882819e40f4d604270a1d3e1292f7b30cae982..8edecdee484904c9e47fa469333490b309733851 100644 (file)
@@ -30,6 +30,8 @@
     <build.suffix>1.0.0</build.suffix>
     <clustering.services.version>0.7.0-SNAPSHOT</clustering.services.version>
     <config.version>0.4.0-SNAPSHOT</config.version>
+    <dlux.loader.version>0.3.0-SNAPSHOT</dlux.loader.version>
+    <dlux.core.version>0.3.0-SNAPSHOT</dlux.core.version>
     <feature.test.version>0.8.0-SNAPSHOT</feature.test.version>
     <forwardingrulesmanager.version>0.5.0</forwardingrulesmanager.version>
     <ietf-inet-types.version>2010.09.24.8-SNAPSHOT</ietf-inet-types.version>
         <version>${yangtools.version}</version>
         <scope>test</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.lispflwomapping</groupId>
+        <artifactId>ui-lispflowmapping</artifactId>
+        <version>${lispflowmapping.version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
   <build>
index 3e424f0cb0860aeb148ffaddf4bae70cadf56489..29375eaf2b1aa8e3ddf1c7a3e15c565547b41633 100644 (file)
@@ -28,6 +28,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <properties>
     <commons.opendaylight.version>1.6.0-SNAPSHOT</commons.opendaylight.version>
     <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+    <dlux.core.version>0.3.0-SNAPSHOT</dlux.core.version>
     <features.file>features.xml</features.file>
     <mdsal.version>1.3.0-SNAPSHOT</mdsal.version>
     <neutron.version>0.6.0-SNAPSHOT</neutron.version>
@@ -83,6 +84,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>features-dlux</artifactId>
+      <version>${dlux.core.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>mappingservice.implementation</artifactId>
@@ -154,6 +163,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>mappingservice.lisp-proto</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>lispflowmapping-ui-bundle</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.neutron</groupId>
       <artifactId>features-neutron</artifactId>
index 1eaadb2870958edf62fa3502e087a86558fd1eba..982f76c985ad67821d6ecbc19e38fec872a52705 100644 (file)
@@ -19,6 +19,7 @@
     <repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
     <!-- <repository>mvn:org.opendaylight.controller/features-netconf-connector/${mdsal.version}/xml/features</repository> -->
     <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.core.version}/xml/features</repository>
 
     <feature name="odl-lispflowmapping-all" description="OpenDaylight :: LISP Flow Mapping :: All" version='${project.version}'>
         <feature version="${project.version}">odl-lispflowmapping-mappingservice</feature>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.neutron/${project.version}</bundle>
     </feature>
 
+    <feature name="odl-lispflowmapping-ui" description="OpenDaylight :: LISP Flow Mapping :: User Interface" version='${project.version}'>
+        <feature version="${yangtools.version}">odl-yangtools-all</feature>
+        <feature version="${dlux.core.version}">odl-dlux-all</feature>
+        <bundle>mvn:org.opendaylight.lispflowmapping/lispflowmapping-ui-bundle/${project.version}</bundle>
+    </feature>
+
 </features>
diff --git a/pom.xml b/pom.xml
index 11a20edf6160b010b8f743f3b77d2a7bef971b05..a36ecdffb5af90973b6a32a53157afd0c88680fe 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -24,6 +24,7 @@
     <module>commons/unittest_tools</module>
     <module>artifacts</module>
     <module>mappingservice</module>
+    <module>ui</module>
     <module>features</module>
     <module>distribution-karaf</module>
     <module>mappingservice/integrationtest</module>
diff --git a/ui/bundle/pom.xml b/ui/bundle/pom.xml
new file mode 100644 (file)
index 0000000..51c6308
--- /dev/null
@@ -0,0 +1,74 @@
+<?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>
+    <parent>
+        <groupId>org.opendaylight.lispflowmapping</groupId>
+        <artifactId>lispflowmapping-ui</artifactId>
+        <version>1.3.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>lispflowmapping-ui-bundle</artifactId>
+    <packaging>bundle</packaging>
+    <name>LISP Flow Mapping UI - Bundle</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.dlux</groupId>
+            <artifactId>loader</artifactId>
+            <version>${dlux.loader.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.lispflowmapping</groupId>
+            <artifactId>lispflowmapping-ui-module</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>target/generated-resources</directory>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <!-- <version>2.6</version> -->
+                <executions>
+                    <execution>
+                        <id>unpack-loader-resources</id>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <phase>generate-resources</phase>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.opendaylight.lispflowmapping</groupId>
+                                    <artifactId>lispflowmapping-ui-module</artifactId>
+                                    <version>${lispflowmapping.version}</version>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/generated-resources</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                            <excludes>META-INF\/**</excludes>
+                            <ignorePermissions>false</ignorePermissions>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+
+
+</project>
diff --git a/ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644 (file)
index 0000000..993f070
--- /dev/null
@@ -0,0 +1,14 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+    <reference id="httpService" availability="mandatory" activation="eager" interface="org.osgi.service.http.HttpService"/>
+    <reference id="loader" availability="mandatory" activation="eager" interface="org.opendaylight.dlux.loader.DluxModuleLoader"/>
+
+    <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.opendaylight.dlux.loader.DluxModule">
+        <property name="httpService" ref="httpService"/>
+        <property name="loader" ref="loader"/>
+        <property name="moduleName" value="lispui"/>
+        <property name="url" value="/src/app/lispui"/>
+        <property name="directory" value="/lispui"/>
+        <property name="requireJs" value="app/lispui/lispui.module"/>
+        <property name="angularJs" value="app.lispui"/>
+    </bean>
+</blueprint>
diff --git a/ui/module/pom.xml b/ui/module/pom.xml
new file mode 100644 (file)
index 0000000..60b7de4
--- /dev/null
@@ -0,0 +1,14 @@
+<?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>
+    <parent>
+        <groupId>org.opendaylight.lispflowmapping</groupId>
+        <artifactId>lispflowmapping-ui</artifactId>
+        <version>1.3.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>lispflowmapping-ui-module</artifactId>
+    <packaging>jar</packaging>
+    <name>LISP Flow Mapping UI - Module</name>
+</project>
diff --git a/ui/module/src/main/resources/lispui/assets/data/locale-en_US.json b/ui/module/src/main/resources/lispui/assets/data/locale-en_US.json
new file mode 100644 (file)
index 0000000..17baf3a
--- /dev/null
@@ -0,0 +1,67 @@
+{
+    "LISP_KEYS": "Keys",
+    "LISP_ADD_KEY": "Add Key",
+    "LISP_GET_KEY": "Get Key",
+    "LISP_EDIT_KEY": "Edit Key",
+
+    "LISP_MAPPINGS": "Mappings",
+    "LISP_ADD_MAPPING": "Add Mapping",
+    "LISP_GET_MAPPING": "Get Mapping",
+    "LISP_EDIT_MAPPING": "Edit Mapping",
+
+    "LISP_TOPOLOGY": "View Topology",
+
+    "LOADING_NODE": "Loading...",
+    "LOADING_ERROR": "Error at loading",
+    "LOADING_SUCCESS": "Load Success",
+    "ADD_KEY_ERROR": "Error Adding Key",
+    "ADD_KEY_SUCCESS": "Key Added",
+    "GET_KEY_ERROR": "Error Getting Key",
+    "GET_KEY_SUCCESS": "Get Key Complete",
+    "ADD_MAPPING_ERROR": "Error Adding Mapping",
+    "ADD_MAPPING_SUCCESS": "Mapping Added",
+    "GET_MAPPING_ERROR": "Error Getting Mapping",
+    "GET_MAPPING_SUCCESS": "Get Mapping Complete",
+
+    "REFRESH_TABLE": "Refresh Table",
+
+    "IID": "IID",
+    "EID": "EID",
+    "KEY_TYPE": "Key Type",
+    "AUTH_KEY": "Authkey",
+    "ACTIONS": "Actions",
+    "FLAGS": "Flags",
+    "TTL": "P/W/MP/MW",
+    "NO_KEY": "No Keys on Database",
+    "NUM_LOCATORS": "# Locators",
+    "LOCATOR_RECORD": "Locator Record",
+    "NO_MAPPINGS": "No Mappings on Database",
+    "EDIT": "Edit",
+    "VIEW": "View",
+    "DELETE": "Delete",
+    "ASK_DELETE_KEY": "Are you sure you want to delete this key?",
+    "ASK_DELETE_MAPPING": "Are you sure you want to delete this mapping?",
+    "YES": "Yes",
+    "NO": "No",
+
+    "BACK": "Back",
+    "HIDE": "hide",
+    "SHOW": "show",
+    "LIST_SHOW_ALL": "show all",
+    "HIDE_SHOW_ALL": "hide all",
+    "YANGUI_LIST_LABEL": "list",
+    "LEAF_LIST_ADD_ELEM": "add leaf list element",
+    "LIST_ADD_ELEM": "add list item",
+    "SHOW_HIDE_LIST": "show / hide list",
+    "LIST_SHOW_ALL": "show all list items",
+    "LIST_DELETE_ITEM": "delete list item",
+    "LIST_INDEX_DUPLICATE": "duplicated index",
+    "LIST_PREV_ITEM": "show previous item",
+    "LIST_NEXT_ITEM": "show next item",
+    "SHOW_HIDE_CON": "show / hide container",
+    "SHOW_HIDE_ELEM": "show / hide element",
+    "LIST_ADD_ITEM": "add item",
+    "LIST_DELETE_ITEM": "delete item",
+    "NOT_VALID_VALUE": "value is not valid"
+
+}
diff --git a/ui/module/src/main/resources/lispui/keys/key.create.tpl.html b/ui/module/src/main/resources/lispui/keys/key.create.tpl.html
new file mode 100644 (file)
index 0000000..e935360
--- /dev/null
@@ -0,0 +1,13 @@
+<div>
+  <h1>{{ 'LISP_ADD_KEY' | translate }}</h1>
+  <a class="btn btn-info add-row" href="#/lispui/keys">{{ 'BACK' | translate }}</a>
+  <div class="form-inline">
+    <div ng-if="node" ng-include src="'src/app/yangui/views/' + '/' + apiType + node.type + '.tpl.html'"></div>
+  </div>
+  <button ng-hide="node === null || selectedOperation === null" class="btn btn-default btn-slim" style="margin-right: 5px" ng-click="executeOperation(selectedOperation)">{{ 'LISP_ADD_KEY' | translate }}</button>
+  <alert ng-show="status.show" type="{{status.type}}" ng-show="status.msg" close="dismissStatus()">
+    <i ng-show="status.isWorking" class="icon-refresh icon-spin"></i>
+    <b> {{ status.msg | translate }}</b>
+    <b> {{ status.rawMsg ? (' - ' + status.rawMsg) : '' }}</b>
+  </alert>
+</div>
diff --git a/ui/module/src/main/resources/lispui/keys/key.get.tpl.html b/ui/module/src/main/resources/lispui/keys/key.get.tpl.html
new file mode 100644 (file)
index 0000000..1ed075e
--- /dev/null
@@ -0,0 +1,13 @@
+<div>
+  <h1>{{ 'LISP_GET_KEY' | translate }}</h1>
+  <a class="btn btn-info add-row" href="#/lispui/keys">{{ 'BACK' | translate }}</a>
+  <div class="form-inline">
+    <div ng-if="node" ng-include src="'src/app/yangui/views/' + '/' + apiType + node.type + '.tpl.html'"></div>
+  </div>
+  <button ng-hide="node === null || selectedOperation === null" class="btn btn-default btn-slim" style="margin-right: 5px" ng-click="executeOperation(selectedOperation)">{{ 'LISP_GET_KEY' | translate }}</button>
+  <alert ng-show="status.show" type="{{status.type}}" ng-show="status.msg" close="dismissStatus()">
+    <i ng-show="status.isWorking" class="icon-refresh icon-spin"></i>
+    <b> {{ status.msg | translate }}</b>
+    <b> {{ status.rawMsg ? (' - ' + status.rawMsg) : '' }}</b>
+  </alert>
+</div>
diff --git a/ui/module/src/main/resources/lispui/keys/key.table.tpl.html b/ui/module/src/main/resources/lispui/keys/key.table.tpl.html
new file mode 100644 (file)
index 0000000..87e8894
--- /dev/null
@@ -0,0 +1,48 @@
+<div>\r
+    <br>\r
+    <button class="btn btn-info add-row" ng-click="loadTable()">{{ 'REFRESH_TABLE' | translate }}</button>\r
+</div>\r
+<table class="footable table">\r
+    <thead>\r
+        <tr>\r
+            <th>{{ 'IID' | translate }}</th>\r
+            <th>{{ 'EID' | translate }}</th>\r
+            <th>{{ 'KEY_TYPE' | translate }}</th>\r
+            <th>{{ 'AUTH_KEY' | translate }}</th>\r
+            <th>{{ 'ACTIONS' | translate }}</th>\r
+        </tr>\r
+    </thead>\r
+    <tbody>\r
+        <tr ng-hide="data.length > 0">\r
+            <td colspan="5" class="centerAlign">{{ 'NO_KEY' | translate }}</td>\r
+        </tr>\r
+        <tr ng-repeat-start="key in data" node-table>\r
+            <td>{{ key.iid }}</td>\r
+            <td>{{ key.eid }}</td>\r
+            <td>{{ key['key-type'] | number }}</td>\r
+            <td>{{ key.authkey }}</td>\r
+            <td><i class="icon-eye-open" ng-click="expandSingleRow(key, data, 'detailHide')"> {{ 'VIEW' | translate }}</i> |\r
+                <i class="icon-trash"><a ng-click="expandSingleRow(key, data, 'deleteHide')"> {{ 'DELETE' | translate }}</a></i>\r
+            </td>\r
+        </tr>\r
+        <tr ng-hide="key.detailHide" node-table>\r
+            <td colspan="5">\r
+                <p>{{ key.data }}</p>\r
+            </td>\r
+        </tr>\r
+        <tr ng-hide="key.deleteHide" ng-repeat-end node-table>\r
+            <td colspan="5">\r
+                <p>{{ 'ASK_DELETE_KEY' | translate }}</p>\r
+                <button class="btn btn-info add-row" ng-click="deleteKey(key)">{{ 'YES' | translate }}</button>\r
+                <button class="btn btn-info add-row" ng-click="expandSingleRow(key, data, 'deleteHide')">{{ 'NO' | translate }}</button>\r
+            </td>\r
+        </tr>\r
+    </tbody>\r
+    <tfoot class="hide-if-no-paging">\r
+        <tr>\r
+            <td colspan="5">\r
+                <div class="pagination pagination-centered"></div>\r
+            </td>\r
+        </tr>\r
+    </tfoot>\r
+</table>\r
diff --git a/ui/module/src/main/resources/lispui/keys/key.tpl.html b/ui/module/src/main/resources/lispui/keys/key.tpl.html
new file mode 100644 (file)
index 0000000..9a08414
--- /dev/null
@@ -0,0 +1,6 @@
+<div>
+  <h1>{{ 'LISP_KEYS' | translate }}</h1>
+  <a class="btn btn-info add-row" href="#/lispui/keys-create">{{ 'LISP_ADD_KEY' | translate }}</a>
+  <a class="btn btn-info add-row" href="#/lispui/keys-get">{{ 'LISP_GET_KEY' | translate }}</a>
+</div>
+<div ng-include src="'src/app/lispui/keys/key.table.tpl.html'"></div>
diff --git a/ui/module/src/main/resources/lispui/keys/lispui.key.controller.js b/ui/module/src/main/resources/lispui/keys/lispui.key.controller.js
new file mode 100644 (file)
index 0000000..2314d43
--- /dev/null
@@ -0,0 +1,49 @@
+define(['app/lispui/lispui.module', 'app/lispui/lispui.services'], function(lispui) {
+
+  lispui.register.controller('KeysLispuiCtrl', ['$scope', 'LispuiDashboardSvc', 'LispuiNodeFormSvc', 'LispuiUtils',
+    function($scope, LispuiDashboardSvc, LispuiNodeFormSvc, LispuiUtils) {
+      $scope.data=[];
+
+      var loadTable = function () {
+        $scope.data=[];
+        LispuiDashboardSvc.getKeys().then(function (keys) {
+          $scope.data = keys;
+        })
+      };
+
+      var deleteKey = function (key) {
+        var postKey = LispuiDashboardSvc.getDeleteKey(key);
+        LispuiDashboardSvc.postDeleteKey().post('', postKey).then(function (success) {
+          $scope.loadTable();
+        })
+      }
+
+      $scope.loadTable = loadTable;
+      $scope.expandSingleRow = LispuiDashboardSvc.expandSingleRow;
+      $scope.deleteKey = deleteKey;
+      loadTable();
+  }]);
+
+  lispui.register.controller('KeysCreateLispuiCtrl',['$scope', 'LispuiNodeFormSvc',
+    function($scope, LispuiNodeFormSvc) {
+      LispuiNodeFormSvc.initValues($scope);
+      LispuiNodeFormSvc.loadNode("add-key", $scope);
+
+      $scope.getNodeName = LispuiNodeFormSvc.getNodeName;
+      $scope.buildRoot = LispuiNodeFormSvc.buildRoot($scope);
+      $scope.executeOperation = LispuiNodeFormSvc.executeOperation($scope);
+
+  }]);
+
+  lispui.register.controller('KeysGetLispuiCtrl',['$scope', 'LispuiNodeFormSvc',
+    function($scope, LispuiNodeFormSvc) {
+      LispuiNodeFormSvc.initValues($scope);
+      LispuiNodeFormSvc.loadNode("get-key", $scope);
+
+      $scope.getNodeName = LispuiNodeFormSvc.getNodeName;
+      $scope.buildRoot = LispuiNodeFormSvc.buildRoot($scope);
+      $scope.executeOperation = LispuiNodeFormSvc.executeOperation($scope);
+
+  }]);
+
+});
diff --git a/ui/module/src/main/resources/lispui/lispui.controller.js b/ui/module/src/main/resources/lispui/lispui.controller.js
new file mode 100644 (file)
index 0000000..50d39d1
--- /dev/null
@@ -0,0 +1,9 @@
+define(['app/lispui/lispui.module', 'app/lispui/lispui.services'], function(lispui) {
+
+  lispui.register.controller('RootLispuiCtrl', function($scope) {
+  });
+
+  lispui.register.controller('VisualizeLispuiCtrl', function($scope, $rootScope) {
+
+  })
+});
diff --git a/ui/module/src/main/resources/lispui/lispui.module.js b/ui/module/src/main/resources/lispui/lispui.module.js
new file mode 100644 (file)
index 0000000..035d5cc
--- /dev/null
@@ -0,0 +1,122 @@
+define(['angularAMD',
+    'app/routingConfig',
+    'angular-ui-router',
+    'app/core/core.services',
+    'common/yangutils/yangutils.services'
+], function() {
+
+    var lispui = angular.module('app.lispui', ['ui.router.state',
+        'app.core', 'app.common.yangUtils', 'restangular'
+    ]);
+
+    lispui.config(function($stateProvider, $controllerProvider,
+        $compileProvider, $provide, $translateProvider,
+        NavHelperProvider) {
+
+        $translateProvider.useStaticFilesLoader({
+            prefix: '/src/app/lispui/assets/data/locale-',
+            suffix: '.json'
+        });
+
+        lispui.register = {
+            controller: $controllerProvider.register,
+            directive: $compileProvider.directive,
+            service: $provide.service,
+            factory: $provide.factory
+        };
+
+        var access = routingConfig.accessLevels;
+        $stateProvider.state('main.lispui', {
+            url: 'lispui',
+            abstract: true,
+            views: {
+                'content': {
+                    templateUrl: '/src/app/lispui/root.tpl.html',
+                    controller: 'RootLispuiCtrl'
+                }
+            }
+        });
+
+        $stateProvider.state('main.lispui.keys', {
+            url: '/keys',
+            views: {
+                'lispui': {
+                    templateUrl: '/src/app/lispui/keys/key.tpl.html',
+                    controller: 'KeysLispuiCtrl'
+                }
+            }
+        });
+
+        $stateProvider.state('main.lispui.keys-create', {
+            url: '/keys-create',
+            views: {
+                'lispui': {
+                    templateUrl: '/src/app/lispui/keys/key.create.tpl.html',
+                    controller: 'KeysCreateLispuiCtrl'
+                }
+            }
+        });
+
+        $stateProvider.state('main.lispui.keys-get', {
+            url: '/keys-get',
+            views: {
+                'lispui': {
+                    templateUrl: '/src/app/lispui/keys/key.get.tpl.html',
+                    controller: 'KeysGetLispuiCtrl'
+                }
+            }
+        });
+
+        $stateProvider.state('main.lispui.mappings', {
+            url: '/mappings',
+            views: {
+                'lispui': {
+                    templateUrl: '/src/app/lispui/mappings/mapping.tpl.html',
+                    controller: 'MappingsLispuiCtrl'
+                }
+            }
+        });
+
+        $stateProvider.state('main.lispui.mappings-create', {
+            url: '/mappings-create',
+            views: {
+                'lispui': {
+                    templateUrl: '/src/app/lispui/mappings/mapping.create.tpl.html',
+                    controller: 'MappingsCreateLispuiCtrl'
+                }
+            }
+        });
+
+        $stateProvider.state('main.lispui.mappings-get', {
+            url: '/mappings-get',
+            views: {
+                'lispui': {
+                    templateUrl: '/src/app/lispui/mappings/mapping.get.tpl.html',
+                    controller: 'MappingsGetLispuiCtrl'
+                }
+            }
+        });
+
+        NavHelperProvider.addToMenu('lispui', {
+            "link": "#/lispui/keys",
+            "title": "LISP UI",
+            "active": "main.lispui",
+            "icon": "icon-sitemap",
+            "page": {
+                "title": "LISP UI",
+                "description": "LISP UI"
+            }
+        });
+
+        NavHelperProvider.addControllerUrl(
+            'app/lispui/lispui.controller');
+        NavHelperProvider.addControllerUrl(
+            'app/lispui/keys/lispui.key.controller');
+        NavHelperProvider.addControllerUrl(
+            'app/lispui/mappings/lispui.mapping.controller'
+        );
+
+    });
+
+    return lispui;
+});
diff --git a/ui/module/src/main/resources/lispui/lispui.services.js b/ui/module/src/main/resources/lispui/lispui.services.js
new file mode 100644 (file)
index 0000000..a623ab4
--- /dev/null
@@ -0,0 +1,703 @@
+define(['app/lispui/lispui.module'], function(lispui) {
+
+    lispui.register.factory('LispuiNodeFormSvc', ['$filter',
+        '$location', 'apiBuilder', 'constants',
+        'eventDispatcher', 'LispuiUtils', 'nodeWrapper',
+        'reqBuilder', 'syncFact', 'YangUIApis', 'yangUtils',
+        'YangUtilsRestangular',
+        function($filter, $location, apiBuilder, constants,
+            eventDispatcher, LispuiUtils, nodeWrapper,
+            reqBuilder, syncFact, YangUIApis, yangUtils,
+            YangUtilsRestangular) {
+            var api = {};
+
+            api.initValues = function(scope) {
+                scope.currentPath = 'src/app/yangui/views/';
+                scope.apiType = '';
+                scope.node = null;
+                scope.selApi = null;
+                scope.selSubApi = null;
+                scope.filterRootNode = null;
+                scope.selectedOperation = null;
+                return scope;
+            };
+
+            ////////// Snippet originally from yangui.controller.js //////////
+            // It has been changed to get only the node desired passed as an input of the function [type]
+            api.loadNode = function(type, scope) {
+
+                loadingCallback(scope, '');
+                yangUtils.generateNodesToApis(function(apis,
+                    allNodes) {
+                    scope.apis = apis;
+                    scope.allNodes = allNodes;
+                    console.info('got data', scope.apis,
+                        allNodes);
+                    scope.treeApis = yangUtils.generateApiTreeData(
+                        apis);
+                    console.info('tree api', scope.treeApis);
+
+                    // Select the api 'mappingservice'
+                    var numApis = scope.apis.length;
+                    for (i = 0; i < numApis; i++)
+                        if (scope.apis[i].module ==
+                            "mappingservice")
+                            scope.selApi = scope.apis[
+                                i];
+                    console.info('selApi:', scope.selApi);
+
+                    if (!scope.selApi) {
+                        errorLoadingCallback(scope,
+                            'Error loading node'
+                        );
+                        return null;
+                    }
+
+                    // Select the subapi 'type' pass as an argument
+                    var numSubApis = scope.selApi.subApis
+                        .length;
+                    for (j = 0; j < numSubApis; j++)
+                        if (scope.selApi.subApis[j]
+                            .node.label == type)
+                            scope.selSubApi = scope
+                            .selApi.subApis[j];
+                    console.info('selSubApi:',
+                        scope.selSubApi);
+
+                    scope.apiType = scope.selSubApi
+                        .pathArray[0].name ===
+                        'operational' ?
+                        'operational/' : '';
+                    scope.node = scope.selSubApi.node;
+                    console.info('node:', scope.node);
+                    scope.filterRootNode = scope.selSubApi
+                        .node;
+                    scope.node.clear();
+                    if (scope.selSubApi && scope.selSubApi
+                        .operations) {
+                        scope.selectedOperation =
+                            scope.selSubApi.operations[
+                                0];
+                    }
+                    successloadingCallback(scope, '');
+
+                }, function(e) {
+                    errorLoadingCallback(scope,
+                        'Error loading node');
+                    console.error(e);
+                });
+
+            };
+            ////////// End snippet originally from yangui.controller.js //////////
+
+
+            ////////// Snippet originally from yangui.controller.js //////////
+            api.executeOperation = function(scope) {
+                    return function(operation, callback,
+                        reqPath) {
+                        var reqString = scope.selSubApi.buildApiRequestString(),
+                            requestData = {},
+                            preparedRequestData = {},
+                            headers = {
+                                "Content-Type": "application/yang.data+json"
+                            };
+
+                        reqString = reqPath ? reqPath.slice(
+                            scope.selApi.basePath.length,
+                            reqPath.length) : reqString;
+                        var requestPath = scope.selApi.basePath +
+                            reqString;
+                        scope.node.buildRequest(reqBuilder,
+                            requestData);
+                        angular.copy(requestData,
+                            preparedRequestData);
+                        preparedRequestData = yangUtils.prepareRequestData(
+                            preparedRequestData,
+                            operation, reqString, scope
+                            .selSubApi);
+                        //requestWorkingCallback();
+
+                        operation = operation === 'DELETE' ?
+                            'REMOVE' : operation;
+
+                        YangUtilsRestangular.one('restconf')
+                            .customOperation(operation.toLowerCase(),
+                                reqString, null, headers,
+                                preparedRequestData).then(
+                                function(data) {
+                                    if (operation ===
+                                        'REMOVE') {
+                                        scope.node.clear();
+                                    }
+
+                                    if (data) {
+                                        scope.node.clear();
+                                        var props = Object.getOwnPropertyNames(
+                                            data);
+
+                                        props.forEach(
+                                            function(p) {
+                                                scope.node
+                                                    .fill(
+                                                        p,
+                                                        data[
+                                                            p
+                                                        ]
+                                                    );
+                                            });
+                                        scope.node.expanded =
+                                            true;
+                                    }
+
+                                    successCallback(scope,
+                                        scope.selSubApi
+                                        .node.label, ''
+                                    );
+
+                                    if (operation === 'GET') {
+                                        requestData = {};
+                                    }
+                                    console.info('Success');
+
+                                    if (angular.isFunction(
+                                            callback)) {
+                                        callback(data);
+                                    }
+
+                                },
+                                function(resp) {
+                                    var errorMsg = '';
+                                    if (resp.data && resp.data
+                                        .errors && resp.data
+                                        .errors.error &&
+                                        resp.data.errors.error
+                                        .length) {
+                                        errorMsg = ': ' +
+                                            resp.data.errors
+                                            .error.map(
+                                                function(e) {
+                                                    return e[
+                                                        'error-message'
+                                                    ];
+                                                }).join(
+                                                ', ');
+                                    }
+
+                                    errorCallback(scope, scope.selSubApi.node.label, errorMsg);
+
+                                    if (operation === 'GET') {
+                                        requestData = {};
+                                    }
+
+                                    console.info(
+                                        'error sending request to',
+                                        scope.selSubApi
+                                        .buildApiRequestString(),
+                                        'reqString',
+                                        reqString,
+                                        'got', resp.status,
+                                        'data', resp.data
+                                    );
+                                }
+                            );
+                    };
+                }
+                ////////// End snippet originally from yangui.controller.js //////////
+
+            // Function required from the html view files imported from the yangui
+            api.getNodeName = function(localeLabel, label) {
+                return label;
+            };
+
+            ////////// Snippet originally from yangui.controller.js //////////
+            api.buildRoot = function(scope) {
+                return function() {
+                    scope.node.buildRequest(reqBuilder, {});
+                };
+            };
+            ////////// End snippet originally from yangui.controller.js //////////
+
+
+            var loadingCallback = function(scope, e) {
+                scope.status = {
+                    show: true,
+                    isWorking: true,
+                    type: 'success',
+                    msg: 'LOADING_NODE',
+                    rawMsg: e || ''
+                };
+            };
+
+            var errorLoadingCallback = function(scope, e) {
+                scope.status = {
+                    show: true,
+                    isWorking: false,
+                    type: 'danger',
+                    msg: 'LOADING_ERROR',
+                    rawMsg: e || ''
+                };
+            };
+
+            var successloadingCallback = function(scope, e) {
+                scope.status = {
+                    show: true,
+                    isWorking: false,
+                    type: 'success',
+                    msg: 'LOADING_SUCCESS',
+                    rawMsg: e || ''
+                };
+
+                setTimeout(function() {
+                    scope.status.show = false;
+                }, 2000);
+            };
+
+            var errorCallback = function(scope, type, e) {
+                var errortype = LispuiUtils.getLocale(type)
+                    .concat('_ERROR');
+                scope.status = {
+                    show: true,
+                    isWorking: false,
+                    type: 'danger',
+                    msg: errortype,
+                    rawMsg: e || ''
+                };
+            };
+
+            var successCallback = function(scope, type, e) {
+                var errortype = LispuiUtils.getLocale(type)
+                    .concat('_SUCCESS');
+                scope.status = {
+                    show: true,
+                    isWorking: false,
+                    type: 'success',
+                    msg: errortype,
+                    rawMsg: e || ''
+                };
+            };
+
+            return api;
+
+        }
+    ]);
+
+    lispui.register.factory('LispuiRestangular', function(Restangular,
+        ENV) {
+        return Restangular.withConfig(function(
+            RestangularConfig) {
+            RestangularConfig.setBaseUrl(ENV.getBaseURL(
+                "MD_SAL"));
+        });
+    });
+
+    lispui.register.factory('LispuiDashboardSvc', ['LispuiNodeFormSvc',
+        'LispuiRestangular', 'LispuiUtils',
+        function(LispuiNodeFormSvc, LispuiRestangular,
+            LispuiUtils) {
+            var api = {};
+
+            api.getAll = function() {
+                return LispuiRestangular.one('restconf').one(
+                    'config').one(
+                    'mappingservice:mapping-database');
+            };
+
+            api.postDeleteKey = function() {
+                return LispuiRestangular.one('restconf').one(
+                    'operations').one(
+                    'mappingservice:remove-key');
+            }
+
+            api.postDeleteMapping = function() {
+                return LispuiRestangular.one('restconf').one(
+                    'operations').one(
+                    'mappingservice:remove-mapping');
+            }
+
+            api.expandSingleRow = function(element, data, op) {
+                temp = element[op];
+                for (k of data) {
+                    k.detailHide = true;
+                    k.deleteHide = true;
+                }
+                element[op] = !temp;
+            };
+
+            api.getOriginalKeys = function() {
+                return api.getAll().get().then(function(
+                    data) {
+                    var database = [];
+                    for (iid of data['mapping-database']['instance-id']) {
+                        if (iid['authentication-key'] != null) {
+                            for (key of iid['authentication-key']) {
+                                console.log('iid', iid.iid)
+                                key.iid = iid.iid;
+                                database.push(key);
+                            }
+                        }
+                    }
+                    console.info('database,', database);
+                    return database;
+                });
+            };
+
+            api.getOriginalMappings = function() {
+                return api.getAll().get().then(function(
+                    data) {
+                    var database = [];
+                    console.info('data:', data);
+                    for (iid of data[
+                            'mapping-database'][
+                            'instance-id'
+                        ]) {
+                        if (iid.mapping != null) {
+                            for (mapping of iid.mapping) {
+                                mapping.iid = iid.iid;
+                                database.push(mapping);
+                            }
+                        }
+                    }
+                    return database;
+                });
+            };
+
+            api.getKeys = function() {
+                return api.getOriginalKeys().then(function(
+                    database) {
+                    var data = []
+                    console.info('database:',
+                        database);
+                    for (key of database) {
+                        key.data = JSON.stringify(
+                            key);
+                        key.detailHide = true;
+                        key.deleteHide = true;
+                        key.url = key.eid.replace(
+                            '/', '%2f');
+                        data.push(key);
+                    }
+                    console.info('keys:', data)
+                    return data;
+                });
+            };
+
+            api.getMappings = function() {
+                return api.getOriginalMappings().then(
+                    function(database) {
+                        var data = [];
+                        for (mapping of database) {
+                            mapping.data = JSON.stringify(
+                                mapping);
+                            mapping.detailHide = true;
+                            mapping.deleteHide = true;
+                            mapping.url = mapping.eid.replace('/', '%2f');
+                            var numLocators = 0;
+                            var locatorString = '';
+                            var mainLocatorRecord =
+                                null;
+                            if (mapping.LocatorRecord) {
+                                numLocators = mapping.LocatorRecord
+                                    .length;
+                                // Take the most important Locator
+                                mainLocatorRecord =
+                                    mapping.LocatorRecord[
+                                        0];
+                                for (i = 1; i <
+                                    numLocators; i++) {
+                                    if (mapping.LocatorRecord[
+                                            i].priority <
+                                        mainLocatorRecord
+                                        .priority ||
+                                        (mapping.LocatorRecord[
+                                                i].priority ==
+                                            mainLocatorRecord
+                                            .priority &&
+                                            mapping.LocatorRecord[
+                                                i].weight >
+                                            mainLocatorRecord
+                                            .weight))
+                                        mainLocatorRecord =
+                                        mapping.LocatorRecord[
+                                            i];
+                                }
+                                locatorString +=
+                                    LispuiUtils.renderLispAddress(
+                                        mainLocatorRecord
+                                        .LispAddressContainer
+                                    );
+                                if (numLocators > 1) {
+                                    numLocators--;
+                                    locatorString +=
+                                        ' (+' +
+                                        numLocators +
+                                        ')';
+                                }
+
+                                // FLAGS
+                                var flags = '';
+                                var previous = false;
+                                if (mainLocatorRecord.localLocator) {
+                                    flags += 'Local';
+                                    previous = true;
+                                }
+                                if (mainLocatorRecord.rlocProbed) {
+                                    flags += previous ?
+                                        ' | Probed' :
+                                        'Probed';
+                                    previous = true;
+                                }
+                                if (mainLocatorRecord.routed) {
+                                    flags += previous ?
+                                        ' | Up' : 'Up';
+                                    previous = true;
+                                }
+
+                                // TTL
+                                var ttl = '';
+                                ttl +=
+                                    mainLocatorRecord.priority
+                                    .toString() + '/' +
+                                    mainLocatorRecord.weight
+                                    .toString();
+                                ttl += '/' +
+                                    mainLocatorRecord.multicastPriority
+                                    .toString() + '/' +
+                                    mainLocatorRecord.multicastWeight
+                                    .toString();
+                                mapping.ttl = ttl;
+                            } else {
+                                locatorString +=
+                                    mapping.action;
+                            }
+                            mapping.locatorString =
+                                locatorString;
+                            mapping.flags = flags;
+
+                            data.push(mapping);
+                        }
+                        return data;
+                    });
+            }
+
+            api.getDeleteKey = function(key) {
+                var postKey = {
+                    "input": {}
+                };
+                if (key.iid == '0' || Object.keys(key.LispAddressContainer)[0] == 'LcafSegmentAddr') {
+                    postKey.input.LispAddressContainer = key.LispAddressContainer;
+                } else {
+                    // In case the IID is not 0 and the LispAddressContainer is not coded as LCAF, code it as LcafSegmentAddr
+                    postKey.input.LispAddressContainer = {
+                        "LcafSegmentAddr": {
+                            "afi": 16387,
+                            "lcafType": 2,
+                            "instanceId": parseInt(key.iid),
+                            "iidMaskLength": 32,
+                            "Address": key.LispAddressContainer
+                        }
+                    }
+                }
+                postKey.input['mask-length'] = key['mask-length'];
+                console.log('postKey', postKey);
+                return postKey;
+            }
+
+            api.getDeleteMapping = function(mapping) {
+                var postMapping = {
+                    "input": {}
+                };
+                if (mapping.iid == '0' || Object.keys(mapping.LispAddressContainer)[0] == 'LcafSegmentAddr') {
+                    postMapping.input.LispAddressContainer = mapping.LispAddressContainer;
+                } else {
+                    // In case the IID is not 0 and the LispAddressContainer is not coded as LCAF, code it as LcafSegmentAddr
+                    postMapping.input.LispAddressContainer = {
+                        "LcafSegmentAddr": {
+                            "afi": 16387,
+                            "lcafType": 2,
+                            "instanceId": parseInt(mapping.iid),
+                            "iidMaskLength": 32,
+                            "Address": mapping.LispAddressContainer
+                        }
+                    }
+                }
+                postMapping.input['mask-length'] = mapping['maskLength'];
+                console.log('postMapping', postMapping);
+                return postMapping;
+            }
+
+            return api;
+        }
+    ]);
+
+    lispui.register.factory('LispuiUtils', ['$filter',
+        function($filter) {
+            var api = {};
+
+            api.getLocale = function(label) {
+                locale = '';
+
+                locale = label == 'add-key' ? 'ADD_KEY' :
+                    locale;
+                locale = label == 'get-key' ? 'GET_KEY' :
+                    locale;
+                locale = label == 'update-key' ? 'EDIT_KEY' :
+                    locale;
+                locale = label == 'add-mapping' ?
+                    'ADD_MAPPING' : locale;
+                locale = label == 'get-mapping' ?
+                    'GET_MAPPING' : locale;
+                locale = label == 'update-mapping' ?
+                    'EDIT_MAPPING' : locale;
+
+                return locale;
+
+            };
+
+            api.getPrettyString = function(input) {
+                output = '<p>';
+                length = input.length;
+                indx = 0;
+                console.info('input:', input);
+                console.info('length:', length);
+
+                for (i = 0; i < length; i++) {
+                    if (input[i] == '{' || input[i] == '[') {
+                        output = output.concat(input[i]).concat(
+                            '<br>');
+                        indx++;
+                        for (j = 0; j < indx; j++)
+                            output = output.concat(
+                                '&nbsp;&nbsp;&nbsp;');
+                    } else if (input[i] == '}' || input[i] ==
+                        ']') {
+                        output = output.concat('<br>');
+                        indx--;
+                        for (j = 0; j < indx; j++)
+                            output = output.concat(
+                                '&nbsp;&nbsp;&nbsp;');
+                        output = output.concat(input[i]);
+                    } else if (input[i] == ',') {
+                        output = output.concat(',<br>');
+                        for (j = 0; j < indx; j++)
+                            output = output.concat(
+                                '&nbsp;&nbsp;&nbsp;');
+                    } else
+                        output = output.concat(input[i]);
+
+                }
+                output = output.concat('</p>');
+                console.info('output:', output);
+                return output;
+            }
+
+            api.getAddress = function(address) {
+                var afi = address.afi;
+                var string = '';
+                if (afi == 1) {
+                    string += address.Ipv4Address;
+                } else if (afi == 2) {
+                    string += address.Ipv6Address;
+                } else if (afi == 16389) {
+                    string += address.MacAddress;
+                } else if (afi == 17) {
+                    string += address.distinguishedName;
+                } else if (afi == 18) {
+                    string += address.AS;
+                }
+                return string;
+            }
+
+            api.renderLispAddress = function(lispAddress) {
+                var string = '';
+
+                if (!lispAddress)
+                    return string;
+
+                var addressType = Object.keys(lispAddress)[
+                    0];
+                var afi = lispAddress[addressType].afi;
+
+                if (afi == 0) {
+                    string += 'no:No Address Present';
+                } else if (afi == 1) {
+                    string += 'ipv4:';
+                    string += api.getAddress(lispAddress[
+                        addressType]);
+                } else if (afi == 2) {
+                    string += 'ipv6:';
+                    string += api.getAddress(lispAddress[
+                        addressType]);
+                } else if (afi == 16389) {
+                    string += 'mac:';
+                    string += api.getAddress(lispAddress[
+                        addressType]);
+                } else if (afi == 17) {
+                    string += 'dn:';
+                    string += api.getAddress(lispAddress[
+                        addressType]);
+                } else if (afi == 18) {
+                    string += 'as:AS';
+                    string += api.getAddress(lispAddress[
+                        addressType]);
+                } else if (afi == 16387) {
+                    var lcaf = lispAddress[addressType].lcafType;
+                    if (lcaf == 1) {
+                        string += 'list:';
+                        //string += '{' + api.getAddress(lispAddress[addressType].);
+                        // TODO
+                    } else if (lcaf == 2) {
+                        string += '[' + lispAddress[
+                                addressType].instanceId +
+                            '] ';
+                        string += api.getAddress(
+                            lispAddress[addressType].Address
+                        );
+                        string += '/' + lispAddress[
+                            addressType].iidMaskLength;
+                    } else if (lcaf == 4) {
+                        string += 'appdata:'
+                            // TODO
+                    } else if (lcaf == 10) {
+                        string += 'elp:';
+                        string += '{';
+                        var hops = lispAddress[addressType]
+                            .Hops;
+                        first = true;
+                        for (hop of hops) {
+                            string += (first) ? '' : '→';
+                            first = false;
+                            string += api.getAddress(hop.hop);
+                        }
+                        string += '}';
+                    } else if (lcaf == 12) {
+                        string += 'srcdst:';
+                        string += api.getAddress(
+                            lispAddress[addressType].srcAddress
+                        );
+                        string += '/' + lispAddress[
+                                addressType].srcMaskLength +
+                            '|';
+                        string += api.getAddress(
+                            lispAddress[addressType].dstAddress
+                        );
+                        string += '/' + lispAddress[
+                            addressType].dstMaskLength;
+                    } else if (lcaf == 15) {
+                        string += api.getAddress(
+                            lispAddress[addressType].key
+                        );
+                        string += '=>';
+                        string += api.getAddress(
+                            lispAddress[addressType].value
+                        );
+                    }
+                }
+
+                return string;
+            }
+
+            return api;
+        }
+    ]);
+
+});
diff --git a/ui/module/src/main/resources/lispui/lispui.tpl.html b/ui/module/src/main/resources/lispui/lispui.tpl.html
new file mode 100644 (file)
index 0000000..d52925a
--- /dev/null
@@ -0,0 +1,16 @@
+<!--
+* Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,
+* and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+
+<div class="container">
+  <div class="row">
+    <div class="col-md-2">
+      <h3>Hello World!</h3>
+    </div>
+    <div class="col-md-10 col-lg-offset-1"></div>
+  </div>
+</div>
diff --git a/ui/module/src/main/resources/lispui/mappings/lispui.mapping.controller.js b/ui/module/src/main/resources/lispui/mappings/lispui.mapping.controller.js
new file mode 100644 (file)
index 0000000..d5a949c
--- /dev/null
@@ -0,0 +1,49 @@
+define(['app/lispui/lispui.module', 'app/lispui/lispui.services'], function(lispui) {
+
+    lispui.register.controller('MappingsLispuiCtrl', ['$scope', 'LispuiDashboardSvc', 'LispuiUtils',
+        function($scope, LispuiDashboardSvc, LispuiUtils) {
+            $scope.data = [];
+
+            var loadTable = function () {
+                $scope.data = [];
+                LispuiDashboardSvc.getMappings().then(function (mappings) {
+                    $scope.data = mappings;
+                });
+            };
+
+            var deleteMapping = function (key) {
+                var postMapping = LispuiDashboardSvc.getDeleteMapping(key)
+                LispuiDashboardSvc.postDeleteMapping().post('', postMapping).then(function (success) {
+                    $scope.loadTable();
+                })
+            }
+
+            $scope.loadTable = loadTable;
+            $scope.expandSingleRow = LispuiDashboardSvc.expandSingleRow;
+            $scope.deleteMapping = deleteMapping
+            loadTable();
+    }]);
+
+    lispui.register.controller('MappingsCreateLispuiCtrl',['$scope', 'LispuiNodeFormSvc',
+        function($scope, LispuiNodeFormSvc) {
+            LispuiNodeFormSvc.initValues($scope);
+            LispuiNodeFormSvc.loadNode("add-mapping", $scope);
+
+            $scope.getNodeName = LispuiNodeFormSvc.getNodeName;
+            $scope.buildRoot = LispuiNodeFormSvc.buildRoot($scope);
+            $scope.executeOperation = LispuiNodeFormSvc.executeOperation($scope);
+
+    }]);
+
+    lispui.register.controller('MappingsGetLispuiCtrl',['$scope', 'LispuiNodeFormSvc',
+        function($scope, LispuiNodeFormSvc) {
+            LispuiNodeFormSvc.initValues($scope);
+            LispuiNodeFormSvc.loadNode("get-mapping", $scope);
+
+            $scope.getNodeName = LispuiNodeFormSvc.getNodeName;
+            $scope.buildRoot = LispuiNodeFormSvc.buildRoot($scope);
+            $scope.executeOperation = LispuiNodeFormSvc.executeOperation($scope);
+
+    }]);
+    
+});
diff --git a/ui/module/src/main/resources/lispui/mappings/mapping.create.tpl.html b/ui/module/src/main/resources/lispui/mappings/mapping.create.tpl.html
new file mode 100644 (file)
index 0000000..b624eca
--- /dev/null
@@ -0,0 +1,13 @@
+<div>
+  <h1>{{ 'LISP_ADD_MAPPING' | translate }}</h1>
+  <a class="btn btn-info add-row" href="#/lispui/mappings">{{ 'BACK' | translate }}</a>
+  <div class="form-inline">
+    <div ng-if="node" ng-include src="'src/app/yangui/views/' + '/' + apiType + node.type + '.tpl.html'"></div>
+  </div>
+  <button ng-hide="node === null || selectedOperation === null" class="btn btn-default btn-slim" style="margin-right: 5px" ng-click="executeOperation(selectedOperation)">{{ 'LISP_ADD_MAPPING' | translate }}</button>
+  <alert ng-show="status.show" type="{{status.type}}" ng-show="status.msg" close="dismissStatus()">
+    <i ng-show="status.isWorking" class="icon-refresh icon-spin"></i>
+    <b> {{ status.msg | translate }}</b>
+    <b> {{ status.rawMsg ? (' - ' + status.rawMsg) : '' }}</b>
+  </alert>
+</div>
diff --git a/ui/module/src/main/resources/lispui/mappings/mapping.get.tpl.html b/ui/module/src/main/resources/lispui/mappings/mapping.get.tpl.html
new file mode 100644 (file)
index 0000000..6f42e66
--- /dev/null
@@ -0,0 +1,13 @@
+<div>
+  <h1>{{ 'LISP_GET_MAPPING' | translate }}</h1>
+  <a class="btn btn-info add-row" href="#/lispui/mappings">{{ 'BACK' | translate }}</a>
+  <div class="form-inline">
+    <div ng-if="node" ng-include src="'src/app/yangui/views/' + '/' + apiType + node.type + '.tpl.html'"></div>
+  </div>
+  <button ng-hide="node === null || selectedOperation === null" class="btn btn-default btn-slim" style="margin-right: 5px" ng-click="executeOperation(selectedOperation)">{{ 'LISP_GET_MAPPING' | translate }}</button>
+  <alert ng-show="status.show" type="{{status.type}}" ng-show="status.msg" close="dismissStatus()">
+    <i ng-show="status.isWorking" class="icon-refresh icon-spin"></i>
+    <b> {{ status.msg | translate }}</b>
+    <b> {{ status.rawMsg ? (' - ' + status.rawMsg) : '' }}</b>
+  </alert>
+</div>
diff --git a/ui/module/src/main/resources/lispui/mappings/mapping.table.tpl.html b/ui/module/src/main/resources/lispui/mappings/mapping.table.tpl.html
new file mode 100644 (file)
index 0000000..7277b31
--- /dev/null
@@ -0,0 +1,50 @@
+<div>\r
+    <br>\r
+    <button class="btn btn-info add-row" ng-click="loadTable()">{{ 'REFRESH_TABLE' | translate }}</button>\r
+</div>\r
+<table class="footable table">\r
+    <thead>\r
+        <tr>\r
+            <th>{{ 'IID' | translate }}</th>\r
+            <th>{{ 'EID' | translate }}</th>\r
+            <th>{{ 'LOCATOR' | translate }}</th>\r
+            <th>{{ 'FLAGS' | translate }}</th>\r
+            <th>{{ 'TTL' | translate }}</th>\r
+            <th>{{ 'ACTIONS' | translate }}</th>\r
+        </tr>\r
+    </thead>\r
+    <tbody>\r
+        <tr ng-hide="data.length > 0">\r
+            <td colspan="6" class="centerAlign">{{ 'NO_MAPPINGS' | translate }}</td>\r
+        </tr>\r
+        <tr ng-repeat-start="mapping in data" node-table>\r
+            <td>{{ mapping.iid }}</td>\r
+            <td>{{ mapping.eid }}</td>\r
+            <td>{{ mapping.locatorString }}</td>\r
+            <td>{{ mapping.flags }}</td>\r
+            <td>{{ mapping.ttl }}</td>\r
+            <td><i class="icon-eye-open" ng-click="expandSingleRow(mapping, data, 'detailHide')"> {{ 'VIEW' | translate }}</i> |\r
+                <i class="icon-trash"><a ng-click="expandSingleRow(mapping, data, 'deleteHide')"> {{ 'DELETE' | translate }}</a></i>\r
+            </td>\r
+        </tr>\r
+        <tr ng-hide="mapping.detailHide" node-table>\r
+            <td colspan="6">\r
+                <p>{{ mapping.data }}</p>\r
+            </td>\r
+        </tr>\r
+        <tr ng-hide="mapping.deleteHide" ng-repeat-end node-table>\r
+            <td colspan="6">\r
+                <p>{{ 'ASK_DELETE_MAPPING' | translate }}</p>\r
+                <button class="btn btn-info add-row" ng-click="deleteMapping(mapping)">{{ 'YES' | translate }}</button>\r
+                <button class="btn btn-info add-row" ng-click="expandSingleRow(mapping, data, 'deleteHide')">{{ 'NO' | translate }}</button>\r
+            </td>\r
+        </tr>\r
+    </tbody>\r
+    <tfoot class="hide-if-no-paging">\r
+        <tr>\r
+            <td colspan="6">\r
+                <div class="pagination pagination-centered"></div>\r
+            </td>\r
+        </tr>\r
+    </tfoot>\r
+</table>\r
diff --git a/ui/module/src/main/resources/lispui/mappings/mapping.tpl.html b/ui/module/src/main/resources/lispui/mappings/mapping.tpl.html
new file mode 100644 (file)
index 0000000..288df5c
--- /dev/null
@@ -0,0 +1,6 @@
+<div>
+  <h1>{{ 'LISP_MAPPINGS' | translate }}</h1>
+  <a class="btn btn-info add-row" href="#/lispui/mappings-create">{{ 'LISP_ADD_MAPPING' | translate }}</a>
+  <a class="btn btn-info add-row" href="#/lispui/mappings-get">{{ 'LISP_GET_MAPPING' | translate }}</a>
+</div>
+<div ng-include src="'src/app/lispui/mappings/mapping.table.tpl.html'"></div>
diff --git a/ui/module/src/main/resources/lispui/root.tpl.html b/ui/module/src/main/resources/lispui/root.tpl.html
new file mode 100644 (file)
index 0000000..39d3a5b
--- /dev/null
@@ -0,0 +1,11 @@
+<div class="menu">
+  <ul class="nav nav-pills">
+    <li ng-class="{ active: isState('main.lispui.keys') || isState('main.lispui.keys-create') || isState('main.lispui.keys-get')}"><a href="#/lispui/keys">{{ 'LISP_KEYS' | translate }}</a></li>
+    <li ng-class="{ active: isState('main.lispui.mappings') || isState('main.lispui.mappings-create') || isState('main.lispui.mappings-get')}"><a href="#/lispui/mappings">{{ 'LISP_MAPPINGS' | translate }}</a></li>
+  </ul>
+
+  <!-- For child state use-->
+  <div ui-view="submenu"></div>
+</div>
+
+<div class="main" ui-view="lispui"></div>
diff --git a/ui/pom.xml b/ui/pom.xml
new file mode 100644 (file)
index 0000000..ebb04b2
--- /dev/null
@@ -0,0 +1,20 @@
+<?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>
+    <parent>
+        <groupId>org.opendaylight.lispflowmapping</groupId>
+        <artifactId>lispflowmapping-commons</artifactId>
+        <version>1.3.0-SNAPSHOT</version>
+        <relativePath>../commons/parent</relativePath>
+    </parent>
+
+    <artifactId>lispflowmapping-ui</artifactId>
+    <packaging>pom</packaging>
+    <name>LISP Flow Mapping UI</name>
+
+    <modules>
+        <module>module</module>
+        <module>bundle</module>
+    </modules>
+</project>