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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
--- /dev/null
+<?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>
--- /dev/null
+<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>
--- /dev/null
+<?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>
--- /dev/null
+{
+ "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"
+
+}
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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
--- /dev/null
+<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>
--- /dev/null
+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);
+
+ }]);
+
+});
--- /dev/null
+define(['app/lispui/lispui.module', 'app/lispui/lispui.services'], function(lispui) {
+
+ lispui.register.controller('RootLispuiCtrl', function($scope) {
+ });
+
+ lispui.register.controller('VisualizeLispuiCtrl', function($scope, $rootScope) {
+
+ })
+});
--- /dev/null
+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;
+});
--- /dev/null
+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(
+ ' ');
+ } else if (input[i] == '}' || input[i] ==
+ ']') {
+ output = output.concat('<br>');
+ indx--;
+ for (j = 0; j < indx; j++)
+ output = output.concat(
+ ' ');
+ output = output.concat(input[i]);
+ } else if (input[i] == ',') {
+ output = output.concat(',<br>');
+ for (j = 0; j < indx; j++)
+ output = output.concat(
+ ' ');
+ } 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;
+ }
+ ]);
+
+});
--- /dev/null
+<!--
+* 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>
--- /dev/null
+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);
+
+ }]);
+
+});
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<?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>