aboutsummaryrefslogtreecommitdiffstats
path: root/3rd_party/static/onap-ui/components
diff options
context:
space:
mode:
authorpkaralis <pkaralis@intracom-telecom.com>2018-12-06 00:43:12 +0200
committerPanagiotis Karalis <pkaralis@intracom-telecom.com>2019-03-20 15:28:23 +0200
commitd0bbf3b8952379883550c6eb2062476a6d15043e (patch)
tree106f65b223054077279bda7ff988a73bea314a34 /3rd_party/static/onap-ui/components
parent5f20495d6e3ec984c4e86fd76399ddf0d042b336 (diff)
Enable Web Portal for ONAP results
The web portal needs to be able to read test results of the ONAP compliance program and display them. In order for the above goal to be achieved, the following two parts should be impacted: 1- A new front-end should be prepared in order to handle and display the results 2- The REST API should be extended in order to support the aforementioned operation. JIRA: DOVETAIL-669 Change-Id: I36bbb6e602a67020d7e27aedbfc776f5cf4f3dc3 Signed-off-by: pkaralis <pkaralis@intracom-telecom.com> Co-Authored-By: Stamatis Katsaounis <mokats@intracom-telecom.com>
Diffstat (limited to '3rd_party/static/onap-ui/components')
-rw-r--r--3rd_party/static/onap-ui/components/application/application.html111
-rw-r--r--3rd_party/static/onap-ui/components/application/applicationController.js110
-rw-r--r--3rd_party/static/onap-ui/components/auth-failure/authFailureController.js33
-rw-r--r--3rd_party/static/onap-ui/components/directory/directory.html34
-rw-r--r--3rd_party/static/onap-ui/components/directory/directoryController.js45
-rw-r--r--3rd_party/static/onap-ui/components/home/home.html170
-rw-r--r--3rd_party/static/onap-ui/components/home/homeController.js58
-rw-r--r--3rd_party/static/onap-ui/components/logout/logout.html1
-rw-r--r--3rd_party/static/onap-ui/components/logout/logoutController.js44
-rw-r--r--3rd_party/static/onap-ui/components/profile/profile.html88
-rw-r--r--3rd_party/static/onap-ui/components/profile/profileController.js68
-rw-r--r--3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json13
-rw-r--r--3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json13
-rw-r--r--3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html60
-rw-r--r--3rd_party/static/onap-ui/components/results-report/resultsReport.html33
-rw-r--r--3rd_party/static/onap-ui/components/results-report/resultsReportController.js224
-rw-r--r--3rd_party/static/onap-ui/components/results/modal/applicationModal.html158
-rw-r--r--3rd_party/static/onap-ui/components/results/modal/applicationView.html103
-rw-r--r--3rd_party/static/onap-ui/components/results/modal/reviewsModal.html41
-rw-r--r--3rd_party/static/onap-ui/components/results/modal/sharedModal.html16
-rw-r--r--3rd_party/static/onap-ui/components/results/results.html168
-rw-r--r--3rd_party/static/onap-ui/components/results/resultsController.js614
22 files changed, 2205 insertions, 0 deletions
diff --git a/3rd_party/static/onap-ui/components/application/application.html b/3rd_party/static/onap-ui/components/application/application.html
new file mode 100644
index 0000000..2238ca4
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/application/application.html
@@ -0,0 +1,111 @@
+<div class="container-fluid common-main-container">
+ <div class="results-table" style="margin-top: 30px; overflow: scroll;">
+ <table class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th>Create Date</th>
+ <th>Owner</th>
+ <th>ONAP version</th>
+ <th>Company Name</th>
+ <th>Company logo</th>
+ <th>Company Website</th>
+ <th>Approve date</th>
+ <th>Test ID</th>
+ <th>xNF Version</th>
+ <th>xNF Name</th>
+ <th>xNF Type</th>
+ <th>xNF Description</th>
+ <th>xNF Id</th>
+ <th>xNF Model Language</th>
+ <th>xNF Checksum (SHA256)</th>
+ <th>Test Period</th>
+ <th>Location</th>
+ <th>Operation</th>
+ </tr>
+ </thead>
+ <script type="text/ng-template" id="product.tpl.html">
+ <div class="input-group">
+ <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
+ <input type="text" value="{{app.product_spec}}">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon">@</span>
+ <input type="text" value="{{app.product_documentation}}">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon"><i class="glyphicon glyphicon-map-marker"></i></span>
+ <input type="text" value="{{app.product_categories | category}}">
+ </div>
+ </script>
+ <script type="text/ng-template" id="lab.tpl.html">
+ <div class="input-group">
+ <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
+ <input type="text" value="{{app.lab_name}}">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon">@</span>
+ <input type="text" value="{{app.lab_email}}">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon"><i class="glyphicon glyphicon-map-marker"></i></span>
+ <input type="text" value="{{app.lab_address}}">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon"><i class="glyphicon glyphicon-phone"></i></span>
+ <input type="text" value="{{app.lab_phone}}">
+ </div>
+ </script>
+ <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
+ <tr ng-if="results.status != 'review'" ng-repeat="app in ctrl.applications">
+ <td>{{ app.creation_date | limitTo: 10 }}</td>
+ <td>{{ app.owner }}</td>
+ <td>{{ app.onap_version }}</td>
+ <td>{{ app.company_name }}</td>
+ <td>{{ app.company_logo }}</td>
+ <td>{{ app.company_website }}</td>
+ <td>{{ app.approve_date | limitTo: 10 }}</td>
+ <td>{{ app.test_id }}</td>
+ <td>{{ app.xnf_version }}</td>
+ <td>{{ app.xnf_name }}</td>
+ <td>{{ app.xnf_type }}</td>
+ <td>{{ app.xnf_description }}</td>
+ <td>{{ app.xnfd_id }}</td>
+ <td>{{ app.xnfd_model_lang }}</td>
+ <td>{{ app.xnf_checksum }}</td>
+ <td>{{ app.xnf_test_period }}</td>
+ <td>
+ <span popover-enable="app.lab_location != 'internal'" uib-popover-template="ctrl.lab_tpl"
+ popover-title="Lab Info" popover-placement="top"
+ popover-trigger="mouseenter">{{ app.lab_location | labLocation}}</span>
+ <i ng-if="app.lab_location != 'internal'" class="glyphicon glyphicon-info-sign opnfv-blue"></i>
+ </td>
+ <td>
+ <a ng-click="ctrl.toggleApproveApp(app._id, 'true')" class="badge badge-info"
+ ng-if="app.approved == 'false'"
+ data-toggle="tooltip" title="Approve Application">
+ <i class="glyphicon glyphicon-ok" ></i>
+ </a>
+ <a ng-click="ctrl.deleteApp(app._id)" class="badge badge-info"
+ data-toggle="tooltip" title="Delete Application">
+ <i class="glyphicon glyphicon-remove" ></i>
+ </a>
+ </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.updatePage()">
+ </uib-pagination>
+ </div>
+ </div>
+</div>
diff --git a/3rd_party/static/onap-ui/components/application/applicationController.js b/3rd_party/static/onap-ui/components/application/applicationController.js
new file mode 100644
index 0000000..094ffdc
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/application/applicationController.js
@@ -0,0 +1,110 @@
+/*
+ * 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('ApplicationController', ApplicationController);
+
+ ApplicationController.$inject = [
+ '$http', '$stateParams', '$window', '$sce',
+ '$uibModal', 'testapiApiUrl', 'raiseAlert', 'ngDialog', '$scope'
+ ];
+
+ /**
+ */
+ function ApplicationController($http, $stateParams, $window, $sce,
+ $uibModal, testapiApiUrl, raiseAlert, ngDialog, $scope) {
+
+ var ctrl = this;
+
+ function init() {
+ ctrl.applications = [];
+
+ ctrl.totalItems = null;
+ ctrl.currentPage = 1;
+ ctrl.itemsPerPage = 5;
+ ctrl.numPages = null;
+
+ ctrl.lab_tpl = "lab.tpl.html";
+ ctrl.product_tpl = "product.tpl.html";
+
+ getApplication();
+ }
+
+ ctrl.updatePage = function() {
+ getApplication();
+ }
+
+ ctrl.deleteApp = function(id) {
+ var resp = confirm('Are you sure you want to delete this application?');
+ if (!resp)
+ return;
+
+ var delUrl = testapiApiUrl + "/cvp/applications/" + id;
+ $http.delete(delUrl)
+ .then(function(ret) {
+ if (ret.data.code && ret.data.code != 0) {
+ alert(ret.data.msg);
+ return;
+ }
+ getApplication();
+ });
+ }
+
+ ctrl.toggleApproveApp = function(id, approved) {
+ if (approved === 'true') {
+ var text = 'Are you sure you want to approve this application?';
+ } else {
+ var text = 'Are you sure you want to remove approval of this application?';
+ }
+
+ var resp = confirm(text);
+ if (!resp)
+ return;
+
+ var updateUrl = testapiApiUrl + "/cvp/applications/" + id;
+ var data = {};
+ data['item'] = 'approved';
+ data['approved'] = approved;
+
+ $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);
+ return;
+ }
+ getApplication();
+ }, function(error) {
+ alert('Error when update data');
+ });
+ }
+
+ function getApplication() {
+ $http.get(testapiApiUrl + "/onap/cvp/applications?page=" + ctrl.currentPage + "&signed&per_page=" + ctrl.itemsPerPage).then(function(response) {
+ ctrl.applications = response.data.applications;
+ ctrl.totalItems = response.data.pagination.total_pages * ctrl.itemsPerPage;
+ ctrl.currentPage = response.data.pagination.current_page;
+ ctrl.numPages = response.data.pagination.total_pages;
+ }, function(error) {
+ /* do nothing */
+ });
+ }
+
+ init();
+ }
+})();
diff --git a/3rd_party/static/onap-ui/components/auth-failure/authFailureController.js b/3rd_party/static/onap-ui/components/auth-failure/authFailureController.js
new file mode 100644
index 0000000..29d1d70
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/auth-failure/authFailureController.js
@@ -0,0 +1,33 @@
+/*
+ * 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('AuthFailureController', AuthFailureController);
+
+ AuthFailureController.$inject = ['$location', '$state', 'raiseAlert'];
+ /**
+ * TestAPI Auth Failure Controller
+ * This controller handles messages from TestAPI API if user auth fails.
+ */
+ function AuthFailureController($location, $state, raiseAlert) {
+ var ctrl = this;
+ ctrl.message = $location.search().message;
+ raiseAlert('danger', 'Authentication Failure:', ctrl.message);
+ $state.go('home');
+ }
+})();
diff --git a/3rd_party/static/onap-ui/components/directory/directory.html b/3rd_party/static/onap-ui/components/directory/directory.html
new file mode 100644
index 0000000..4a04bd7
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/directory/directory.html
@@ -0,0 +1,34 @@
+<div class="container-fluid common-main-container">
+ <h3>ONAP Verified Product Directory</h3>
+ <div>
+ <h4>Compliance Marks Granted to {{ctrl.companyID}}</h4>
+ <img src="api/v1/cvp/applications/getlogo/{{ctrl.company_logo}}" alt="Company Logo">
+ <table class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th>Product Name</th>
+ <th>Description</th>
+ <th>Model Language</th>
+ <th>Artifact Checksum (SHA256)</th>
+ <th>Product Version</th>
+ <th>Version</th>
+ <th>Date</th>
+ <th>Product Info</th>
+ </tr>
+ </thead>
+ <tbody class="directory_inner" style="overflow: hidden; text-overflow: ellipsis;">
+ <tr style="vertical-align: center;" ng-repeat="prod in ctrl.directory"
+ ng-if="prod.company_name==ctrl.companyID && prod.approved=='true'">
+ <td style="width: 250px;">{{ prod.xnf_name }}</td>
+ <td style="width: 350px;">{{ prod.xnf_description }}</td>
+ <td style="width: 350px;">{{ prod.xnfd_model_lang }}</td>
+ <td style="width: 350px;">{{ prod.xnf_checksum }}</td>
+ <td style="width: 150px;">{{ prod.xnf_version }}</td>
+ <td style="width: 150px;">{{ prod.onap_version }}</td>
+ <td style="width: 150px;">{{ prod.approve_date | limitTo: 10 }}</td>
+ <td style="width: 150px;"><a href="{{ prod.company_website }}" target="_blank" rel="noopener">{{ prod.company_website }}</a></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/3rd_party/static/onap-ui/components/directory/directoryController.js b/3rd_party/static/onap-ui/components/directory/directoryController.js
new file mode 100644
index 0000000..a4fc6f3
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/directory/directoryController.js
@@ -0,0 +1,45 @@
+/*
+ * 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('DirectoryController', DirectoryController);
+
+ DirectoryController.$inject = ['$http', '$stateParams',
+ 'testapiApiUrl'
+ ];
+
+ /**
+ * This controller handles the directory page
+ */
+ function DirectoryController($http, $stateParams, testapiApiUrl) {
+ var ctrl = this;
+
+ ctrl.companyID = $stateParams.companyID;
+ ctrl.company_logo = $stateParams.logo;
+ getDirectory();
+
+ function getDirectory() {
+ $http.get(testapiApiUrl + "/onap/cvp/applications").then(function(response) {
+ ctrl.directory = response.data.applications;
+ }, function(error) {
+ /* do nothing */
+ });
+ }
+ }
+
+})();
diff --git a/3rd_party/static/onap-ui/components/home/home.html b/3rd_party/static/onap-ui/components/home/home.html
new file mode 100644
index 0000000..4db08b0
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/home/home.html
@@ -0,0 +1,170 @@
+<div class="container-fluid">
+ <div class="row">
+ <div class="col-md-2 home-category" ng-style="{'height': ctrl.height}">
+ <div class="panel-group" id="accordion">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="panel-title">
+ <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
+ Governance &amp; Workflow
+ </a>
+ </div>
+ </div>
+ <div id="collapseOne" class="panel-collapse collapse">
+ <div class="panel-body">
+ <div>
+ <a href="https://www.opnfv.org/verified"
+ target="_blank" rel="noopener">Overview&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="https://www.opnfv.org/wp-content/uploads/sites/12/2018/09/LFN_CVP_Guidelines-1.0.0.pdf"
+ target="_blank" rel="noopener">Governance Guidelines&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="https://www.opnfv.org/wp-content/uploads/sites/12/2018/09/OVP-Terms-and-Conditions-092418.pdf"
+ target="_blank" rel="noopener">Terms &amp; Conditions&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/certificationworkflow/index.html"
+ target="_blank" rel="noopener">Process Workflow&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=dc24bf38-ea41-40d4-9e58-9babc6eec778"
+ target="_blank" rel="noopener">Participation Form&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="https://wiki.onap.org/display/DW/VNF+Badging"
+ target="_blank" rel="noopener">ONAP Verified Brand Guidelines&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="panel panel-default" style="margin-top: 0px;">
+ <div class="panel-heading">
+ <div class="panel-title">
+ <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo">
+ Release 2018.11
+ </a>
+ </div>
+ </div>
+ <div id="collapseTwo" class="panel-collapse collapse">
+ <div class="panel-body">
+ <div>
+ <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/userguide/testing_guide.html"
+ target="_blank" rel="noopener">ONAPVP / Dovetail User Guide&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/userguide/cli_reference.html"
+ target="_blank" rel="noopener">Dovetail CLI&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="https://wiki.onap.org/display/DW/ONAP+Modeling+specification"
+ target="_blank" rel="noopener">Test Specifications&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="https://wiki.onap.org/display/DW/Release+Calendar"
+ target="_blank" rel="noopener">Release Notes&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/reviewerguide/index.html"
+ target="_blank" rel="noopener">Reviewer Guide&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ <div>
+ <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/ovpaddendum/index.html"
+ target="_blank" rel="noopener">Guidelines Addendum&nbsp;
+ <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-md-10">
+ <div class="common-main-container">
+ <div class="home-content-title">
+ <h2>ONAP Verified Program verifies products and services with the "ONAP Verified" mark.</h2>
+ </div>
+ <div class="home-content">
+ <div class="col-md-2">
+ <img class="home-content-img" src="onap-ui/assets/img/icon.png" alt="ONAP">
+ </div>
+ <div class="col-md-10">
+ <p class="home-content-text" style="padding-bottom: 40px;">
+ The ONAP Verified Program demonstrates the readiness and availability of commercial VNF/PNF
+ products and services by implementing Specification defined by Compliance Verification
+ Committee(CVC). This open source community-led initiative allows vendors and service
+ providers to establish baseline conformance and interoperability while retaining distinct
+ and value-added innovations across features and capabilities and requires verified products
+ to complete additional functional, high-availability tests. View the directory of verified
+ products and services below and navigate through the links in the left-hand menu to learn
+ more and get started. You will find step-by-step instructions as well as a participation form.
+ Use this portal to upload your test results when ready. Please send any questions to
+ <a href="mailto:compliance@lists.lfnetworking.org">compliance@lists.lfnetworking.org</a><sup>
+ <span class="glyphicon glyphicon-envelope" style="font-size: 60%;" aria-hidden="true"></span></sup>.
+ </p>
+ </div>
+ </div>
+ <div id="directory_break">
+ </div>
+ <div class="home-content-title">
+ <h1>ONAP Verified Products Directory</h1>
+ Click on rows for more product verification details per company.
+ </div>
+ <div class="directory_main">
+ <table id="directory_inner" class="">
+ <thead>
+ <tr>
+ <th>Company Name &amp; Logo</th>
+ <th>Test Agency</th>
+ <th>Product Name</th>
+ <th>Product Version</th>
+ <th>Modeling Language</th>
+ <th>Type</th>
+ <th>Version</th>
+ </tr>
+ </thead>
+ <tbody style="overflow: hidden; text-overflow: ellipsis;">
+ <tr class="company_row" ng-click="ctrl.getCompany(app)"
+ ng-repeat="app in ctrl.applications | filter:{approved:true} | orderBy : '-approve_date'">
+ <td style="width: 400px;">
+ <img class="company_logo" ng-src="api/v1/cvp/applications/getlogo/{{app.company_logo}}" alt="{{app.company_logo}}">
+ {{ app.company_name }}
+ </td>
+ <td style="width: 300px;">{{ app.lab_location }}</td>
+ <td style="width: 300px;">{{ app.xnf_name }}</td>
+ <td style="width: 150px;">{{ app.xnf_version }}</td>
+ <td style="width: 150px;">{{ app.xnfd_model_lang }}</td>
+ <td style="width: 150px;">N/A</td>
+ <td style="width: 150px;">{{ app.onap_version}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/3rd_party/static/onap-ui/components/home/homeController.js b/3rd_party/static/onap-ui/components/home/homeController.js
new file mode 100644
index 0000000..678dd2a
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/home/homeController.js
@@ -0,0 +1,58 @@
+/*
+ * 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('HomeController', HomeController);
+
+ HomeController.$inject = [
+ '$http', '$rootScope', '$state', 'testapiApiUrl'
+ ];
+
+ /**
+ * TestAPI Results Controller
+ * This controller is for the '/results' page where a user can browse
+ * a listing of community uploaded results.
+ */
+ function HomeController($http, $rootScope, $state, testapiApiUrl) {
+ var ctrl = this;
+ getApplication();
+
+ ctrl.height = $(document).height() + 500;
+
+ ctrl.gotoApplication = function() {
+ if ($rootScope.auth.isAuthenticated) {
+ $state.go('application');
+ } else {
+ $rootScope.auth.doSignIn('cas');
+ }
+ }
+
+ function getApplication() {
+ $http.get(testapiApiUrl + "/onap/cvp/applications").then(function(response) {
+ ctrl.applications = response.data.applications;
+ }, function(error) {
+ /* do nothing */
+ });
+ }
+
+ ctrl.getCompany = function(row) {
+ $state.go('directory', {'companyID': row.company_name, 'logo': row.company_logo});
+ }
+
+ }
+})();
diff --git a/3rd_party/static/onap-ui/components/logout/logout.html b/3rd_party/static/onap-ui/components/logout/logout.html
new file mode 100644
index 0000000..38a5c36
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/logout/logout.html
@@ -0,0 +1 @@
+<div cg-busy="{promise:ctrl.redirectWait,message:'Logging you out...'}"></div>
diff --git a/3rd_party/static/onap-ui/components/logout/logoutController.js b/3rd_party/static/onap-ui/components/logout/logoutController.js
new file mode 100644
index 0000000..1b6d78c
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/logout/logoutController.js
@@ -0,0 +1,44 @@
+/*
+ * 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('LogoutController', LogoutController);
+
+ LogoutController.$inject = [
+ '$location', '$window', '$timeout'
+ ];
+
+ /**
+ * TestAPI Logout Controller
+ * This controller handles logging out. In order to fully logout, the
+ * openstackid_session cookie must also be removed. The way to do that
+ * is to have the user's browser make a request to the openstackid logout
+ * page. We do this by placing the logout link as the src for an html
+ * image. After some time, the user is redirected home.
+ */
+ function LogoutController($location, $window, $timeout) {
+ var ctrl = this;
+
+ ctrl.openid_logout_url = $location.search().openid_logout;
+ var img = new Image(0, 0);
+ img.src = ctrl.openid_logout_url;
+ ctrl.redirectWait = $timeout(function() {
+ $window.location.href = '/';
+ }, 500);
+ }
+})();
diff --git a/3rd_party/static/onap-ui/components/profile/profile.html b/3rd_party/static/onap-ui/components/profile/profile.html
new file mode 100644
index 0000000..cb73335
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/profile/profile.html
@@ -0,0 +1,88 @@
+<div class="container-fluid common-main-container">
+ <h3>User profile</h3>
+ <div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div>
+ <div>
+ <table class="table table-striped table-hover">
+ <tbody>
+ <tr>
+ <td>User name</td>
+ <td>{{auth.currentUser.fullname}}</td>
+ </tr>
+ <tr>
+ <td>User OpenId</td>
+ <td>{{auth.currentUser.openid}}</td>
+ </tr>
+ <tr>
+ <td>Email</td>
+ <td>{{auth.currentUser.email}}</td>
+ </tr>
+ <tr>
+ <td>Role</td>
+ <td>{{auth.currentUser.role}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <br>
+ <br>
+ <h3>Organization Details</h3>
+ <table class="table table-striped table-hover">
+ <tbody>
+ <tr>
+ <td>Company Name</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'companyName', $data)"
+ editable-text="ctrl.profile.companyName">{{ ctrl.profile.companyName || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Company website</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'companyWebsite', $data)"
+ editable-url="ctrl.profile.companyWebsite">{{ ctrl.profile.companyWebsite || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Name</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryContactName', $data)"
+ editable-text="ctrl.profile.primaryContactName">{{ ctrl.profile.primaryContactName || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Business email</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryBusinessEmail', $data)"
+ editable-email="ctrl.profile.primaryBusinessEmail">{{ ctrl.profile.primaryBusinessEmail || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Postal Address</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryPostalAddress', $data)"
+ editable-text="ctrl.profile.primaryPostalAddress">{{ ctrl.profile.primaryPostalAddress || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Phone Number</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryPhoneNumber', $data)"
+ editable-tel="ctrl.profile.primaryPhoneNumber">{{ ctrl.profile.primaryPhoneNumber || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/3rd_party/static/onap-ui/components/profile/profileController.js b/3rd_party/static/onap-ui/components/profile/profileController.js
new file mode 100644
index 0000000..1b84d76
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/profile/profileController.js
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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('ProfileController', ProfileController);
+
+ ProfileController.$inject = [
+ '$scope', '$state', '$http', 'testapiApiUrl'
+ ];
+
+ /**
+ * TestAPI Profile Controller
+ * This controller handles user's profile page, where a user can view
+ * account-specific information.
+ */
+ function ProfileController($scope, $state, $http, testapiApiUrl) {
+
+ var ctrl = this;
+
+ ctrl.changeProfileDetails = changeProfileDetails;
+
+ // Must be authenticated to view this page.
+ if (!$scope.auth.isAuthenticated) {
+ $state.go('home');
+ }
+
+ ctrl.authRequest = $scope.auth.doSignCheck();
+ ctrl.profile = $scope.auth.currentUser;
+
+ function changeProfileDetails(profile, key, newValue){
+ if (profile[key] === newValue) {
+ return;
+ }
+ var updateUrl = testapiApiUrl + "/profile";
+
+ var data = {};
+ data[key] = 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 {
+ profile[key] = newValue;
+ }
+ }, function(error) {
+ alert("Error when update data");
+ });
+ }
+ }
+})();
diff --git a/3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json b/3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json
new file mode 100644
index 0000000..1f584f4
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json
@@ -0,0 +1,13 @@
+{
+ "mandatory": {
+ "onap-vvp.validate.heat": {
+ "cases": [
+ "onap-vvp.validate.heat"
+ ],
+ "total": 1
+ }
+ },
+ "optional": {
+
+ }
+}
diff --git a/3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json b/3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json
new file mode 100644
index 0000000..de01e83
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json
@@ -0,0 +1,13 @@
+{
+ "mandatory": {
+ "onap-vtp.validate.csar": {
+ "cases": [
+ "onap-vtp.validate.csar"
+ ],
+ "total": 1
+ }
+ },
+ "optional": {
+
+ }
+}
diff --git a/3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html b/3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html
new file mode 100644
index 0000000..3f3e9c9
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html
@@ -0,0 +1,60 @@
+<!--
+HTML for each accordion group that separates the status types on the results
+report page.
+-->
+
+Test Filters:<br>
+<div class="btn-toolbar" role="toolbar">
+ <div class="btn-group button-margin" data-toggle="buttons">
+ <label class="btn btn-default" ng-click="ctrl.changeStatus('total')"
+ ng-class="{'active': ctrl.testStatus === 'total'}">
+ <input type="radio" ng-model="ctrl.testStatus" value="total" name="total">
+ <span class="text-primary">All</span>
+ </label>
+ <label class="btn btn-default" ng-click="ctrl.changeStatus('passed')"
+ ng-class="{'active': ctrl.testStatus === 'passed'}">
+ <input type="radio" ng-model="ctrl.testStatus" value="passed" name="passed">
+ <span class="text-success">Passed</span>
+ </label>
+ <label class="btn btn-default" ng-click="ctrl.changeStatus('not passed')"
+ ng-class="{'active': ctrl.testStatus === 'not passed'}">
+ <input type="radio" ng-model="ctrl.testStatus" value="not passed" name="not passed">
+ <span class="text-danger">Not Passed</span>
+ </label>
+ </div>
+ <div class="btn-group button-margin" style="float: right;">
+ <button type="button" class="btn btn-default" ng-click="ctrl.openAll()">Expand</button>
+ <button type="button" class="btn btn-default" ng-click="ctrl.folderAll()">Collapse</button>
+ </div>
+</div>
+
+<uib-accordion-group ng-repeat="(type,data) in ctrl.data" is-open="isOpen">
+ <uib-accordion-heading>
+ {{ type }}: {{ ctrl.statistics[type].total }} tests
+ <i class="pull-right glyphicon"
+ ng-class="{'glyphicon-chevron-down': isOpen, 'glyphicon-chevron-right': !isOpen}"></i>
+ </uib-accordion-heading>
+ <ol class="capabilities">
+ <li ng-repeat="(area, value) in data"
+ ng-show="(ctrl.testStatus == 'passed' && value.pass != 0) || (ctrl.testStatus == 'not passed' && value.fail != 0) || ctrl.testStatus == 'total'">
+ <a ng-click="value.folder = !value.folder">
+ {{ area }}
+ <span ng-if="ctrl.testStatus == 'total'"
+ ng-class="{'text-success': value.total == value.pass, 'text-warning': (value.pass < value.total && value.pass > 0), 'text-danger': value.pass == 0}">
+ [{{ value.pass }}/{{ value.total }}]
+ </span>
+ <span ng-if="ctrl.testStatus == 'passed'" class="text-success">[{{ value.pass }}]</span>
+ <span ng-if="ctrl.testStatus == 'not passed'" class="text-danger">[{{ value.fail }}]</span>
+ </a>
+ <a uib-tooltip="view log" ng-click="ctrl.gotoResultLog(area)"><span class="glyphicon glyphicon-cog"></span></a>
+ <ul class="list-unstyled" uib-collapse="value.folder">
+ <li ng-repeat="case in value.cases"
+ ng-if="(ctrl.testStatus=='passed' && ctrl.case_list.indexOf(case) > -1) || (ctrl.testStatus=='not passed' && ctrl.case_list.indexOf(case) == -1) || ctrl.testStatus=='total'">
+ <span ng-class="{'glyphicon glyphicon-ok text-success':ctrl.case_list.indexOf(case) > -1, 'glyphicon glyphicon-remove text-warning':ctrl.case_list.indexOf(case) == -1}"
+ aria-hidden="true"></span>
+ <a ng-click="ctrl.gotoDoc(case)">{{ case }}</a>
+ </li>
+ </ul>
+ </li>
+ </ol>
+</uib-accordion-group>
diff --git a/3rd_party/static/onap-ui/components/results-report/resultsReport.html b/3rd_party/static/onap-ui/components/results-report/resultsReport.html
new file mode 100644
index 0000000..38e602d
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results-report/resultsReport.html
@@ -0,0 +1,33 @@
+<div class="container-fluid common-main-container">
+ <h3>Test Run Results</h3>
+
+ <div ng-show="ctrl.testId" class="container-fluid">
+ <div class="row">
+ <div class="pull-left">
+ <div class="test-report">
+ <strong>ONAP Version:</strong> {{ctrl.version}}<br>
+ <strong>Test ID:</strong> {{ctrl.testId}}<br>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <strong>Total: {{ctrl.statistics.total}}, Pass: {{ ctrl.statistics.pass}}, Rate: {{ ctrl.statistics.pass / ctrl.statistics.total * 100 | number:2 }}%</strong><br>
+ <strong>Mandatory Total: {{ctrl.statistics.mandatory.total}}, Pass: {{ ctrl.statistics.mandatory.pass }}, Rate: {{ ctrl.statistics.mandatory.pass / ctrl.statistics.mandatory.total * 100 | number:2 }}%</strong><br>
+ <strong>Optional Total: {{ctrl.statistics.optional.total}}, Pass: {{ ctrl.statistics.optional.pass }}, Rate: {{ ctrl.statistics.optional.pass / ctrl.statistics.optional.total * 100 | number:2 }}%</strong><br>
+ <hr>
+ <strong>{{ ctrl.validation }}</strong><br>
+
+ <div>
+ <hr>
+ <h4>Test Result Overview</h4>
+ <uib-accordion close-others=false>
+ <!-- The ng-repeat is used to pass in a local variable to the template. -->
+ <ng-include
+ src="ctrl.detailsTemplate"
+ onload="isOpen = true">
+ </ng-include>
+ <br>
+ </uib-accordion>
+ </div>
+</div>
diff --git a/3rd_party/static/onap-ui/components/results-report/resultsReportController.js b/3rd_party/static/onap-ui/components/results-report/resultsReportController.js
new file mode 100644
index 0000000..09601ad
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results-report/resultsReportController.js
@@ -0,0 +1,224 @@
+/*
+ * 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('ResultsReportController', ResultsReportController);
+
+ ResultsReportController.$inject = [
+ '$scope', '$http', '$stateParams', '$window',
+ 'testapiApiUrl'
+ ];
+
+ /**
+ * TestAPI Results Report Controller
+ * This controller is for the '/results/<test run ID>' page where a user can
+ * view details for a specific test run.
+ */
+ function ResultsReportController($scope, $http, $stateParams, $window,
+ testapiApiUrl) {
+
+ var ctrl = this;
+
+ ctrl.testStatus = 'total';
+ ctrl.case_list = [];
+ ctrl.data = {};
+ ctrl.statistics = {
+ 'total': 0, 'pass': 0, 'fail': 0,
+ 'mandatory': {'total': 0, 'pass': 0, 'fail': 0, 'area': 0},
+ 'optional': {'total': 0, 'pass': 0, 'fail': 0, 'area': 0}
+ };
+
+ ctrl.gotoDoc = gotoDoc;
+ ctrl.openAll = openAll;
+ ctrl.folderAll = folderAll;
+ ctrl.gotoResultLog = gotoResultLog;
+ ctrl.changeStatus = changeStatus;
+
+ /** The testID extracted from the URL route. */
+ ctrl.testId = $stateParams.testID;
+ ctrl.innerId = $stateParams.innerID;
+ ctrl.validation = '';
+ ctrl.vnf_type = '';
+ ctrl.vnf_checksum = '';
+ ctrl.version = '';
+
+ /** The HTML template that all accordian groups will use. */
+ ctrl.detailsTemplate = 'onap-ui/components/results-report/partials/' +
+ 'reportDetails.html';
+
+ $scope.load_finish = false;
+
+ function changeStatus(value) {
+ ctrl.testStatus = value;
+ }
+
+ function extend(case_list) {
+ angular.forEach(case_list, function(ele) {
+ ctrl.case_list.push(ele);
+ });
+ }
+
+ function strip(word) {
+ return word.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ }
+
+ function gotoResultLog(case_name) {
+ var case_area = case_name.split(".")[0];
+ var log_url = "/logs/" + ctrl.testId + "/results/";
+ log_url += case_area + "_logs/" + case_name + ".out";
+ var is_reachable = false;
+
+ $.ajax({
+ url: log_url,
+ async: false,
+ success: function (response) {
+ is_reachable = true;
+ },
+ error: function (response) {
+ alert("Log file could not be found. Please confirm this case has been executed successfully.");
+ }
+ });
+
+ if (is_reachable == true) {
+ window.open(log_url);
+ }
+ }
+
+ $scope.$watch('load_finish', function() {
+ if ($scope.load_finish == true) {
+ var case_url = 'onap-ui/components/results-report/data/' + ctrl.version + '/' + ctrl.vnf_type + '-testcases.json'
+ $http.get(case_url).then(function(response) {
+ ctrl.data = response.data;
+
+ angular.forEach(ctrl.data.mandatory, function(value, name) {
+ ctrl.data.mandatory[name].folder = true;
+ ctrl.data.mandatory[name].pass = 0;
+ ctrl.data.mandatory[name].fail = 0;
+ angular.forEach(value.cases, function(sub_case) {
+ ctrl.statistics.total += 1;
+ ctrl.statistics.mandatory.total += 1;
+ if (ctrl.case_list.indexOf(sub_case) > -1) {
+ ctrl.data.mandatory[name].pass += 1;
+ ctrl.statistics.mandatory.pass += 1;
+ ctrl.statistics.pass += 1;
+ } else {
+ ctrl.data.mandatory[name].fail += 1;
+ ctrl.statistics.mandatory.fail += 1;
+ ctrl.statistics.fail += 1;
+ }
+ });
+ });
+
+ angular.forEach(ctrl.data.optional, function(value, name) {
+ ctrl.data.optional[name].folder = true;
+ ctrl.data.optional[name].pass = 0;
+ ctrl.data.optional[name].fail = 0;
+ angular.forEach(value.cases, function(sub_case) {
+ ctrl.statistics.total += 1;
+ ctrl.statistics.optional.total += 1;
+ if (ctrl.case_list.indexOf(sub_case) > -1) {
+ ctrl.data.optional[name].pass += 1;
+ ctrl.statistics.optional.pass += 1;
+ ctrl.statistics.pass += 1;
+ } else {
+ ctrl.data.optional[name].fail += 1;
+ ctrl.statistics.optional.fail += 1;
+ ctrl.statistics.fail += 1;
+ }
+
+ });
+ });
+
+ ctrl.statistics.mandatory.area = Object.keys(ctrl.data.mandatory).length;
+ ctrl.statistics.optional.area = Object.keys(ctrl.data.optional).length;
+ }, function(error) {
+ alert('error to get test case info');
+ });
+ }
+ });
+
+ function generate_format_data() {
+ var test_url = testapiApiUrl + '/onap/tests/' + ctrl.innerId;
+ $http.get(test_url).then(function(test_resp) {
+ ctrl.validation = test_resp.data.validation;
+
+ angular.forEach(test_resp.data.results, function(result, index) {
+ var result_url = testapiApiUrl + '/results/' + result;
+ $http.get(result_url).then(function(result_resp) {
+
+ ctrl.version = result_resp.data.version;
+ ctrl.vnf_type = result_resp.data.vnf_type;
+
+ angular.forEach(result_resp.data.testcases_list, function(testcase, index) {
+ var sub_case_list = get_sub_case_list_2019_04(testcase);
+ extend(sub_case_list);
+ });
+
+ if (index == test_resp.data.results.length - 1) {
+ $scope.load_finish = true;
+ }
+ }, function(result_error) {
+ /* do nothing */
+ });
+ });
+
+ }, function(test_error) {
+ alert('Error when get test record');
+ });
+ }
+
+ function get_sub_case_list_2019_04(result) {
+ var case_list = [];
+ if (result.sub_testcase.length == 0 && result.result == "PASS") {
+ case_list.push(result.name);
+ } else {
+ angular.forEach(result.sub_testcase, function(subtest, index) {
+ if (subtest.result == "PASS") {
+ case_list.push(subtest.name)
+ }
+ });
+ }
+ return case_list;
+ }
+
+ function gotoDoc(sub_case) {
+ /* not implemented */
+ }
+
+ function openAll() {
+ angular.forEach(ctrl.data.mandatory, function(ele, id) {
+ ele.folder = false;
+ });
+ angular.forEach(ctrl.data.optional, function(ele, id) {
+ ele.folder = false;
+ });
+ }
+
+ function folderAll() {
+ angular.forEach(ctrl.data.mandatory, function(ele, id) {
+ ele.folder = true;
+ });
+ angular.forEach(ctrl.data.optional, function(ele, id) {
+ ele.folder = true;
+ });
+ }
+
+ generate_format_data();
+ }
+
+})();
diff --git a/3rd_party/static/onap-ui/components/results/modal/applicationModal.html b/3rd_party/static/onap-ui/components/results/modal/applicationModal.html
new file mode 100644
index 0000000..0ca4b84
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results/modal/applicationModal.html
@@ -0,0 +1,158 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Application Details</p>
+ </div>
+ </div>
+
+ <div class="row" style="margin-top: 20px;">
+ <div class="col-lg-12 container">
+ <p class="message" style="display: none;"></p>
+ <fieldset>
+ <div class="field text col-md-4">
+ <label class="left">Company Name</label>
+ <i uib-tooltip="Company Name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.company_name"
+ ng-init="ctrl.company_name=auth.currentUser.companyName" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Company Logo</label>
+ <i uib-tooltip="Required dimensions (Max Values): {width: 165pixels, height: 40pixels}" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input class="form-control btn btn-success-cust cvp-btn medium accent-color regular-button"
+ modal-file-model="logoFile" type="file" style="padding: 0;" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Company Website</label>
+ <i uib-tooltip="Company Website" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="url" class="text form-control" ng-model="ctrl.company_website"
+ ng-init="ctrl.company_website=auth.currentUser.companyWebsite" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary Contact Name</label>
+ <i uib-tooltip="Primary Contact name (optional)"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.primary_contact_name"
+ ng-init="ctrl.primary_contact_name=auth.currentUser.primaryContactName" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary Contact Number</label>
+ <i uib-tooltip="Primary Contact phone number(optional)"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="tel" class="text form-control" ng-model="ctrl.primary_phone_number"
+ ng-init="ctrl.primary_phone_number=auth.currentUser.primaryPhoneNumber" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary Contact Email</label>
+ <i uib-tooltip="Primary Contact email (optional)"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="email" class="text form-control" ng-model="ctrl.primary_business_email"
+ ng-init="ctrl.primary_business_email=auth.currentUser.primaryBusinessEmail" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Test Agency</label>
+ <i uib-tooltip="Location" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <select class="form-control" ng-model="ctrl.lab_location" ng-init="ctrl.lab_location='internal'" required>
+ <option value="internal">1st Party - Submitter</option>
+ <option value="third">3rd Party - External Lab</option>
+ </select>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Version</label>
+ <i uib-tooltip="xNF Version"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.xnf_version" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Name</label>
+ <i uib-tooltip="xNF Name"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.xnf_name" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Test Type</label>
+ <i uib-tooltip="xNF Type" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <select class="form-control" ng-model="ctrl.xnf_type" ng-init="ctrl.xnf_type='VNF'" required>
+ <option value="VNF">VNF</option>
+ </select>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Description</label>
+ <i uib-tooltip="xNF Description"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.xnf_description" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNFD Id</label>
+ <i uib-tooltip="xNFD Id" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.xnfd_id" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Test Category</label>
+ <i uib-tooltip="Define test category<" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <select class="form-control" ng-model="ctrl.xnf_test_period" ng-init="ctrl.xnf_test_period='Packaging Compliance Test'" required>
+ <option value="Packaging Compliance Test">Packaging Compliance Test</option>
+ <option value="Lifecycle">Lifecycle Test</option>
+ <option value="Functional">Functional Test</option>
+ <option value="Performance">Performance Test</option>
+ </select>
+ </div>
+ </div>
+ <div ng-if="ctrl.lab_location=='third'" class="field text">
+ <div class="field text col-md-4">
+ <label class="left">Lab Name</label>
+ <i uib-tooltip="Lab Name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="text" class="text form-control" ng-model="ctrl.lab_name" required>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Email</label>
+ <i uib-tooltip="Lab Email" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="email" class="text form-control" ng-model="ctrl.lab_email" required>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Address</label>
+ <i uib-tooltip="Lab Address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="text" class="text form-control" ng-model="ctrl.lab_address" required>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Phone Number</label>
+ <i uib-tooltip="Lab Phone Number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="tel" class="text form-control" ng-model="ctrl.lab_phone" required>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+ <button class="btn btn-default"
+ ng-click="ctrl.openConfirmModal(ctrl.tempResult)">Submit</button>
+</div>
+
+<style type="text/css">
+ .ngdialog.custom-background .ngdialog-content {
+ background: #ffffff;
+ }
+</style>
diff --git a/3rd_party/static/onap-ui/components/results/modal/applicationView.html b/3rd_party/static/onap-ui/components/results/modal/applicationView.html
new file mode 100644
index 0000000..79341f8
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results/modal/applicationView.html
@@ -0,0 +1,103 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Application Details</p>
+ </div>
+ </div>
+
+ <div class="row" style="margin-top: 20px;">
+ <div class="col-lg-12 container">
+ <p class="message" style="display: none;"></p>
+ <fieldset>
+ <div class="field text col-md-4">
+ <label class="left">Company Name</label>
+ <div class="middleColumn">{{ ctrl.application.company_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Company Logo</label>
+ <div class="middleColumn">{{ ctrl.application.company_logo }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Company Website</label>
+ <div class="middleColumn">{{ ctrl.application.company_website }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">ONAP Version</label>
+ <div class="middleColumn">{{ ctrl.application.onap_version }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary Contact Name</label>
+ <div class="middleColumn">{{ ctrl.application.primary_contact_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary Contact Number</label>
+ <div class="middleColumn">{{ ctrl.application.primary_phone_number }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary Contact Email</label>
+ <div class="middleColumn">{{ ctrl.application.primary_business_email }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Test Agency</label>
+ <div class="middleColumn">{{ ctrl.application.lab_location }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Version</label>
+ <div class="middleColumn">{{ ctrl.application.xnf_version }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Name</label>
+ <div class="middleColumn">{{ ctrl.application.xnf_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Test Type</label>
+ <div class="middleColumn">{{ ctrl.application.xnf_type }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Description</label>
+ <div class="middleColumn">{{ ctrl.application.xnf_description }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNFD Id</label>
+ <div class="middleColumn">{{ ctrl.application.xnfd_id }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Model Language</label>
+ <div class="middleColumn">{{ ctrl.application.xnfd_model_lang }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Test Category</label>
+ <div class="middleColumn">{{ ctrl.application.xnf_test_period }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">xNF Checksum (SHA256)</label>
+ <div class="middleColumn">{{ ctrl.application.xnf_checksum }}</div>
+ </div>
+ <div ng-if="ctrl.lab_location=='third'" class="field text">
+ <div class="field text col-md-4">
+ <label class="left">Lab Name</label>
+ <div>{{ ctrl.application.lab_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Email</label>
+ <div>{{ ctrl.application.lab_email }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Address</label>
+ <div>{{ ctrl.application.lab_address }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Phone Number</label>
+ <div>{{ ctrl.application.lab_phone }}</div>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+</div>
+
+<style type="text/css">
+ .ngdialog.custom-background .ngdialog-content {
+ background: #ffffff;
+ }
+</style>
diff --git a/3rd_party/static/onap-ui/components/results/modal/reviewsModal.html b/3rd_party/static/onap-ui/components/results/modal/reviewsModal.html
new file mode 100644
index 0000000..c93d1ef
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results/modal/reviewsModal.html
@@ -0,0 +1,41 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Community Reviews</p>
+ </div>
+ </div>
+
+ <div class="row" style="margin-top: 20px;">
+ <div class="col-lg-12 container">
+ <div cg-busy="{promise:ctrl.reviewsRequest,message:'Loading'}"></div>
+ <div ng-show="ctrl.reviews" class="results-table" style="width: 100%; overflow-x: scroll;">
+ <table ng-data="ctrl.reviews" ng-show="ctrl.reviews" class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th>Reviewer</th>
+ <th>Linux Foundation OpenId</th>
+ <th>Email</th>
+ <th>Review Date</th>
+ <th>Outcome</th>
+ </tr>
+ </thead>
+ <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
+ <tr ng-repeat="(index, review) in ctrl.reviews">
+ <td>{{ review.reviewer_name }}</td>
+ <td>{{ review.reviewer_openid }}</td>
+ <td>{{ review.reviewer_email }}</td>
+ <td>{{ review.creation_date | limitTo:19}}</td>
+ <td>{{ review.outcome }}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+</div>
+
+<style type="text/css">
+ .ngdialog.custom-background .ngdialog-content {
+ background: #ffffff;
+ }
+</style>
diff --git a/3rd_party/static/onap-ui/components/results/modal/sharedModal.html b/3rd_party/static/onap-ui/components/results/modal/sharedModal.html
new file mode 100644
index 0000000..021a355
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results/modal/sharedModal.html
@@ -0,0 +1,16 @@
+<div>
+ <h4>Enter user name or email</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/3rd_party/static/onap-ui/components/results/results.html b/3rd_party/static/onap-ui/components/results/results.html
new file mode 100644
index 0000000..ce43036
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results/results.html
@@ -0,0 +1,168 @@
+<div class="container-fluid common-main-container">
+ <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 btn btn-success-cust cvp-btn medium accent-color regular-button" type="file"
+ file-model="resultFile">
+ </div>
+ <div class="form-group col-m-3">
+ <a class="btn btn-success-cust cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadFile()">
+ <span>upload result</span>
+ </a>
+ </div>
+ <div>
+ <label>{{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" style="width: 100%; overflow-x: scroll;">
+ <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>ONAP Version</th>
+ <th>Modeling Language</th>
+ <th>Owner</th>
+ <th>File Name</th>
+ <th>Label</th>
+ <th>Status</th>
+ <th>Log</th>
+ <th>Application</th>
+ <th>Review Status</th>
+ <th class="col-md-2">Operation</th>
+ <th class="col-md-2">Share List</th>
+ </tr>
+ </thead>
+
+ <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
+ <tr ng-repeat="(index, result) in ctrl.data.tests">
+ <td>{{ result.upload_date | limitTo:19}}</td>
+ <td>
+ <a uib-tooltip="{{ result.id }}" tooltip-placement="top" tooltip-append-to-body="true"
+ ng-click="ctrl.gotoResultDetail(result.id, result._id)">{{ result.id | limitTo:8 }}</a>
+ </td>
+ <td>{{ result.version || "2019.04" }}</td>
+ <td>{{ result.vnf_type.toUpperCase() }}</td>
+ <td>{{ result.owner }}</td>
+ <td>{{ result.filename || "None"}}</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeLabel(result, 'label', $data)"
+ editable-text="result.label">{{ result.label || "None" }}</a>
+ </div>
+ </td>
+ <td>{{ result.status }}</td>
+ <td><a ng-click="ctrl.downloadLogs(result.id)">logs</a></td>
+ <td>
+ <a ng-if="result.status !='private'" ng-click="ctrl.openApplicationView(result)">View Application</a>
+ <div ng-if="result.status == 'private'">Not created</div>
+ </td>
+ <td><a ng-if="result.status !='private'" ng-click="ctrl.openReviewsModal(result.id)">View Reviews</a>
+ <div ng-if="result.status == 'private'"></div>
+ </td>
+ <td>
+ <div class="btn-group" uib-dropdown>
+ <a id="single-button" type="button" class="btn btn-success-cust cvp-btn 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.openid == result.owner && ctrl.isUserResults"
+ class="menu-item menu-item-type-post_type menu-item-object-page">
+ <a ng-class="{'hide': result.status != 'review'}"
+ ng-click="ctrl.deleteApplication(result)">withdraw submit</a>
+ </li>
+ <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults"
+ class="menu-item menu-item-type-post_type menu-item-object-page">
+ <a ng-class="{'hide': result.status != 'private'}"
+ ng-click="ctrl.openApplicationModal(result)">submit to review</a>
+ </li>
+ <li role="menuitem"
+ ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults"
+ class="menu-item menu-item-type-post_type menu-item-object-page">
+ <a ng-class="{'hide': (result.voted == 'true') || (result.status != 'review')}"
+ ng-click="ctrl.toApprove(result)">approve</a>
+ </li>
+ <li role="menuitem"
+ ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults"
+ class="menu-item menu-item-type-post_type menu-item-object-page">
+ <a ng-class="{'hide': (result.voted == 'true') || (result.status != 'review')}"
+ ng-click="ctrl.toDisapprove(result)">not approve</a>
+ </li>
+ <li role="menuitem"
+ ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults"
+ class="menu-item menu-item-type-post_type menu-item-object-page">
+ <a ng-class="{'hide': (result.voted == 'false') || (result.status != 'review')}"
+ ng-click="ctrl.toUndo(result)">undo</a>
+ </li>
+ <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults"
+ 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 && ctrl.isUserResults"
+ 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-two" type="button"
+ class="btn btn-success-cust cvp-btn 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-two"
+ style="min-width: 200%;">
+ <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 ng-if="auth.currentUser.openid == result.owner" 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;
+ }
+</style>
diff --git a/3rd_party/static/onap-ui/components/results/resultsController.js b/3rd_party/static/onap-ui/components/results/resultsController.js
new file mode 100644
index 0000000..d459495
--- /dev/null
+++ b/3rd_party/static/onap-ui/components/results/resultsController.js
@@ -0,0 +1,614 @@
+/*
+ * 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]);
+ });
+ });
+ }
+ };
+ }]);
+
+ angular
+ .module('testapiApp')
+ .directive('modalFileModel', ['$parse', function ($parse) {
+ return {
+ restrict: 'A',
+ link: function(scope, element, attrs) {
+ var model = $parse(attrs.modalFileModel);
+ var modelSetter = model.assign;
+
+ element.bind('change', function(){
+ scope.$apply(function(){
+ modelSetter(scope.$parent, 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.gotoResultDetail = gotoResultDetail;
+ ctrl.toggleCheck = toggleCheck;
+ ctrl.changeLabel = changeLabel;
+ ctrl.toApprove = toApprove;
+ ctrl.toDisapprove = toDisapprove;
+ ctrl.toUndo = toUndo;
+ ctrl.toReview = toReview;
+ ctrl.toPrivate = toPrivate;
+ ctrl.removeSharedUser = removeSharedUser;
+ ctrl.addSharedUser = addSharedUser;
+ ctrl.openSharedModal = openSharedModal;
+ ctrl.downloadLogs = downloadLogs;
+ ctrl.deleteApplication = deleteApplication;
+ ctrl.deleteTest = deleteTest;
+ ctrl.openApplicationModal = openApplicationModal;
+ ctrl.openApplicationView = openApplicationView;
+ ctrl.submitApplication = submitApplication;
+ ctrl.openConfirmModal = openConfirmModal;
+ ctrl.openReviewsModal = openReviewsModal;
+
+ /** 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';
+
+ /** Check to see if this page should display community results. */
+ ctrl.isReviewer = $scope.auth.currentUser.role.indexOf('reviewer') != -1;
+ ctrl.isAdministrator = $scope.auth.currentUser.role.indexOf('administrator') != -1;
+
+ ctrl.currentUser = $scope.auth.currentUser ? $scope.auth.currentUser.openid : null;
+
+ // Should only be on user-results-page if authenticated.
+ if (!$scope.auth.isAuthenticated) {
+ $state.go('home');
+ }
+ // Should only be on community-results if reviewer
+ if (!ctrl.isUserResults && !ctrl.isReviewer) {
+ $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 = '';
+
+ ctrl.authRequest = $scope.auth.doSignCheck().then(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 + "/onap/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 deleteApplication (result) {
+ var resp = confirm('Are you sure you want to delete this application?');
+ if (!resp)
+ return;
+
+ $http.get(testapiApiUrl + "/onap/cvp/applications?test_id=" + result.id).then(function(response) {
+ ctrl.application = response.data.applications[0];
+ var app_id = ctrl.application._id;
+ var delUrl = testapiApiUrl + "/cvp/applications/" + app_id;
+ $http.delete(delUrl)
+ .then(function(ret) {
+ if (ret.data.code && ret.data.code != 0) {
+ alert(ret.data.msg);
+ return;
+ }
+ result['status'] = 'private';
+ });
+
+ }, function(error) {
+ /* do nothing */
+ });
+
+ }
+
+ function submitApplication(result) {
+ var file = $scope.logoFile;
+ var logo_name = null;
+ if (typeof file !== 'undefined') {
+
+ var fd = new FormData();
+ fd.append('file', file);
+ fd.append('company_name', ctrl.company_name)
+
+ $http.post(testapiApiUrl + "/cvp/applications/uploadlogo", fd, {
+ transformRequest: angular.identity,
+ headers: {'Content-Type': undefined}
+ }).then(function(resp) {
+ if (resp.data.code && resp.data.code != 0) {
+ alert(resp.data.msg);
+ return;
+ } else {
+ logo_name = resp.data.filename;
+ var data = {
+ "description": ctrl.description,
+ "onap_version": result.version,
+ "company_name": ctrl.company_name,
+ "company_logo": logo_name,
+ "company_website": ctrl.company_website,
+ "approve_date": "",
+ "approved": "false",
+ "test_id": result.id,
+ "lab_location": ctrl.lab_location,
+ "lab_email": ctrl.lab_email,
+ "lab_address": ctrl.lab_address,
+ "lab_phone": ctrl.lab_phone,
+ "xnf_version": ctrl.xnf_version,
+ "certification_type": ctrl.certification_type,
+ "xnf_name": ctrl.xnf_name,
+ "xnf_type": ctrl.xnf_type,
+ "xnf_description": ctrl.xnf_description,
+ "xnfd_id": ctrl.xnfd_id,
+ "xnfd_model_lang": result.vnf_type.toUpperCase(),
+ "xnf_checksum": result.vnf_checksum,
+ "xnf_test_period": ctrl.xnf_test_period,
+ "primary_contact_name": ctrl.primary_contact_name,
+ "primary_phone_number": ctrl.primary_phone_number,
+ "primary_business_email": ctrl.primary_business_email
+ };
+
+ $http.post(testapiApiUrl + "/onap/cvp/applications", data).then(function(resp) {
+ if (resp.data.code && resp.data.code != 0) {
+ alert(resp.data.msg);
+ return;
+ }
+ toggleCheck(result, 'status', 'review');
+ }, function(error) {
+ /* do nothing */
+ });
+ }
+ }, function(error) {
+ /* do nothing */
+ });
+ logo_name = file.name;
+ }
+ ngDialog.close();
+ }
+
+ function openConfirmModal(result) {
+ var resp = confirm("Are you sure to submit?");
+ if (resp) {
+ ctrl.submitApplication(result);
+ }
+ }
+
+ function openApplicationModal(result) {
+ ctrl.tempResult = result;
+ ngDialog.open({
+ preCloseCallback: function(value) {
+ },
+ template: 'onap-ui/components/results/modal/applicationModal.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function openApplicationView(result) {
+
+ $http.get(testapiApiUrl + "/onap/cvp/applications?test_id=" + result.id).then(function(response) {
+ ctrl.application = response.data.applications[0];
+ }, function(error) {
+ /* do nothing */
+ });
+
+ ctrl.tempResult = result;
+ ngDialog.open({
+ preCloseCallback: function(value) {
+ },
+ template: 'onap-ui/components/results/modal/applicationView.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function getReviews(test) {
+ var reviews_url = testapiApiUrl + '/onap/reviews?test_id=' + test;
+ ctrl.reviewsRequest =
+ $http.get(reviews_url).success(function (data) {
+ ctrl.reviews = data.reviews;
+ }).error(function (error) {
+ ctrl.reviews = null;
+ });
+ }
+
+ function openReviewsModal(test) {
+ getReviews(test);
+ ngDialog.open({
+ preCloseCallback: function(value) {
+ },
+ template: 'onap-ui/components/results/modal/reviewsModal.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function toggleCheck(result, item, newValue) {
+ var id = result._id;
+ var updateUrl = testapiApiUrl + "/onap/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;
+ }
+ }, function(error) {
+ alert('Error when update data');
+ });
+ }
+
+ function changeLabel(result, key, data){
+ if (result[key] !== data) {
+ toggleCheck(result, key, data);
+ }
+ }
+
+ function doReview(test, outcome) {
+ var createUrl = testapiApiUrl + "/onap/reviews";
+ var data = {
+ 'test_id': test.id,
+ 'outcome': outcome
+ };
+
+ $http.post(createUrl, 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 {
+ if (outcome === null) {
+ test.voted = 'false';
+ } else {
+ test.voted = 'true';
+ }
+ }
+ }, function(error) {
+ alert('Error when creating review');
+ });
+ }
+
+ function toApprove(test) {
+ var resp = confirm('Once you approve a test result, your action will become visible. Do you want to proceed?');
+ if (resp) {
+ doReview(test, 'positive');
+ }
+ }
+
+ function toDisapprove(test) {
+ var resp = confirm('Once you disapprove a test result, your action will become visible. Do you want to proceed?');
+ if (resp) {
+ doReview(test, 'negative');
+ }
+ }
+
+ function toUndo(test) {
+ var resp = confirm('Once you undo your previous vote, your action will become visible. Do you want to proceed?');
+ if (resp) {
+ doReview(test, null);
+ }
+ }
+
+ function toReview(result, value){
+ var resp = confirm('Once you submit a test result for review, it will become readable to all ONAPVP 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: 'onap-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}
+ }).then(function(data){
+
+ if(data.data.code && data.data.code != 0){
+ alert(data.data.msg);
+ return;
+ }
+
+ ctrl.uploadState = "";
+ data.data.filename = file.name;
+ var createTestUrl = testapiApiUrl + "/onap/tests"
+
+ $http.post(createTestUrl, data.data).then(function(data){
+ if (data.data.code && data.data.code != 0) {
+ alert(data.data.msg);
+ } else {
+ ctrl.update();
+ }
+ }, function(error){
+ });
+
+ }, function(error){
+ ctrl.uploadState = "Upload failed. Error code is " + error.status;
+ });
+ }
+
+ function uploadFile(){
+ var file = $scope.resultFile;
+
+ var uploadUrl = testapiApiUrl + "/onap/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 + '/onap/tests';
+ var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd');
+ var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd');
+
+ content_url += '?page=' + ctrl.currentPage;
+ content_url += '&per_page=' + ctrl.itemsPerPage;
+ if (start) {
+ content_url += '&from=' + start + ' 00:00:00';
+ }
+ if (end) {
+ content_url += '&to=' + end + ' 23:59:59';
+ }
+ if (ctrl.isUserResults) {
+ content_url += '&signed';
+ } else {
+ content_url += '&status={"$ne":"private"}&review';
+ }
+
+ 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;
+ }).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);
+ }
+ });
+ }
+ }
+
+ function gotoResultDetail(testId, innerID) {
+ $state.go('resultsDetail', {'testID': testId, 'innerID': innerID});
+ }
+ }
+})();