diff options
Diffstat (limited to 'sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module')
12 files changed, 1771 insertions, 0 deletions
diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/pom.xml b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/pom.xml new file mode 100644 index 00000000..c47134aa --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/pom.xml @@ -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> + <artifactId>mwtnConnect</artifactId> + <groupId>com.highstreet.technologies.odl.dlux</groupId> + <version>0.5.1-SNAPSHOT</version> + </parent> + <artifactId>mwtnConnect-module</artifactId> + <name>${prefix} ${project.artifactId}</name> + <packaging>jar</packaging> +</project>
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/images/mwtnConnect.png b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/images/mwtnConnect.png Binary files differnew file mode 100755 index 00000000..7417076f --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/images/mwtnConnect.png diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/images/sdncConnect.png b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/images/sdncConnect.png Binary files differnew file mode 100755 index 00000000..4542dc13 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/images/sdncConnect.png diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect-custom.css b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect-custom.css new file mode 100644 index 00000000..1fb5c597 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect-custom.css @@ -0,0 +1,85 @@ +/** + * Add your application related css here + * width: 1260px; + */ + +.modal-dialog { + width: 690px; + margin: 30px auto; +} + +.modal-dialog .modal-lg { + min-width: 690px; + width: 690px; +} + +.requiredNesGrid span { + color: #393939; +} +.mwtn-form-control { + font-family:'Courier New'; + /* display: block; */ + width: 600px; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #000000; + vertical-align: middle; + background-color: #eeeeee; + background-image: none; + border: 1px solid #d5d5d5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -webkit-transition: all border-color ease-in-out .15s, box-shadow ease-in-out .15s linear; + -moz-transition: all border-color ease-in-out .15s, box-shadow ease-in-out .15s linear; + -ms-transition: all border-color ease-in-out .15s, box-shadow ease-in-out .15s linear; + -o-transition: all border-color ease-in-out .15s, box-shadow ease-in-out .15s linear; + transition: all border-color ease-in-out .15s, box-shadow ease-in-out .15s linear; +} + + +.green { + color: darkgreen; +} +.green span { + color: darkgreen; +} + +h3.modal-title { + color: #393939; +} + +.modal-body span { + color: #393939; +} + +.modal-body h3 { + color: #393939; +} + +.modal-body .green span { + color: darkgreen; +} + +.requiredNesGrid { + height: 600px; + background-color: white; +} + +.unknownNesGrid { + height: 600px; + background-color: white; +} + +.unknownNesGrid .ui-grid-cell-contents span { + color: #393939; +} + +.yangCapabilitiesGrid { + height: 300px; + background-color: white; +} diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.controller.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.controller.js new file mode 100644 index 00000000..c72795c8 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.controller.js @@ -0,0 +1,1143 @@ +/* + * Copyright (c) 2016 highstreet technologies GmbH 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 + */ + +define(['app/mwtnConnect/mwtnConnect.module', + 'app/mwtnConnect/mwtnConnect.services', + 'app/mwtnCommons/mwtnCommons.module'], + function(mwtnConnectApp) { + + mwtnConnectApp.register.controller('mwtnConnectCtrl', ['$scope', '$rootScope', '$timeout', '$window', '$q', 'uiGridConstants', '$uibModal', '$mwtnConnect', '$mwtnLog', 'NetConfServer', + function($scope, $rootScope, $timeout, $window, $q, uiGridConstants, $uibModal, $mwtnConnect, $mwtnLog, NetConfServer) { + + var COMPONENT = 'mwtnConnectCtrl'; + $mwtnLog.info({component: COMPONENT, message: 'mwtnConnectCtrl started!'}); + + $rootScope.section_logo = 'src/app/mwtnConnect/images/sdncConnect.png'; // Add your topbar logo location here such as 'assets/images/logo_topology.gif' + + $scope.highlightFilteredHeader = $mwtnConnect.highlightFilteredHeader; + + $scope.oneAtATime = true; + $scope.status = {requiredNes: true}; + $scope.spinner = {}; + $scope.spinner.TEST = true; + + var requiredNesConnectionStatusCellTemplate = [ + '<div class="ui-grid-cell-contents" ng-class="{ \'green\': grid.getCellValue(row, col) === \'connected\'}">', + ' <i ng-class="{\'fa fa-link\': grid.getCellValue(row, col) === \'connected\', \'fa fa-chain-broken\': grid.getCellValue(row, col) !== \'connected\'}" aria-hidden="true"></i>', + ' <span>{{grid.getCellValue(row, col)}}</span>', + '</div>'].join(''); + + var nameCellTemplate = [ + '<div class="ui-grid-cell-contents">', + ' <a href="{{row.entity.webUri}}" target="_blank" title="Access NE web application" ng-show="row.entity.webUri">', + ' <i class="fa fa-external-link" aria-hidden="true"></i>', + ' <span>{{grid.getCellValue(row, col)}}</span>', + ' </a>', + ' <span ng-show="!row.entity.webUri">{{grid.getCellValue(row, col)}}</span>', + '</div>'].join(''); + + // '<button class="btn btn-primary" ng-click="grid.appScope.edit(row.entity)"><i class="fa fa-pencil"></i></button>', + // '<button class="btn btn-default" ng-click="grid.appScope.delete(row.entity)"><i class="fa fa-times mwtnError"></i></button>', + var requiredNesActionCellTemplate = [ + '<span> </span>', + '<div class="btn-group">', + ' <button class="btn btn-primary" ng-click="grid.appScope.connect(row.entity)" title="Mount"><i class="fa fa-link" aria-hidden="true"></i></button>', + ' <button class="btn btn-warning" ng-click="grid.appScope.disconnect(row.entity)" title="Unmount"><i class="fa fa-chain-broken" aria-hidden="true"></i></button>', + ' <button class="btn btn-success" ng-click="grid.appScope.showDetails(row.entity)" title="Information"><i class="fa fa-info-circle" aria-hidden="true"></i></button>', + '<div class="btn-group">', + '<span> </span>', + '</div>', + ' <a class="btn btn-primary" ng-href="#/pnfFault/{{row.entity.name}}" title="Fault Management" target="fm">F</a>', + ' <a class="btn btn-primary" ng-href="#/pnfBrowser/{{row.entity.name}}" title="Configuration Management" target="cm">C</a>', + ' <a class="btn btn-default" title="Accounting Management" target="am">A</a>', + ' <a class="btn btn-primary" ng-href="#/pnfPerformanceHistory/{{row.entity.name}}" title="Performance Management" target="pm">P</a>', + ' <a class="btn btn-default" title="Security Management" target="sm">S</a>', + '</div>', + '<span> </span>', + '<div class="btn-group">', + ' <a class="btn btn-primary" ng-href="#/pnfInventory/{{row.entity.name}}" title="Inventory Management" target="im">I</a>', + '</div>', + '<span> </span>'].join(''); + + + $scope.requiredNesGridOptions = JSON.parse(JSON.stringify($mwtnConnect.gridOptions)); + $scope.requiredNesGridOptions.rowHeight = 44; + $scope.requiredNesGridOptions.columnDefs = [ + { field: 'connectionStatus', type: 'string', displayName: 'Connection status', headerCellClass: $scope.highlightFilteredHeader, width : 160, cellTemplate: requiredNesConnectionStatusCellTemplate }, + // { field: 'id', type: 'number', displayName: 'Id', headerCellClass: $scope.highlightFilteredHeader, width : 50, cellClass: 'number', pinnedLeft : true , sort: { + // direction: uiGridConstants.ASC, + // ignoreSort: false, + // priority: 0 + // }}, + { field: 'name', type: 'string', displayName: 'Name', headerCellClass: $scope.highlightFilteredHeader, width : 230, cellTemplate: nameCellTemplate, pinnedLeft : true , sort: { + direction: uiGridConstants.ASC, + ignoreSort: false, + priority: 0 + }}, + { field: 'ipaddress', type: 'number', displayName: 'IP address', headerCellClass: $scope.highlightFilteredHeader, width : 140, cellClass: 'number' }, + { field: 'port', type: 'number', displayName: 'Port', headerCellClass: $scope.highlightFilteredHeader, width : 80, cellClass: 'number' }, + { field: 'client', type: 'number', displayName: 'Client', headerCellClass: $scope.highlightFilteredHeader, width : 140 }, + { field: 'username', type: 'string', displayName: 'User name', headerCellClass: $scope.highlightFilteredHeader, width : 100, visible: false }, + { field: 'password', type: 'string', displayName: 'Password', headerCellClass: $scope.highlightFilteredHeader, width : 100, visible: false }, + { field: 'radioSignalIds', type: 'string', displayName: 'Radio signal ids', headerCellClass: $scope.highlightFilteredHeader, width : 150, visible: false}, + { + name : 'actions', + enableSorting : false, + enableFiltering: false, + cellTemplate: requiredNesActionCellTemplate, + width : 400, + pinnedRight : true + } + ]; + + var unknownNesActionCellTemplate = [ + '<a class="vCenter" ng-class="{attention: grid.appScope.hover, hidden: onfAirInterfaceRevision}" >', + '<button class="btn btn-default" ng-show="row.entity[\'node-id\'] !== \'controller-config\'" ng-click="grid.appScope.unmount(row.entity)">Unmount</button>', + '<button class="btn btn-primary" ng-show="row.entity[\'node-id\'] !== \'controller-config\' && row.entity.onfCoreModelRevision" ng-click="grid.appScope.addToRequiredNetworkElements(row.entity)">', + '<i class="pull-left fa fa-spinner fa-pulse" ng-show="row.entity.spinner"></i>', + '<span class="white">{{ "MWTN_MAKE_KNOWN" | translate }}<span>', + '</button>', + '<button class="btn btn-default" ng-click="grid.appScope.showDetails(row.entity, false)"><i class="fa fa-info-circle" aria-hidden="true"></i></button>', + '</a>' ].join('<span> </span>'); + $scope.unknownNesGridOptions = JSON.parse(JSON.stringify($mwtnConnect.gridOptions)); + $scope.unknownNesGridOptions.rowHeight = 44; + $scope.unknownNesGridOptions.columnDefs = [ + { field: 'node-id', type: 'string', displayName: 'Name', headerCellClass: $scope.highlightFilteredHeader, width : 200, sort: { + direction: uiGridConstants.ASC, + priority: 0 + }}, + { field: 'netconf-node-topology:host', type: 'number', displayName: 'IP address', headerCellClass: $scope.highlightFilteredHeader, width : 150, cellClass: 'number' }, + { field: 'netconf-node-topology:port', type: 'number', displayName: 'NetConf port', headerCellClass: $scope.highlightFilteredHeader, width : 120, cellClass: 'number' }, + { field: 'onfCoreModelRevision', type: 'string', displayName: 'CoreModel revision', headerCellClass: $scope.highlightFilteredHeader, width : 160, cellClass: 'number' }, + { field: 'onfAirInterfaceRevision', type: 'string', displayName: 'AirInterface revision', headerCellClass: $scope.highlightFilteredHeader, width : 160, cellClass: 'number' }, + { field: 'netconf-node-topology:connection-status', type: 'string', displayName: 'Connection status', headerCellClass: $scope.highlightFilteredHeader, width : 160 }, + { + name : 'actions', + enableSorting : false, + enableFiltering: false, + cellTemplate: unknownNesActionCellTemplate, + width : 330, + pinnedRight : true + } + ]; + + /** + * Request all defined (required) network elements from database and + * update the corresponding table in the ui. + */ + var getRequiredNetworkElements = function() { + $mwtnConnect.getRequiredNetworkElements().then(function(networkElements) { + $scope.requiredNesGridOptions.data = networkElements; + getActualNetworkElements(); + }, function(error){ + $scope.requiredNesGridOptions.data = []; + }); + }; + getRequiredNetworkElements(); + + /** + * A function, which returns a boolean, which indicates, whether a network + * element is required or not. + * @param {string} neId - A mount point identifier. + * @return {boolean} True, if network element is required in the network, otherwise false. + */ + var isRequired = function(neId) { + if ($scope.requiredNesGridOptions.data) { + var result = false; + $scope.requiredNesGridOptions.data.map(function(rne) { + if (rne.name === neId) result = true; + }); + return result; + } else { + return false; + } + }; + + var setConnectionStatus = function(neId, connectionStatus) { + if ($scope.requiredNesGridOptions.data) { + $scope.requiredNesGridOptions.data.map(function(rne) { + if (rne.name === neId) rne.connectionStatus = connectionStatus; + }); + } + }; + + var setValues = function(ane) { + if ($scope.requiredNesGridOptions.data) { + + var getExtension = function(extensions, name) { + if (extensions === undefined) { + return undefined; + } + var result = extensions.filter(function(ex){ + return ex['value-name'] === name; + }).map(function(ex){ + return ex.value; + }); + if (result.length > 0) { + result = result[0]; + } else { + result = undefined; + } + return result; + }; + + $scope.requiredNesGridOptions.data.map(function(rne) { + // TODO use filter! and avoid push? + if (rne.name === ane['node-id']) { + rne.connectionStatus = ane['netconf-node-topology:connection-status']; + rne.ipaddress = ane['netconf-node-topology:host']; + rne.port = ane['netconf-node-topology:port']; + rne.client = ane.client; + + rne.onfCapabilities = ane.onfCapabilities; + + var extensions = ['webUri', 'cliAddress', 'appCommand']; + extensions.map(function(extension){ + rne[extension] = undefined; + }); + if (ane.onfCoreModelRevision) { + $mwtnConnect.getActualNetworkElement(ane['node-id'], ane.onfCoreModelRevision).then(function(success){ + success = $mwtnConnect.yangifyObject(success); + extensions.map(function(extension){ + rne[extension] = getExtension(success['network-element'].extension, extension); + }); + }, function(error){ + // ignore + }); + } + } + }); + } + }; + + var getActualNetworkElements = function() { + // aneHash = []; + if ($scope.requiredNesGridOptions.data) { + $scope.requiredNesGridOptions.data.map(function(ne) { + // ne.connectionStatus = 'disconnected'; + }); + } + $mwtnConnect.getMountPoints().then(function(mountpoints) { + $scope.unknownNesGridOptions.data = []; + mountpoints.map(function(mountpoint) { + if (isRequired(mountpoint['node-id'])) { + // setConnectionStatus(ne['node-id'], ne['netconf-node-topology:connection-status']); + setValues(mountpoint); + } else { + // console.log('mountpoint', JSON.stringify(mountpoint)); + $scope.unknownNesGridOptions.data.push(mountpoint); + } + }); + }, function(error){ + $mwtnLog.info({component: COMPONENT, message: JSON.stringify(error)}); + }); + }; + + $scope.netconfServer = {}; + + /** + * A function which inquires data from a netconf server and stores it in a database. + * @param {{'node-id': string, ipAddress: string, port: number, username: string, password: string}} netconfServer - A netConf server object with all connectivity parameters. + */ + $scope.addToRequiredNetworkElements = function(netconfServer) { + + $scope.netconfServer = netconfServer; + var neId = netconfServer['node-id']; + + var index = $scope.unknownNesGridOptions.data.map(function(item) { + return item['node-id']; + }).indexOf(netconfServer['node-id']); + + if (index !== -1 ) { + $mwtnConnect.getSingleDocument('mwtn', 'required-networkelement', neId).then(function(doc){ + // Network element alrady exists in database + doc.required = true; + $scope.unknownNesGridOptions.data[index].spinner = true; + // add to aai + // $onapAai.createPnf(neId, doc).then(function(success){ + // // do nothing + // }, function(error) { + // // do nothing + // }); + // add to es + $mwtnConnect.createSingleDocument('mwtn', 'required-networkelement', neId, doc).then(function(success){ + $timeout(function() { + $scope.status.requiredNes = true; + $scope.unknownNesGridOptions.data[index].spinner = false; + }, 1000); + }, function(error) { + $timeout(function() { + $scope.status.requiredNes = true; + $scope.unknownNesGridOptions.data[index].spinner = false; + }, 1000); + console.log(JSON.stringify(error)); + }); + }, function(error) { + // Network element does not exist in database, data inqured from real network element + var modalInstance = $uibModal.open({ + animation: true, + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: 'src/app/mwtnConnect/templates/addToRequired.tpl.html', + controller: 'AddToRequiredMessageCtrl', + size: 'lg', + resolve: { + netconfServer: function () { + return $scope.netconfServer; + } + } + }); + + modalInstance.result.then(function (netconfServer) { + $scope.unknownNesGridOptions.data[index].spinner = true; + $mwtnConnect.addRequiredNetworkElement(netconfServer).then(function(success){ + $mwtnLog.info({component: COMPONENT, message: 'Adding to database: ' + netconfServer['node-id']}); + + // $onapAai.createPnf(netconfServer['node-id'], success.config.data).then(function(success){ + // // do nothing + // }, function(error) { + // // do nothing + // }); + + $timeout(function() { + $scope.status.requiredNes = true; + $scope.unknownNesGridOptions.data[index].spinner = false; + }, 1000); + }, function(error){ + $scope.unknownNesGridOptions.data[index].spinner = false; + $mwtnLog.error({component: COMPONENT, message: JSON.stringify(error)}); + }); + }, function () { + $mwtnLog.info({component: COMPONENT, message: 'Creation of new planned NetworkElement dismissed!'}); + }); + }); + } + }; + + $scope.newMountingPoint = { + name: 'new-netconf-server', + ipaddress: '127.0.0.1', + port: 830, + username: 'admin', + password: 'admin' + }; + + $scope.mount = function() { + $scope.mountError = undefined; + $scope.mountSuccess = undefined; + $scope.processing = true; + $mwtnConnect.mount($scope.newMountingPoint).then(function(success){ + $scope.processing = false; + $scope.mountSuccess = ['NETCONF server', $scope.newMountingPoint.name, 'successfully mounted.'].join(' '); + }, function(error){ + $scope.processing = false; + $scope.mountError = ['NETCONF server', $scope.newMountingPoint.name, 'could not be mounted.'].join(' '); + }); + }; + + $scope.connect = function(ne) { + ne.connectionStatus = 'connecting...'; + $mwtnConnect.mount(ne).then(function(success){ + // ne.connectionStatus = 'connected'; + }, function(error){ + // ne.connectionStatus = 'connected'; + }); + }; + + $scope.disconnect = function(ne) { + ne.connectionStatus = 'connecting...'; + $mwtnConnect.unmount(ne.name).then(function(success){ + ne.connectionStatus = 'disconnected'; + }, function(error){ + ne.connectionStatus = 'unknown'; + }); + }; + + $scope.showDetails = function(ne, required) { + $scope.currentNetworkElement = ne; + $scope.currentNetworkElement.required = required; + if (required !== false) { + $scope.currentNetworkElement.required = true; + } + var modalInstance = $uibModal.open({ + animation: true, + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: 'src/app/mwtnConnect/templates/mountPointDetails.tpl.html', + controller: 'MountPointDetailsCtrl', + size: 'lg', + resolve: { + currentNetworkElement: function () { + return $scope.currentNetworkElement; + } + } + }); + + modalInstance.result.then(function(success) { + if (success.hide || success.delete) { + var nodeId = success.hide || success.delete; + $scope.requiredNesGridOptions.data.map(function(item, index, array){ + if (item.name === nodeId) { + array.splice(index, 1); + } + }); + } + $mwtnLog.info({component: COMPONENT, message: 'Mointpoint details closed'}); + }, function (error) { + $mwtnLog.info({component: COMPONENT, message: 'Mointpoint details dismissed!'}); + }); + }; + + var removeFromNodeList = function(nodeId) { + var index = $scope.unknownNesGridOptions.data.length; + while (index--) { + if ($scope.unknownNesGridOptions.data[index]['node-id'] === nodeId) { + $scope.unknownNesGridOptions.data.splice(index, 1); + } + } + }; + + $scope.unmount = function(netConfServer) { + netConfServer['netconf-node-topology:connection-status'] = 'disconnecting...'; + $mwtnConnect.unmount(netConfServer['node-id']).then(function(response) { + $mwtnLog.info({component: COMPONENT, message: 'Mounting point deleted: ' + netConfServer['node-id'] }); + removeFromNodeList(netConfServer['node-id']); + }, function(error){ + $mwtnLog.info({component: COMPONENT, message: 'Unmounting of '+netConfServer['node-id']+' failed!'}); + removeFromNodeList(netConfServer['node-id']); + }); + }; + + $scope.edit = function(row) { + console.info(JSON.stringify(row)); + }; + $scope.delete = function(row) { + console.info(JSON.stringify(row)); + }; + + // Connection status log + $scope.gridOptionsConnectionStatusLog = { + paginationPageSizes: [25, 100, 1000, 10000], + paginationPageSize: 25, + useExternalPagination: true, + useExternalSorting: true, + enablePaginationControls: false, + enableFiltering: true, + useExternalFiltering: true, + maxCount: 0, + columnDefs : [ + // { field: 'id', type: 'number', displayName: 'No.', headerCellClass: $scope.highlightFilteredHeader, width : 50, cellClass: 'number', pinnedLeft : true }, + { field: 'timestamp', type: 'string', displayName: 'Timestamp', headerCellClass: $scope.highlightFilteredHeader, width : 200, sort: { + direction: uiGridConstants.DESC, + priority: 1 + } }, + { field: 'nodeName', type: 'string', displayName: 'Node name', headerCellClass: $scope.highlightFilteredHeader, width: 200 }, + { field: 'connectionStatus', type: 'string', displayName: 'Connection status', headerCellClass: $scope.highlightFilteredHeader, width: 500, cellTemplate: requiredNesConnectionStatusCellTemplate } + ], + data: 'data', + onRegisterApi: function(gridApi) { + $scope.gridApi = gridApi; + $scope.gridApi.core.on.filterChanged( $scope, $scope.filter); + $scope.gridApi.core.on.sortChanged( $scope, $scope.sortChanged ); + $scope.sortChanged($scope.gridApi.grid, [ $scope.gridOptionsConnectionStatusLog.columnDefs[1] ] ); + + $scope.gridApi.pagination.on.paginationChanged($scope, function (newPage, pageSize) { + $scope.paginationOptions.pageNumber = newPage; + $scope.paginationOptions.pageSize = pageSize; + getPage(); + }); + } + }; + + // data visible in connection status log + $scope.data = []; + + //stateobject + $scope.state = { + filter: false, + sort: false, + lastfilter: null, + lastSort: null + }; + + //filter + $scope.filter = function() { + var grid = this.grid; + var columns=[]; + + //get all columns where data was typed in + angular.forEach(grid.columns, function(value, key) { + if(value.filters[0].term) { + + var col = findColumn(value.displayName); + var val = value.filters[0].term; + + switch (col) { + case 'event.timeStamp': + //convert timestamp to db format + val = $mwtnConnect.TimeStampToONFFormat(value.filters[0].term); + break; + case 'event.type': + if ('connected'.startsWith(value.filters[0].term.toLowerCase())) { + val = 'ObjectCreationNotificationXml'.toLowerCase(); + } + if ('disconnected'.startsWith(value.filters[0].term.toLowerCase())) { + val = 'ObjectDeletionNotificationXml'.toLowerCase(); + } + break; + } + columns.push({ column: col, value: val }); //create column object + } + }); + + if (columns.length ===0 ) { //all filter data cleared away + $scope.state.filter = false; + $scope.state.lastfilter = null; + + //get unfiltered data + $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize, + $scope.paginationOptions.pageSize, + $scope.state.lastSort, + $scope.state.lastfilter).then(function(response) { + if (response.data.hits.hits) { + processResponseRecreateList(response); + } + }); + } else { + //base filter string + var filter = {"query": {"bool":{"must":[]}}}; + //create filter objects + var prefixs = columns.map(function(obj){ + var prefixObj={}; + prefixObj[obj.column] = obj.value;//add like: {column: "fault.counter", value: "1"} => {"fault.counter":1} + return {prefix:prefixObj}; // => {"prefix":{...}} + }); + prefixs.push({"match":{"event.nodeName":"SDN-Controller"}}); + + //add objects to must property + filter.query.bool.must = prefixs; + //save filter + $scope.state.lastfilter=filter; + $scope.state.filter=true; + + //send data to sdnevents/eventlog/_search + $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize, + $scope.paginationOptions.pageSize, + $scope.state.lastSort, + $scope.state.lastfilter).then(function(response) { + if (response.data.hits.total>0) { //only, when hits exist + processResponseRecreateList(response); + $scope.gridOptionsConnectionStatusLog.totalItems = response.data.hits.total; + } else { + //clear data from list + $scope.data=[]; + $scope.gridOptionsConnectionStatusLog.totalItems = 0; + $scope.gridOptionsConnectionStatusLog.maxCount = 0; + $scope.state.filter=false; + $scope.state.lastfilter=null; + } + }); + } + }; + + //sort + $scope.sortChanged=function(grid, sortColumns){ // sortColumns is an array containing just the column sorted in the grid + if (sortColumns.length > 0) { + if (sortColumns[0].sort) { + var name = sortColumns[0].displayName; // the name of the column sorted + var direction = sortColumns[0].sort.direction; // the direction of the column sorted: "desc" or "asc" + sort(direction, findColumn(name) ); + } + } else { + $scope.state.sort = false; + $scope.state.lastSort=null; + //get unsorted data + $mwtnConnect.getData( ($scope.paginationOptions.pageNumber-1) * $scope.paginationOptions.pageSize, + $scope.paginationOptions.pageSize, + $scope.state.lastSort, + $scope.state.lastfilter).then(function(response) { + processResponseRecreateList(response); + }, function(error) { + processResponseRecreateList([]); + }); + } + }; + + var processResponseRecreateList = function(response) { + if (!response.data || !response.data.hits) { + $scope.data = []; + $scope.gridOptionsConnectionStatusLog.totalItems = 0; // needed by ui-grid to calculate page number, always update! + $scope.gridOptionsConnectionStatusLog.maxCount = 0; + return; + } + + if($scope.gridOptionsConnectionStatusLog.maxCount < response.data.hits.total){ + $scope.gridOptionsConnectionStatusLog.maxCount = response.data.hits.total; //only if total is higher (can be lower due to eg filtering) + } + var list = response.data.hits.hits.map(function(entry) { + + var status = 'unknown'; + if (entry._source.event.type === 'ObjectCreationNotificationXml' ) { + status = 'connected'; + } else if (entry._source.event.type === 'ObjectDeletionNotificationXml' ) { + status = 'disconnected'; + } + return { + id: entry._id, + timestamp: $mwtnConnect.formatTimeStamp(entry._source.event.timeStamp), + nodeName: entry._source.event.objectId, + connectionStatus: status + }; + }); + $scope.data=list; + $scope.gridOptionsConnectionStatusLog.totalItems = response.data.hits.total; // needed by ui-grid to calculate page number, always update! + }; + + $scope.paginationOptions = { + pageNumber: 1, + pageSize: 25, + sort: null + }; + + var getPage = function() { + //from, how many, sort, filter + $mwtnConnect.getData( ($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize, + $scope.paginationOptions.pageSize, + $scope.state.lastSort, + $scope.state.lastfilter).then(function (success) { + $scope.gridOptionsConnectionStatusLog.totalItems = success.data.hits.total; + processResponseRecreateList(success); + }, function(error) { + $scope.gridOptionsConnectionStatusLog.totalItems = success.data.hits.total; + processResponseRecreateList([]); + $mwtnLog.info({component: COMPONENT, message: JSON.stringify(error)}); + }); + }; + + var processResponseAddToList = function(response) { + if (response.data.hits.hits) { + if($scope.gridOptionsConnectionStatusLog.maxCount < response.data.hits.total) { + $scope.gridOptionsConnectionStatusLog.maxCount = response.data.hits.total; //only if total is higher (can be lower due to eg filtering) + } + response.data.hits.hits.map(function(entry) { + var status = 'disconnected'; + if (entry._source.event.type === 'ObjectCreationNotificationXml' ) { + status = 'connected'; + } + var log = { + id: entry._id, + timestamp: $mwtnConnect.formatTimeStamp(entry._source.event.timeStamp), + nodeName: entry._source.event.objectId, + connectionStatus: status + }; + $scope.data.push(log); + }); + } + $scope.gridOptionsConnectionStatusLog.totalItems = response.data.hits.total; // needed by ui-grid to calculate page number, always update! + }; + + var sort = function (direction, columnName) { + + var sortObj={}; + var sort = [ sortObj ]; + switch (direction) { + case uiGridConstants.ASC: + //create sort object + sortObj[columnName]={order : 'asc'}; + sort = [ sortObj ]; + //save last sort + $scope.state.lastSort=sort; + + $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize, + $scope.paginationOptions.pageSize, + $scope.state.lastSort, + $scope.state.lastfilter).then(function(response) { + if (response.data.hits.hits) { + processResponseRecreateList(response); + $scope.state.sort=true; + } + }); + break; + + case uiGridConstants.DESC: + sortObj[columnName]={order : 'desc'}; + sort = [ sortObj]; + $scope.state.lastSort=sort; + + $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,$scope.paginationOptions.pageSize,$scope.state.lastSort,$scope.state.lastfilter).then(function(response) { + if (response.data.hits.hits) { + processResponseRecreateList(response); + $scope.state.sort=true; + } + }); + break; + + case undefined: + + $scope.state.sort=false; + $scope.state.lastSort=null; + + $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize, + $scope.paginationOptions.pageSize, + $scope.state.lastSort, + $scope.state.lastfilter).then(function(response) { + processResponseRecreateList(response); + }); + break; + } + }; + + var findColumn= function(name) { + if(name === 'Timestamp'){ return 'event.timeStamp'; } + else if(name === 'Node name'){ return 'event.objectId'; } + else if(name === 'Connection status'){ return 'event.type'; } + }; + + $scope.paginationStatusMessage = function() { + + var startnum=($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize+1; + var pagenednum=($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize+1+$scope.data.length; + if(pagenednum>$scope.gridOptionsConnectionStatusLog.totalItems) pagenednum=pagenednum-1; //reduce by initial added 1 + + if($scope.state.filter){ + var filterTpl = 'Showing {0} to {1} of {2} items (filtered from {3} total items)'; + return filterTpl.format(startnum, pagenednum, $scope.gridOptionsConnectionStatusLog.totalItems, $scope.gridOptionsConnectionStatusLog.maxCount); + + } else { + var defaultTpl = 'Showing {0} to {1} of {2} total items'; + return defaultTpl.format( startnum, pagenednum, $scope.gridOptionsConnectionStatusLog.maxCount); + } + }; + + $scope.refreshLog = function() { + + + var from = ($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize; + var size = $scope.paginationOptions.pageSize; + $scope.processing = true; + $scope.spinner.connectionStatusLog = true; + $mwtnConnect.getData(from, size, $scope.state.lastSort, $scope.state.lastfilter).then(function(logEntries){ + $scope.processing = false; + $scope.spinner.connectionStatusLog = false; + processResponseRecreateList(logEntries); + }, function(error){ + $scope.processing = false; + $scope.spinner.connectionStatusLog = false; + console.error(JSON.stringify(error)); + }); + }; + + // browser events + $scope.status = {requiredNes : true}; + $scope.separator = $mwtnConnect.separator; //' ' + $scope.$watch('status', function(status, oldValue) { + Object.keys(status).map(function(key){ + if (status[key] && status[key] !== oldValue[key]) { + switch (key) { + case 'requiredNes': + getRequiredNetworkElements(); + break; + case 'unkownNes': + getActualNetworkElements(); + break; + case 'mount': + $scope.mountSuccess = undefined; + $scope.mountError = undefined; + break; + case 'connectionStatusLog': + $window.dispatchEvent(new Event("resize")); + $scope.refreshLog(); + break; + } + } + }); + }, true); + + // odl events + // actualNetworkElements - NE added/deleted + var listenToActualNetworkElementsNotifications = function(socketLocation) { + try { + var notificatinSocket = new WebSocket(socketLocation); + + notificatinSocket.onmessage = function(event) { + console.log('Event received.'); + setTimeout(function() { + getActualNetworkElements(); + }, 1000); + }; + notificatinSocket.onerror = function(error) { + console.error("Socket error: " + error); + }; + notificatinSocket.onopen = function(event) { + console.info("Socket connection opened."); + }; + notificatinSocket.onclose = function(event) { + console.info("Socket connection closed."); + }; + } catch (e) { + console.error("Error when creating WebSocket" + e); + } + }; + + // var path = '/network-topology:network-topology/network-topology:topology[network-topology:topology-id = "topology-netconf"]'; + // var path = "/opendaylight-inventory:nodes"; // [sko] works! + var path = '/network-topology:network-topology'; // for whatever reason it does not work, but work in Lithium. + $mwtnConnect.registerForOdlEvents(path, function(socketLocation) { + listenToActualNetworkElementsNotifications(socketLocation); + }); + + var listenToEventManagerNotifications = function() { + $mwtnConnect.getMwtnWebSocketUrl().then(function(success){ + try { + var notificationSocket = new WebSocket(success); + + notificationSocket.onmessage = function(event) { + // we process our received event here + if (typeof event.data === 'string') { + // console.log("Client Received:\n" + event.data); + // console.log("---------------------------"); + $mwtnConnect.formatData(event).then(function(formated) { + switch (formated.notifType) { + case 'ProblemNotification': + case 'AttributeValueChangedNotification': + // ignore + break; + case 'ObjectCreationNotification': + case 'ObjectDeletionNotification': + if (formated.nodeName === 'SDN-Controller') { + $timeout(function() {getActualNetworkElements();}, 500); + } + break; + default: + console.error('Missing implementation for', formated.notifType); + } + }, function(error) { + // do nothing + }); + } + }; + + notificationSocket.onerror = function(error) { + console.log("Socket error: " + error); + }; + + notificationSocket.onopen = function(event) { + console.log("Socket connection opened."); + + function subscribe() { + if (notificationSocket.readyState === notificationSocket.OPEN) { + var data = { + 'data' : 'scopes', + 'scopes' : [ 'ObjectCreationNotification', 'ObjectDeletionNotification' ] + }; + notificationSocket.send(JSON.stringify(data)); + } + } + subscribe(); + }; + + notificationSocket.onclose = function(event) { + console.log("Socket connection closed."); + }; + } catch (e) { + console.error("Error when creating WebSocket.\n" + e); + } + }, function(error){ + console.error("Error when creating WebSocket.\n" + error); + }); + }; + listenToEventManagerNotifications(); + + }]); + + mwtnConnectApp.register.controller('AddToRequiredMessageCtrl', ['$scope', '$uibModalInstance', '$mwtnConnect', 'netconfServer', + function ($scope, $uibModalInstance, $mwtnConnect, netconfServer) { + + $scope.netconfServer = netconfServer; + + $mwtnConnect.getMountPoint(netconfServer['node-id']).then( + /** + * @param {{'node-id':string, 'netconf-node-topology:tcp-only': boolean, 'netconf-node-topology:host', string, 'netconf-node-topology:keepalive-delay':number, 'netconf-node-topology:port':number, 'netconf-node-topology:username':string, 'netconf-node-topology:password': string}} mountpoint - The mointpoint form topology-netconf + */ + function(mountpoint) { + $scope.netconfServer.username = mountpoint['netconf-node-topology:username']; + $scope.netconfServer.password = mountpoint['netconf-node-topology:password']; + }, + function(error){ + console.log(JSON.stringify(error)); + } + ); + + $scope.sites = []; + var sort = [ { + id : { + order : 'asc' + } + }]; + $mwtnConnect.getAllData('mwtn', 'site', 0, 20, sort).then( + function(sites){ + // console.log(JSON.stringify(sites)); + if (sites.data.hits.hits) { + sites.data.hits.hits.map(function(site){ + $scope.sites.push({id:site._source.id, name:site._source.name}); + }); + // console.log($scope.sites); + } + }, + function(error){ + $scope.sites = []; + } + ); + + $scope.ok = function () { + $uibModalInstance.close($scope.netconfServer); + }; + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + + $scope.$watch('netconfServer.site', function(newValue, oldValue) { + if (newValue !== oldValue) { + var sort = [ { + id : { + order : 'asc' + } + }]; + var query = { + prefix: { + name: newValue + } + }; + + $mwtnConnect.getFilteredSortedData('mwtn', 'site', 0, 20, sort, query).then( + function(sites){ + // console.log(JSON.stringify(sites)); + if (sites.data.hits.hits) { + $scope.sites = sites.data.hits.hits.map(function(site){ + return {id:site._source.id, name:site._source.name}; + }); + // console.log($scope.sites); + } + }, + function(error){ + $scope.sites = []; + } + ); + } + }); + }]); + + mwtnConnectApp.register.controller('MountPointDetailsCtrl', ['$scope', '$uibModalInstance', '$uibModal', '$mwtnConnect', '$mwtnLog', 'currentNetworkElement', + function ($scope, $uibModalInstance, $uibModal, $mwtnConnect, $mwtnLog, currentNetworkElement) { + + var COMPONENT = 'MountPointDetailsCtrl'; + // $mwtnLog.info({component: COMPONENT, message: 'MountPointDetailsCtrl started!'}); + + $scope.data = { + ne: currentNetworkElement, + web: { + supported: false, + protocol: 'http', + ipAddress: '127.0.0.1', + port: 80, + url: '/', + getLink : function() { + if (currentNetworkElement.webUri) { + return currentNetworkElement.webUri; + } + return [this.protocol,'://', this.ipAddress, this.url ].join(''); + } + }, + terminal: { + supported: false, + copied: false, + protocol: 'ssh', + user: 'cli', + ipAddress: '127.0.0.1', + getCommand : function() { + if (currentNetworkElement.cliAddress) { + return currentNetworkElement.cliAddress; + } + return [this.protocol, ' ', this.user, '@', this.ipAddress].join(''); + }, + copyToClipboard : function () { + $scope.data.application.copied = false; + this.copied = true; + var message = 'Copied to clipboard! ' + this.getCommand(); + $mwtnLog.info({component: COMPONENT, message: message}); + } + }, + application: { + supported: false, + copied: false, + commandTemplate: 'VendorApp --ne {0}', + ipAddress: '127.0.0.1', + getCommand : function() { + if (currentNetworkElement.appCommand) { + return currentNetworkElement.appCommand; + } + return this.commandTemplate.format(this.ipAddress); + }, + copyToClipboard : function () { + $scope.data.terminal.copied = false; + $scope.data.application.copied = true; + var message = 'Copied to clipboard! ' + this.getCommand(); + $mwtnLog.info({component: COMPONENT, message: message}); + } + } + }; + + var nodeId = $scope.data.ne.name || $scope.data.ne['node-id']; + $mwtnConnect.getMountPoint(nodeId).then(function(success){ + $scope.data.mountpoint = success; + }, function(error){ + $scope.data.mountpoint = undefined; + }); + + if (currentNetworkElement.webUri && currentNetworkElement.webUri !== '') { + $scope.data.web.supported = true; + $scope.data.web.protocol = currentNetworkElement.webUri.split(':')[0]; + var matches = currentNetworkElement.webUri.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i); + $scope.data.web.ipAddress = matches && matches[1]; // ipAddress will be null if no match is found + } + if (currentNetworkElement.cliAddress && currentNetworkElement.cliAddress !== '') { + $scope.data.terminal.supported = true; + var matches = currentNetworkElement.cliAddress.match(/([^@]+)@([^@]+)/i); + $scope.data.terminal.user = matches && matches[1]; + $scope.data.terminal.ipAddress = matches && matches[2]; + } + if (currentNetworkElement.appCommand && currentNetworkElement.appCommand !== '') { + $scope.data.application.supported = true; + // [sko] TODO once a mediator supports it + } + + $scope.yangCapabilitiesGridOptions = JSON.parse(JSON.stringify($mwtnConnect.gridOptions)); + $scope.yangCapabilitiesGridOptions.columnDefs = [ + { field: 'module', type: 'string', displayName: 'module', headerCellClass: $scope.highlightFilteredHeader, width : 600 }, + { field: 'revision', type: 'string', displayName: 'Revision', headerCellClass: $scope.highlightFilteredHeader, width : 150} + ]; + $scope.yangCapabilitiesGridOptions.data = currentNetworkElement.onfCapabilities; + + // clipboard + $scope.supported = false; + $scope.error = function (err) { + $mwtnLog.error({component: COMPONENT, message: err}); + }; + + $scope.ok = function () { + $uibModalInstance.close({ne: currentNetworkElement}); + }; + + $scope.hide = function (ne) { + $scope.hideNe = ne; + var modalInstance = $uibModal.open({ + animation: true, + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: 'src/app/mwtnConnect/templates/confirmHide.tpl.html', + controller: 'MountPointHideCtrl', + size: 'lg', + resolve: { + hideNe: function () { + return $scope.hideNe; + } + } + }); + + modalInstance.result.then( + function(neId) { + $mwtnConnect.getSingleDocument('mwtn', 'required-networkelement', neId).then( + function(doc){ + doc.required = false; + $mwtnConnect.createSingleDocument('mwtn', 'required-networkelement', neId, doc).then( + function(success){ + $uibModalInstance.close({hide: neId}); + }, + function(error) { + $uibModalInstance.close({hide: neId}); + } + ); + }, + function(error) { + $uibModalInstance.close({hide: neId}); + } + ); + $mwtnLog.info({component: COMPONENT, message: 'Confirm hide closed'}); + }, + function (error) { + $mwtnLog.info({component: COMPONENT, message: 'Confirm hide dismissed!'}); + } + ); + }; + + $scope.delete = function (ne) { + $scope.deleteNe = ne; + var modalInstance = $uibModal.open({ + animation: true, + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: 'src/app/mwtnConnect/templates/confirmDelete.tpl.html', + controller: 'MountPointDeleteCtrl', + size: 'lg', + resolve: { + deleteNe: function () { + return $scope.deleteNe; + } + } + }); + + modalInstance.result.then(function(success) { + // delete from AAi + // $onapAai.deletePnf(success).then(function(deleted){ + // $mwtnLog.info({component: COMPONENT, message: success + ' deleted from AAI.'}); + // }, function(error){ + // $mwtnLog.info({component: COMPONENT, message: 'Deletion from AAI failed: ' + success + '\n' + error}); + // }); + // delete from ES + $mwtnConnect.deleteSingleDocument('mwtn', 'required-networkelement', success).then(function(deleted){ + $mwtnLog.info({component: COMPONENT, message: success + ' deleted from database.'}); + $uibModalInstance.close({hide: success}); + }, function(error){ + $mwtnLog.info({component: COMPONENT, message: 'Deletion from database failed: ' + success + '\n' + error}); + }); + }, function (error) { + $mwtnLog.info({component: COMPONENT, message: 'Confirm delete dismissed!'}); + }); + }; + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + }]); + + mwtnConnectApp.register.controller('MountPointHideCtrl', ['$scope', '$uibModalInstance', '$mwtnConnect', '$mwtnLog', 'hideNe', + function ($scope, $uibModalInstance, $mwtnConnect, $mwtnLog, hideNe) { + $scope.hideNe = hideNe; + $scope.ok = function () { + $uibModalInstance.close($scope.hideNe.name); + }; + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + + }]); + + mwtnConnectApp.register.controller('MountPointDeleteCtrl', ['$scope', '$uibModalInstance', '$mwtnConnect', '$mwtnLog', 'deleteNe', + function ($scope, $uibModalInstance, $mwtnConnect, $mwtnLog, deleteNe) { + $scope.deleteNe = deleteNe; + $scope.ok = function () { + $uibModalInstance.close($scope.deleteNe.name); + }; + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + + }]); + +});
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.module.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.module.js new file mode 100644 index 00000000..c280a956 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.module.js @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 highstreet technologies GmbH 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 + */ + +define(['angularAMD', + 'app/routingConfig', + 'app/core/core.services', + 'common/config/env.module', + 'app/mwtnCommons/mwtnCommons.module'], function(ng) { + var mwtnConnectApp = angular.module('app.mwtnConnect', [ 'ui.grid', 'ui.bootstrap', 'app.core', + 'ui.router.state', 'config', 'ui.grid.exporter', + 'ui.grid.moveColumns', 'ui.grid.pinning', 'ui.grid.selection', + 'ui.grid.resizeColumns', 'angular-clipboard' ]); + + mwtnConnectApp.config(function($stateProvider, $compileProvider, $controllerProvider, $provide, NavHelperProvider, $translateProvider) { + + mwtnConnectApp.register = { + controller : $controllerProvider.register, + directive : $compileProvider.directive, + factory : $provide.factory, + service : $provide.service + }; + + NavHelperProvider.addControllerUrl('app/mwtnConnect/mwtnConnect.controller'); + NavHelperProvider.addToMenu('mwtnConnect', { + "link" : "#/connect", + "active" : "main.mwtnConnect", + "title" : "Connect", + "icon" : "fa fa-plug", // Add navigation icon css class here + "page" : { + "title" : "Connect", + "description" : "Connection supervision of physical network function to ONAP SDN-C-4-Wireless" + } + }); + + var access = routingConfig.accessLevels; + + $stateProvider.state('main.mwtnConnect', { + url: 'connect', + access: access.admin, + views : { + 'content' : { + templateUrl: 'src/app/mwtnConnect/mwtnConnect.tpl.html', + controller: 'mwtnConnectCtrl' + } + } + }); + + }); + + return mwtnConnectApp; +}); diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.services.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.services.js new file mode 100644 index 00000000..8f8b55c7 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.services.js @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 highstreet technologies GmbH 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 + */ + +define(['app/mwtnConnect/mwtnConnect.module','app/mwtnCommons/mwtnCommons.services'],function(mwtnConnectApp) { + + + mwtnConnectApp.register.factory('$mwtnConnect', function($q, $mwtnCommons, $mwtnDatabase, $mwtnLog) { + + var COMPONENT = '$mwtnConnect'; + $mwtnLog.info({component: COMPONENT, message: '$mwtnConnect started!'}); + + var service = {}; + + service.addRequiredNetworkElement = $mwtnCommons.addRequiredNetworkElement; + service.createSingleDocument = $mwtnDatabase.createSingleDocument; + service.deleteSingleDocument = $mwtnDatabase.deleteSingleDocument; + service.formatData = $mwtnCommons.formatData; + service.formatTimeStamp = $mwtnCommons.formatTimeStamp; + service.getAllData = $mwtnDatabase.getAllData; + service.getFilteredSortedData = $mwtnDatabase.getFilteredSortedData; + service.getMountPoint = $mwtnCommons.getMountPoint; + service.getMountPoints = $mwtnCommons.getMountPoints; + service.getActualNetworkElement = $mwtnCommons.getActualNetworkElement; + service.getRequiredNetworkElements = $mwtnCommons.getRequiredNetworkElements; + service.getMwtnWebSocketUrl = $mwtnCommons.getMwtnWebSocketUrl; + service.getSingleDocument = $mwtnDatabase.getSingleDocument; + service.gridOptions = $mwtnCommons.gridOptions; + service.highlightFilteredHeader = $mwtnCommons.highlightFilteredHeader; + + service.registerForOdlEvents = $mwtnCommons.registerForOdlEvents; + service.separator = $mwtnCommons.separator; + + service.mount = $mwtnCommons.mount; + service.unmount = $mwtnCommons.unmount; + service.yangifyObject = $mwtnCommons.yangifyObject; + + + service.getData = function(from, size, sort, query){ + if (!sort) { //default sort value + sort = [ { 'event.timeStamp' : {order : 'desc'}}]; + } + if (!query) { //default filter value + query= {prefix: {'event.nodeName': 'SDN-Controller'}}; + } + return getFilteredSortedData(from, size, sort, query); + }; + + var getFilteredSortedData = function(from, size, sort, query){ + var deferred = $q.defer(); + $mwtnDatabase.getFilteredSortedData('sdnevents', 'eventlog', from, size, sort, query).then(function(success){ + deferred.resolve(success); + }, function(error){ + $mwtnLog.error({component: 'private getFilteredSortedData', message: JSON.stringify(error.data)}); + deferred.reject(error); + }); + return deferred.promise; + }; + + service.TimeStampToONFFormat = function(timestamp) { + timestamp=timestamp.split('-').join(''); + timestamp=timestamp.split(':').join(''); + timestamp=timestamp.split(' ').join(''); + timestamp=timestamp.replace('UTC','Z'); + return timestamp; + }; + + return service; + }); + +}); diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.tpl.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.tpl.html new file mode 100644 index 00000000..73fc0fcf --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/mwtnConnect.tpl.html @@ -0,0 +1,150 @@ +<ht-header help-link='sdnr/connect/0.4.0/README.md'></ht-header> + +<uib-accordion close-others="oneAtATime"> + +<div uib-accordion-group class="panel-primary" + is-open="status.requiredNes"> + <uib-accordion-heading> + <i class="pull-left fa" ng-class="{'fa-chevron-down': status.requiredNes, 'fa-chevron-right': !status.requiredNes}"></i> + <span>{{'MWTN_REQUIRED_NETWORK_ELEMENTS' | translate}}</span> + </uib-accordion-heading> + <div id="requiredNesGrid" ui-grid="requiredNesGridOptions" + ui-grid-exporter ui-grid-selection ui-grid-pinning + ui-grid-resize-columns ui-grid-move-columns class="requiredNesGrid"> + </div> +</div> + +<div uib-accordion-group class="panel-default" + is-open="status.unkownNes"> + <uib-accordion-heading> + <i class="pull-left fa" ng-class="{'fa-chevron-down': status.unkownNes, 'fa-chevron-right': !status.unkownNes}"></i> + <span>{{'MWTN_UNKNOWN_NETWORK_ELEMENTS' | translate}}</span> + </uib-accordion-heading> + <div id="unknownNesGrid" ui-grid="unknownNesGridOptions" + ui-grid-exporter ui-grid-selection ui-grid-pinning + ui-grid-resize-columns ui-grid-move-columns class="unknownNesGrid"> + </div> +</div> + +<div uib-accordion-group class="panel-default" + is-open="status.mount"> + <uib-accordion-heading> + <i class="pull-left fa" ng-class="{'fa-chevron-down': status.mount, 'fa-chevron-right': !status.mount}"></i> + <span>{{'Mount NETCONF Servers (devices, nodes, mediators, controllers, ...)' | translate}}</span> + </uib-accordion-heading> + <div class="container"> + <div class="row" ng-repeat="(key, value) in newMountingPoint"> + <div class="col-md-2 text-right"> + <span>{{['mwtn', key].join('_').toUpperCase() | translate}}</span> + </div> + <div class="col-md-4"> + <input type="text" class="form-control" + ng-model="newMountingPoint[key]"></input> + </div> + </div> + <div class="row"> + <div class="col-md-6 text-right"> + <br /> + <button type="button" class="btn btn-primary" ng-click="mount()"> + <i class="fa fa-spinner" ng-class="{'fa-pulse':processing}" ng-show="processing" aria-hidden="true"></i> + <span>{{'MWTN_MOUNT' | translate}}</span> + </button> + </div> + </div> + <div class="row"> + <div class="col-md-6"> + <br /> + <span class="mwtnSuccess" style="color: darkgreen;">{{mountSuccess}}</span> + <span class="mwtnError" style="color: red;">{{mountError}}</span> + </div> + </div> + </div> +</div> + +<div uib-accordion-group class="panel-default" + is-open="status.connectionStatusLog"> + <uib-accordion-heading> + <i class="pull-left fa" ng-class="{'fa-chevron-down': status.connectionStatusLog, 'fa-chevron-right': !status.connectionStatusLog}"></i> + <span>{{'MWTN_CONNECTION_STATUS_LOG' | translate}}</span> + <i class="pull-right fa fa-spinner fa-pulse" ng-show="spinner.connectionStatusLog"></i> + </uib-accordion-heading> + + <div id="mwtnConnectGridConnectionStatusLog" + ui-grid="gridOptionsConnectionStatusLog" + ui-grid-pagination + ui-grid-exporter + ui-grid-selection + ui-grid-pinning + ui-grid-resize-columns + ui-grid-move-columns class="mwtnConnectGrid"> + </div> + + <div class="ht-pagination"> + <button class="btn btn-default" + ng-disabled="paginationOptions.pageNumber === 1" + ng-click="gridApi.pagination.seek(1)" + ng-class="{'cancelCursor':paginationOptions.pageNumber === 1}" + role="menuitem" type="button" title="Page to first" aria-label="Page to first"> + <i class="fa fa-step-backward "></i> + </button> + <button class="btn btn-default" + ng-disabled="paginationOptions.pageNumber === 1" + ng-class="{'cancelCursor':paginationOptions.pageNumber === 1}" + ng-click="gridApi.pagination.previousPage()" + + role="menuitem" type="button" title="Previous Page" aria-label="Previous Page"> + <i class="fa fa-play fa-rotate-180 "></i> + </button> + <input class="btn btn-default" style="text-align:right;" border="1" + ng-model="paginationOptions.pageNumber" + ng-change="seekPage(paginationOptions.pageNumber)" + type="text" style="width:20px;"/> + <span class="dark"> / {{ gridApi.pagination.getTotalPages() }}</span> + + <button class="btn btn-default" role="menuitem" type="button" title="Next Page" aria-label="Next Page" + ng-disabled="gridApi.pagination.pageNumber === gridApi.pagination.getTotalPages()" + ng-click="gridApi.pagination.nextPage()"> + <i class="fa fa-play "></i> + </button> + <button class="btn btn-default" ng-disabled="gridApi.pagination.pageNumber === gridApi.pagination.getTotalPages()" + ng-click="gridApi.pagination.seek(gridApi.pagination.getTotalPages())" + role="menuitem" type="button" title="Page to last" aria-label="Page to last"> + <i class="fa fa-step-forward "></i> + </button> + + <select + class="btn btn-default" name="repeatSelect" id="repeatSelect" + ng-init="gridOptionsConnectionStatusLog.paginationPageSize = gridOptionsConnectionStatusLog.paginationPageSizes[0]" + ng-model="gridOptionsConnectionStatusLog.paginationPageSize" + ng-options="option for option in gridOptionsConnectionStatusLog.paginationPageSizes"></select> + + <span class="dark"> items per page </span> + + <span class="pull-right dark">{{ paginationStatusMessage() }}</span> + + </div> + + <div class="text-right"> + <!-- + <button type="button" id="clearLog" class="btn btn-warning" ng-click="clearLog()"> + <i class="fa fa-times" aria-hidden="true"></i> + <span>Clear log...</span> + </button> + see gird menu Export ... + <button type="button" id="saveLog" class="btn btn-default" ng-click="saveLog()"> + <i class="fa fa-save" aria-hidden="true"></i> + <span>Save...</span> + </button> --> + <button type="button" id="refreshLog" class="btn btn-primary" ng-click="refreshLog()"> + <span>{{'MWTN_REFRESH' | translate}}</span> + </button> + </div> + +</div> + +</uib-accordion> + +<hr /> +<div class="owl"> + <span class="white">ONAP SDN-R | ONF Wireless for @distversion@ - Build: @buildtime@</span> +</div>
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/addToRequired.tpl.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/addToRequired.tpl.html new file mode 100644 index 00000000..d2a0903a --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/addToRequired.tpl.html @@ -0,0 +1,79 @@ + +<div class="modal-header"> + <h3 class="modal-title" id="modal-title">{{'Add to required NetworkElements' | translate}}</h3> +</div> +<div class="modal-body" id="modal-body"> + + <div class="container" style="max-width: 600px;"> + + <div class="row"> + <div class="col-md-12"> + <span>Create a new NetworkElement in planning database as clone of existing real NetworkElement.</span> + </div> + </div> + + <div class="row"> + <div class="col-md-4 text-right"> + <span>{{'MWTN_NAME' | translate}}</span> + </div> + <div class="col-md-4"> + <input class="form-control" type="text" ng-model="netconfServer['node-id']"></input> + </div> + </div> + + <div class="row"> + <div class="col-md-4 text-right"> + <span>{{'MWTN_IPADDRESS' | translate}}</span> + </div> + <div class="col-md-4"> + <input class="form-control" type="text" ng-model="netconfServer['netconf-node-topology:host']"></input> + </div> + </div> + + <div class="row"> + <div class="col-md-4 text-right"> + <span>{{'MWTN_NETCONF_PORT' | translate}}</span> + </div> + <div class="col-md-4"> + <input class="form-control" type="text" ng-model="netconfServer['netconf-node-topology:port']"></input> + </div> + </div> + + <div class="row"> + <div class="col-md-4 text-right"> + <span>{{'MWTN_USERNAME' | translate}}</span> + </div> + <div class="col-md-4"> + <input class="form-control" type="text" ng-model="netconfServer.username"></input> + </div> + </div> + + <div class="row"> + <div class="col-md-4 text-right"> + <span>{{'MWTN_PASSWORD' | translate}}</span> + </div> + <div class="col-md-4"> + <input class="form-control" type="password" ng-model="netconfServer.password"></input> + </div> + </div> + + <div class="row"> + <div class="col-md-4 text-right"> + <span>{{'MWTN_SITE' | translate}}</span> + </div> + <div class="col-md-4"> + <div class="form-group"> + <input list="sites" class="form-control" ng-model="netconfServer.site"> + <datalist id="sites"> + <option ng-repeat="site in sites" value="{{site.id}}" >{{site.name}}</option> + </datalist> + </div> + </div> + </div> + + </div> +</div> +<div class="modal-footer"> + <button class="btn btn-primary" type="button" ng-click="ok()">{{'MWTN_ADD_TO_REQUIRED_NETWORKELEMENTS' | translate}}</button> + <button class="btn btn-warning" type="button" ng-click="cancel()">{{'MWTN_CANCEL' | translate}}</button> +</div>
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/confirmDelete.tpl.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/confirmDelete.tpl.html new file mode 100644 index 00000000..03a7de72 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/confirmDelete.tpl.html @@ -0,0 +1,23 @@ +<div class="modal-header"> + <h3 class="modal-title" id="modal-title">{{'MWTN_DELETE' | translate}}</h3> +</div> +<div class="modal-body" id="modal-body"> + <div class="container" style="max-width: 600px;"> + <div class="row"> + <div class="col-md-12"> + <span>Delete {{node.id}} from the planning database.</span> + <br/> + <span>All the planning data for this network element will be lost.</span> + </div> + </div> + </div> +</div> +<div class="modal-footer"> + <button class="btn btn-danger" type="button" ng-click="ok()"> + <i class="fa fa-trash" aria-hidden="true"></i> + <span>{{'MWTN_DELETE' | translate}}</span> + </button> + <button class="btn btn-warning" type="button" ng-click="cancel()"> + <span>{{'MWTN_CANCEL' | translate}}</span> + </button> +</div>
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/confirmHide.tpl.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/confirmHide.tpl.html new file mode 100644 index 00000000..c52ee3f4 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/confirmHide.tpl.html @@ -0,0 +1,21 @@ +<div class="modal-header"> + <h3 class="modal-title" id="modal-title">{{'MWTN_HIDE' | translate}}</h3> +</div> +<div class="modal-body" id="modal-body"> + <div class="container" style="max-width: 600px;"> + <div class="row"> + <div class="col-md-12"> + <span>Remove {{node.id}} from the list of required network elements.</span> + </div> + </div> + </div> +</div> +<div class="modal-footer"> + <button class="btn btn-primary" type="button" ng-click="ok()"> + <i class="fa fa-times" aria-hidden="true"></i> + <span>{{'MWTN_HIDE' | translate}}</span> + </button> + <button class="btn btn-warning" type="button" ng-click="cancel()"> + <span>{{'MWTN_CANCEL' | translate}}</span> + </button> +</div>
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/mountPointDetails.tpl.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/mountPointDetails.tpl.html new file mode 100644 index 00000000..56563b4f --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/mwtnConnect/mwtnConnect-module/src/main/resources/mwtnConnect/templates/mountPointDetails.tpl.html @@ -0,0 +1,125 @@ +<div class="modal-header"> + <h3 class="modal-title" id="modal-title">{{ data.ne.name }}{{ data.ne['node-id'] }}</h3> +</div> +<div class="modal-body" id="modal-body" ng-hide="data.ne.required"> + <div class="row"> + <div class="col-md-2 text-right"> + <span>{{'MWTN_NETWORKELEMENT' | translate}}</span> + </div> + <div class="col-md-10"> + <b>{{data.ne['node-id']}}</b> + </div> + </div> + <div class="row"> + <div class="col-md-2 text-right"> + <span>{{'MWTN_IPADDRESS' | translate}}</span> + </div> + <div class="col-md-10"> + <b>{{data.ne['netconf-node-topology:host']}}</b> + </div> + </div> + <div class="row"> + <div class="col-md-2 text-right"> + <span>{{'MWTN_PORT' | translate}}</span> + </div> + <div class="col-md-10"> + <b>{{data.ne['netconf-node-topology:port']}}</b> + </div> + </div> + <div class="row"> + <div class="col-md-2 text-right"> + <span>{{'MWTN_USERNAME' | translate}}</span> + </div> + <div class="col-md-10"> + <b>{{data.mountpoint['netconf-node-topology:username']}}</b> + </div> + </div> + <div class="row"> + <div class="col-md-2 text-right"> + <span>{{'MWTN_PASSWORD' | translate}}</span> + </div> + <div class="col-md-10"> + <b>{{data.mountpoint['netconf-node-topology:password']}}</b> + </div> + </div> +</div> +<div class="modal-body" id="modal-body" ng-show="data.ne.required"> + <!-- web --> + <div ng-show="data.web.supported"> + <p> + <span>The network element supports a native web user interface.</span> + <br/> + <span> Please use following link:</span> + <div class="input-append"> + <input class="mwtn-form-control" type="text" value="{{ data.web.getLink() }}" readonly></input> + <a class="btn btn-default" href="{{ data.web.getLink() }}" target="_blank"> + <i class="fa fa-external-link" aria-hidden="true"></i> + </a> + </div> + <p> + </div> + <div ng-show="!data.web.supported"> + <p>The network element does not support a native web user interface.</p> + </div> + <!-- terminal --> + <hr/> + <div ng-show="data.terminal.supported"> + <p> + <span>The network element supports a native terminal or console application.</span> + <br/> + <span>Please the copy button and paste the command into a terminal window:</span> + <p> + <div class="input-append"> + <input class="mwtn-form-control" type="text" value="{{ data.terminal.getCommand() }}" readonly></input> + <button class="btn btn-default" type="button" clipboard supported="supported" text="data.terminal.getCommand()" on-copied="data.terminal.copyToClipboard()" on-error="error(err)"> + <i class="fa fa-clipboard" aria-hidden="true"></i> + </button> + <span ng-show="data.terminal.copied === true" class="green">Check your clipboard.</span> + </div> + </div> + <div ng-show="!data.web.supported"> + <p>The network element does not support a native terminal or console application.</p> + </div> + + <!-- application --> + <hr/> + <div ng-show="data.application.supported"> + <p> + <span>The network element can be managed via a pre-installed application.</span> + <br/> + <span>Please the copy button and paste the command into a terminal window:</span> + <p> + <div class="input-append"> + <input class="mwtn-form-control" type="text" value="{{ data.application.getCommand() }}" readonly></input> + <button class="btn btn-default" type="button" clipboard supported="supported" text="data.application.getCommand()" on-copied="data.application.copyToClipboard()" on-error="error(err)"> + <i class="fa fa-clipboard" aria-hidden="true"></i> + </button> + <span ng-show="data.application.copied === true" class="green">Check your clipboard.</span> + </div> + </div> + +</div> +<div class="modal-body" id="modal-body"> + <!-- yang capabilites --> + <hr/> + <h3>{{ 'MWTN_YANG_CAPABILITIES' | translate }}</h3> + <div id="yangCapabilitiesGrid" + ui-grid="yangCapabilitiesGridOptions" + ui-grid-exporter ui-grid-selection ui-grid-pinning + ui-grid-resize-columns + ui-grid-move-columns class="yangCapabilitiesGrid"> + </div> +</div> +<div class="modal-footer"> + <button class="btn btn-danger" type="button" ng-show="data.ne.required" ng-click="delete(data.ne)"> + <i class="fa fa-trash" aria-hidden="true"></i> + <span>{{'MWTN_DELETE' | translate}}...</span> + </button> + <button class="btn btn-warning" type="button" ng-show="data.ne.required" ng-click="hide(data.ne)"> + <i class="fa fa-times" aria-hidden="true"></i> + <span>{{'MWTN_HIDE' | translate}}...</span> + </button> + <button class="btn btn-primary" type="button" ng-click="ok()"> + <span>{{'MWTN_CLOSE' | translate}}</span> + </button> +</div> |