From 3bc75572f3cf412e39be0651357b8667877b17c9 Mon Sep 17 00:00:00 2001
From: Paul Van Eck <pvaneck@us.ibm.com>
Date: Wed, 9 Nov 2016 15:56:32 -0800
Subject: [PATCH] Add UI enhancements

* Provide ability for Foundation admin to mark/unmark
  a test run as verified.
* Explicitly show a test run's associated guideline/target.
* If a test is associated to a product, display that product.
* Change share/unshare to yes/no in edit dropdown.

Change-Id: Iffd4c6b99799be9b8f026b6c4a55922a9e5cb4e4
---
 refstack-ui/app/assets/css/style.css          |  6 +++
 .../results-report/resultsReport.html         | 38 +++++++++++++++++--
 .../results-report/resultsReportController.js | 35 ++++++++++++++---
 .../app/components/results/results.html       |  6 +--
 refstack-ui/tests/unit/ControllerSpec.js      | 19 ++++++++++
 5 files changed, 91 insertions(+), 13 deletions(-)

diff --git a/refstack-ui/app/assets/css/style.css b/refstack-ui/app/assets/css/style.css
index 235b79dc..3f3b4e60 100644
--- a/refstack-ui/app/assets/css/style.css
+++ b/refstack-ui/app/assets/css/style.css
@@ -80,6 +80,12 @@ h1, h2, h3, h4, h5, h6 {
   cursor: help;
 }
 
+.checkbox-verified {
+  border: 1px solid #A9A9A9;
+  text-align: center;
+  width: 150px;
+}
+
 .capabilities {
   color: #4B4B4B;
 }
diff --git a/refstack-ui/app/components/results-report/resultsReport.html b/refstack-ui/app/components/results-report/resultsReport.html
index 84960e5d..0b3c366d 100644
--- a/refstack-ui/app/components/results-report/resultsReport.html
+++ b/refstack-ui/app/components/results-report/resultsReport.html
@@ -5,22 +5,50 @@
         <div class="pull-left">
             <div class="test-report">
                 <strong>Test ID:</strong> {{ctrl.testId}}<br />
-                <div ng-if="ctrl.isEditingAllowed()"><strong>Cloud ID:</strong> {{ctrl.resultsData.cpid}}<br /></div>
+                <div ng-if="ctrl.isResultAdmin()"><strong>Cloud ID:</strong> {{ctrl.resultsData.cpid}}<br /></div>
                 <strong>Upload Date:</strong> {{ctrl.resultsData.created_at}} UTC<br />
                 <strong>Duration:</strong> {{ctrl.resultsData.duration_seconds}} seconds<br />
                 <strong>Total Number of Passed Tests:</strong>
                 <a title="See all passed tests" ng-click="ctrl.openFullTestListModal()">
                     {{ctrl.resultsData.results.length}}
-                </a><br />
-                <hr>
+                </a>
             </div>
+            <hr>
+            <div ng-show="ctrl.resultsData.product_version">
+                <strong>Product:</strong>
+                {{ctrl.resultsData.product_version.product_info.name}}
+                <span ng-if="ctrl.resultsData.product_version.version">
+                    ({{ctrl.resultsData.product_version.version}})
+                </span><br />
+            </div>
+            <div ng-show="ctrl.resultsData.meta.guideline">
+                <strong>Associated Guideline:</strong>
+                {{ctrl.resultsData.meta.guideline.slice(0, -5)}}
+            </div>
+            <div ng-show="ctrl.resultsData.meta.target">
+                <strong>Associated Target Program:</strong>
+                {{ctrl.targetMappings[ctrl.resultsData.meta.target]}}
+            </div>
+            <hr>
         </div>
         <div class="pull-right">
-            <div ng-show="ctrl.isEditingAllowed()">
+            <div ng-show="ctrl.isResultAdmin() && !ctrl.resultsData.verification_status">
                 <button class="btn btn-warning" ng-hide="ctrl.isShared()" ng-click="ctrl.shareTestRun(true)" confirm="Are you sure you want to share these test run results with the community?">Share</button>
                 <button class="btn btn-success" ng-show="ctrl.isShared()" ng-click="ctrl.shareTestRun(false)">Unshare</button>
                 <button type="button" class="btn btn-danger" ng-click="ctrl.deleteTestRun()" confirm="Are you sure you want to delete these test run results?">Delete</button>
             </div>
+            <div ng-show="ctrl.resultsData.user_role === 'foundation'">
+                <hr>
+                <div class="checkbox checkbox-verified">
+                    <label><input type="checkbox"
+                                  ng-model="ctrl.isVerified"
+                                  ng-change="ctrl.updateVerificationStatus()"
+                                  ng-true-value="1"
+                                  ng-false-value="0">
+                                  <strong>Verified</strong>
+                    </label>
+                </div>
+            </div>
         </div>
     </div>
 </div>
@@ -84,6 +112,8 @@
                 <span ng-if="ctrl.nonFlagPassCount !== ctrl.totalNonFlagCount" class="no">NO</span>
             </strong>
         </p>
+        <p ng-if="ctrl.resultsData.verification_status"><strong>Verified:</strong>
+            <span class="yes">YES</span>
 
         <hr>
         <h4>Capability Overview</h4>
diff --git a/refstack-ui/app/components/results-report/resultsReportController.js b/refstack-ui/app/components/results-report/resultsReportController.js
index d28053a6..b53184e7 100644
--- a/refstack-ui/app/components/results-report/resultsReportController.js
+++ b/refstack-ui/app/components/results-report/resultsReportController.js
@@ -36,10 +36,11 @@
 
         ctrl.getVersionList = getVersionList;
         ctrl.getResults = getResults;
