[web-cvp]missing files in web sites 45/44545/1
authorgrakiss <grakiss.wanglei@huawei.com>
Mon, 9 Oct 2017 08:58:59 +0000 (04:58 -0400)
committergrakiss <grakiss.wanglei@huawei.com>
Mon, 9 Oct 2017 08:58:59 +0000 (04:58 -0400)
JIRA: DOVETAIL-522

some files missing due to incorrect .gitignore settings

Change-Id: I4d81842afcb6f2734abeebbdcde56ec5b3e1655b
Signed-off-by: grakiss <grakiss.wanglei@huawei.com>
.gitignore
cvp/3rd_party/static/testapi-ui/components/results/modal/sharedModal.html [new file with mode: 0644]
cvp/3rd_party/static/testapi-ui/components/results/results.html [new file with mode: 0644]
cvp/3rd_party/static/testapi-ui/components/results/resultsController.js [new file with mode: 0644]

index 9ae58f1..86930ad 100644 (file)
@@ -33,5 +33,4 @@ unittest_results.log
 *.sw?
 docs_build/
 docs_output/
-results/
 pre_config/
diff --git a/cvp/3rd_party/static/testapi-ui/components/results/modal/sharedModal.html b/cvp/3rd_party/static/testapi-ui/components/results/modal/sharedModal.html
new file mode 100644 (file)
index 0000000..de3b125
--- /dev/null
@@ -0,0 +1,19 @@
+<div>
+
+    <h4>Enter user name</h4>
+    <input type="text" ng-model="ctrl.userName" />
+
+    <div style="text-align:center;margin-top:20px;">
+        <button class="btn btn-default" ng-disabled="ctrl.userName==null || ctrl.userName==''" ng-click="ctrl.addSharedUser(ctrl.tempResult, ctrl.userName)">Commit</button>
+    </div>
+
+</div>
+
+
+<style>
+    input {
+        border-radius: 10px;
+        border: 1px solid #eeeeee;
+        width: 100%;
+    }
+</style>
diff --git a/cvp/3rd_party/static/testapi-ui/components/results/results.html b/cvp/3rd_party/static/testapi-ui/components/results/results.html
new file mode 100644 (file)
index 0000000..18de5ea
--- /dev/null
@@ -0,0 +1,91 @@
+<h3>{{ctrl.pageHeader}}</h3>
+<p>{{ctrl.pageParagraph}}</p>
+<form class="form-inline" ng-show="ctrl.isUserResults">
+<h4>Upload Results<i class="glyphicon glyphicon-question-sign opnfv-blue" uib-tooltip="results file is logs.xxx.tar.gz under your dovetail installation path"></i></h4>
+<div class="form-group col-m-3">
+     <input class="form-contrl nectar-button medium accent-color regular-button" type = "file" file-model = "resultFile"/>
+</div>
+<div class="form-group col-m-3">
+     <a class="nectar-button medium accent-color regular-button" ng-click="ctrl.uploadFile()"><span>upload result</span></a>
+</div>
+<div>
+<lable>{{ctrl.uploadState}}</label>
+</div>
+</form>
+<div class="row" style="margin-bottom:24px;"></div>
+<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div>
+<div cg-busy="{promise:ctrl.resultsRequest,message:'Loading'}"></div>
+<div ng-show="ctrl.data" class="results-table">
+    <table ng-data="ctrl.data.result" ng-show="ctrl.data" class="table table-striped table-hover">
+        <thead>
+            <tr>
+                <th>Upload Date</th>
+                <th>Test ID</th>
+                <th>Status</th>
+                <th>Log</th>
+                <th class="col-md-2">Operation</th>
+                <th class="col-md-2">Share List</th>
+            </tr>
+        </thead>
+
+        <tbody>
+            <tr ng-repeat="(index, result) in ctrl.data.tests">
+                <td>{{ result.upload_date }}</td>
+                <td><a ng-click="ctrl.gotoResultDetail(result.id, result._id)">{{ result.id }}</a></td>
+                <td>{{ result.status }}</td>
+                <td><a ng-click="ctrl.downloadLogs(result.id)">logs</a></td>
+               <td>
+                    <div class="btn-group" uib-dropdown>
+                        <a id="single-button" type="button" class="nectar-button medium accent-color regular-button" uib-dropdown-toggle>
+                            Operation<span class="caret"></span>
+                        </a>
+                        <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
+                            <li role="menuitem" ng-if="auth.currentUser.role == 'user'" class="menu-item menu-item-type-post_type menu-item-object-page"><a ng-class="{'hide': result.status != 'review'}" ng-click="ctrl.toPrivate(result, 'private')">withdraw submit</a></li>
+                            <li role="menuitem" ng-if="auth.currentUser.role == 'user'" class="menu-item menu-item-type-post_type menu-item-object-page"><a ng-class="{'hide': result.status != 'private'}" ng-click="ctrl.toReview(result, 'review')">submit to review</a></li>
+                            <li role="menuitem" ng-if="auth.currentUser.role.indexOf('reviewer') != -1" class="menu-item menu-item-type-post_type menu-item-object-page"><a ng-class="{'hide': result.status == 'approved'}" ng-click="ctrl.toggleCheck(result, 'status', 'approve')">approve</a></li>
+                            <li role="menuitem" ng-if="auth.currentUser.role.indexOf('reviewer') != -1" class="menu-item menu-item-type-post_type menu-item-object-page"><a ng-class="{'hide': result.status == 'not approved'}" ng-click="ctrl.toggleCheck(result, 'status', 'not approve')">not approve</a></li>
+                            <li role="menuitem" class="menu-item menu-item-type-post_type menu-item-object-page"><a ng-click="ctrl.openSharedModal(result)">share with</a></li>
+                            <li role="menuitem" ng-if="auth.currentUser.openid == result.owner" class="menu-item menu-item-type-post_type menu-item-object-page"><a ng-click="ctrl.deleteTest(result._id)">delete</a></li>
+                        </ul>
+                    </div>
+                </td>
+                <td>
+                    <div class="btn-group" uib-dropdown>
+                        <a id="single-button" type="button" class="nectar-button medium accent-color regular-button" style="width:130px" uib-dropdown-toggle>
+                            Share List<span class="caret"></span>
+                        </a>
+                        <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button" style="min-width:150%">
+                            <li class="menu-item menu-item-type-post_type menu-item-object-page" role="menuitem" ng-repeat="share in result.shared track by $index"><span>{{ share }}<i class="pull-right glyphicon glyphicon-remove" ng-click="ctrl.removeSharedUser(result, share)"></i></span></li>
+                        </ul>
+                    </div>
+                </td>
+
+            </tr>
+        </tbody>
+    </table>
+
+    <div class="pages">
+        <uib-pagination
+            total-items="ctrl.totalItems"
+            ng-model="ctrl.currentPage"
+            items-per-page="ctrl.itemsPerPage"
+            max-size="ctrl.maxSize"
+            class="pagination-sm"
+            boundary-links="true"
+            rotate="false"
+            num-pages="ctrl.numPages"
+            ng-change="ctrl.update()">
+        </uib-pagination>
+    </div>
+</div>
+</div>
+<div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
+    <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
+    <span class="sr-only">Error:</span>
+    {{ctrl.error}}
+</div>
+
+<style>
+.button-disabled {
+    pointer-events:none;
+}
diff --git a/cvp/3rd_party/static/testapi-ui/components/results/resultsController.js b/cvp/3rd_party/static/testapi-ui/components/results/resultsController.js
new file mode 100644 (file)
index 0000000..471cec0
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function () {
+    'use strict';
+
+    angular
+        .module('testapiApp')
+        .controller('ResultsController', ResultsController);
+
+    angular
+        .module('testapiApp')
+        .directive('fileModel', ['$parse', function ($parse) {
+            return {
+               restrict: 'A',
+               link: function(scope, element, attrs) {
+                  var model = $parse(attrs.fileModel);
+                  var modelSetter = model.assign;
+
+                  element.bind('change', function(){
+                     scope.$apply(function(){
+                        modelSetter(scope, element[0].files[0]);
+                     });
+                  });
+               }
+            };
+         }]);
+
+    ResultsController.$inject = [
+        '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert', 'ngDialog', '$resource'
+    ];
+
+    /**
+     * TestAPI Results Controller
+     * This controller is for the '/results' page where a user can browse
+     * a listing of community uploaded results.
+     */
+    function ResultsController($scope, $http, $filter, $state, testapiApiUrl, raiseAlert, ngDialog, $resource) {
+        var ctrl = this;
+
+        ctrl.uploadFile=uploadFile;
+        ctrl.update = update;
+        ctrl.open = open;
+        ctrl.clearFilters = clearFilters;
+        ctrl.associateMeta = associateMeta;
+        ctrl.getVersionList = getVersionList;
+        ctrl.getUserProducts = getUserProducts;
+        ctrl.associateProductVersion = associateProductVersion;
+        ctrl.getProductVersions = getProductVersions;
+        ctrl.prepVersionEdit = prepVersionEdit;
+        ctrl.gotoResultDetail = gotoResultDetail;
+        ctrl.toggleCheck = toggleCheck;
+        ctrl.toReview = toReview;
+        ctrl.toPrivate = toPrivate;
+        ctrl.removeSharedUser = removeSharedUser;
+        ctrl.addSharedUser = addSharedUser;
+        ctrl.openSharedModal = openSharedModal;
+        ctrl.downloadLogs = downloadLogs;
+        ctrl.deleteTest = deleteTest;
+
+        /** Mappings of Interop WG components to marketing program names. */
+        ctrl.targetMappings = {
+            'platform': 'Openstack Powered Platform',
+            'compute': 'OpenStack Powered Compute',
+            'object': 'OpenStack Powered Object Storage'
+        };
+
+        /** Initial page to be on. */
+        ctrl.currentPage = 1;
+
+        /**
+         * How many results should display on each page. Since pagination
+         * is server-side implemented, this value should match the
+         * 'results_per_page' configuration of the TestAPI server which
+         * defaults to 20.
+         */
+        ctrl.itemsPerPage = 20;
+
+        /**
+         * How many page buttons should be displayed at max before adding
+         * the '...' button.
+         */
+        ctrl.maxSize = 5;
+
+        /** The upload date lower limit to be used in filtering results. */
+        ctrl.startDate = '';
+
+        /** The upload date upper limit to be used in filtering results. */
+        ctrl.endDate = '';
+
+        /** The date format for the date picker. */
+        ctrl.format = 'yyyy-MM-dd';
+
+       ctrl.userName = null;
+
+        /** Check to see if this page should display user-specific results. */
+        // ctrl.isUserResults = $state.current.name === 'userResults';
+        // need auth to browse
+        ctrl.isUserResults = $state.current.name === 'userResults';
+
+        ctrl.currentUser = $scope.auth.name;
+        console.log($scope.auth);
+
+        // Should only be on user-results-page if authenticated.
+        if (ctrl.isUserResults && !$scope.auth.isAuthenticated) {
+            $state.go('home');
+        }
+
+        ctrl.pageHeader = ctrl.isUserResults ?
+            'Private test results' : 'Community test results';
+
+        ctrl.pageParagraph = ctrl.isUserResults ?
+            'Your most recently uploaded test results are listed here.' :
+            'The most recently uploaded community test results are listed ' +
+            'here.';
+
+        ctrl.uploadState = '';
+
+        if (ctrl.isUserResults) {
+            ctrl.authRequest = $scope.auth.doSignCheck()
+                .then(ctrl.update);
+            // ctrl.getUserProducts();
+        } else {
+            ctrl.update();
+        }
+
+        function downloadLogs(id) {
+            // var logsUrl = testapiApiUrl + "/logs/log_" + id+".tar.gz";
+            var logsUrl = "/logs/" + id+"/results/";
+            window.location.href = logsUrl;
+            // $http.get(logsUrl);
+        }
+
+        function deleteTest(inner_id) {
+          var resp = confirm('Are you sure to delete this test?');
+          if (!resp)
+            return;
+
+          var delUrl = testapiApiUrl + "/tests/" + inner_id;
+          $http.get(delUrl)
+            .then( function(resp) {
+              var results = resp.data.results;
+              $http.delete(delUrl)
+                .then( function(ret) {
+                  if(ret.data.code && ret.data.code != 0) {
+                    alert(ret.data.msg);
+                    return;
+                  }
+                  ctrl.update();
+                  angular.forEach(results, function(ele) {
+                    delUrl = testapiApiUrl + "/results/" + ele;
+                    $http.delete(delUrl);
+                  });
+                });
+            });
+        }
+
+        function toggleCheck(result, item, newValue) {
+            var id = result.id;
+           var updateUrl = testapiApiUrl + "/tests/"+id;
+
+           var data = {};
+           data['item'] = item;
+           data[item] = newValue;
+
+           $http.put(updateUrl, JSON.stringify(data), {
+                transformRequest: angular.identity,
+                headers: {'Content-Type': 'application/json'}})
+           .then( function(ret) {
+                 if(ret.data.code && ret.data.code != 0) {
+                     alert(ret.data.msg);
+                 }
+                 else {
+                    result[item] = newValue;
+                    console.log('update success');
+                 }
+           }, function(response){
+            });
+        }
+
+       function toReview(result, value){
+           var resp = confirm('Once you submit a test result for review, it will become readable to all CVP reviewers. Do you want to proceed?');
+           if(resp){
+               toggleCheck(result, 'status', value);
+           }
+       }
+
+       function toPrivate(result, value){
+           var resp = confirm('Do you want to proceed?');
+           if(resp){
+               toggleCheck(result, 'status', value);
+           }
+       }
+
+       function openSharedModal(result){
+               ctrl.tempResult = result;
+                ngDialog.open({
+                    preCloseCallback: function(value) {
+                    },
+                    template: 'testapi-ui/components/results/modal/sharedModal.html',
+                    scope: $scope,
+                    className: 'ngdialog-theme-default',
+                    width: 950,
+                    showClose: true,
+                    closeByDocument: true
+                });
+       }
+
+       function addSharedUser(result, userId){
+            var tempList = copy(result.shared);
+           tempList.push(userId);
+           toggleCheck(result, 'shared', tempList);
+           ngDialog.close();
+       }
+
+       function removeSharedUser(result, userId){
+           var tempList = copy(result.shared);
+           var idx = tempList.indexOf(userId);
+           if(idx != -1){
+               tempList.splice(idx, 1);
+               toggleCheck(result, 'shared', tempList);
+           }
+       }
+
+       function copy(arrList){
+           var tempList = [];
+           angular.forEach(arrList, function(ele){
+               tempList.push(ele);
+           });
+           return tempList;
+       }
+
+        function uploadFileToUrl(file, uploadUrl){
+            var fd = new FormData();
+            fd.append('file', file);
+
+            $http.post(uploadUrl, fd, {
+                transformRequest: angular.identity,
+                headers: {'Content-Type': undefined}
+            })
+            .success(function(data){
+                ctrl.uploadState = "";
+                var createTestUrl = testapiApiUrl + "/tests"
+                var fd = new FormData();
+                fd.append('results',data.results);
+                fd.append('id',data.id);
+                $http.post(createTestUrl, data)
+                .success(function(data, status){
+                  if (data.code && data.code != 0) {
+                    alert(data.msg);
+                  } else {
+                    ctrl.update();
+                  }
+                });
+             })
+
+            .error(function(data, status){
+                ctrl.uploadState = "Upload failed. Error code is " + status;
+            });
+        }
+
+        function uploadFile(){
+           var file = $scope.resultFile;
+           console.log('file is ' );
+           console.dir(file);
+
+           var uploadUrl = testapiApiUrl + "/results/upload";
+           uploadFileToUrl(file, uploadUrl);
+        };
+
+        /**
+         * This will contact the TestAPI API to get a listing of test run
+         * results.
+         */
+        function update() {
+            ctrl.showError = false;
+            // Construct the API URL based on user-specified filters.
+            var content_url = testapiApiUrl + '/tests' +
+                '?page=' + ctrl.currentPage;
+            var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd');
+            if (start) {
+                content_url =
+                    content_url + '&from=' + start + ' 00:00:00';
+            }
+            var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd');
+            if (end) {
+                content_url = content_url + '&to=' + end + ' 23:59:59';
+            }
+            if (ctrl.isUserResults) {
+                content_url = content_url + '&signed'+'&per_page='+ ctrl.itemsPerPage;
+            }
+            ctrl.resultsRequest =
+                $http.get(content_url).success(function (data) {
+                    ctrl.data = data;
+                    ctrl.totalItems = ctrl.data.pagination.total_pages * ctrl.itemsPerPage;
+                    ctrl.currentPage = ctrl.data.pagination.current_page;
+                    ctrl.numPages = ctrl.data.pagination.total_pages;
+                    console.log(ctrl.data);
+                }).error(function (error) {
+                    ctrl.data = null;
+                    ctrl.totalItems = 0;
+                    ctrl.showError = true;
+                    ctrl.error =
+                        'Error retrieving results listing from server: ' +
+                        angular.toJson(error);
+                });
+        }
+
+        /**
+         * This is called when the date filter calendar is opened. It
+         * does some event handling, and sets a scope variable so the UI
+         * knows which calendar was opened.
+         * @param {Object} $event - The Event object
+         * @param {String} openVar - Tells which calendar was opened
+         */
+        function open($event, openVar) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            ctrl[openVar] = true;
+        }
+
+        /**
+         * This function will clear all filters and update the results
+         * listing.
+         */
+        function clearFilters() {
+            ctrl.startDate = null;
+            ctrl.endDate = null;
+            ctrl.update();
+        }
+
+        /**
+         * This will send an API request in order to associate a metadata
+         * key-value pair with the given testId
+         * @param {Number} index - index of the test object in the results list
+         * @param {String} key - metadata key
+         * @param {String} value - metadata value
+         */
+        function associateMeta(index, key, value) {
+            var testId = ctrl.data.results[index].id;
+            var metaUrl = [
+                testapiApiUrl, '/results/', testId, '/meta/', key
+            ].join('');
+
+            var editFlag = key + 'Edit';
+            if (value) {
+                ctrl.associateRequest = $http.post(metaUrl, value)
+                    .success(function () {
+                        ctrl.data.results[index][editFlag] = false;
+                    }).error(function (error) {
+                        raiseAlert('danger', error.title, error.detail);
+                    });
+            }
+            else {
+                ctrl.unassociateRequest = $http.delete(metaUrl)
+                    .success(function () {
+                        ctrl.data.results[index][editFlag] = false;
+                    }).error(function (error) {
+                        if (error.code == 404) {
+                            // Key doesn't exist, so count it as a success,
+                            // and don't raise an alert.
+                            ctrl.data.results[index][editFlag] = false;
+                        }
+                        else {
+                            raiseAlert('danger', error.title, error.detail);
+                        }
+                    });
+            }
+        }
+
+        /**
+         * Retrieve an array of available capability files from the TestAPI
+         * API server, sort this array reverse-alphabetically, and store it in
+         * a scoped variable.
+         * Sample API return array: ["2015.03.json", "2015.04.json"]
+         */
+        function getVersionList() {
+            if (ctrl.versionList) {
+                return;
+            }
+            var content_url = testapiApiUrl + '/guidelines';
+            ctrl.versionsRequest =
+                $http.get(content_url).success(function (data) {
+                    ctrl.versionList = data.sort().reverse();
+                }).error(function (error) {
+                    raiseAlert('danger', error.title,
+                               'Unable to retrieve version list');
+                });
+        }
+
+        /**
+         * Get products user has management rights to or all products depending
+         * on the passed in parameter value.
+         */
+        function getUserProducts() {
+            if (ctrl.products) {
+                return;
+            }
+            var contentUrl = testapiApiUrl + '/products';
+            ctrl.productsRequest =
+                $http.get(contentUrl).success(function (data) {
+                    ctrl.products = {};
+                    angular.forEach(data.products, function(prod) {
+                        if (prod.can_manage) {
+                            ctrl.products[prod.id] = prod;
+                        }
+                    });
+                }).error(function (error) {
+                    ctrl.products = null;
+                    ctrl.showError = true;
+                    ctrl.error =
+                        'Error retrieving Products listing from server: ' +
+                        angular.toJson(error);
+                });
+        }
+
+        /**
+         * Send a PUT request to the API server to associate a product with
+         * a test result.
+         */
+        function associateProductVersion(result) {
+            var verId = (result.selectedVersion ?
+                         result.selectedVersion.id : null);
+            var testId = result.id;
+            var url = testapiApiUrl + '/results/' + testId;
+            ctrl.associateRequest = $http.put(url, {'product_version_id':
+                                                    verId})
+                .success(function (data) {
+                    result.product_version = result.selectedVersion;
+                    if (result.selectedVersion) {
+                        result.product_version.product_info =
+                            result.selectedProduct;
+                    }
+                    result.productEdit = false;
+                }).error(function (error) {
+                    raiseAlert('danger', error.title, error.detail);
+                });
+        }
+
+        /**
+         * Get all versions for a product.
+         */
+        function getProductVersions(result) {
+            if (!result.selectedProduct) {
+                result.productVersions = [];
+                result.selectedVersion = null;
+                return;
+            }
+
+            var url = testapiApiUrl + '/products/' +
+                result.selectedProduct.id + '/versions';
+            ctrl.getVersionsRequest = $http.get(url)
+                .success(function (data) {
+                    result.productVersions = data;
+
+                    // If the test result isn't already associated to a
+                    // version, default it to the null version.
+                    if (!result.product_version) {
+                        angular.forEach(data, function(ver) {
+                            if (!ver.version) {
+                                result.selectedVersion = ver;
+                            }
+                        });
+                    }
+                }).error(function (error) {
+                    raiseAlert('danger', error.title, error.detail);
+                });
+        }
+
+        /**
+         * Instantiate variables needed for editing product/version
+         * associations.
+         */
+        function prepVersionEdit(result) {
+            result.productEdit = true;
+            if (result.product_version) {
+                result.selectedProduct =
+                    ctrl.products[result.product_version.product_info.id];
+            }
+            result.selectedVersion = result.product_version;
+            ctrl.getProductVersions(result);
+        }
+
+
+
+        function gotoResultDetail(testId, innerID) {
+            $state.go('resultsDetail', {'testID': testId, 'innerID': innerID});
+        }
+
+    }
+})();