diff options
Diffstat (limited to '3rd_party/static/onap-ui/components')
22 files changed, 2205 insertions, 0 deletions
diff --git a/3rd_party/static/onap-ui/components/application/application.html b/3rd_party/static/onap-ui/components/application/application.html new file mode 100644 index 0000000..2238ca4 --- /dev/null +++ b/3rd_party/static/onap-ui/components/application/application.html @@ -0,0 +1,111 @@ +<div class="container-fluid common-main-container"> + <div class="results-table" style="margin-top: 30px; overflow: scroll;"> + <table class="table table-striped table-hover"> + <thead> + <tr> + <th>Create Date</th> + <th>Owner</th> + <th>ONAP version</th> + <th>Company Name</th> + <th>Company logo</th> + <th>Company Website</th> + <th>Approve date</th> + <th>Test ID</th> + <th>xNF Version</th> + <th>xNF Name</th> + <th>xNF Type</th> + <th>xNF Description</th> + <th>xNF Id</th> + <th>xNF Model Language</th> + <th>xNF Checksum (SHA256)</th> + <th>Test Period</th> + <th>Location</th> + <th>Operation</th> + </tr> + </thead> + <script type="text/ng-template" id="product.tpl.html"> + <div class="input-group"> + <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span> + <input type="text" value="{{app.product_spec}}"> + </div> + <div class="input-group"> + <span class="input-group-addon">@</span> + <input type="text" value="{{app.product_documentation}}"> + </div> + <div class="input-group"> + <span class="input-group-addon"><i class="glyphicon glyphicon-map-marker"></i></span> + <input type="text" value="{{app.product_categories | category}}"> + </div> + </script> + <script type="text/ng-template" id="lab.tpl.html"> + <div class="input-group"> + <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span> + <input type="text" value="{{app.lab_name}}"> + </div> + <div class="input-group"> + <span class="input-group-addon">@</span> + <input type="text" value="{{app.lab_email}}"> + </div> + <div class="input-group"> + <span class="input-group-addon"><i class="glyphicon glyphicon-map-marker"></i></span> + <input type="text" value="{{app.lab_address}}"> + </div> + <div class="input-group"> + <span class="input-group-addon"><i class="glyphicon glyphicon-phone"></i></span> + <input type="text" value="{{app.lab_phone}}"> + </div> + </script> + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-if="results.status != 'review'" ng-repeat="app in ctrl.applications"> + <td>{{ app.creation_date | limitTo: 10 }}</td> + <td>{{ app.owner }}</td> + <td>{{ app.onap_version }}</td> + <td>{{ app.company_name }}</td> + <td>{{ app.company_logo }}</td> + <td>{{ app.company_website }}</td> + <td>{{ app.approve_date | limitTo: 10 }}</td> + <td>{{ app.test_id }}</td> + <td>{{ app.xnf_version }}</td> + <td>{{ app.xnf_name }}</td> + <td>{{ app.xnf_type }}</td> + <td>{{ app.xnf_description }}</td> + <td>{{ app.xnfd_id }}</td> + <td>{{ app.xnfd_model_lang }}</td> + <td>{{ app.xnf_checksum }}</td> + <td>{{ app.xnf_test_period }}</td> + <td> + <span popover-enable="app.lab_location != 'internal'" uib-popover-template="ctrl.lab_tpl" + popover-title="Lab Info" popover-placement="top" + popover-trigger="mouseenter">{{ app.lab_location | labLocation}}</span> + <i ng-if="app.lab_location != 'internal'" class="glyphicon glyphicon-info-sign opnfv-blue"></i> + </td> + <td> + <a ng-click="ctrl.toggleApproveApp(app._id, 'true')" class="badge badge-info" + ng-if="app.approved == 'false'" + data-toggle="tooltip" title="Approve Application"> + <i class="glyphicon glyphicon-ok" ></i> + </a> + <a ng-click="ctrl.deleteApp(app._id)" class="badge badge-info" + data-toggle="tooltip" title="Delete Application"> + <i class="glyphicon glyphicon-remove" ></i> + </a> + </td> + </tr> + </tbody> + </table> + + <div class="pages"> + <uib-pagination + total-items="ctrl.totalItems" + ng-model="ctrl.currentPage" + items-per-page="ctrl.itemsPerPage" + max-size="ctrl.maxSize" + class="pagination-sm" + boundary-links="true" + rotate="false" + num-pages="ctrl.numPages" + ng-change="ctrl.updatePage()"> + </uib-pagination> + </div> + </div> +</div> diff --git a/3rd_party/static/onap-ui/components/application/applicationController.js b/3rd_party/static/onap-ui/components/application/applicationController.js new file mode 100644 index 0000000..094ffdc --- /dev/null +++ b/3rd_party/static/onap-ui/components/application/applicationController.js @@ -0,0 +1,110 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ApplicationController', ApplicationController); + + ApplicationController.$inject = [ + '$http', '$stateParams', '$window', '$sce', + '$uibModal', 'testapiApiUrl', 'raiseAlert', 'ngDialog', '$scope' + ]; + + /** + */ + function ApplicationController($http, $stateParams, $window, $sce, + $uibModal, testapiApiUrl, raiseAlert, ngDialog, $scope) { + + var ctrl = this; + + function init() { + ctrl.applications = []; + + ctrl.totalItems = null; + ctrl.currentPage = 1; + ctrl.itemsPerPage = 5; + ctrl.numPages = null; + + ctrl.lab_tpl = "lab.tpl.html"; + ctrl.product_tpl = "product.tpl.html"; + + getApplication(); + } + + ctrl.updatePage = function() { + getApplication(); + } + + ctrl.deleteApp = function(id) { + var resp = confirm('Are you sure you want to delete this application?'); + if (!resp) + return; + + var delUrl = testapiApiUrl + "/cvp/applications/" + id; + $http.delete(delUrl) + .then(function(ret) { + if (ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + return; + } + getApplication(); + }); + } + + ctrl.toggleApproveApp = function(id, approved) { + if (approved === 'true') { + var text = 'Are you sure you want to approve this application?'; + } else { + var text = 'Are you sure you want to remove approval of this application?'; + } + + var resp = confirm(text); + if (!resp) + return; + + var updateUrl = testapiApiUrl + "/cvp/applications/" + id; + var data = {}; + data['item'] = 'approved'; + data['approved'] = approved; + + $http.put(updateUrl, JSON.stringify(data), { + transformRequest: angular.identity, + headers: {'Content-Type': 'application/json'}}).then(function(ret) { + if (ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + return; + } + getApplication(); + }, function(error) { + alert('Error when update data'); + }); + } + + function getApplication() { + $http.get(testapiApiUrl + "/onap/cvp/applications?page=" + ctrl.currentPage + "&signed&per_page=" + ctrl.itemsPerPage).then(function(response) { + ctrl.applications = response.data.applications; + ctrl.totalItems = response.data.pagination.total_pages * ctrl.itemsPerPage; + ctrl.currentPage = response.data.pagination.current_page; + ctrl.numPages = response.data.pagination.total_pages; + }, function(error) { + /* do nothing */ + }); + } + + init(); + } +})(); diff --git a/3rd_party/static/onap-ui/components/auth-failure/authFailureController.js b/3rd_party/static/onap-ui/components/auth-failure/authFailureController.js new file mode 100644 index 0000000..29d1d70 --- /dev/null +++ b/3rd_party/static/onap-ui/components/auth-failure/authFailureController.js @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('AuthFailureController', AuthFailureController); + + AuthFailureController.$inject = ['$location', '$state', 'raiseAlert']; + /** + * TestAPI Auth Failure Controller + * This controller handles messages from TestAPI API if user auth fails. + */ + function AuthFailureController($location, $state, raiseAlert) { + var ctrl = this; + ctrl.message = $location.search().message; + raiseAlert('danger', 'Authentication Failure:', ctrl.message); + $state.go('home'); + } +})(); diff --git a/3rd_party/static/onap-ui/components/directory/directory.html b/3rd_party/static/onap-ui/components/directory/directory.html new file mode 100644 index 0000000..4a04bd7 --- /dev/null +++ b/3rd_party/static/onap-ui/components/directory/directory.html @@ -0,0 +1,34 @@ +<div class="container-fluid common-main-container"> + <h3>ONAP Verified Product Directory</h3> + <div> + <h4>Compliance Marks Granted to {{ctrl.companyID}}</h4> + <img src="api/v1/cvp/applications/getlogo/{{ctrl.company_logo}}" alt="Company Logo"> + <table class="table table-striped table-hover"> + <thead> + <tr> + <th>Product Name</th> + <th>Description</th> + <th>Model Language</th> + <th>Artifact Checksum (SHA256)</th> + <th>Product Version</th> + <th>Version</th> + <th>Date</th> + <th>Product Info</th> + </tr> + </thead> + <tbody class="directory_inner" style="overflow: hidden; text-overflow: ellipsis;"> + <tr style="vertical-align: center;" ng-repeat="prod in ctrl.directory" + ng-if="prod.company_name==ctrl.companyID && prod.approved=='true'"> + <td style="width: 250px;">{{ prod.xnf_name }}</td> + <td style="width: 350px;">{{ prod.xnf_description }}</td> + <td style="width: 350px;">{{ prod.xnfd_model_lang }}</td> + <td style="width: 350px;">{{ prod.xnf_checksum }}</td> + <td style="width: 150px;">{{ prod.xnf_version }}</td> + <td style="width: 150px;">{{ prod.onap_version }}</td> + <td style="width: 150px;">{{ prod.approve_date | limitTo: 10 }}</td> + <td style="width: 150px;"><a href="{{ prod.company_website }}" target="_blank" rel="noopener">{{ prod.company_website }}</a></td> + </tr> + </tbody> + </table> + </div> +</div> diff --git a/3rd_party/static/onap-ui/components/directory/directoryController.js b/3rd_party/static/onap-ui/components/directory/directoryController.js new file mode 100644 index 0000000..a4fc6f3 --- /dev/null +++ b/3rd_party/static/onap-ui/components/directory/directoryController.js @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('DirectoryController', DirectoryController); + + DirectoryController.$inject = ['$http', '$stateParams', + 'testapiApiUrl' + ]; + + /** + * This controller handles the directory page + */ + function DirectoryController($http, $stateParams, testapiApiUrl) { + var ctrl = this; + + ctrl.companyID = $stateParams.companyID; + ctrl.company_logo = $stateParams.logo; + getDirectory(); + + function getDirectory() { + $http.get(testapiApiUrl + "/onap/cvp/applications").then(function(response) { + ctrl.directory = response.data.applications; + }, function(error) { + /* do nothing */ + }); + } + } + +})(); diff --git a/3rd_party/static/onap-ui/components/home/home.html b/3rd_party/static/onap-ui/components/home/home.html new file mode 100644 index 0000000..4db08b0 --- /dev/null +++ b/3rd_party/static/onap-ui/components/home/home.html @@ -0,0 +1,170 @@ +<div class="container-fluid"> + <div class="row"> + <div class="col-md-2 home-category" ng-style="{'height': ctrl.height}"> + <div class="panel-group" id="accordion"> + <div class="panel panel-default"> + <div class="panel-heading"> + <div class="panel-title"> + <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne"> + Governance & Workflow + </a> + </div> + </div> + <div id="collapseOne" class="panel-collapse collapse"> + <div class="panel-body"> + <div> + <a href="https://www.opnfv.org/verified" + target="_blank" rel="noopener">Overview + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="https://www.opnfv.org/wp-content/uploads/sites/12/2018/09/LFN_CVP_Guidelines-1.0.0.pdf" + target="_blank" rel="noopener">Governance Guidelines + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="https://www.opnfv.org/wp-content/uploads/sites/12/2018/09/OVP-Terms-and-Conditions-092418.pdf" + target="_blank" rel="noopener">Terms & Conditions + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/certificationworkflow/index.html" + target="_blank" rel="noopener">Process Workflow + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=dc24bf38-ea41-40d4-9e58-9babc6eec778" + target="_blank" rel="noopener">Participation Form + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="https://wiki.onap.org/display/DW/VNF+Badging" + target="_blank" rel="noopener">ONAP Verified Brand Guidelines + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + </div> + </div> + </div> + <div class="panel panel-default" style="margin-top: 0px;"> + <div class="panel-heading"> + <div class="panel-title"> + <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo"> + Release 2018.11 + </a> + </div> + </div> + <div id="collapseTwo" class="panel-collapse collapse"> + <div class="panel-body"> + <div> + <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/userguide/testing_guide.html" + target="_blank" rel="noopener">ONAPVP / Dovetail User Guide + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/userguide/cli_reference.html" + target="_blank" rel="noopener">Dovetail CLI + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="https://wiki.onap.org/display/DW/ONAP+Modeling+specification" + target="_blank" rel="noopener">Test Specifications + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="https://wiki.onap.org/display/DW/Release+Calendar" + target="_blank" rel="noopener">Release Notes + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/reviewerguide/index.html" + target="_blank" rel="noopener">Reviewer Guide + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + <div> + <a href="http://docs.opnfv.org/en/stable-fraser/submodules/dovetail/docs/testing/user/ovpaddendum/index.html" + target="_blank" rel="noopener">Guidelines Addendum + <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> + </a> + </div> + </div> + </div> + </div> + </div> + </div> + + <div class="col-md-10"> + <div class="common-main-container"> + <div class="home-content-title"> + <h2>ONAP Verified Program verifies products and services with the "ONAP Verified" mark.</h2> + </div> + <div class="home-content"> + <div class="col-md-2"> + <img class="home-content-img" src="onap-ui/assets/img/icon.png" alt="ONAP"> + </div> + <div class="col-md-10"> + <p class="home-content-text" style="padding-bottom: 40px;"> + The ONAP Verified Program demonstrates the readiness and availability of commercial VNF/PNF + products and services by implementing Specification defined by Compliance Verification + Committee(CVC). This open source community-led initiative allows vendors and service + providers to establish baseline conformance and interoperability while retaining distinct + and value-added innovations across features and capabilities and requires verified products + to complete additional functional, high-availability tests. View the directory of verified + products and services below and navigate through the links in the left-hand menu to learn + more and get started. You will find step-by-step instructions as well as a participation form. + Use this portal to upload your test results when ready. Please send any questions to + <a href="mailto:compliance@lists.lfnetworking.org">compliance@lists.lfnetworking.org</a><sup> + <span class="glyphicon glyphicon-envelope" style="font-size: 60%;" aria-hidden="true"></span></sup>. + </p> + </div> + </div> + <div id="directory_break"> + </div> + <div class="home-content-title"> + <h1>ONAP Verified Products Directory</h1> + Click on rows for more product verification details per company. + </div> + <div class="directory_main"> + <table id="directory_inner" class=""> + <thead> + <tr> + <th>Company Name & Logo</th> + <th>Test Agency</th> + <th>Product Name</th> + <th>Product Version</th> + <th>Modeling Language</th> + <th>Type</th> + <th>Version</th> + </tr> + </thead> + <tbody style="overflow: hidden; text-overflow: ellipsis;"> + <tr class="company_row" ng-click="ctrl.getCompany(app)" + ng-repeat="app in ctrl.applications | filter:{approved:true} | orderBy : '-approve_date'"> + <td style="width: 400px;"> + <img class="company_logo" ng-src="api/v1/cvp/applications/getlogo/{{app.company_logo}}" alt="{{app.company_logo}}"> + {{ app.company_name }} + </td> + <td style="width: 300px;">{{ app.lab_location }}</td> + <td style="width: 300px;">{{ app.xnf_name }}</td> + <td style="width: 150px;">{{ app.xnf_version }}</td> + <td style="width: 150px;">{{ app.xnfd_model_lang }}</td> + <td style="width: 150px;">N/A</td> + <td style="width: 150px;">{{ app.onap_version}}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> +</div> diff --git a/3rd_party/static/onap-ui/components/home/homeController.js b/3rd_party/static/onap-ui/components/home/homeController.js new file mode 100644 index 0000000..678dd2a --- /dev/null +++ b/3rd_party/static/onap-ui/components/home/homeController.js @@ -0,0 +1,58 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('HomeController', HomeController); + + HomeController.$inject = [ + '$http', '$rootScope', '$state', 'testapiApiUrl' + ]; + + /** + * TestAPI Results Controller + * This controller is for the '/results' page where a user can browse + * a listing of community uploaded results. + */ + function HomeController($http, $rootScope, $state, testapiApiUrl) { + var ctrl = this; + getApplication(); + + ctrl.height = $(document).height() + 500; + + ctrl.gotoApplication = function() { + if ($rootScope.auth.isAuthenticated) { + $state.go('application'); + } else { + $rootScope.auth.doSignIn('cas'); + } + } + + function getApplication() { + $http.get(testapiApiUrl + "/onap/cvp/applications").then(function(response) { + ctrl.applications = response.data.applications; + }, function(error) { + /* do nothing */ + }); + } + + ctrl.getCompany = function(row) { + $state.go('directory', {'companyID': row.company_name, 'logo': row.company_logo}); + } + + } +})(); diff --git a/3rd_party/static/onap-ui/components/logout/logout.html b/3rd_party/static/onap-ui/components/logout/logout.html new file mode 100644 index 0000000..38a5c36 --- /dev/null +++ b/3rd_party/static/onap-ui/components/logout/logout.html @@ -0,0 +1 @@ +<div cg-busy="{promise:ctrl.redirectWait,message:'Logging you out...'}"></div> diff --git a/3rd_party/static/onap-ui/components/logout/logoutController.js b/3rd_party/static/onap-ui/components/logout/logoutController.js new file mode 100644 index 0000000..1b6d78c --- /dev/null +++ b/3rd_party/static/onap-ui/components/logout/logoutController.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('LogoutController', LogoutController); + + LogoutController.$inject = [ + '$location', '$window', '$timeout' + ]; + + /** + * TestAPI Logout Controller + * This controller handles logging out. In order to fully logout, the + * openstackid_session cookie must also be removed. The way to do that + * is to have the user's browser make a request to the openstackid logout + * page. We do this by placing the logout link as the src for an html + * image. After some time, the user is redirected home. + */ + function LogoutController($location, $window, $timeout) { + var ctrl = this; + + ctrl.openid_logout_url = $location.search().openid_logout; + var img = new Image(0, 0); + img.src = ctrl.openid_logout_url; + ctrl.redirectWait = $timeout(function() { + $window.location.href = '/'; + }, 500); + } +})(); diff --git a/3rd_party/static/onap-ui/components/profile/profile.html b/3rd_party/static/onap-ui/components/profile/profile.html new file mode 100644 index 0000000..cb73335 --- /dev/null +++ b/3rd_party/static/onap-ui/components/profile/profile.html @@ -0,0 +1,88 @@ +<div class="container-fluid common-main-container"> + <h3>User profile</h3> + <div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div> + <div> + <table class="table table-striped table-hover"> + <tbody> + <tr> + <td>User name</td> + <td>{{auth.currentUser.fullname}}</td> + </tr> + <tr> + <td>User OpenId</td> + <td>{{auth.currentUser.openid}}</td> + </tr> + <tr> + <td>Email</td> + <td>{{auth.currentUser.email}}</td> + </tr> + <tr> + <td>Role</td> + <td>{{auth.currentUser.role}}</td> + </tr> + </tbody> + </table> + </div> + <br> + <br> + <h3>Organization Details</h3> + <table class="table table-striped table-hover"> + <tbody> + <tr> + <td>Company Name</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'companyName', $data)" + editable-text="ctrl.profile.companyName">{{ ctrl.profile.companyName || "None" }}</a> + </div> + </td> + </tr> + <tr> + <td>Company website</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'companyWebsite', $data)" + editable-url="ctrl.profile.companyWebsite">{{ ctrl.profile.companyWebsite || "None" }}</a> + </div> + </td> + </tr> + <tr> + <td>Primary Contact Name</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryContactName', $data)" + editable-text="ctrl.profile.primaryContactName">{{ ctrl.profile.primaryContactName || "None" }}</a> + </div> + </td> + </tr> + <tr> + <td>Primary Contact Business email</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryBusinessEmail', $data)" + editable-email="ctrl.profile.primaryBusinessEmail">{{ ctrl.profile.primaryBusinessEmail || "None" }}</a> + </div> + </td> + </tr> + <tr> + <td>Primary Contact Postal Address</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryPostalAddress', $data)" + editable-text="ctrl.profile.primaryPostalAddress">{{ ctrl.profile.primaryPostalAddress || "None" }}</a> + </div> + </td> + </tr> + <tr> + <td>Primary Contact Phone Number</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryPhoneNumber', $data)" + editable-tel="ctrl.profile.primaryPhoneNumber">{{ ctrl.profile.primaryPhoneNumber || "None" }}</a> + </div> + </td> + </tr> + </tbody> + </table> + </div> +</div> diff --git a/3rd_party/static/onap-ui/components/profile/profileController.js b/3rd_party/static/onap-ui/components/profile/profileController.js new file mode 100644 index 0000000..1b84d76 --- /dev/null +++ b/3rd_party/static/onap-ui/components/profile/profileController.js @@ -0,0 +1,68 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ProfileController', ProfileController); + + ProfileController.$inject = [ + '$scope', '$state', '$http', 'testapiApiUrl' + ]; + + /** + * TestAPI Profile Controller + * This controller handles user's profile page, where a user can view + * account-specific information. + */ + function ProfileController($scope, $state, $http, testapiApiUrl) { + + var ctrl = this; + + ctrl.changeProfileDetails = changeProfileDetails; + + // Must be authenticated to view this page. + if (!$scope.auth.isAuthenticated) { + $state.go('home'); + } + + ctrl.authRequest = $scope.auth.doSignCheck(); + ctrl.profile = $scope.auth.currentUser; + + function changeProfileDetails(profile, key, newValue){ + if (profile[key] === newValue) { + return; + } + var updateUrl = testapiApiUrl + "/profile"; + + var data = {}; + data[key] = newValue; + + $http.put(updateUrl, JSON.stringify(data), { + transformRequest: angular.identity, + headers: {'Content-Type': 'application/json'}}).then(function(ret) { + if (ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + } else { + profile[key] = newValue; + } + }, function(error) { + alert("Error when update data"); + }); + } + } +})(); diff --git a/3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json b/3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json new file mode 100644 index 0000000..1f584f4 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results-report/data/2019.04/heat-testcases.json @@ -0,0 +1,13 @@ +{ + "mandatory": { + "onap-vvp.validate.heat": { + "cases": [ + "onap-vvp.validate.heat" + ], + "total": 1 + } + }, + "optional": { + + } +} diff --git a/3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json b/3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json new file mode 100644 index 0000000..de01e83 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results-report/data/2019.04/tosca-testcases.json @@ -0,0 +1,13 @@ +{ + "mandatory": { + "onap-vtp.validate.csar": { + "cases": [ + "onap-vtp.validate.csar" + ], + "total": 1 + } + }, + "optional": { + + } +} diff --git a/3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html b/3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html new file mode 100644 index 0000000..3f3e9c9 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results-report/partials/reportDetails.html @@ -0,0 +1,60 @@ +<!-- +HTML for each accordion group that separates the status types on the results +report page. +--> + +Test Filters:<br> +<div class="btn-toolbar" role="toolbar"> + <div class="btn-group button-margin" data-toggle="buttons"> + <label class="btn btn-default" ng-click="ctrl.changeStatus('total')" + ng-class="{'active': ctrl.testStatus === 'total'}"> + <input type="radio" ng-model="ctrl.testStatus" value="total" name="total"> + <span class="text-primary">All</span> + </label> + <label class="btn btn-default" ng-click="ctrl.changeStatus('passed')" + ng-class="{'active': ctrl.testStatus === 'passed'}"> + <input type="radio" ng-model="ctrl.testStatus" value="passed" name="passed"> + <span class="text-success">Passed</span> + </label> + <label class="btn btn-default" ng-click="ctrl.changeStatus('not passed')" + ng-class="{'active': ctrl.testStatus === 'not passed'}"> + <input type="radio" ng-model="ctrl.testStatus" value="not passed" name="not passed"> + <span class="text-danger">Not Passed</span> + </label> + </div> + <div class="btn-group button-margin" style="float: right;"> + <button type="button" class="btn btn-default" ng-click="ctrl.openAll()">Expand</button> + <button type="button" class="btn btn-default" ng-click="ctrl.folderAll()">Collapse</button> + </div> +</div> + +<uib-accordion-group ng-repeat="(type,data) in ctrl.data" is-open="isOpen"> + <uib-accordion-heading> + {{ type }}: {{ ctrl.statistics[type].total }} tests + <i class="pull-right glyphicon" + ng-class="{'glyphicon-chevron-down': isOpen, 'glyphicon-chevron-right': !isOpen}"></i> + </uib-accordion-heading> + <ol class="capabilities"> + <li ng-repeat="(area, value) in data" + ng-show="(ctrl.testStatus == 'passed' && value.pass != 0) || (ctrl.testStatus == 'not passed' && value.fail != 0) || ctrl.testStatus == 'total'"> + <a ng-click="value.folder = !value.folder"> + {{ area }} + <span ng-if="ctrl.testStatus == 'total'" + ng-class="{'text-success': value.total == value.pass, 'text-warning': (value.pass < value.total && value.pass > 0), 'text-danger': value.pass == 0}"> + [{{ value.pass }}/{{ value.total }}] + </span> + <span ng-if="ctrl.testStatus == 'passed'" class="text-success">[{{ value.pass }}]</span> + <span ng-if="ctrl.testStatus == 'not passed'" class="text-danger">[{{ value.fail }}]</span> + </a> + <a uib-tooltip="view log" ng-click="ctrl.gotoResultLog(area)"><span class="glyphicon glyphicon-cog"></span></a> + <ul class="list-unstyled" uib-collapse="value.folder"> + <li ng-repeat="case in value.cases" + ng-if="(ctrl.testStatus=='passed' && ctrl.case_list.indexOf(case) > -1) || (ctrl.testStatus=='not passed' && ctrl.case_list.indexOf(case) == -1) || ctrl.testStatus=='total'"> + <span ng-class="{'glyphicon glyphicon-ok text-success':ctrl.case_list.indexOf(case) > -1, 'glyphicon glyphicon-remove text-warning':ctrl.case_list.indexOf(case) == -1}" + aria-hidden="true"></span> + <a ng-click="ctrl.gotoDoc(case)">{{ case }}</a> + </li> + </ul> + </li> + </ol> +</uib-accordion-group> diff --git a/3rd_party/static/onap-ui/components/results-report/resultsReport.html b/3rd_party/static/onap-ui/components/results-report/resultsReport.html new file mode 100644 index 0000000..38e602d --- /dev/null +++ b/3rd_party/static/onap-ui/components/results-report/resultsReport.html @@ -0,0 +1,33 @@ +<div class="container-fluid common-main-container"> + <h3>Test Run Results</h3> + + <div ng-show="ctrl.testId" class="container-fluid"> + <div class="row"> + <div class="pull-left"> + <div class="test-report"> + <strong>ONAP Version:</strong> {{ctrl.version}}<br> + <strong>Test ID:</strong> {{ctrl.testId}}<br> + </div> + </div> + </div> + </div> + + <strong>Total: {{ctrl.statistics.total}}, Pass: {{ ctrl.statistics.pass}}, Rate: {{ ctrl.statistics.pass / ctrl.statistics.total * 100 | number:2 }}%</strong><br> + <strong>Mandatory Total: {{ctrl.statistics.mandatory.total}}, Pass: {{ ctrl.statistics.mandatory.pass }}, Rate: {{ ctrl.statistics.mandatory.pass / ctrl.statistics.mandatory.total * 100 | number:2 }}%</strong><br> + <strong>Optional Total: {{ctrl.statistics.optional.total}}, Pass: {{ ctrl.statistics.optional.pass }}, Rate: {{ ctrl.statistics.optional.pass / ctrl.statistics.optional.total * 100 | number:2 }}%</strong><br> + <hr> + <strong>{{ ctrl.validation }}</strong><br> + + <div> + <hr> + <h4>Test Result Overview</h4> + <uib-accordion close-others=false> + <!-- The ng-repeat is used to pass in a local variable to the template. --> + <ng-include + src="ctrl.detailsTemplate" + onload="isOpen = true"> + </ng-include> + <br> + </uib-accordion> + </div> +</div> diff --git a/3rd_party/static/onap-ui/components/results-report/resultsReportController.js b/3rd_party/static/onap-ui/components/results-report/resultsReportController.js new file mode 100644 index 0000000..09601ad --- /dev/null +++ b/3rd_party/static/onap-ui/components/results-report/resultsReportController.js @@ -0,0 +1,224 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ResultsReportController', ResultsReportController); + + ResultsReportController.$inject = [ + '$scope', '$http', '$stateParams', '$window', + 'testapiApiUrl' + ]; + + /** + * TestAPI Results Report Controller + * This controller is for the '/results/<test run ID>' page where a user can + * view details for a specific test run. + */ + function ResultsReportController($scope, $http, $stateParams, $window, + testapiApiUrl) { + + var ctrl = this; + + ctrl.testStatus = 'total'; + ctrl.case_list = []; + ctrl.data = {}; + ctrl.statistics = { + 'total': 0, 'pass': 0, 'fail': 0, + 'mandatory': {'total': 0, 'pass': 0, 'fail': 0, 'area': 0}, + 'optional': {'total': 0, 'pass': 0, 'fail': 0, 'area': 0} + }; + + ctrl.gotoDoc = gotoDoc; + ctrl.openAll = openAll; + ctrl.folderAll = folderAll; + ctrl.gotoResultLog = gotoResultLog; + ctrl.changeStatus = changeStatus; + + /** The testID extracted from the URL route. */ + ctrl.testId = $stateParams.testID; + ctrl.innerId = $stateParams.innerID; + ctrl.validation = ''; + ctrl.vnf_type = ''; + ctrl.vnf_checksum = ''; + ctrl.version = ''; + + /** The HTML template that all accordian groups will use. */ + ctrl.detailsTemplate = 'onap-ui/components/results-report/partials/' + + 'reportDetails.html'; + + $scope.load_finish = false; + + function changeStatus(value) { + ctrl.testStatus = value; + } + + function extend(case_list) { + angular.forEach(case_list, function(ele) { + ctrl.case_list.push(ele); + }); + } + + function strip(word) { + return word.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + } + + function gotoResultLog(case_name) { + var case_area = case_name.split(".")[0]; + var log_url = "/logs/" + ctrl.testId + "/results/"; + log_url += case_area + "_logs/" + case_name + ".out"; + var is_reachable = false; + + $.ajax({ + url: log_url, + async: false, + success: function (response) { + is_reachable = true; + }, + error: function (response) { + alert("Log file could not be found. Please confirm this case has been executed successfully."); + } + }); + + if (is_reachable == true) { + window.open(log_url); + } + } + + $scope.$watch('load_finish', function() { + if ($scope.load_finish == true) { + var case_url = 'onap-ui/components/results-report/data/' + ctrl.version + '/' + ctrl.vnf_type + '-testcases.json' + $http.get(case_url).then(function(response) { + ctrl.data = response.data; + + angular.forEach(ctrl.data.mandatory, function(value, name) { + ctrl.data.mandatory[name].folder = true; + ctrl.data.mandatory[name].pass = 0; + ctrl.data.mandatory[name].fail = 0; + angular.forEach(value.cases, function(sub_case) { + ctrl.statistics.total += 1; + ctrl.statistics.mandatory.total += 1; + if (ctrl.case_list.indexOf(sub_case) > -1) { + ctrl.data.mandatory[name].pass += 1; + ctrl.statistics.mandatory.pass += 1; + ctrl.statistics.pass += 1; + } else { + ctrl.data.mandatory[name].fail += 1; + ctrl.statistics.mandatory.fail += 1; + ctrl.statistics.fail += 1; + } + }); + }); + + angular.forEach(ctrl.data.optional, function(value, name) { + ctrl.data.optional[name].folder = true; + ctrl.data.optional[name].pass = 0; + ctrl.data.optional[name].fail = 0; + angular.forEach(value.cases, function(sub_case) { + ctrl.statistics.total += 1; + ctrl.statistics.optional.total += 1; + if (ctrl.case_list.indexOf(sub_case) > -1) { + ctrl.data.optional[name].pass += 1; + ctrl.statistics.optional.pass += 1; + ctrl.statistics.pass += 1; + } else { + ctrl.data.optional[name].fail += 1; + ctrl.statistics.optional.fail += 1; + ctrl.statistics.fail += 1; + } + + }); + }); + + ctrl.statistics.mandatory.area = Object.keys(ctrl.data.mandatory).length; + ctrl.statistics.optional.area = Object.keys(ctrl.data.optional).length; + }, function(error) { + alert('error to get test case info'); + }); + } + }); + + function generate_format_data() { + var test_url = testapiApiUrl + '/onap/tests/' + ctrl.innerId; + $http.get(test_url).then(function(test_resp) { + ctrl.validation = test_resp.data.validation; + + angular.forEach(test_resp.data.results, function(result, index) { + var result_url = testapiApiUrl + '/results/' + result; + $http.get(result_url).then(function(result_resp) { + + ctrl.version = result_resp.data.version; + ctrl.vnf_type = result_resp.data.vnf_type; + + angular.forEach(result_resp.data.testcases_list, function(testcase, index) { + var sub_case_list = get_sub_case_list_2019_04(testcase); + extend(sub_case_list); + }); + + if (index == test_resp.data.results.length - 1) { + $scope.load_finish = true; + } + }, function(result_error) { + /* do nothing */ + }); + }); + + }, function(test_error) { + alert('Error when get test record'); + }); + } + + function get_sub_case_list_2019_04(result) { + var case_list = []; + if (result.sub_testcase.length == 0 && result.result == "PASS") { + case_list.push(result.name); + } else { + angular.forEach(result.sub_testcase, function(subtest, index) { + if (subtest.result == "PASS") { + case_list.push(subtest.name) + } + }); + } + return case_list; + } + + function gotoDoc(sub_case) { + /* not implemented */ + } + + function openAll() { + angular.forEach(ctrl.data.mandatory, function(ele, id) { + ele.folder = false; + }); + angular.forEach(ctrl.data.optional, function(ele, id) { + ele.folder = false; + }); + } + + function folderAll() { + angular.forEach(ctrl.data.mandatory, function(ele, id) { + ele.folder = true; + }); + angular.forEach(ctrl.data.optional, function(ele, id) { + ele.folder = true; + }); + } + + generate_format_data(); + } + +})(); diff --git a/3rd_party/static/onap-ui/components/results/modal/applicationModal.html b/3rd_party/static/onap-ui/components/results/modal/applicationModal.html new file mode 100644 index 0000000..0ca4b84 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results/modal/applicationModal.html @@ -0,0 +1,158 @@ +<div class="container-fluid common-main-container"> + <div class="top-site-banner"> + <div class="container"> + <p class="p1">Application Details</p> + </div> + </div> + + <div class="row" style="margin-top: 20px;"> + <div class="col-lg-12 container"> + <p class="message" style="display: none;"></p> + <fieldset> + <div class="field text col-md-4"> + <label class="left">Company Name</label> + <i uib-tooltip="Company Name" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="text" class="text form-control" ng-model="ctrl.company_name" + ng-init="ctrl.company_name=auth.currentUser.companyName" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Company Logo</label> + <i uib-tooltip="Required dimensions (Max Values): {width: 165pixels, height: 40pixels}" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input class="form-control btn btn-success-cust cvp-btn medium accent-color regular-button" + modal-file-model="logoFile" type="file" style="padding: 0;" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Company Website</label> + <i uib-tooltip="Company Website" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="url" class="text form-control" ng-model="ctrl.company_website" + ng-init="ctrl.company_website=auth.currentUser.companyWebsite" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Primary Contact Name</label> + <i uib-tooltip="Primary Contact name (optional)" + class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="text" class="text form-control" ng-model="ctrl.primary_contact_name" + ng-init="ctrl.primary_contact_name=auth.currentUser.primaryContactName" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Primary Contact Number</label> + <i uib-tooltip="Primary Contact phone number(optional)" + class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="tel" class="text form-control" ng-model="ctrl.primary_phone_number" + ng-init="ctrl.primary_phone_number=auth.currentUser.primaryPhoneNumber" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Primary Contact Email</label> + <i uib-tooltip="Primary Contact email (optional)" + class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="email" class="text form-control" ng-model="ctrl.primary_business_email" + ng-init="ctrl.primary_business_email=auth.currentUser.primaryBusinessEmail" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Test Agency</label> + <i uib-tooltip="Location" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <select class="form-control" ng-model="ctrl.lab_location" ng-init="ctrl.lab_location='internal'" required> + <option value="internal">1st Party - Submitter</option> + <option value="third">3rd Party - External Lab</option> + </select> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Version</label> + <i uib-tooltip="xNF Version" + class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="text" class="text form-control" ng-model="ctrl.xnf_version" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Name</label> + <i uib-tooltip="xNF Name" + class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="text" class="text form-control" ng-model="ctrl.xnf_name" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Test Type</label> + <i uib-tooltip="xNF Type" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <select class="form-control" ng-model="ctrl.xnf_type" ng-init="ctrl.xnf_type='VNF'" required> + <option value="VNF">VNF</option> + </select> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Description</label> + <i uib-tooltip="xNF Description" + class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="text" class="text form-control" ng-model="ctrl.xnf_description" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">xNFD Id</label> + <i uib-tooltip="xNFD Id" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <input type="text" class="text form-control" ng-model="ctrl.xnfd_id" required> + </div> + </div> + <div class="field text col-md-4"> + <label class="left">Test Category</label> + <i uib-tooltip="Define test category<" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <div class="middleColumn"> + <select class="form-control" ng-model="ctrl.xnf_test_period" ng-init="ctrl.xnf_test_period='Packaging Compliance Test'" required> + <option value="Packaging Compliance Test">Packaging Compliance Test</option> + <option value="Lifecycle">Lifecycle Test</option> + <option value="Functional">Functional Test</option> + <option value="Performance">Performance Test</option> + </select> + </div> + </div> + <div ng-if="ctrl.lab_location=='third'" class="field text"> + <div class="field text col-md-4"> + <label class="left">Lab Name</label> + <i uib-tooltip="Lab Name" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <input type="text" class="text form-control" ng-model="ctrl.lab_name" required> + </div> + <div class="field text col-md-4"> + <label class="left">Lab Email</label> + <i uib-tooltip="Lab Email" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <input type="email" class="text form-control" ng-model="ctrl.lab_email" required> + </div> + <div class="field text col-md-4"> + <label class="left">Lab Address</label> + <i uib-tooltip="Lab Address" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <input type="text" class="text form-control" ng-model="ctrl.lab_address" required> + </div> + <div class="field text col-md-4"> + <label class="left">Lab Phone Number</label> + <i uib-tooltip="Lab Phone Number" class="glyphicon glyphicon-question-sign opnfv-blue"></i> + <input type="tel" class="text form-control" ng-model="ctrl.lab_phone" required> + </div> + </div> + </fieldset> + </div> + </div> + <button class="btn btn-default" + ng-click="ctrl.openConfirmModal(ctrl.tempResult)">Submit</button> +</div> + +<style type="text/css"> + .ngdialog.custom-background .ngdialog-content { + background: #ffffff; + } +</style> diff --git a/3rd_party/static/onap-ui/components/results/modal/applicationView.html b/3rd_party/static/onap-ui/components/results/modal/applicationView.html new file mode 100644 index 0000000..79341f8 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results/modal/applicationView.html @@ -0,0 +1,103 @@ +<div class="container-fluid common-main-container"> + <div class="top-site-banner"> + <div class="container"> + <p class="p1">Application Details</p> + </div> + </div> + + <div class="row" style="margin-top: 20px;"> + <div class="col-lg-12 container"> + <p class="message" style="display: none;"></p> + <fieldset> + <div class="field text col-md-4"> + <label class="left">Company Name</label> + <div class="middleColumn">{{ ctrl.application.company_name }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Company Logo</label> + <div class="middleColumn">{{ ctrl.application.company_logo }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Company Website</label> + <div class="middleColumn">{{ ctrl.application.company_website }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">ONAP Version</label> + <div class="middleColumn">{{ ctrl.application.onap_version }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Primary Contact Name</label> + <div class="middleColumn">{{ ctrl.application.primary_contact_name }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Primary Contact Number</label> + <div class="middleColumn">{{ ctrl.application.primary_phone_number }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Primary Contact Email</label> + <div class="middleColumn">{{ ctrl.application.primary_business_email }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Test Agency</label> + <div class="middleColumn">{{ ctrl.application.lab_location }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Version</label> + <div class="middleColumn">{{ ctrl.application.xnf_version }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Name</label> + <div class="middleColumn">{{ ctrl.application.xnf_name }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Test Type</label> + <div class="middleColumn">{{ ctrl.application.xnf_type }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Description</label> + <div class="middleColumn">{{ ctrl.application.xnf_description }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">xNFD Id</label> + <div class="middleColumn">{{ ctrl.application.xnfd_id }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Model Language</label> + <div class="middleColumn">{{ ctrl.application.xnfd_model_lang }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Test Category</label> + <div class="middleColumn">{{ ctrl.application.xnf_test_period }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">xNF Checksum (SHA256)</label> + <div class="middleColumn">{{ ctrl.application.xnf_checksum }}</div> + </div> + <div ng-if="ctrl.lab_location=='third'" class="field text"> + <div class="field text col-md-4"> + <label class="left">Lab Name</label> + <div>{{ ctrl.application.lab_name }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Lab Email</label> + <div>{{ ctrl.application.lab_email }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Lab Address</label> + <div>{{ ctrl.application.lab_address }}</div> + </div> + <div class="field text col-md-4"> + <label class="left">Lab Phone Number</label> + <div>{{ ctrl.application.lab_phone }}</div> + </div> + </div> + </fieldset> + </div> + </div> +</div> + +<style type="text/css"> + .ngdialog.custom-background .ngdialog-content { + background: #ffffff; + } +</style> diff --git a/3rd_party/static/onap-ui/components/results/modal/reviewsModal.html b/3rd_party/static/onap-ui/components/results/modal/reviewsModal.html new file mode 100644 index 0000000..c93d1ef --- /dev/null +++ b/3rd_party/static/onap-ui/components/results/modal/reviewsModal.html @@ -0,0 +1,41 @@ +<div class="container-fluid common-main-container"> + <div class="top-site-banner"> + <div class="container"> + <p class="p1">Community Reviews</p> + </div> + </div> + + <div class="row" style="margin-top: 20px;"> + <div class="col-lg-12 container"> + <div cg-busy="{promise:ctrl.reviewsRequest,message:'Loading'}"></div> + <div ng-show="ctrl.reviews" class="results-table" style="width: 100%; overflow-x: scroll;"> + <table ng-data="ctrl.reviews" ng-show="ctrl.reviews" class="table table-striped table-hover"> + <thead> + <tr> + <th>Reviewer</th> + <th>Linux Foundation OpenId</th> + <th>Email</th> + <th>Review Date</th> + <th>Outcome</th> + </tr> + </thead> + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-repeat="(index, review) in ctrl.reviews"> + <td>{{ review.reviewer_name }}</td> + <td>{{ review.reviewer_openid }}</td> + <td>{{ review.reviewer_email }}</td> + <td>{{ review.creation_date | limitTo:19}}</td> + <td>{{ review.outcome }}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> +</div> + +<style type="text/css"> + .ngdialog.custom-background .ngdialog-content { + background: #ffffff; + } +</style> diff --git a/3rd_party/static/onap-ui/components/results/modal/sharedModal.html b/3rd_party/static/onap-ui/components/results/modal/sharedModal.html new file mode 100644 index 0000000..021a355 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results/modal/sharedModal.html @@ -0,0 +1,16 @@ +<div> + <h4>Enter user name or email</h4> + <input type="text" ng-model="ctrl.userName"> + <div style="text-align: center; margin-top: 20px;"> + <button class="btn btn-default" ng-disabled="ctrl.userName==null || ctrl.userName==''" + ng-click="ctrl.addSharedUser(ctrl.tempResult, ctrl.userName)">Commit</button> + </div> +</div> + +<style> + input { + border-radius: 10px; + border: 1px solid #eeeeee; + width: 100%; + } +</style> diff --git a/3rd_party/static/onap-ui/components/results/results.html b/3rd_party/static/onap-ui/components/results/results.html new file mode 100644 index 0000000..ce43036 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results/results.html @@ -0,0 +1,168 @@ +<div class="container-fluid common-main-container"> + <h3>{{ctrl.pageHeader}}</h3> + <p>{{ctrl.pageParagraph}}</p> + <form class="form-inline" ng-show="ctrl.isUserResults"> + <h4>Upload Results + <i class="glyphicon glyphicon-question-sign opnfv-blue" + uib-tooltip="results file is logs.xxx.tar.gz under your dovetail installation path"></i> + </h4> + <div class="form-group col-m-3"> + <input class="form-contrl btn btn-success-cust cvp-btn medium accent-color regular-button" type="file" + file-model="resultFile"> + </div> + <div class="form-group col-m-3"> + <a class="btn btn-success-cust cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadFile()"> + <span>upload result</span> + </a> + </div> + <div> + <label>{{ctrl.uploadState}}</label> + </div> + </form> + <div class="row" style="margin-bottom: 24px;"></div> + <div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div> + <div cg-busy="{promise:ctrl.resultsRequest,message:'Loading'}"></div> + + <div ng-show="ctrl.data" class="results-table" style="width: 100%; overflow-x: scroll;"> + <table ng-data="ctrl.data.result" ng-show="ctrl.data" class="table table-striped table-hover"> + <thead> + <tr> + <th>Upload Date</th> + <th>Test ID</th> + <th>ONAP Version</th> + <th>Modeling Language</th> + <th>Owner</th> + <th>File Name</th> + <th>Label</th> + <th>Status</th> + <th>Log</th> + <th>Application</th> + <th>Review Status</th> + <th class="col-md-2">Operation</th> + <th class="col-md-2">Share List</th> + </tr> + </thead> + + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-repeat="(index, result) in ctrl.data.tests"> + <td>{{ result.upload_date | limitTo:19}}</td> + <td> + <a uib-tooltip="{{ result.id }}" tooltip-placement="top" tooltip-append-to-body="true" + ng-click="ctrl.gotoResultDetail(result.id, result._id)">{{ result.id | limitTo:8 }}</a> + </td> + <td>{{ result.version || "2019.04" }}</td> + <td>{{ result.vnf_type.toUpperCase() }}</td> + <td>{{ result.owner }}</td> + <td>{{ result.filename || "None"}}</td> + <td> + <div class="popover-wrapper"> + <a editable-theme="bs3" onbeforesave="ctrl.changeLabel(result, 'label', $data)" + editable-text="result.label">{{ result.label || "None" }}</a> + </div> + </td> + <td>{{ result.status }}</td> + <td><a ng-click="ctrl.downloadLogs(result.id)">logs</a></td> + <td> + <a ng-if="result.status !='private'" ng-click="ctrl.openApplicationView(result)">View Application</a> + <div ng-if="result.status == 'private'">Not created</div> + </td> + <td><a ng-if="result.status !='private'" ng-click="ctrl.openReviewsModal(result.id)">View Reviews</a> + <div ng-if="result.status == 'private'"></div> + </td> + <td> + <div class="btn-group" uib-dropdown> + <a id="single-button" type="button" class="btn btn-success-cust cvp-btn medium accent-color regular-button" + uib-dropdown-toggle> + Operation<span class="caret"></span> + </a> + <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button"> + <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-class="{'hide': result.status != 'review'}" + ng-click="ctrl.deleteApplication(result)">withdraw submit</a> + </li> + <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-class="{'hide': result.status != 'private'}" + ng-click="ctrl.openApplicationModal(result)">submit to review</a> + </li> + <li role="menuitem" + ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-class="{'hide': (result.voted == 'true') || (result.status != 'review')}" + ng-click="ctrl.toApprove(result)">approve</a> + </li> + <li role="menuitem" + ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-class="{'hide': (result.voted == 'true') || (result.status != 'review')}" + ng-click="ctrl.toDisapprove(result)">not approve</a> + </li> + <li role="menuitem" + ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-class="{'hide': (result.voted == 'false') || (result.status != 'review')}" + ng-click="ctrl.toUndo(result)">undo</a> + </li> + <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-click="ctrl.openSharedModal(result)">share with</a> + </li> + <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults" + class="menu-item menu-item-type-post_type menu-item-object-page"> + <a ng-click="ctrl.deleteTest(result._id)">delete</a> + </li> + </ul> + </div> + </td> + <td> + <div class="btn-group" uib-dropdown> + <a id="single-button-two" type="button" + class="btn btn-success-cust cvp-btn medium accent-color regular-button" style="width: 130px;" + uib-dropdown-toggle> + Share List<span class="caret"></span> + </a> + <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button-two" + style="min-width: 200%;"> + <li class="menu-item menu-item-type-post_type menu-item-object-page" role="menuitem" + ng-repeat="share in result.shared track by $index"> + <span> + {{ share }} + <i ng-if="auth.currentUser.openid == result.owner" class="pull-right glyphicon glyphicon-remove" + ng-click="ctrl.removeSharedUser(result, share)"></i> + </span> + </li> + </ul> + </div> + </td> + </tr> + </tbody> + </table> + <div class="pages"> + <uib-pagination + total-items="ctrl.totalItems" + ng-model="ctrl.currentPage" + items-per-page="ctrl.itemsPerPage" + max-size="ctrl.maxSize" + class="pagination-sm" + boundary-links="true" + rotate="false" + num-pages="ctrl.numPages" + ng-change="ctrl.update()"> + </uib-pagination> + </div> + </div> +</div> + +<div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> + <span class="sr-only">Error:</span> + {{ctrl.error}} +</div> + + +<style> + .button-disabled { + pointer-events: none; + } +</style> diff --git a/3rd_party/static/onap-ui/components/results/resultsController.js b/3rd_party/static/onap-ui/components/results/resultsController.js new file mode 100644 index 0000000..d459495 --- /dev/null +++ b/3rd_party/static/onap-ui/components/results/resultsController.js @@ -0,0 +1,614 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ResultsController', ResultsController); + + angular + .module('testapiApp') + .directive('fileModel', ['$parse', function ($parse) { + return { + restrict: 'A', + link: function(scope, element, attrs) { + var model = $parse(attrs.fileModel); + var modelSetter = model.assign; + + element.bind('change', function(){ + scope.$apply(function(){ + modelSetter(scope, element[0].files[0]); + }); + }); + } + }; + }]); + + angular + .module('testapiApp') + .directive('modalFileModel', ['$parse', function ($parse) { + return { + restrict: 'A', + link: function(scope, element, attrs) { + var model = $parse(attrs.modalFileModel); + var modelSetter = model.assign; + + element.bind('change', function(){ + scope.$apply(function(){ + modelSetter(scope.$parent, element[0].files[0]); + }); + }); + } + }; + }]); + + ResultsController.$inject = [ + '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert', 'ngDialog', '$resource' + ]; + + /** + * TestAPI Results Controller + * This controller is for the '/results' page where a user can browse + * a listing of community uploaded results. + */ + function ResultsController($scope, $http, $filter, $state, testapiApiUrl, raiseAlert, ngDialog, $resource) { + var ctrl = this; + + ctrl.uploadFile=uploadFile; + ctrl.update = update; + ctrl.open = open; + ctrl.clearFilters = clearFilters; + ctrl.associateMeta = associateMeta; + ctrl.gotoResultDetail = gotoResultDetail; + ctrl.toggleCheck = toggleCheck; + ctrl.changeLabel = changeLabel; + ctrl.toApprove = toApprove; + ctrl.toDisapprove = toDisapprove; + ctrl.toUndo = toUndo; + ctrl.toReview = toReview; + ctrl.toPrivate = toPrivate; + ctrl.removeSharedUser = removeSharedUser; + ctrl.addSharedUser = addSharedUser; + ctrl.openSharedModal = openSharedModal; + ctrl.downloadLogs = downloadLogs; + ctrl.deleteApplication = deleteApplication; + ctrl.deleteTest = deleteTest; + ctrl.openApplicationModal = openApplicationModal; + ctrl.openApplicationView = openApplicationView; + ctrl.submitApplication = submitApplication; + ctrl.openConfirmModal = openConfirmModal; + ctrl.openReviewsModal = openReviewsModal; + + /** Mappings of Interop WG components to marketing program names. */ + ctrl.targetMappings = { + 'platform': 'Openstack Powered Platform', + 'compute': 'OpenStack Powered Compute', + 'object': 'OpenStack Powered Object Storage' + }; + + /** Initial page to be on. */ + ctrl.currentPage = 1; + + /** + * How many results should display on each page. Since pagination + * is server-side implemented, this value should match the + * 'results_per_page' configuration of the TestAPI server which + * defaults to 20. + */ + ctrl.itemsPerPage = 20; + + /** + * How many page buttons should be displayed at max before adding + * the '...' button. + */ + ctrl.maxSize = 5; + + /** The upload date lower limit to be used in filtering results. */ + ctrl.startDate = ''; + + /** The upload date upper limit to be used in filtering results. */ + ctrl.endDate = ''; + + /** The date format for the date picker. */ + ctrl.format = 'yyyy-MM-dd'; + + ctrl.userName = null; + + /** Check to see if this page should display user-specific results. */ + ctrl.isUserResults = $state.current.name === 'userResults'; + + /** Check to see if this page should display community results. */ + ctrl.isReviewer = $scope.auth.currentUser.role.indexOf('reviewer') != -1; + ctrl.isAdministrator = $scope.auth.currentUser.role.indexOf('administrator') != -1; + + ctrl.currentUser = $scope.auth.currentUser ? $scope.auth.currentUser.openid : null; + + // Should only be on user-results-page if authenticated. + if (!$scope.auth.isAuthenticated) { + $state.go('home'); + } + // Should only be on community-results if reviewer + if (!ctrl.isUserResults && !ctrl.isReviewer) { + $state.go('home'); + } + + ctrl.pageHeader = ctrl.isUserResults ? + 'Private test results' : 'Community test results'; + + ctrl.pageParagraph = ctrl.isUserResults ? + 'Your most recently uploaded test results are listed here.' : + 'The most recently uploaded community test results are listed ' + + 'here.'; + + ctrl.uploadState = ''; + + ctrl.authRequest = $scope.auth.doSignCheck().then(ctrl.update); + + function downloadLogs(id) { + // var logsUrl = testapiApiUrl + "/logs/log_" + id+".tar.gz"; + var logsUrl = "/logs/" + id + "/results/"; + window.location.href = logsUrl; + // $http.get(logsUrl); + } + + function deleteTest(inner_id) { + var resp = confirm('Are you sure to delete this test?'); + if (!resp) + return; + + var delUrl = testapiApiUrl + "/onap/tests/" + inner_id; + $http.get(delUrl) + .then( function(resp) { + var results = resp.data.results; + $http.delete(delUrl) + .then( function(ret) { + if(ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + return; + } + ctrl.update(); + angular.forEach(results, function(ele) { + delUrl = testapiApiUrl + "/results/" + ele; + $http.delete(delUrl); + }); + }); + }); + } + + function deleteApplication (result) { + var resp = confirm('Are you sure you want to delete this application?'); + if (!resp) + return; + + $http.get(testapiApiUrl + "/onap/cvp/applications?test_id=" + result.id).then(function(response) { + ctrl.application = response.data.applications[0]; + var app_id = ctrl.application._id; + var delUrl = testapiApiUrl + "/cvp/applications/" + app_id; + $http.delete(delUrl) + .then(function(ret) { + if (ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + return; + } + result['status'] = 'private'; + }); + + }, function(error) { + /* do nothing */ + }); + + } + + function submitApplication(result) { + var file = $scope.logoFile; + var logo_name = null; + if (typeof file !== 'undefined') { + + var fd = new FormData(); + fd.append('file', file); + fd.append('company_name', ctrl.company_name) + + $http.post(testapiApiUrl + "/cvp/applications/uploadlogo", fd, { + transformRequest: angular.identity, + headers: {'Content-Type': undefined} + }).then(function(resp) { + if (resp.data.code && resp.data.code != 0) { + alert(resp.data.msg); + return; + } else { + logo_name = resp.data.filename; + var data = { + "description": ctrl.description, + "onap_version": result.version, + "company_name": ctrl.company_name, + "company_logo": logo_name, + "company_website": ctrl.company_website, + "approve_date": "", + "approved": "false", + "test_id": result.id, + "lab_location": ctrl.lab_location, + "lab_email": ctrl.lab_email, + "lab_address": ctrl.lab_address, + "lab_phone": ctrl.lab_phone, + "xnf_version": ctrl.xnf_version, + "certification_type": ctrl.certification_type, + "xnf_name": ctrl.xnf_name, + "xnf_type": ctrl.xnf_type, + "xnf_description": ctrl.xnf_description, + "xnfd_id": ctrl.xnfd_id, + "xnfd_model_lang": result.vnf_type.toUpperCase(), + "xnf_checksum": result.vnf_checksum, + "xnf_test_period": ctrl.xnf_test_period, + "primary_contact_name": ctrl.primary_contact_name, + "primary_phone_number": ctrl.primary_phone_number, + "primary_business_email": ctrl.primary_business_email + }; + + $http.post(testapiApiUrl + "/onap/cvp/applications", data).then(function(resp) { + if (resp.data.code && resp.data.code != 0) { + alert(resp.data.msg); + return; + } + toggleCheck(result, 'status', 'review'); + }, function(error) { + /* do nothing */ + }); + } + }, function(error) { + /* do nothing */ + }); + logo_name = file.name; + } + ngDialog.close(); + } + + function openConfirmModal(result) { + var resp = confirm("Are you sure to submit?"); + if (resp) { + ctrl.submitApplication(result); + } + } + + function openApplicationModal(result) { + ctrl.tempResult = result; + ngDialog.open({ + preCloseCallback: function(value) { + }, + template: 'onap-ui/components/results/modal/applicationModal.html', + scope: $scope, + className: 'ngdialog-theme-default custom-background', + width: 950, + showClose: true, + closeByDocument: true + }); + } + + function openApplicationView(result) { + + $http.get(testapiApiUrl + "/onap/cvp/applications?test_id=" + result.id).then(function(response) { + ctrl.application = response.data.applications[0]; + }, function(error) { + /* do nothing */ + }); + + ctrl.tempResult = result; + ngDialog.open({ + preCloseCallback: function(value) { + }, + template: 'onap-ui/components/results/modal/applicationView.html', + scope: $scope, + className: 'ngdialog-theme-default custom-background', + width: 950, + showClose: true, + closeByDocument: true + }); + } + + function getReviews(test) { + var reviews_url = testapiApiUrl + '/onap/reviews?test_id=' + test; + ctrl.reviewsRequest = + $http.get(reviews_url).success(function (data) { + ctrl.reviews = data.reviews; + }).error(function (error) { + ctrl.reviews = null; + }); + } + + function openReviewsModal(test) { + getReviews(test); + ngDialog.open({ + preCloseCallback: function(value) { + }, + template: 'onap-ui/components/results/modal/reviewsModal.html', + scope: $scope, + className: 'ngdialog-theme-default custom-background', + width: 950, + showClose: true, + closeByDocument: true + }); + } + + function toggleCheck(result, item, newValue) { + var id = result._id; + var updateUrl = testapiApiUrl + "/onap/tests/"+ id; + + var data = {}; + data['item'] = item; + data[item] = newValue; + + $http.put(updateUrl, JSON.stringify(data), { + transformRequest: angular.identity, + headers: {'Content-Type': 'application/json'}}).then(function(ret) { + if(ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + } else { + result[item] = newValue; + } + }, function(error) { + alert('Error when update data'); + }); + } + + function changeLabel(result, key, data){ + if (result[key] !== data) { + toggleCheck(result, key, data); + } + } + + function doReview(test, outcome) { + var createUrl = testapiApiUrl + "/onap/reviews"; + var data = { + 'test_id': test.id, + 'outcome': outcome + }; + + $http.post(createUrl, JSON.stringify(data), { + transformRequest: angular.identity, + headers: {'Content-Type': 'application/json'}}).then(function(ret) { + if (ret.data.code && ret.data.code != 0) { + alert(ret.data.msg); + } else { + if (outcome === null) { + test.voted = 'false'; + } else { + test.voted = 'true'; + } + } + }, function(error) { + alert('Error when creating review'); + }); + } + + function toApprove(test) { + var resp = confirm('Once you approve a test result, your action will become visible. Do you want to proceed?'); + if (resp) { + doReview(test, 'positive'); + } + } + + function toDisapprove(test) { + var resp = confirm('Once you disapprove a test result, your action will become visible. Do you want to proceed?'); + if (resp) { + doReview(test, 'negative'); + } + } + + function toUndo(test) { + var resp = confirm('Once you undo your previous vote, your action will become visible. Do you want to proceed?'); + if (resp) { + doReview(test, null); + } + } + + function toReview(result, value){ + var resp = confirm('Once you submit a test result for review, it will become readable to all ONAPVP reviewers. Do you want to proceed?'); + if(resp){ + toggleCheck(result, 'status', value); + } + } + + function toPrivate(result, value){ + var resp = confirm('Do you want to proceed?'); + if(resp){ + toggleCheck(result, 'status', value); + } + } + + function openSharedModal(result){ + ctrl.tempResult = result; + ngDialog.open({ + preCloseCallback: function(value) { + }, + template: 'onap-ui/components/results/modal/sharedModal.html', + scope: $scope, + className: 'ngdialog-theme-default', + width: 950, + showClose: true, + closeByDocument: true + }); + } + + function addSharedUser(result, userId){ + var tempList = copy(result.shared); + tempList.push(userId); + toggleCheck(result, 'shared', tempList); + ngDialog.close(); + } + + function removeSharedUser(result, userId){ + var tempList = copy(result.shared); + var idx = tempList.indexOf(userId); + if(idx != -1){ + tempList.splice(idx, 1); + toggleCheck(result, 'shared', tempList); + } + } + + function copy(arrList){ + var tempList = []; + angular.forEach(arrList, function(ele){ + tempList.push(ele); + }); + return tempList; + } + + function uploadFileToUrl(file, uploadUrl){ + var fd = new FormData(); + fd.append('file', file); + + $http.post(uploadUrl, fd, { + transformRequest: angular.identity, + headers: {'Content-Type': undefined} + }).then(function(data){ + + if(data.data.code && data.data.code != 0){ + alert(data.data.msg); + return; + } + + ctrl.uploadState = ""; + data.data.filename = file.name; + var createTestUrl = testapiApiUrl + "/onap/tests" + + $http.post(createTestUrl, data.data).then(function(data){ + if (data.data.code && data.data.code != 0) { + alert(data.data.msg); + } else { + ctrl.update(); + } + }, function(error){ + }); + + }, function(error){ + ctrl.uploadState = "Upload failed. Error code is " + error.status; + }); + } + + function uploadFile(){ + var file = $scope.resultFile; + + var uploadUrl = testapiApiUrl + "/onap/results/upload"; + uploadFileToUrl(file, uploadUrl); + }; + + /** + * This will contact the TestAPI API to get a listing of test run + * results. + */ + function update() { + ctrl.showError = false; + // Construct the API URL based on user-specified filters. + var content_url = testapiApiUrl + '/onap/tests'; + var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd'); + var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd'); + + content_url += '?page=' + ctrl.currentPage; + content_url += '&per_page=' + ctrl.itemsPerPage; + if (start) { + content_url += '&from=' + start + ' 00:00:00'; + } + if (end) { + content_url += '&to=' + end + ' 23:59:59'; + } + if (ctrl.isUserResults) { + content_url += '&signed'; + } else { + content_url += '&status={"$ne":"private"}&review'; + } + + ctrl.resultsRequest = + $http.get(content_url).success(function (data) { + ctrl.data = data; + ctrl.totalItems = ctrl.data.pagination.total_pages * ctrl.itemsPerPage; + ctrl.currentPage = ctrl.data.pagination.current_page; + ctrl.numPages = ctrl.data.pagination.total_pages; + }).error(function (error) { + ctrl.data = null; + ctrl.totalItems = 0; + ctrl.showError = true; + ctrl.error = + 'Error retrieving results listing from server: ' + + angular.toJson(error); + }); + } + + /** + * This is called when the date filter calendar is opened. It + * does some event handling, and sets a scope variable so the UI + * knows which calendar was opened. + * @param {Object} $event - The Event object + * @param {String} openVar - Tells which calendar was opened + */ + function open($event, openVar) { + $event.preventDefault(); + $event.stopPropagation(); + ctrl[openVar] = true; + } + + /** + * This function will clear all filters and update the results + * listing. + */ + function clearFilters() { + ctrl.startDate = null; + ctrl.endDate = null; + ctrl.update(); + } + + /** + * This will send an API request in order to associate a metadata + * key-value pair with the given testId + * @param {Number} index - index of the test object in the results list + * @param {String} key - metadata key + * @param {String} value - metadata value + */ + function associateMeta(index, key, value) { + var testId = ctrl.data.results[index].id; + var metaUrl = [ + testapiApiUrl, '/results/', testId, '/meta/', key + ].join(''); + + var editFlag = key + 'Edit'; + if (value) { + ctrl.associateRequest = $http.post(metaUrl, value) + .success(function () { + ctrl.data.results[index][editFlag] = false; + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } + else { + ctrl.unassociateRequest = $http.delete(metaUrl) + .success(function () { + ctrl.data.results[index][editFlag] = false; + }).error(function (error) { + if (error.code == 404) { + // Key doesn't exist, so count it as a success, + // and don't raise an alert. + ctrl.data.results[index][editFlag] = false; + } + else { + raiseAlert('danger', error.title, error.detail); + } + }); + } + } + + function gotoResultDetail(testId, innerID) { + $state.go('resultsDetail', {'testID': testId, 'innerID': innerID}); + } + } +})(); |