-        ctrl.isEditingAllowed = isEditingAllowed;
+        ctrl.isResultAdmin = isResultAdmin;
         ctrl.isShared = isShared;
         ctrl.shareTestRun = shareTestRun;
         ctrl.deleteTestRun = deleteTestRun;
+        ctrl.updateVerificationStatus = updateVerificationStatus;
         ctrl.updateGuidelines = updateGuidelines;
         ctrl.getTargetCapabilities = getTargetCapabilities;
         ctrl.buildCapabilityV1_2 = buildCapabilityV1_2;
@@ -114,6 +115,7 @@
                 $http.get(content_url).success(function (data) {
                     ctrl.resultsData = data;
                     ctrl.version = ctrl.resultsData.meta.guideline;
+                    ctrl.isVerified = ctrl.resultsData.verification_status;
                     if (ctrl.resultsData.meta.target) {
                         ctrl.target = ctrl.resultsData.meta.target;
                     }
@@ -127,14 +129,14 @@
         }
 
         /**
-         * This tells you whether the current results can be edited/managed
-         * based on if the current user is the owner of the results set.
-         * @returns {Boolean} true if editing is allowed
+         * This tells you whether the current user has administrative
+         * privileges for the test result.
+         * @returns {Boolean} true if the user has admin privileges.
          */
-        function isEditingAllowed() {
+        function isResultAdmin() {
             return Boolean(ctrl.resultsData &&
                 (ctrl.resultsData.user_role === 'owner' ||
-                 ctrl.resultsData.user_role == 'foundation'));
+                 ctrl.resultsData.user_role === 'foundation'));
         }
         /**
          * This tells you whether the current results are shared with the
@@ -190,6 +192,27 @@
                 });
         }
 
+        /**
+         * This will send a request to the API to delete the current
+         * test results set.
+         */
+        function updateVerificationStatus() {
+            var content_url = [
+                refstackApiUrl, '/results/', ctrl.testId
+            ].join('');
+            var data = {'verification_status': ctrl.isVerified};
+            ctrl.updateRequest =
+                $http.put(content_url, data).success(
+                    function () {
+                        ctrl.resultsData.verification_status = ctrl.isVerified;
+                        raiseAlert('success', '',
+                                   'Verification status changed!');
+                    }).error(function (error) {
+                        ctrl.isVerified = ctrl.resultsData.verification_status;
+                        raiseAlert('danger', error.title, error.detail);
+                    });
+        }
+
         /**
          * This will contact the Refstack API server to retrieve the JSON
          * content of the guideline file corresponding to the selected
diff --git a/refstack-ui/app/components/results/results.html b/refstack-ui/app/components/results/results.html
index 2552fba3..1f0c3b9c 100644
--- a/refstack-ui/app/components/results/results.html
+++ b/refstack-ui/app/components/results/results.html
@@ -32,7 +32,7 @@
                 </span>
             </p>
         </div>
-        <div class="col-md-3"style="margin-top:24px;">
+        <div class="col-md-3" style="margin-top:24px;">
             <button type="submit" class="btn btn-primary" ng-click="ctrl.update()">Filter</button>
             <button type="submit" class="btn btn-primary btn-danger" ng-click="ctrl.clearFilters()">Clear</button>
         </div>
@@ -82,8 +82,8 @@
                     <select ng-if="result.sharedEdit"
                             ng-model="result.meta.shared"
                             class="form-inline">
-                            <option value="true">Share</option>
-                            <option value="">Unshare</option>
+                            <option value="true">Yes</option>
+                            <option value="">No</option>
                     </select>
                     <a ng-if="!result.sharedEdit"
                        ng-click="result.sharedEdit = true"
diff --git a/refstack-ui/tests/unit/ControllerSpec.js b/refstack-ui/tests/unit/ControllerSpec.js
index c8028e07..fb185e6d 100644
--- a/refstack-ui/tests/unit/ControllerSpec.js
+++ b/refstack-ui/tests/unit/ControllerSpec.js
@@ -381,6 +381,12 @@ describe('Refstack controllers', function () {
             ctrl = $controller('ResultsReportController',
                 {$stateParams: stateparams}
             );
+            $httpBackend.when('GET', fakeApiUrl +
+                '/results/1234').respond(fakeResultResponse);
+            $httpBackend.when('GET', fakeApiUrl +
+                '/guidelines').respond(['2015.03.json', '2015.04.json']);
+            $httpBackend.when('GET', fakeApiUrl +
+                '/guidelines/2015.04.json').respond(fakeCapabilityResponse);
         }));
 
         it('should make all necessary API requests to get results ' +
@@ -705,6 +711,19 @@ describe('Refstack controllers', function () {
                 expect(ctrl.getStatusTestCount('required')).toEqual(-1);
             });
 
+        it('should have a method to update the verification status of a test',
+            function () {
+                $httpBackend.flush();
+                ctrl.isVerified = 1;
+                $httpBackend.expectPUT(fakeApiUrl + '/results/1234',
+                    {'verification_status': ctrl.isVerified}).respond(204, '');
+                $httpBackend.when('GET', /\.html$/).respond(200);
+                ctrl.updateVerificationStatus();
+                $httpBackend.flush();
+                expect(ctrl.resultsData.verification_status).toEqual(1);
+
+            });
+
         it('should have a method to open a modal for the full passed test list',
             function () {
                 var modal;