From d0bbf3b8952379883550c6eb2062476a6d15043e Mon Sep 17 00:00:00 2001 From: pkaralis Date: Thu, 6 Dec 2018 00:43:12 +0200 Subject: Enable Web Portal for ONAP results The web portal needs to be able to read test results of the ONAP compliance program and display them. In order for the above goal to be achieved, the following two parts should be impacted: 1- A new front-end should be prepared in order to handle and display the results 2- The REST API should be extended in order to support the aforementioned operation. JIRA: DOVETAIL-669 Change-Id: I36bbb6e602a67020d7e27aedbfc776f5cf4f3dc3 Signed-off-by: pkaralis Co-Authored-By: Stamatis Katsaounis --- .../components/application/application.html | 111 ++++ .../application/applicationController.js | 110 ++++ .../auth-failure/authFailureController.js | 33 ++ .../onap-ui/components/directory/directory.html | 34 ++ .../components/directory/directoryController.js | 45 ++ 3rd_party/static/onap-ui/components/home/home.html | 170 ++++++ .../onap-ui/components/home/homeController.js | 58 ++ .../static/onap-ui/components/logout/logout.html | 1 + .../onap-ui/components/logout/logoutController.js | 44 ++ .../static/onap-ui/components/profile/profile.html | 88 +++ .../components/profile/profileController.js | 68 +++ .../data/2019.04/heat-testcases.json | 13 + .../data/2019.04/tosca-testcases.json | 13 + .../results-report/partials/reportDetails.html | 60 ++ .../components/results-report/resultsReport.html | 33 ++ .../results-report/resultsReportController.js | 224 ++++++++ .../components/results/modal/applicationModal.html | 158 ++++++ .../components/results/modal/applicationView.html | 103 ++++ .../components/results/modal/reviewsModal.html | 41 ++ .../components/results/modal/sharedModal.html | 16 + .../static/onap-ui/components/results/results.html | 168 ++++++ .../components/results/resultsController.js | 614 +++++++++++++++++++++ 22 files changed, 2205 insertions(+) create mode 100644 3rd_party/static/onap-ui/components/application/application.html create mode 100644 3rd_party/static/onap-ui/components/application/applicationController.js create mode 100644 3rd_party/static/onap-ui/components/auth-failure/authFailureController.js create mode 100644 3rd_party/static/onap-ui/components/directory/directory.html create mode 100644 3rd_party/static/onap-ui/components/directory/directoryController.js create mode 100644 3rd_party/static/onap-ui/components/home/home.html create mode 100644 3rd_party/static/onap-ui/components/home/homeController.js create mode 100644 3rd_party/static/onap-ui/components/logout/logout.html create mode 100644 3rd_party/static/onap-ui/components/logout/logoutController.js create mode 100644 3rd_party/static/onap-ui/components/profile/profile.html create mode 100644 3rd_party/static/onap-ui/components/profile/profileController.js create mode 100644 3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json create mode 100644 3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json create mode 100644 3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html create mode 100644 3rd_party/static/onap-ui/components/results-report/resultsReport.html create mode 100644 3rd_party/static/onap-ui/components/results-report/resultsReportController.js create mode 100644 3rd_party/static/onap-ui/components/results/modal/applicationModal.html create mode 100644 3rd_party/static/onap-ui/components/results/modal/applicationView.html create mode 100644 3rd_party/static/onap-ui/components/results/modal/reviewsModal.html create mode 100644 3rd_party/static/onap-ui/components/results/modal/sharedModal.html create mode 100644 3rd_party/static/onap-ui/components/results/results.html create mode 100644 3rd_party/static/onap-ui/components/results/resultsController.js (limited to '3rd_party/static/onap-ui/components') 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 @@ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Create DateOwnerONAP versionCompany NameCompany logoCompany WebsiteApprove dateTest IDxNF VersionxNF NamexNF TypexNF DescriptionxNF IdxNF Model LanguagexNF Checksum (SHA256)Test PeriodLocationOperation
{{ app.creation_date | limitTo: 10 }}{{ app.owner }}{{ app.onap_version }}{{ app.company_name }}{{ app.company_logo }}{{ app.company_website }}{{ app.approve_date | limitTo: 10 }}{{ app.test_id }}{{ app.xnf_version }}{{ app.xnf_name }}{{ app.xnf_type }}{{ app.xnf_description }}{{ app.xnfd_id }}{{ app.xnfd_model_lang }}{{ app.xnf_checksum }}{{ app.xnf_test_period }} + {{ app.lab_location | labLocation}} + + + + + + + + +
+ +
+ + +
+
+
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 @@ +
+

ONAP Verified Product Directory

+
+

Compliance Marks Granted to {{ctrl.companyID}}

+ Company Logo + + + + + + + + + + + + + + + + + + + + + + + + + +
Product NameDescriptionModel LanguageArtifact Checksum (SHA256)Product VersionVersionDateProduct Info
{{ prod.xnf_name }}{{ prod.xnf_description }}{{ prod.xnfd_model_lang }}{{ prod.xnf_checksum }}{{ prod.xnf_version }}{{ prod.onap_version }}{{ prod.approve_date | limitTo: 10 }}{{ prod.company_website }}
+
+
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 @@ +
+
+ + +
+
+
+

