aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPanagiotis Karalis <pkaralis@intracom-telecom.com>2019-01-24 15:04:15 +0200
committerPanagiotis Karalis <pkaralis@intracom-telecom.com>2019-04-10 18:06:01 +0300
commit71bdc6752f47b7da7282f786570fbe717973fb6d (patch)
treef8bc25e843293b52bd7012d9861941498f7a1b58
parentc64b58a5a89ae7ac51f4f7b41e2842980e112346 (diff)
Enhanced OVP Web Portal
The OVP web portal is updated with some improvements. Those improvements are focused on the styling part of the portal as well as on the introduction of new functions related to the reviews, applications and the generally flow. JIRA: DOVETAIL-670 JIRA: DOVETAIL-760 Change-Id: Ic5ca90eaaee36de43486ff55ad9aa788136587c6 Signed-off-by: Panagiotis Karalis <pkaralis@intracom-telecom.com>
-rw-r--r--3rd_party/static/testapi-ui/app.js24
-rw-r--r--3rd_party/static/testapi-ui/assets/css/cvp-style.css28
-rw-r--r--3rd_party/static/testapi-ui/components/application/application.html231
-rw-r--r--3rd_party/static/testapi-ui/components/application/applicationController.js198
-rw-r--r--3rd_party/static/testapi-ui/components/profile/profile.html61
-rw-r--r--3rd_party/static/testapi-ui/components/profile/profileController.js26
-rw-r--r--3rd_party/static/testapi-ui/components/results/modal/applicationModal.html191
-rw-r--r--3rd_party/static/testapi-ui/components/results/modal/applicationView.html107
-rw-r--r--3rd_party/static/testapi-ui/components/results/modal/reviewsModal.html41
-rw-r--r--3rd_party/static/testapi-ui/components/results/results.html57
-rw-r--r--3rd_party/static/testapi-ui/components/results/resultsController.js262
-rw-r--r--3rd_party/static/testapi-ui/index.html4
-rw-r--r--3rd_party/static/testapi-ui/shared/header/header.html7
-rw-r--r--opnfv_testapi/resources/test_handlers.py5
-rw-r--r--opnfv_testapi/router/url_mappings.py1
15 files changed, 892 insertions, 351 deletions
diff --git a/3rd_party/static/testapi-ui/app.js b/3rd_party/static/testapi-ui/app.js
index edf7663..55603aa 100644
--- a/3rd_party/static/testapi-ui/app.js
+++ b/3rd_party/static/testapi-ui/app.js
@@ -55,11 +55,11 @@
templateUrl: 'testapi-ui/components/guidelines/guidelines.html',
controller: 'GuidelinesController as ctrl'
}).
- // state('communityResults', {
- // url: '/community_results',
- // templateUrl: 'testapi-ui/components/results/results.html',
- // controller: 'ResultsController as ctrl'
- // }).
+ state('communityResults', {
+ url: '/community_results',
+ templateUrl: 'testapi-ui/components/results/results.html',
+ controller: 'ResultsController as ctrl'
+ }).
state('userResults', {
url: '/user_results',
templateUrl: 'testapi-ui/components/results/results.html',
@@ -173,12 +173,26 @@
$rootScope.auth.doSignIn = doSignIn;
$rootScope.auth.doSignOut = doSignOut;
$rootScope.auth.doSignCheck = doSignCheck;
+ $rootScope.auth.canReview = canReview;
var sign_in_url = testapiApiUrl + '/auth/signin';
var sign_out_url = testapiApiUrl + '/auth/signout';
var profile_url = testapiApiUrl + '/profile';
+ function canReview(user) {
+ if (typeof user.role == undefined) {
+ return false;
+ } else if (user.role.indexOf('administrator') != -1) {
+ return true;
+ } else if (user.role.indexOf('reviewer') != -1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
/** This function initiates a sign in. */
function doSignIn(type) {
$rootScope.auth.type = type;
diff --git a/3rd_party/static/testapi-ui/assets/css/cvp-style.css b/3rd_party/static/testapi-ui/assets/css/cvp-style.css
index ed1d938..e6d3ab1 100644
--- a/3rd_party/static/testapi-ui/assets/css/cvp-style.css
+++ b/3rd_party/static/testapi-ui/assets/css/cvp-style.css
@@ -2,6 +2,15 @@
font-size: 18px;
}
+.nav>li>a:hover,
+.nav>li>a:focus,
+.nav>li.active,
+.nav>li.active>a {
+ background-color: #27CFC3;
+ color: #1C1C1C;
+}
+
+
table {
font-size: 15px;
}
@@ -96,3 +105,22 @@ table .btn.medium {
a {
cursor: pointer;
}
+
+.btn-success-cust {
+color: #fff;
+background-color: #27CFC3;
+border-color: #27CFC3;
+}
+
+.btn-success-cust:focus, .btn-success-cust:hover {
+border-color: #1FA79C;
+background-color: #1FA79C;
+}
+
+input:invalid {
+ border: 2px dashed red;
+}
+
+input:valid {
+ border: 2px solid black;
+}
diff --git a/3rd_party/static/testapi-ui/components/application/application.html b/3rd_party/static/testapi-ui/components/application/application.html
index 0b45ab3..5e78546 100644
--- a/3rd_party/static/testapi-ui/components/application/application.html
+++ b/3rd_party/static/testapi-ui/components/application/application.html
@@ -1,207 +1,4 @@
<div class="container-fluid common-main-container">
- <div class="top-site-banner">
- <div class="container">
- <p class="p1">Complete this application then start your CVP journey</p>
- </div>
- </div>
-
- <div class="row" style="margin-top: 20px;">
- <div class="col-lg-12 container">
- <form id="OsLogoProgramForm_Form" action="/brand/logo-request/Form" method="post"
- enctype="application/x-www-form-urlencoded">
- <p id="OsLogoProgramForm_Form_error" class="message" style="display: none;"></p>
- <fieldset>
- <div class="field text col-md-4">
- <label class="left" >Organization name</label>
- <i uib-tooltip="Organization name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.organization_name" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Organization website (if public)</label>
- <i uib-tooltip="Organization website if it is public"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.organization_web" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="col-md-4"></div>
- <div class="field email text col-md-4">
- <label class="left">Product name and/or identifier</label>
- <i uib-tooltip="Product name and/or identifier" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="email text form-control" ng-model="ctrl.product_name" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Product specifications</label>
- <i uib-tooltip="A link of product specifications"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.product_spec" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Product public documentation</label>
- <i uib-tooltip="A link of product public documentation"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.product_documentation" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Product categories</label>
- <i uib-tooltip="Product categories" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <select class="form-control" ng-model="ctrl.product_categories">
- <option value="soft&hard">software and hardware</option>
- <option value="soft&3rd">software and third party hardware</option>
- </select>
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary contact name</label>
- <i uib-tooltip="Primary contact name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_name" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary business email</label>
- <i uib-tooltip="Only the Business email address should be used for official communication with OPNFV CVP"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_email" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary postal address</label>
- <i uib-tooltip="Primary postal address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_address" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary phone number</label>
- <i uib-tooltip="Primary phone number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_phone" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Description</label>
- <i uib-tooltip="Product Description" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.description">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">SUT Version</label>
- <i uib-tooltip="SUT Version" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.sut_version">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">SUT HW Version</label>
- <i uib-tooltip="SUT HW Version - leave blank if not applicable"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.sut_hw_version">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">OVP Version</label>
- <i uib-tooltip="OVP Version" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.ovp_version">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">OVP Category</label>
- <i uib-tooltip="OVP Category" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.ovp_category">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Company Logo</label>
- <i uib-tooltip="Company Logo" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.company_logo">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Approve Date</label>
- <i uib-tooltip="Approve Date - YYYY-MM-DD" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.approve_date">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Approved</label>
- <i uib-tooltip="Approved - insert true or false" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.approved">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Test ID</label>
- <i uib-tooltip="Test ID - enter approved test_id"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.test_id">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Location</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">
- <option value="internal">internal vendor lab</option>
- <option value="third">third-party lab</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">
- </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="text" class="text form-control" ng-model="ctrl.lab_email">
- </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">
- </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="text" class="text form-control" ng-model="ctrl.lab_phone">
- </div>
- </div>
- </fieldset>
- </form>
- </div>
- </div>
- <div class="Actions">
- <button class="btn btn-success cvp-btn" ng-click="ctrl.openConfirmModal()">Submit</button>
- </div>
<div class="results-table" style="margin-top: 30px; overflow: scroll;">
<table class="table table-striped table-hover">
<thead>
@@ -217,7 +14,7 @@
<th>Primary business email</th>
<th>Primary postal address</th>
<th>Primary phone number</th>
- <th>Owner</th>
+ <th>User ID</th>
<th>Description</th>
<th>SUT version</th>
<th>SUT HW version</th>
@@ -225,7 +22,6 @@
<th>OVP category</th>
<th>Company logo</th>
<th>Approve date</th>
- <th>Approved</th>
<th>Test ID</th>
<th>Location</th>
<th>Operation</th>
@@ -284,7 +80,6 @@
<td>{{ app.ovp_category }}</td>
<td>{{ app.company_logo }}</td>
<td>{{ app.approve_date }}</td>
- <td>{{ app.approved }}</td>
<td>{{ app.test_id }}</td>
<td>
<span popover-enable="app.lab_location != 'internal'" uib-popover-template="ctrl.lab_tpl"
@@ -293,7 +88,13 @@
<i ng-if="app.lab_location != 'internal'" class="glyphicon glyphicon-info-sign opnfv-blue"></i>
</td>
<td>
- <a ng-click="ctrl.deleteApp(app._id)" class="badge badge-info">
+ <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>
@@ -315,20 +116,4 @@
</uib-pagination>
</div>
</div>
-
- <div>
- <br>
- <h3>Company Logo Upload for Directory</h3>
- <form enctype="multipart/form-data" method="post">
- <div class="form-group col-m-3">
- <input class="form-contrl btn btn-success cvp-btn medium accent-color regular-button" file-model="logoFile"
- type="file">
- </div>
- <div class="form-group col-m-3">
- <a class="btn btn-success cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadLogo()">
- <span>Upload Logo</span>
- </a>
- </div>
- </form>
- </div>
</div>
diff --git a/3rd_party/static/testapi-ui/components/application/applicationController.js b/3rd_party/static/testapi-ui/components/application/applicationController.js
index e2a4f75..6ae157e 100644
--- a/3rd_party/static/testapi-ui/components/application/applicationController.js
+++ b/3rd_party/static/testapi-ui/components/application/applicationController.js
@@ -28,35 +28,36 @@
$uibModal, testapiApiUrl, raiseAlert, ngDialog, $scope) {
var ctrl = this;
- ctrl.uploadLogo = uploadLogo;
+// ctrl.uploadLogo = uploadLogo;
function init() {
- ctrl.organization_name = null;
- ctrl.organization_web = null;
- ctrl.product_name = null;
- ctrl.product_spec = null;
- ctrl.product_documentation = null;
- ctrl.product_categories = "soft&hard";
- ctrl.prim_name = null;
- ctrl.prim_email = null;
- ctrl.prim_address = null;
- ctrl.prim_phone = null;
- ctrl.description = null;
- ctrl.sut_version = null;
- ctrl.sut_hw_version = null;
- ctrl.ovp_version = "2018.01";
- ctrl.ovp_category = "Infrastructure";
- ctrl.company_logo = null;
- ctrl.approve_date = null;
- ctrl.approved = "false";
- ctrl.test_id = null;
- ctrl.lab_location = "internal";
- ctrl.lab_name = null;
- ctrl.lab_email = null;
- ctrl.lab_address = null;
- ctrl.lab_phone = null;
ctrl.applications = [];
- ctrl.showApplications = [];
+// ctrl.organization_name = null;
+// ctrl.organization_web = null;
+// ctrl.product_name = null;
+// ctrl.product_spec = null;
+// ctrl.product_documentation = null;
+// ctrl.product_categories = "soft&hard";
+// ctrl.prim_name = null;
+// ctrl.prim_email = null;
+// ctrl.prim_address = null;
+// ctrl.prim_phone = null;
+// ctrl.description = null;
+// ctrl.sut_version = null;
+// ctrl.sut_hw_version = null;
+// ctrl.ovp_version = "2018.01";
+// ctrl.ovp_category = "Infrastructure";
+// ctrl.company_logo = null;
+// ctrl.approve_date = null;
+// ctrl.approved = "false";
+// ctrl.test_id = null;
+// ctrl.lab_location = "internal";
+// ctrl.lab_name = null;
+// ctrl.lab_email = null;
+// ctrl.lab_address = null;
+// ctrl.lab_phone = null;
+// ctrl.applications = [];
+// ctrl.showApplications = [];
ctrl.totalItems = null;
ctrl.currentPage = 1;
@@ -70,52 +71,52 @@
}
- ctrl.submitForm = function() {
- var data = {
- "organization_name": ctrl.organization_name,
- "organization_web": ctrl.organization_web,
- "product_name": ctrl.product_name,
- "product_spec": ctrl.product_spec,
- "product_documentation": ctrl.product_documentation,
- "product_categories": ctrl.product_categories,
- "prim_name": ctrl.prim_name,
- "prim_email": ctrl.prim_email,
- "prim_address": ctrl.prim_address,
- "prim_phone": ctrl.prim_phone,
- "description": ctrl.description,
- "sut_version": ctrl.sut_version,
- "sut_hw_version": ctrl.sut_hw_version,
- "ovp_version": ctrl.ovp_version,
- "ovp_category": ctrl.ovp_category,
- "company_logo": ctrl.company_logo,
- "approve_date": ctrl.approve_date,
- "approved": ctrl.approved,
- "test_id": ctrl.test_id,
- "lab_location": ctrl.lab_location,
- "lab_email": ctrl.lab_email,
- "lab_address": ctrl.lab_address,
- "lab_phone": ctrl.lab_phone
- };
- $http.post(testapiApiUrl + "/cvp/applications", data).then(function(resp) {
- if (resp.data.code && resp.data.code != 0) {
- alert(resp.data.msg);
- return;
- }
- getApplication();
- }, function(error) {
- });
- }
-
- ctrl.openConfirmModal = function() {
- var resp = confirm("Are you sure to submit?");
- if (resp) {
- ctrl.submitForm();
- }
- }
-
- ctrl.cancelSubmit = function() {
- ngDialog.close();
- }
+// ctrl.submitForm = function() {
+// var data = {
+// "organization_name": ctrl.organization_name,
+// "organization_web": ctrl.organization_web,
+// "product_name": ctrl.product_name,
+// "product_spec": ctrl.product_spec,
+// "product_documentation": ctrl.product_documentation,
+// "product_categories": ctrl.product_categories,
+// "prim_name": ctrl.prim_name,
+// "prim_email": ctrl.prim_email,
+// "prim_address": ctrl.prim_address,
+// "prim_phone": ctrl.prim_phone,
+// "description": ctrl.description,
+// "sut_version": ctrl.sut_version,
+// "sut_hw_version": ctrl.sut_hw_version,
+// "ovp_version": ctrl.ovp_version,
+// "ovp_category": ctrl.ovp_category,
+// "company_logo": ctrl.company_logo,
+// "approve_date": ctrl.approve_date,
+// "approved": ctrl.approved,
+// "test_id": ctrl.test_id,
+// "lab_location": ctrl.lab_location,
+// "lab_email": ctrl.lab_email,
+// "lab_address": ctrl.lab_address,
+// "lab_phone": ctrl.lab_phone
+// };
+// $http.post(testapiApiUrl + "/cvp/applications", data).then(function(resp) {
+// if (resp.data.code && resp.data.code != 0) {
+// alert(resp.data.msg);
+// return;
+// }
+// getApplication();
+// }, function(error) {
+// });
+// }
+
+// ctrl.openConfirmModal = function() {
+// var resp = confirm("Are you sure to submit?");
+// if (resp) {
+// ctrl.submitForm();
+// }
+// }
+//
+// ctrl.cancelSubmit = function() {
+// ngDialog.close();
+// }
ctrl.updatePage = function() {
getApplication();
@@ -136,23 +137,52 @@
});
}
- function uploadLogo() {
- var file = $scope.logoFile;
- var fd = new FormData();
- fd.append('file', file);
+ 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;
- $http.post(testapiApiUrl + "/cvp/applications/uploadlogo", fd, {
+ 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': undefined}
- }).then(function(resp) {
- if (resp.data.code && resp.data.code != 0) {
- alert(resp.data.msg);
- return;
- }
+ 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 uploadLogo() {
+// var file = $scope.logoFile;
+// var fd = new FormData();
+// fd.append('file', file);
+//
+// $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;
+// }
+// }, function(error) {
+// });
+//
+// };
function getApplication() {
$http.get(testapiApiUrl + "/cvp/applications?page=" + ctrl.currentPage + "&signed&per_page=" + ctrl.itemsPerPage).then(function(response) {
diff --git a/3rd_party/static/testapi-ui/components/profile/profile.html b/3rd_party/static/testapi-ui/components/profile/profile.html
index 563adbf..cfcc79a 100644
--- a/3rd_party/static/testapi-ui/components/profile/profile.html
+++ b/3rd_party/static/testapi-ui/components/profile/profile.html
@@ -23,6 +23,67 @@
</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 ng-show="ctrl.pubkeys">
<div class="container-fluid">
<div class="row">
diff --git a/3rd_party/static/testapi-ui/components/profile/profileController.js b/3rd_party/static/testapi-ui/components/profile/profileController.js
index 0660e19..506771d 100644
--- a/3rd_party/static/testapi-ui/components/profile/profileController.js
+++ b/3rd_party/static/testapi-ui/components/profile/profileController.js
@@ -51,12 +51,38 @@
ctrl.updatePubKeys = updatePubKeys;
ctrl.openImportPubKeyModal = openImportPubKeyModal;
ctrl.openShowPubKeyModal = openShowPubKeyModal;
+ 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");
+ });
+ }
+
/**
* This function will fetch all the user's public keys from the
* server and store them in an array.
diff --git a/3rd_party/static/testapi-ui/components/results/modal/applicationModal.html b/3rd_party/static/testapi-ui/components/results/modal/applicationModal.html
new file mode 100644
index 0000000..e7c4609
--- /dev/null
+++ b/3rd_party/static/testapi-ui/components/results/modal/applicationModal.html
@@ -0,0 +1,191 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Complete this application then start your CVP journey</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" >Organization name</label>
+ <i uib-tooltip="Organization name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.organization_name"
+ ng-init="ctrl.organization_name=auth.currentUser.companyName" required
+ aria-required="true">
+ </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">Organization website</label>
+ <i uib-tooltip="Organization website if it is public"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="url" class="text form-control" ng-model="ctrl.organization_web"
+ ng-init="ctrl.organization_web=auth.currentUser.companyWebsite" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product name and/or identifier</label>
+ <i uib-tooltip="Product name and/or identifier" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="email text form-control" ng-model="ctrl.product_name" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product specifications</label>
+ <i uib-tooltip="A link of product specifications"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.product_spec" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product public documentation</label>
+ <i uib-tooltip="A link of product public documentation"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.product_documentation" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product categories</label>
+ <i uib-tooltip="Product categories" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <select class="form-control" ng-model="ctrl.product_categories" ng-init="ctrl.product_categories='soft&hard'">
+ <option value="soft&hard">software and hardware</option>
+ <option value="soft&3rd">software and third party hardware</option>
+ </select>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary contact name</label>
+ <i uib-tooltip="Primary contact name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.prim_name"
+ ng-init="ctrl.prim_name=auth.currentUser.primaryContactName" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary business email</label>
+ <i uib-tooltip="Only the Business email address should be used for official communication with OPNFV CVP"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="email" class="text form-control" ng-model="ctrl.prim_email"
+ ng-init="ctrl.prim_email=auth.currentUser.primaryBusinessEmail" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary postal address</label>
+ <i uib-tooltip="Primary postal address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.prim_address"
+ ng-init="ctrl.prim_address=auth.currentUser.primaryPostalAddress" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary phone number</label>
+ <i uib-tooltip="Primary phone number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.prim_phone"
+ ng-init="ctrl.prim_phone=auth.currentUser.primaryPhoneNumber" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Description</label>
+ <i uib-tooltip="Product Description" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.description" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Version</label>
+ <i uib-tooltip="SUT Version" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.sut_version" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Label</label>
+ <i uib-tooltip="SUT Label" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.sut_label" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT HW Version</label>
+ <i uib-tooltip="SUT HW Version - leave blank if not applicable"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.sut_hw_version" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">OVP Category</label>
+ <i uib-tooltip="OVP Category" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.ovp_category" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Location</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'">
+ <option value="internal">internal vendor lab</option>
+ <option value="third">third-party lab</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="text" 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="text" 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/testapi-ui/components/results/modal/applicationView.html b/3rd_party/static/testapi-ui/components/results/modal/applicationView.html
new file mode 100644
index 0000000..3cbbcb5
--- /dev/null
+++ b/3rd_party/static/testapi-ui/components/results/modal/applicationView.html
@@ -0,0 +1,107 @@
+<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">Organization name</label>
+ <div class="middleColumn">{{ ctrl.application.organization_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">Organization website</label>
+ <div class="middleColumn">{{ ctrl.application.organization_web }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product name and/or identifier</label>
+ <div class="middleColumn">{{ ctrl.application.product_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product specifications</label>
+ <div class="middleColumn">{{ ctrl.application.product_spec }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product public documentation</label>
+ <div class="middleColumn">{{ ctrl.application.product_documentation }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product categories</label>
+ <div class="middleColumn">{{ ctrl.application.product_categories }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary contact name</label>
+ <div class="middleColumn">{{ ctrl.application.prim_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary business email</label>
+ <div class="middleColumn">{{ ctrl.application.prim_email }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary postal address</label>
+ <div class="middleColumn">{{ ctrl.application.prim_address }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary phone number</label>
+ <div class="middleColumn">{{ ctrl.application.prim_phone }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Description</label>
+ <div class="middleColumn">{{ ctrl.application.description }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Version</label>
+ <div class="middleColumn">{{ ctrl.application.sut_version }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Label</label>
+ <div class="middleColumn">{{ ctrl.application.sut_label }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT HW Version</label>
+ <div class="middleColumn">{{ ctrl.application.sut_hw_version }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">OVP Category</label>
+ <div class="middleColumn">{{ ctrl.application.ovp_category }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Location</label>
+ <div class="middleColumn">{{ ctrl.application.lab_location }}</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/testapi-ui/components/results/modal/reviewsModal.html b/3rd_party/static/testapi-ui/components/results/modal/reviewsModal.html
new file mode 100644
index 0000000..c93d1ef
--- /dev/null
+++ b/3rd_party/static/testapi-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/testapi-ui/components/results/results.html b/3rd_party/static/testapi-ui/components/results/results.html
index bc15169..30bcd94 100644
--- a/3rd_party/static/testapi-ui/components/results/results.html
+++ b/3rd_party/static/testapi-ui/components/results/results.html
@@ -1,17 +1,18 @@
<div class="container-fluid common-main-container">
<h3>{{ctrl.pageHeader}}</h3>
<p>{{ctrl.pageParagraph}}</p>
- <form class="form-inline" ng-show="ctrl.isUserResults">
+ <form class="form-inline" ng-show="ctrl.isUserResults"
+ ng-if="auth.isAuthenticated && auth.currentUser.role.indexOf('user') != -1">
<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 cvp-btn medium accent-color regular-button" type="file"
+ <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 cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadFile()">
+ <a class="btn btn-success-cust cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadFile()">
<span>upload result</span>
</a>
</div>
@@ -36,7 +37,8 @@
<th>Status</th>
<th>Log</th>
<th>SUT</th>
- <th>SUT Version</th>
+ <th>Application</th>
+ <th>Review Status</th>
<th class="col-md-2">Operation</th>
<th class="col-md-2">Share List</th>
</tr>
@@ -62,43 +64,52 @@
<td><a ng-click="ctrl.downloadLogs(result.id)">logs</a></td>
<td><a ng-click="ctrl.gotoSUT(result.id)">info</a></td>
<td>
- <div class="popover-wrapper">
- <a editable-theme="bs3" onbeforesave="ctrl.changeLabel(result, 'sut_label', $data)"
- editable-text="result.sut_label">{{ result.sut_label || "None" }}</a>
- </div>
+ <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 cvp-btn medium accent-color regular-button"
+ <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"
+ <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.toPrivate(result, 'private')">withdraw submit</a>
+ <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"
+ <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.toReview(result, 'review')">submit to review</a>
+ 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('administrator') != -1"
+ <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.status == 'approved' || result.status == 'private'}"
- ng-click="ctrl.toggleCheck(result, 'status', 'approved')">approve</a>
+ <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('administrator') != -1"
+ <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.status == 'not approved' || result.status == 'private'}"
- ng-click="ctrl.toggleCheck(result, 'status', 'not approved')">not approve</a>
+ <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"
+ <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"
+ <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>
@@ -108,7 +119,7 @@
<td>
<div class="btn-group" uib-dropdown>
<a id="single-button-two" type="button"
- class="btn btn-success cvp-btn medium accent-color regular-button" style="width: 130px;"
+ 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>
diff --git a/3rd_party/static/testapi-ui/components/results/resultsController.js b/3rd_party/static/testapi-ui/components/results/resultsController.js
index 6e4e0ac..1fb4f0d 100644
--- a/3rd_party/static/testapi-ui/components/results/resultsController.js
+++ b/3rd_party/static/testapi-ui/components/results/resultsController.js
@@ -37,6 +37,24 @@
};
}]);
+ 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'
];
@@ -62,7 +80,6 @@
ctrl.gotoSUT = gotoSUT;
ctrl.gotoResultDetail = gotoResultDetail;
ctrl.toggleCheck = toggleCheck;
- ctrl.changeLabel = changeLabel;
ctrl.toReview = toReview;
ctrl.toPrivate = toPrivate;
ctrl.removeSharedUser = removeSharedUser;
@@ -70,6 +87,16 @@
ctrl.openSharedModal = openSharedModal;
ctrl.downloadLogs = downloadLogs;
ctrl.deleteTest = deleteTest;
+ ctrl.deleteApplication = deleteApplication;
+ ctrl.openApplicationModal = openApplicationModal;
+ ctrl.toApprove = toApprove;
+ ctrl.toDisapprove = toDisapprove;
+ ctrl.toUndo = toUndo;
+ ctrl.openConfirmModal = openConfirmModal;
+ ctrl.openApplicationView = openApplicationView;
+ ctrl.submitApplication = submitApplication;
+ ctrl.openReviewsModal = openReviewsModal;
+ ctrl.doReview = doReview;
/** Mappings of Interop WG components to marketing program names. */
ctrl.targetMappings = {
@@ -110,10 +137,17 @@
// ctrl.isUserResults = $state.current.name === 'userResults';
// need auth to browse
ctrl.isUserResults = $state.current.name === 'userResults';
+ 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 user-results-page if authenticated.
if (ctrl.isUserResults && !$scope.auth.isAuthenticated) {
$state.go('home');
}
@@ -167,6 +201,216 @@
});
}
+ function deleteApplication (result) {
+ var resp = confirm('Are you sure you want to delete this application?');
+ if (!resp)
+ return;
+
+ $http.get(testapiApiUrl + "/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.organization_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 = {
+ "organization_name": ctrl.organization_name,
+ "organization_web": ctrl.organization_web,
+ "product_name": ctrl.product_name,
+ "product_spec": ctrl.product_spec,
+ "product_documentation": ctrl.product_documentation,
+ "product_categories": ctrl.product_categories,
+ "prim_name": ctrl.prim_name,
+ "prim_email": ctrl.prim_email,
+ "prim_address": ctrl.prim_address,
+ "prim_phone": ctrl.prim_phone,
+ "description": ctrl.description,
+ "sut_version": ctrl.sut_version,
+ "sut_label": ctrl.sut_label,
+ "sut_hw_version": ctrl.sut_hw_version,
+ "ovp_version": result.version,
+ "ovp_category": ctrl.ovp_category,
+ "company_logo": logo_name,
+ "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
+ };
+
+ $http.post(testapiApiUrl + "/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: 'testapi-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 + "/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: 'testapi-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 + '/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: 'testapi-ui/components/results/modal/reviewsModal.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function doReview(test, outcome) {
+ var createUrl = testapiApiUrl + "/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 OVP 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 toggleCheck(result, item, newValue) {
var id = result._id;
var updateUrl = testapiApiUrl + "/tests/"+ id;
@@ -189,10 +433,6 @@
});
}
- function changeLabel(result, key, data){
- toggleCheck(result, key, data);
- }
-
function toReview(result, value){
var resp = confirm('Once you submit a test result for review, it will become readable to all OVP reviewers. Do you want to proceed?');
if(resp){
@@ -291,20 +531,24 @@
function update() {
ctrl.showError = false;
// Construct the API URL based on user-specified filters.
- var content_url = testapiApiUrl + '/tests' +
- '?page=' + ctrl.currentPage;
+ var content_url = testapiApiUrl + '/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 =
content_url + '&from=' + start + ' 00:00:00';
}
- var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd');
if (end) {
content_url = content_url + '&to=' + end + ' 23:59:59';
}
if (ctrl.isUserResults) {
- content_url = content_url + '&signed'+'&per_page='+ ctrl.itemsPerPage;
+ content_url += '&signed';
+ } else {
+ content_url += '&status={"$ne":"private"}&review';
}
+
ctrl.resultsRequest =
$http.get(content_url).success(function (data) {
ctrl.data = data;
diff --git a/3rd_party/static/testapi-ui/index.html b/3rd_party/static/testapi-ui/index.html
index 94aff67..961e4cf 100644
--- a/3rd_party/static/testapi-ui/index.html
+++ b/3rd_party/static/testapi-ui/index.html
@@ -30,6 +30,7 @@
<link rel="stylesheet" href="testapi-ui/node_modules/ng-dialog/css/ngDialog.min.css">
<link rel="stylesheet" href="testapi-ui/node_modules/ng-dialog/css/ngDialog-theme-default.min.css">
<link rel="stylesheet" href="testapi-ui/node_modules/angular-xeditable/dist/css/xeditable.min.css">
+ <link rel="stylesheet" href="testapi-ui/assets/css/combine.css">
<!-- CSS Internal Code -->
<link rel="stylesheet" href="testapi-ui/assets/css/cvp-style.css">
@@ -75,7 +76,8 @@
</head>
<body class="container-fluid home page-template-default page page-id-6 do-etfw tribe-no-js ascend wpb-js-composer
- js-comp-ver-5.2.1 vc_responsive index-header">
+ js-comp-ver-5.2.1 vc_responsive index-header"
+ ng-controller="HeaderController as header">
<header ng-include src="'testapi-ui/shared/header/header.html'"></header>
<div ui-view></div>
<footer ng-include src="'testapi-ui/shared/footer/footer.html'"></footer>
diff --git a/3rd_party/static/testapi-ui/shared/header/header.html b/3rd_party/static/testapi-ui/shared/header/header.html
index 54470e7..fad240c 100644
--- a/3rd_party/static/testapi-ui/shared/header/header.html
+++ b/3rd_party/static/testapi-ui/shared/header/header.html
@@ -19,7 +19,12 @@
ng-if="auth.isAuthenticated && auth.currentUser.role.indexOf('administrator') != -1">
<a ui-sref="application">Applications</a>
</li>
- <li ng-class="{ active: header.isActive('/user_results')}" ng-if="auth.isAuthenticated">
+ <li ng-class="{ active: header.isActive('/community_results')}"
+ ng-if="auth.isAuthenticated && auth.canReview(auth.currentUser)">
+ <a ui-sref="communityResults">Incoming Reviews</a>
+ </li>
+ <li ng-class="{ active: header.isActive('/user_results')}"
+ ng-if="auth.isAuthenticated && auth.currentUser.role.indexOf('user') != -1">
<a ui-sref="userResults">My Results</a>
</li>
<li ng-class="{ active: header.isActive('/profile')}" ng-if="auth.isAuthenticated">
diff --git a/opnfv_testapi/resources/test_handlers.py b/opnfv_testapi/resources/test_handlers.py
index 7ab20dc..7c5078a 100644
--- a/opnfv_testapi/resources/test_handlers.py
+++ b/opnfv_testapi/resources/test_handlers.py
@@ -294,11 +294,6 @@ class TestsGURHandler(GenericTestHandler):
self.finish_request({'code': 403, 'msg': msg})
return
- if not self.is_onap and not test['sut_label']:
- msg = 'Please fill out SUT version before submission'
- self.finish_request({'code': 403, 'msg': msg})
- return
-
query['owner'] = curr_user
db_keys.append('owner')
diff --git a/opnfv_testapi/router/url_mappings.py b/opnfv_testapi/router/url_mappings.py
index 65c8480..4dc4893 100644
--- a/opnfv_testapi/router/url_mappings.py
+++ b/opnfv_testapi/router/url_mappings.py
@@ -56,6 +56,7 @@ mappings = [
(r'/api/v1/auth/signin_return_cas', sign.SigninReturnCasHandler),
(r'/api/v1/auth/signout', sign.SignoutHandler),
(r'/api/v1/profile', user.ProfileHandler),
+ (r'/api/v1/reviews', review_handlers.ReviewsCLHandler)
]