summaryrefslogtreecommitdiffstats
path: root/3rd_party/static/onap-ui/components
diff options
context:
space:
mode:
authorDan Xu <xudan16@huawei.com>2019-03-22 07:44:31 +0000
committerGerrit Code Review <gerrit@opnfv.org>2019-03-22 07:44:31 +0000
commitaab171fe0b7b749a7414cc8d652b5f4662743106 (patch)
tree2108f5db2442bdbbd327ee80f2a17c9bf496d079 /3rd_party/static/onap-ui/components
parent3b78fa2aeb6c69efb86c68ba5f6c7d7efccfb024 (diff)
parentd0bbf3b8952379883550c6eb2062476a6d15043e (diff)
Merge changes I36bbb6e6,I2f597763
* changes: Enable Web Portal for ONAP results Prepare Web Portal for ONAP integration
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});
+ }
+ }
+})();