ONAP Verified Program verifies products and services with the "ONAP Verified" mark.

+
+
+
+ ONAP +
+
+

+ 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 + compliance@lists.lfnetworking.org + . +

+
+
+
+
+
+

ONAP Verified Products Directory

+ Click on rows for more product verification details per company. +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
Company Name & LogoTest AgencyProduct NameProduct VersionModeling LanguageTypeVersion
+ + {{ app.company_name }} + {{ app.lab_location }}{{ app.xnf_name }}{{ app.xnf_version }}{{ app.xnfd_model_lang }}N/A{{ app.onap_version}}
+
+
+
+
+
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 @@ +
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 @@ +
+

User profile

+
+
+ + + + + + + + + + + + + + + + + + + +
User name{{auth.currentUser.fullname}}
User OpenId{{auth.currentUser.openid}}
Email{{auth.currentUser.email}}
Role{{auth.currentUser.role}}
+
+
+
+

Organization Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Company Name + +
Company website + +
Primary Contact Name + +
Primary Contact Business email + +
Primary Contact Postal Address + +
Primary Contact Phone Number + +
+
+ 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 @@ + + +Test Filters:
+ + + + + {{ type }}: {{ ctrl.statistics[type].total }} tests + + +
    +
  1. + + {{ area }} + + [{{ value.pass }}/{{ value.total }}] + + [{{ value.pass }}] + [{{ value.fail }}] + + + +
  2. +
+
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 @@ +
+

Test Run Results

+ +
+
+
+
+ ONAP Version: {{ctrl.version}}
+ Test ID: {{ctrl.testId}}
+
+
+
+
+ + Total: {{ctrl.statistics.total}}, Pass: {{ ctrl.statistics.pass}}, Rate: {{ ctrl.statistics.pass / ctrl.statistics.total * 100 | number:2 }}%
+ Mandatory Total: {{ctrl.statistics.mandatory.total}}, Pass: {{ ctrl.statistics.mandatory.pass }}, Rate: {{ ctrl.statistics.mandatory.pass / ctrl.statistics.mandatory.total * 100 | number:2 }}%
+ Optional Total: {{ctrl.statistics.optional.total}}, Pass: {{ ctrl.statistics.optional.pass }}, Rate: {{ ctrl.statistics.optional.pass / ctrl.statistics.optional.total * 100 | number:2 }}%
+
+ {{ ctrl.validation }}
+ +
+
+

Test Result Overview

+ + + + +
+
+
+
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/' 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 @@ +
+
+
+

Application Details

+
+
+ +
+
+ +
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+
+ +
+ + 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 @@ +
+
+
+

Application Details

+
+
+ +
+
+ +
+
+ +
{{ ctrl.application.company_name }}
+
+
+ +
{{ ctrl.application.company_logo }}
+
+
+ +
{{ ctrl.application.company_website }}
+
+
+ +
{{ ctrl.application.onap_version }}
+
+
+ +
{{ ctrl.application.primary_contact_name }}
+
+
+ +
{{ ctrl.application.primary_phone_number }}
+
+
+ +
{{ ctrl.application.primary_business_email }}
+
+
+ +
{{ ctrl.application.lab_location }}
+
+
+ +
{{ ctrl.application.xnf_version }}
+
+
+ +
{{ ctrl.application.xnf_name }}
+
+
+ +
{{ ctrl.application.xnf_type }}
+
+
+ +
{{ ctrl.application.xnf_description }}
+
+
+ +
{{ ctrl.application.xnfd_id }}
+
+
+ +
{{ ctrl.application.xnfd_model_lang }}
+
+
+ +
{{ ctrl.application.xnf_test_period }}
+
+
+ +
{{ ctrl.application.xnf_checksum }}
+
+
+
+ +
{{ ctrl.application.lab_name }}
+
+
+ +
{{ ctrl.application.lab_email }}
+
+
+ +
{{ ctrl.application.lab_address }}
+
+
+ +
{{ ctrl.application.lab_phone }}
+
+
+
+
+
+
+ + 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 @@ +
+
+
+

Community Reviews

+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + +
ReviewerLinux Foundation OpenIdEmailReview DateOutcome
{{ review.reviewer_name }}{{ review.reviewer_openid }}{{ review.reviewer_email }}{{ review.creation_date | limitTo:19}}{{ review.outcome }}
+
+
+
+
+ + 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 @@ +
+

Enter user name or email

+ +
+ +
+
+ + 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 @@ +
+

{{ctrl.pageHeader}}

+

{{ctrl.pageParagraph}}

+
+

Upload Results + +

+
+ +
+ +
+ +
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Upload DateTest IDONAP VersionModeling LanguageOwnerFile NameLabelStatusLogApplicationReview StatusOperationShare List
{{ result.upload_date | limitTo:19}} + {{ result.id | limitTo:8 }} + {{ result.version || "2019.04" }}{{ result.vnf_type.toUpperCase() }}{{ result.owner }}{{ result.filename || "None"}} + + {{ result.status }}logs + View Application +
Not created
+
View Reviews +
+
+
+ + Operation + + +
+
+
+ + Share List + + +
+
+
+ + +
+
+
+ + + + + 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}); + } + } +})(); -- cgit 1.2.3-korg