From 30b87f5d9c3fd3a27755e3974435afab2a42d081 Mon Sep 17 00:00:00 2001 From: SerenaFeng Date: Tue, 21 Nov 2017 14:54:15 +0800 Subject: move self-developed front-end codes to ui/ Change-Id: I0b64661e73d940a577f27ded9322086788e4f5f3 Signed-off-by: SerenaFeng --- testapi/3rd_party/static/testapi-ui/Gruntfile.js | 162 ---- testapi/3rd_party/static/testapi-ui/app.js | 260 ------ testapi/3rd_party/static/testapi-ui/config.json | 1 - .../3rd_party/static/testapi-ui/favicon-16x16.png | Bin 638 -> 0 bytes .../3rd_party/static/testapi-ui/favicon-32x32.png | Bin 1540 -> 0 bytes testapi/3rd_party/static/testapi-ui/favicon.ico | Bin 318 -> 0 bytes testapi/3rd_party/static/testapi-ui/index.html | 62 -- testapi/3rd_party/static/testapi-ui/package.json | 18 - testapi/3rd_party/static/testapi-ui/robots.txt | 4 - .../testapi-ui/shared/alerts/alertModal.html | 8 - .../testapi-ui/shared/alerts/alertModalFactory.js | 74 -- .../testapi-ui/shared/alerts/confirmModal.html | 23 - .../shared/alerts/confirmModalFactory.js | 67 -- .../3rd_party/static/testapi-ui/shared/filters.js | 55 -- .../static/testapi-ui/shared/header/header.html | 55 -- .../testapi-ui/shared/header/headerController.js | 63 -- testapi/opnfv_testapi/ui/Gruntfile.js | 162 ++++ testapi/opnfv_testapi/ui/about/about.html | 32 - testapi/opnfv_testapi/ui/app.js | 260 ++++++ .../ui/auth-failure/authFailureController.js | 33 - .../opnfv_testapi/ui/components/about/about.html | 32 + .../auth-failure/authFailureController.js | 33 + testapi/opnfv_testapi/ui/components/home/home.html | 23 + .../opnfv_testapi/ui/components/logout/logout.html | 1 + .../ui/components/logout/logoutController.js | 44 ++ testapi/opnfv_testapi/ui/components/pods/pods.html | 76 ++ .../ui/components/pods/podsController.js | 122 +++ .../ui/components/profile/importPubKeyModal.html | 27 + .../ui/components/profile/profile.html | 44 ++ .../ui/components/profile/profileController.js | 219 ++++++ .../ui/components/profile/showPubKeyModal.html | 11 + .../ui/components/projects/project/project.html | 25 + .../projects/project/projectController.js | 183 +++++ .../components/projects/project/updateModal.html | 26 + .../ui/components/projects/projects.html | 52 ++ .../ui/components/projects/projectsController.js | 94 +++ .../results-report/partials/editTestModal.html | 65 ++ .../results-report/partials/fullTestListModal.html | 13 + .../results-report/partials/reportDetails.html | 87 +++ .../components/results-report/resultsReport.html | 185 +++++ .../results-report/resultsReportController.js | 869 +++++++++++++++++++++ .../ui/components/results/results.html | 115 +++ .../ui/components/results/resultsController.js | 370 +++++++++ testapi/opnfv_testapi/ui/config.json | 1 + testapi/opnfv_testapi/ui/favicon-16x16.png | Bin 0 -> 638 bytes testapi/opnfv_testapi/ui/favicon-32x32.png | Bin 0 -> 1540 bytes testapi/opnfv_testapi/ui/favicon.ico | Bin 0 -> 318 bytes testapi/opnfv_testapi/ui/home/home.html | 23 - testapi/opnfv_testapi/ui/index.html | 62 ++ testapi/opnfv_testapi/ui/logout/logout.html | 1 - .../opnfv_testapi/ui/logout/logoutController.js | 44 -- testapi/opnfv_testapi/ui/package.json | 18 + testapi/opnfv_testapi/ui/pods/pods.html | 76 -- testapi/opnfv_testapi/ui/pods/podsController.js | 122 --- .../ui/profile/importPubKeyModal.html | 27 - testapi/opnfv_testapi/ui/profile/profile.html | 44 -- .../opnfv_testapi/ui/profile/profileController.js | 219 ------ .../opnfv_testapi/ui/profile/showPubKeyModal.html | 11 - .../opnfv_testapi/ui/projects/project/project.html | 25 - .../ui/projects/project/projectController.js | 183 ----- .../ui/projects/project/updateModal.html | 26 - testapi/opnfv_testapi/ui/projects/projects.html | 52 -- .../ui/projects/projectsController.js | 94 --- .../ui/results-report/partials/editTestModal.html | 65 -- .../results-report/partials/fullTestListModal.html | 13 - .../ui/results-report/partials/reportDetails.html | 87 --- .../ui/results-report/resultsReport.html | 185 ----- .../ui/results-report/resultsReportController.js | 869 --------------------- testapi/opnfv_testapi/ui/results/results.html | 115 --- .../opnfv_testapi/ui/results/resultsController.js | 370 --------- testapi/opnfv_testapi/ui/robots.txt | 4 + .../opnfv_testapi/ui/shared/alerts/alertModal.html | 8 + .../ui/shared/alerts/alertModalFactory.js | 74 ++ .../ui/shared/alerts/confirmModal.html | 23 + .../ui/shared/alerts/confirmModalFactory.js | 67 ++ testapi/opnfv_testapi/ui/shared/filters.js | 55 ++ testapi/opnfv_testapi/ui/shared/header/header.html | 55 ++ .../ui/shared/header/headerController.js | 63 ++ testapi/setup.cfg | 2 +- 79 files changed, 3569 insertions(+), 3569 deletions(-) delete mode 100644 testapi/3rd_party/static/testapi-ui/Gruntfile.js delete mode 100644 testapi/3rd_party/static/testapi-ui/app.js delete mode 100644 testapi/3rd_party/static/testapi-ui/config.json delete mode 100755 testapi/3rd_party/static/testapi-ui/favicon-16x16.png delete mode 100755 testapi/3rd_party/static/testapi-ui/favicon-32x32.png delete mode 100644 testapi/3rd_party/static/testapi-ui/favicon.ico delete mode 100644 testapi/3rd_party/static/testapi-ui/index.html delete mode 100644 testapi/3rd_party/static/testapi-ui/package.json delete mode 100644 testapi/3rd_party/static/testapi-ui/robots.txt delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/alerts/alertModal.html delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/alerts/alertModalFactory.js delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/filters.js delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/header/header.html delete mode 100644 testapi/3rd_party/static/testapi-ui/shared/header/headerController.js create mode 100644 testapi/opnfv_testapi/ui/Gruntfile.js delete mode 100644 testapi/opnfv_testapi/ui/about/about.html create mode 100644 testapi/opnfv_testapi/ui/app.js delete mode 100644 testapi/opnfv_testapi/ui/auth-failure/authFailureController.js create mode 100644 testapi/opnfv_testapi/ui/components/about/about.html create mode 100644 testapi/opnfv_testapi/ui/components/auth-failure/authFailureController.js create mode 100644 testapi/opnfv_testapi/ui/components/home/home.html create mode 100644 testapi/opnfv_testapi/ui/components/logout/logout.html create mode 100644 testapi/opnfv_testapi/ui/components/logout/logoutController.js create mode 100644 testapi/opnfv_testapi/ui/components/pods/pods.html create mode 100644 testapi/opnfv_testapi/ui/components/pods/podsController.js create mode 100644 testapi/opnfv_testapi/ui/components/profile/importPubKeyModal.html create mode 100644 testapi/opnfv_testapi/ui/components/profile/profile.html create mode 100644 testapi/opnfv_testapi/ui/components/profile/profileController.js create mode 100644 testapi/opnfv_testapi/ui/components/profile/showPubKeyModal.html create mode 100644 testapi/opnfv_testapi/ui/components/projects/project/project.html create mode 100644 testapi/opnfv_testapi/ui/components/projects/project/projectController.js create mode 100644 testapi/opnfv_testapi/ui/components/projects/project/updateModal.html create mode 100644 testapi/opnfv_testapi/ui/components/projects/projects.html create mode 100644 testapi/opnfv_testapi/ui/components/projects/projectsController.js create mode 100644 testapi/opnfv_testapi/ui/components/results-report/partials/editTestModal.html create mode 100644 testapi/opnfv_testapi/ui/components/results-report/partials/fullTestListModal.html create mode 100644 testapi/opnfv_testapi/ui/components/results-report/partials/reportDetails.html create mode 100644 testapi/opnfv_testapi/ui/components/results-report/resultsReport.html create mode 100644 testapi/opnfv_testapi/ui/components/results-report/resultsReportController.js create mode 100644 testapi/opnfv_testapi/ui/components/results/results.html create mode 100644 testapi/opnfv_testapi/ui/components/results/resultsController.js create mode 100644 testapi/opnfv_testapi/ui/config.json create mode 100755 testapi/opnfv_testapi/ui/favicon-16x16.png create mode 100755 testapi/opnfv_testapi/ui/favicon-32x32.png create mode 100644 testapi/opnfv_testapi/ui/favicon.ico delete mode 100644 testapi/opnfv_testapi/ui/home/home.html create mode 100644 testapi/opnfv_testapi/ui/index.html delete mode 100644 testapi/opnfv_testapi/ui/logout/logout.html delete mode 100644 testapi/opnfv_testapi/ui/logout/logoutController.js create mode 100644 testapi/opnfv_testapi/ui/package.json delete mode 100644 testapi/opnfv_testapi/ui/pods/pods.html delete mode 100644 testapi/opnfv_testapi/ui/pods/podsController.js delete mode 100644 testapi/opnfv_testapi/ui/profile/importPubKeyModal.html delete mode 100644 testapi/opnfv_testapi/ui/profile/profile.html delete mode 100644 testapi/opnfv_testapi/ui/profile/profileController.js delete mode 100644 testapi/opnfv_testapi/ui/profile/showPubKeyModal.html delete mode 100644 testapi/opnfv_testapi/ui/projects/project/project.html delete mode 100644 testapi/opnfv_testapi/ui/projects/project/projectController.js delete mode 100644 testapi/opnfv_testapi/ui/projects/project/updateModal.html delete mode 100644 testapi/opnfv_testapi/ui/projects/projects.html delete mode 100644 testapi/opnfv_testapi/ui/projects/projectsController.js delete mode 100644 testapi/opnfv_testapi/ui/results-report/partials/editTestModal.html delete mode 100644 testapi/opnfv_testapi/ui/results-report/partials/fullTestListModal.html delete mode 100644 testapi/opnfv_testapi/ui/results-report/partials/reportDetails.html delete mode 100644 testapi/opnfv_testapi/ui/results-report/resultsReport.html delete mode 100644 testapi/opnfv_testapi/ui/results-report/resultsReportController.js delete mode 100644 testapi/opnfv_testapi/ui/results/results.html delete mode 100644 testapi/opnfv_testapi/ui/results/resultsController.js create mode 100644 testapi/opnfv_testapi/ui/robots.txt create mode 100644 testapi/opnfv_testapi/ui/shared/alerts/alertModal.html create mode 100644 testapi/opnfv_testapi/ui/shared/alerts/alertModalFactory.js create mode 100644 testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html create mode 100644 testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js create mode 100644 testapi/opnfv_testapi/ui/shared/filters.js create mode 100644 testapi/opnfv_testapi/ui/shared/header/header.html create mode 100644 testapi/opnfv_testapi/ui/shared/header/headerController.js (limited to 'testapi') diff --git a/testapi/3rd_party/static/testapi-ui/Gruntfile.js b/testapi/3rd_party/static/testapi-ui/Gruntfile.js deleted file mode 100644 index 13f484f..0000000 --- a/testapi/3rd_party/static/testapi-ui/Gruntfile.js +++ /dev/null @@ -1,162 +0,0 @@ - -module.exports = function (grunt) { - require('load-grunt-tasks')(grunt); - require('grunt-protractor-coverage')(grunt); - grunt.loadNpmTasks('grunt-shell-spawn'); - grunt.loadNpmTasks('grunt-wait'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.initConfig({ - connect: { - server: { - options: { - port: 8000, - base: './', - middleware: function(connect, options, middlewares) { - middlewares.unshift(function(req, res, next) { - if (req.method.toUpperCase() == 'POST' || req.method.toUpperCase() == "PUT"){ - req.method='GET'; - } - return next(); - }); - return middlewares; - } - } - } - }, - copy: { - assets: { - expand: true, - cwd: 'assets', - src: '**', - dest: 'testapi-ui/assets', - }, - components: { - expand: true, - cwd: '../../../opnfv_testapi/ui', - src: '**', - dest: 'components', - }, - copyComponents: { - expand: true, - cwd: 'components', - src: '**', - dest: 'testapi-ui/components', - }, - shared: { - expand: true, - cwd: 'shared', - src: '**', - dest: 'testapi-ui/shared', - }, - filesPng: { - expand: true, - src: '*.png', - dest: 'testapi-ui/', - }, - filesIco: { - expand: true, - src: '*.ico', - dest: 'testapi-ui/', - }, - filesJs: { - expand: true, - src: 'app.js', - dest: 'testapi-ui/', - }, - filesJson: { - expand: true, - src: 'config.json', - dest: 'testapi-ui/', - } - }, - wait: { - default: { - options: { - delay: 3000 - } - } - }, - shell: { - updateSelenium: { - command: 'node_modules/protractor/bin/webdriver-manager update', - options: { - async: false - } - }, - startSelenium: { - command: 'node_modules/protractor/bin/webdriver-manager start', - options: { - async: true - } - }, - deleteFiles: { - command: 'rm -r testapi-ui && rm -r components', - options: { - async: false - } - }, - options: { - stdout: false, - stderr: false - } - }, - instrument: { - files: ['components/**/*.js'], - options: { - lazy: false, - basePath: "./testapi-ui/" - } - }, - karma: { - unit: { - configFile: '../../../opnfv_testapi/tests/UI/karma.conf.js' - } - }, - protractor_coverage: { - options: { - keepAlive: true, - noColor: false, - coverageDir: '../../../opnfv_testapi/tests/UI/coverage', - args: { - specs: ['../../../opnfv_testapi/tests/UI/e2e/podsControllerSpec.js', - '../../../opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js', - '../../../opnfv_testapi/tests/UI/e2e/projectControllerSpec.js'] - } - }, - local: { - options: { - configFile: '../../../opnfv_testapi/tests/UI/protractor-conf.js' - } - } - }, - makeReport: { - src: '../../../opnfv_testapi/tests/UI/coverage/*.json', - options: { - print: 'detail' - } - } - }); - grunt.registerTask('test', [ - 'karma:unit' - ]); - grunt.registerTask('e2e', [ - 'copy:assets', - 'copy:components', - 'copy:copyComponents', - 'copy:shared', - 'copy:filesPng', - 'copy:filesIco', - 'copy:filesJs', - 'copy:filesJson', - 'instrument', - 'connect', - 'shell:updateSelenium', - 'shell:startSelenium', - 'wait:default', - 'protractor_coverage', - 'makeReport', - 'shell:deleteFiles' - - ]); -} diff --git a/testapi/3rd_party/static/testapi-ui/app.js b/testapi/3rd_party/static/testapi-ui/app.js deleted file mode 100644 index dbb56a6..0000000 --- a/testapi/3rd_party/static/testapi-ui/app.js +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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'; - - /** Main app module where application dependencies are listed. */ - angular - .module('testapiApp', [ - 'ui.router','ui.bootstrap', 'cgBusy', - 'ngResource', 'angular-confirm' - ]); - - angular - .module('testapiApp') - .config(configureRoutes); - - angular - .module('testapiApp') - .directive('dynamicModel', ['$compile', '$parse', function ($compile, $parse) { - return { - restrict: 'A', - terminal: true, - priority: 100000, - link: function (scope, elem) { - var name = $parse(elem.attr('dynamic-model'))(scope); - elem.removeAttr('dynamic-model'); - elem.attr('ng-model', name); - $compile(elem)(scope); - } - }; - }]); - - configureRoutes.$inject = ['$stateProvider', '$urlRouterProvider']; - - /** - * Handle application routing. Specific templates and controllers will be - * used based on the URL route. - */ - function configureRoutes($stateProvider, $urlRouterProvider) { - $urlRouterProvider.otherwise('/'); - $stateProvider. - state('home', { - url: '/', - templateUrl: 'testapi-ui/components/home/home.html' - }). - state('about', { - url: '/about', - templateUrl: 'testapi-ui/components/about/about.html' - }). - state('pods', { - url: '/pods', - templateUrl: 'testapi-ui/components/pods/pods.html', - controller: 'PodsController as ctrl' - }). - state('projects', { - url: '/projects', - templateUrl: 'testapi-ui/components/projects/projects.html', - controller: 'ProjectsController as ctrl' - }). - state('project', { - url: '/projects/:name', - templateUrl: 'testapi-ui/components/projects/project/project.html', - controller: 'ProjectController as ctrl' - }). - state('communityResults', { - url: '/community_results', - templateUrl: 'testapi-ui/components/results/results.html', - controller: 'ResultsController as ctrl' - }). - state('userResults', { - url: '/user_results', - templateUrl: 'testapi-ui/components/results/results.html', - controller: 'ResultsController as ctrl' - }). - state('resultsDetail', { - url: '/results/:testID', - templateUrl: 'testapi-ui/components/results-report' + - '/resultsReport.html', - controller: 'ResultsReportController as ctrl' - }). - state('profile', { - url: '/profile', - templateUrl: 'testapi-ui/components/profile/profile.html', - controller: 'ProfileController as ctrl' - }). - state('authFailure', { - url: '/auth_failure', - templateUrl: 'testapi-ui/components/home/home.html', - controller: 'AuthFailureController as ctrl' - }). - state('logout', { - url: '/logout', - templateUrl: 'testapi-ui/components/logout/logout.html', - controller: 'LogoutController as ctrl' - }). - state('userVendors', { - url: '/user_vendors', - templateUrl: '/testapi-ui/components/vendors/vendors.html', - controller: 'VendorsController as ctrl' - }). - state('publicVendors', { - url: '/public_vendors', - templateUrl: '/testapi-ui/components/vendors/vendors.html', - controller: 'VendorsController as ctrl' - }). - state('vendor', { - url: '/vendor/:vendorID', - templateUrl: '/swagger/testapi-ui/components/vendors/vendor.html', - controller: 'VendorController as ctrl' - }). - state('userProducts', { - url: '/user_products', - templateUrl: '/testapi-ui/components/products/products.html', - controller: 'ProductsController as ctrl' - }). - state('publicProducts', { - url: '/public_products', - templateUrl: '/testapi-ui/components/products/products.html', - controller: 'ProductsController as ctrl' - }). - state('cloud', { - url: '/cloud/:id', - templateUrl: '/testapi-ui/components/products/cloud.html', - controller: 'ProductController as ctrl' - }). - state('distro', { - url: '/distro/:id', - templateUrl: '/testapi-ui/components/products/distro.html', - controller: 'ProductController as ctrl' - }); - } - - angular - .module('testapiApp') - .config(disableHttpCache); - - disableHttpCache.$inject = ['$httpProvider']; - - /** - * Disable caching in $http requests. This is primarily for IE, as it - * tends to cache Angular IE requests. - */ - function disableHttpCache($httpProvider) { - if (!$httpProvider.defaults.headers.get) { - $httpProvider.defaults.headers.get = {}; - } - $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; - $httpProvider.defaults.headers.get.Pragma = 'no-cache'; - } - - angular - .module('testapiApp') - .run(setup); - - setup.$inject = [ - '$http', '$rootScope', '$window', '$state', 'testapiApiUrl' - ]; - - /** - * Set up the app with injections into $rootscope. This is mainly for auth - * functions. - */ - function setup($http, $rootScope, $window, $state, testapiApiUrl) { - - $rootScope.auth = {}; - $rootScope.auth.doSignIn = doSignIn; - $rootScope.auth.doSignOut = doSignOut; - $rootScope.auth.doSignCheck = doSignCheck; - $rootScope.auth.doSubmitterCheck = doSubmitterCheck; - - var sign_in_url = testapiApiUrl + '/auth/signin'; - var sign_out_url = testapiApiUrl + '/auth/signout'; - var profile_url = testapiApiUrl + '/profile'; - - /** This function initiates a sign in. */ - function doSignIn() { - $window.location.href = sign_in_url; - } - - /** This function will initate a sign out. */ - function doSignOut() { - $rootScope.auth.currentUser = null; - $rootScope.auth.isAuthenticated = false; - $rootScope.auth.projectNames = []; - $window.location.href = sign_out_url; - } - - /** - * This function checks to see if a user is logged in and - * authenticated. - */ - function doSignCheck() { - return $http.get(profile_url, {withCredentials: true}). - success(function (data) { - $rootScope.auth.currentUser = data; - $rootScope.auth.isAuthenticated = true; - $rootScope.auth.projectNames = $rootScope.auth.doSubmitterCheck(data.groups); - }). - error(function () { - $rootScope.auth.currentUser = null; - $rootScope.auth.isAuthenticated = false; - $rootScope.auth.projectNames = []; - }); - } - - function doSubmitterCheck(groups){ - var projectNames = [] - for(var index=0;index=0){ - projectNames.push(groups[index].split('-')[2]) - } - } - return projectNames; - } - - $rootScope.auth.doSignCheck(); - } - - angular - .element(document) - .ready(loadConfig); - - /** - * Load config and start up the angular application. - */ - function loadConfig() { - - var $http = angular.injector(['ng']).get('$http'); - - /** - * Store config variables as constants, and start the app. - */ - function startApp(config) { - // Add config options as constants. - angular.forEach(config, function(value, key) { - angular.module('testapiApp').constant(key, value); - }); - - angular.bootstrap(document, ['testapiApp']); - } - - $http.get('testapi-ui/config.json').success(function (data) { - startApp(data); - }).error(function () { - startApp({}); - }); - } -})(); diff --git a/testapi/3rd_party/static/testapi-ui/config.json b/testapi/3rd_party/static/testapi-ui/config.json deleted file mode 100644 index 5d48c7b..0000000 --- a/testapi/3rd_party/static/testapi-ui/config.json +++ /dev/null @@ -1 +0,0 @@ -{"testapiApiUrl": "http://localhost:8000/api/v1"} diff --git a/testapi/3rd_party/static/testapi-ui/favicon-16x16.png b/testapi/3rd_party/static/testapi-ui/favicon-16x16.png deleted file mode 100755 index e08c8a1..0000000 Binary files a/testapi/3rd_party/static/testapi-ui/favicon-16x16.png and /dev/null differ diff --git a/testapi/3rd_party/static/testapi-ui/favicon-32x32.png b/testapi/3rd_party/static/testapi-ui/favicon-32x32.png deleted file mode 100755 index 7bf57e2..0000000 Binary files a/testapi/3rd_party/static/testapi-ui/favicon-32x32.png and /dev/null differ diff --git a/testapi/3rd_party/static/testapi-ui/favicon.ico b/testapi/3rd_party/static/testapi-ui/favicon.ico deleted file mode 100644 index 156019a..0000000 Binary files a/testapi/3rd_party/static/testapi-ui/favicon.ico and /dev/null differ diff --git a/testapi/3rd_party/static/testapi-ui/index.html b/testapi/3rd_party/static/testapi-ui/index.html deleted file mode 100644 index ac29aca..0000000 --- a/testapi/3rd_party/static/testapi-ui/index.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - TestAPI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - diff --git a/testapi/3rd_party/static/testapi-ui/package.json b/testapi/3rd_party/static/testapi-ui/package.json deleted file mode 100644 index dc99239..0000000 --- a/testapi/3rd_party/static/testapi-ui/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "devDependencies": { - "grunt": "~1.0.1", - "grunt-contrib-connect": "^1.0.2", - "grunt-contrib-copy": "^1.0.0", - "grunt-karma": "~2.0.0", - "grunt-protractor-coverage": "^0.2.18", - "grunt-protractor-runner": "~5.0.0", - "grunt-shell-spawn": "~0.3.10", - "grunt-wait": "~0.1.0", - "karma": "~1.7.1", - "karma-chrome-launcher": "~2.2.0", - "karma-coverage": "~1.1.1", - "karma-jasmine": "~1.1.0", - "load-grunt-tasks": "~3.5.2", - "protractor-http-mock": "^0.10.0" - } -} diff --git a/testapi/3rd_party/static/testapi-ui/robots.txt b/testapi/3rd_party/static/testapi-ui/robots.txt deleted file mode 100644 index 93c4420..0000000 --- a/testapi/3rd_party/static/testapi-ui/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -# robotstxt.org - -User-agent: * - diff --git a/testapi/3rd_party/static/testapi-ui/shared/alerts/alertModal.html b/testapi/3rd_party/static/testapi-ui/shared/alerts/alertModal.html deleted file mode 100644 index 59fd500..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/alerts/alertModal.html +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/testapi/3rd_party/static/testapi-ui/shared/alerts/alertModalFactory.js b/testapi/3rd_party/static/testapi-ui/shared/alerts/alertModalFactory.js deleted file mode 100644 index 929f543..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/alerts/alertModalFactory.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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') - .factory('raiseAlert', raiseAlert); - - raiseAlert.$inject = ['$uibModal']; - - /** - * This allows alert pop-ups to be raised. Just inject it as a dependency - * in the calling controller. - */ - function raiseAlert($uibModal) { - return function(mode, title, text) { - $uibModal.open({ - templateUrl: 'testapi-ui/shared/alerts/alertModal.html', - controller: 'RaiseAlertModalController as alert', - backdrop: true, - keyboard: true, - backdropClick: true, - size: 'md', - resolve: { - data: function () { - return { - mode: mode, - title: title, - text: text - }; - } - } - }); - }; - } - - angular - .module('testapiApp') - .controller('RaiseAlertModalController', RaiseAlertModalController); - - RaiseAlertModalController.$inject = ['$uibModalInstance', 'data']; - - /** - * This is the controller for the alert pop-up. - */ - function RaiseAlertModalController($uibModalInstance, data) { - var ctrl = this; - - ctrl.close = close; - ctrl.data = data; - - /** - * This method will close the alert modal. The modal will close - * when the user clicks the close button or clicks outside of the - * modal. - */ - function close() { - $uibModalInstance.close(); - } - } -})(); diff --git a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html b/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html deleted file mode 100644 index e5397e0..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js b/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js deleted file mode 100644 index aba205e..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js +++ /dev/null @@ -1,67 +0,0 @@ -(function () { - 'use strict'; - - angular - .module('testapiApp') - .factory('confirmModal', confirmModal); - - confirmModal.$inject = ['$uibModal']; - - /** - * Opens confirm modal dialog with input textbox - */ - function confirmModal($uibModal) { - return function(text, successHandler) { - $uibModal.open({ - templateUrl: '/testapi-ui/shared/alerts/confirmModal.html', - controller: 'CustomConfirmModalController as confirmModal', - size: 'md', - resolve: { - data: function () { - return { - text: text, - successHandler: successHandler - }; - } - } - }); - }; - } - - angular - .module('testapiApp') - .controller('CustomConfirmModalController', - CustomConfirmModalController); - - CustomConfirmModalController.$inject = ['$uibModalInstance', 'data']; - - /** - * This is the controller for the alert pop-up. - */ - function CustomConfirmModalController($uibModalInstance, data) { - var ctrl = this; - - ctrl.confirm = confirm; - ctrl.cancel = cancel; - - ctrl.data = angular.copy(data); - - /** - * Initiate confirmation and call the success handler with the - * input text. - */ - function confirm() { - $uibModalInstance.close(); - if (angular.isDefined(ctrl.data.successHandler)) { - ctrl.data.successHandler(ctrl.inputText); - } - } - - /** - * Close the confirm modal without initiating changes. - */ - function cancel() { - $uibModalInstance.dismiss('cancel'); - } - } -})(); diff --git a/testapi/3rd_party/static/testapi-ui/shared/filters.js b/testapi/3rd_party/static/testapi-ui/shared/filters.js deleted file mode 100644 index 4a4b7bd..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/filters.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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'; - - /** - * Convert an object of objects to an array of objects to use with ng-repeat - * filters. - */ - angular - .module('testapiApp') - .filter('arrayConverter', arrayConverter); - - /** - * Convert an object of objects to an array of objects to use with ng-repeat - * filters. - */ - function arrayConverter() { - return function (objects) { - var array = []; - angular.forEach(objects, function (object, key) { - if (!('id' in object)) { - object.id = key; - } - array.push(object); - }); - return array; - }; - } - - angular - .module('testapiApp') - .filter('capitalize', capitalize); - - /** - * Angular filter that will capitalize the first letter of a string. - */ - function capitalize() { - return function (string) { - return string.substring(0, 1).toUpperCase() + string.substring(1); - }; - } -})(); diff --git a/testapi/3rd_party/static/testapi-ui/shared/header/header.html b/testapi/3rd_party/static/testapi-ui/shared/header/header.html deleted file mode 100644 index 4b3f8dd..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/header/header.html +++ /dev/null @@ -1,55 +0,0 @@ -
TestAPI -TestAPI -
- - diff --git a/testapi/3rd_party/static/testapi-ui/shared/header/headerController.js b/testapi/3rd_party/static/testapi-ui/shared/header/headerController.js deleted file mode 100644 index 0a14a41..0000000 --- a/testapi/3rd_party/static/testapi-ui/shared/header/headerController.js +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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('HeaderController', HeaderController); - - HeaderController.$inject = ['$location']; - - /** - * TestAPI Header Controller - * This controller is for the header template which contains the site - * navigation. - */ - function HeaderController($location) { - var ctrl = this; - - ctrl.isActive = isActive; - ctrl.isCatalogActive = isCatalogActive; - - /** Whether the Navbar is collapsed for small displays. */ - ctrl.navbarCollapsed = true; - - /** - * This determines whether a button should be in the active state based - * on the URL. - */ - function isActive(viewLocation) { - var path = $location.path().substr(0, viewLocation.length); - if (path === viewLocation) { - // Make sure "/" only matches when viewLocation is "/". - if (!($location.path().substr(0).length > 1 && - viewLocation.length === 1 )) { - return true; - } - } - return false; - } - - /** This determines the active state for the catalog dropdown. Type - * parameter should be passed in to specify if the catalog is the - * public or user one. - */ - function isCatalogActive(type) { - return ctrl.isActive('/' + type + '_vendors') - || ctrl.isActive('/' + type + '_products'); - } - } -})(); diff --git a/testapi/opnfv_testapi/ui/Gruntfile.js b/testapi/opnfv_testapi/ui/Gruntfile.js new file mode 100644 index 0000000..13f484f --- /dev/null +++ b/testapi/opnfv_testapi/ui/Gruntfile.js @@ -0,0 +1,162 @@ + +module.exports = function (grunt) { + require('load-grunt-tasks')(grunt); + require('grunt-protractor-coverage')(grunt); + grunt.loadNpmTasks('grunt-shell-spawn'); + grunt.loadNpmTasks('grunt-wait'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.initConfig({ + connect: { + server: { + options: { + port: 8000, + base: './', + middleware: function(connect, options, middlewares) { + middlewares.unshift(function(req, res, next) { + if (req.method.toUpperCase() == 'POST' || req.method.toUpperCase() == "PUT"){ + req.method='GET'; + } + return next(); + }); + return middlewares; + } + } + } + }, + copy: { + assets: { + expand: true, + cwd: 'assets', + src: '**', + dest: 'testapi-ui/assets', + }, + components: { + expand: true, + cwd: '../../../opnfv_testapi/ui', + src: '**', + dest: 'components', + }, + copyComponents: { + expand: true, + cwd: 'components', + src: '**', + dest: 'testapi-ui/components', + }, + shared: { + expand: true, + cwd: 'shared', + src: '**', + dest: 'testapi-ui/shared', + }, + filesPng: { + expand: true, + src: '*.png', + dest: 'testapi-ui/', + }, + filesIco: { + expand: true, + src: '*.ico', + dest: 'testapi-ui/', + }, + filesJs: { + expand: true, + src: 'app.js', + dest: 'testapi-ui/', + }, + filesJson: { + expand: true, + src: 'config.json', + dest: 'testapi-ui/', + } + }, + wait: { + default: { + options: { + delay: 3000 + } + } + }, + shell: { + updateSelenium: { + command: 'node_modules/protractor/bin/webdriver-manager update', + options: { + async: false + } + }, + startSelenium: { + command: 'node_modules/protractor/bin/webdriver-manager start', + options: { + async: true + } + }, + deleteFiles: { + command: 'rm -r testapi-ui && rm -r components', + options: { + async: false + } + }, + options: { + stdout: false, + stderr: false + } + }, + instrument: { + files: ['components/**/*.js'], + options: { + lazy: false, + basePath: "./testapi-ui/" + } + }, + karma: { + unit: { + configFile: '../../../opnfv_testapi/tests/UI/karma.conf.js' + } + }, + protractor_coverage: { + options: { + keepAlive: true, + noColor: false, + coverageDir: '../../../opnfv_testapi/tests/UI/coverage', + args: { + specs: ['../../../opnfv_testapi/tests/UI/e2e/podsControllerSpec.js', + '../../../opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js', + '../../../opnfv_testapi/tests/UI/e2e/projectControllerSpec.js'] + } + }, + local: { + options: { + configFile: '../../../opnfv_testapi/tests/UI/protractor-conf.js' + } + } + }, + makeReport: { + src: '../../../opnfv_testapi/tests/UI/coverage/*.json', + options: { + print: 'detail' + } + } + }); + grunt.registerTask('test', [ + 'karma:unit' + ]); + grunt.registerTask('e2e', [ + 'copy:assets', + 'copy:components', + 'copy:copyComponents', + 'copy:shared', + 'copy:filesPng', + 'copy:filesIco', + 'copy:filesJs', + 'copy:filesJson', + 'instrument', + 'connect', + 'shell:updateSelenium', + 'shell:startSelenium', + 'wait:default', + 'protractor_coverage', + 'makeReport', + 'shell:deleteFiles' + + ]); +} diff --git a/testapi/opnfv_testapi/ui/about/about.html b/testapi/opnfv_testapi/ui/about/about.html deleted file mode 100644 index 65860a8..0000000 --- a/testapi/opnfv_testapi/ui/about/about.html +++ /dev/null @@ -1,32 +0,0 @@ -

TestAPI Documentation

- -

TestAPI is a source of tools for test results collection of OPNFV clouds.

-

To learn more about TestAPI, visit the links below.

- -
    -
  1. - - About TestAPI -
  2. -
  3. - - How do I declare project in TestAPI -
  4. -
  5. - - How do I declare test case in TestAPI -
  6. -
  7. - - How do I push my results to TestAPI -
  8. -
- diff --git a/testapi/opnfv_testapi/ui/app.js b/testapi/opnfv_testapi/ui/app.js new file mode 100644 index 0000000..dbb56a6 --- /dev/null +++ b/testapi/opnfv_testapi/ui/app.js @@ -0,0 +1,260 @@ +/* + * 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'; + + /** Main app module where application dependencies are listed. */ + angular + .module('testapiApp', [ + 'ui.router','ui.bootstrap', 'cgBusy', + 'ngResource', 'angular-confirm' + ]); + + angular + .module('testapiApp') + .config(configureRoutes); + + angular + .module('testapiApp') + .directive('dynamicModel', ['$compile', '$parse', function ($compile, $parse) { + return { + restrict: 'A', + terminal: true, + priority: 100000, + link: function (scope, elem) { + var name = $parse(elem.attr('dynamic-model'))(scope); + elem.removeAttr('dynamic-model'); + elem.attr('ng-model', name); + $compile(elem)(scope); + } + }; + }]); + + configureRoutes.$inject = ['$stateProvider', '$urlRouterProvider']; + + /** + * Handle application routing. Specific templates and controllers will be + * used based on the URL route. + */ + function configureRoutes($stateProvider, $urlRouterProvider) { + $urlRouterProvider.otherwise('/'); + $stateProvider. + state('home', { + url: '/', + templateUrl: 'testapi-ui/components/home/home.html' + }). + state('about', { + url: '/about', + templateUrl: 'testapi-ui/components/about/about.html' + }). + state('pods', { + url: '/pods', + templateUrl: 'testapi-ui/components/pods/pods.html', + controller: 'PodsController as ctrl' + }). + state('projects', { + url: '/projects', + templateUrl: 'testapi-ui/components/projects/projects.html', + controller: 'ProjectsController as ctrl' + }). + state('project', { + url: '/projects/:name', + templateUrl: 'testapi-ui/components/projects/project/project.html', + controller: 'ProjectController as ctrl' + }). + state('communityResults', { + url: '/community_results', + templateUrl: 'testapi-ui/components/results/results.html', + controller: 'ResultsController as ctrl' + }). + state('userResults', { + url: '/user_results', + templateUrl: 'testapi-ui/components/results/results.html', + controller: 'ResultsController as ctrl' + }). + state('resultsDetail', { + url: '/results/:testID', + templateUrl: 'testapi-ui/components/results-report' + + '/resultsReport.html', + controller: 'ResultsReportController as ctrl' + }). + state('profile', { + url: '/profile', + templateUrl: 'testapi-ui/components/profile/profile.html', + controller: 'ProfileController as ctrl' + }). + state('authFailure', { + url: '/auth_failure', + templateUrl: 'testapi-ui/components/home/home.html', + controller: 'AuthFailureController as ctrl' + }). + state('logout', { + url: '/logout', + templateUrl: 'testapi-ui/components/logout/logout.html', + controller: 'LogoutController as ctrl' + }). + state('userVendors', { + url: '/user_vendors', + templateUrl: '/testapi-ui/components/vendors/vendors.html', + controller: 'VendorsController as ctrl' + }). + state('publicVendors', { + url: '/public_vendors', + templateUrl: '/testapi-ui/components/vendors/vendors.html', + controller: 'VendorsController as ctrl' + }). + state('vendor', { + url: '/vendor/:vendorID', + templateUrl: '/swagger/testapi-ui/components/vendors/vendor.html', + controller: 'VendorController as ctrl' + }). + state('userProducts', { + url: '/user_products', + templateUrl: '/testapi-ui/components/products/products.html', + controller: 'ProductsController as ctrl' + }). + state('publicProducts', { + url: '/public_products', + templateUrl: '/testapi-ui/components/products/products.html', + controller: 'ProductsController as ctrl' + }). + state('cloud', { + url: '/cloud/:id', + templateUrl: '/testapi-ui/components/products/cloud.html', + controller: 'ProductController as ctrl' + }). + state('distro', { + url: '/distro/:id', + templateUrl: '/testapi-ui/components/products/distro.html', + controller: 'ProductController as ctrl' + }); + } + + angular + .module('testapiApp') + .config(disableHttpCache); + + disableHttpCache.$inject = ['$httpProvider']; + + /** + * Disable caching in $http requests. This is primarily for IE, as it + * tends to cache Angular IE requests. + */ + function disableHttpCache($httpProvider) { + if (!$httpProvider.defaults.headers.get) { + $httpProvider.defaults.headers.get = {}; + } + $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; + $httpProvider.defaults.headers.get.Pragma = 'no-cache'; + } + + angular + .module('testapiApp') + .run(setup); + + setup.$inject = [ + '$http', '$rootScope', '$window', '$state', 'testapiApiUrl' + ]; + + /** + * Set up the app with injections into $rootscope. This is mainly for auth + * functions. + */ + function setup($http, $rootScope, $window, $state, testapiApiUrl) { + + $rootScope.auth = {}; + $rootScope.auth.doSignIn = doSignIn; + $rootScope.auth.doSignOut = doSignOut; + $rootScope.auth.doSignCheck = doSignCheck; + $rootScope.auth.doSubmitterCheck = doSubmitterCheck; + + var sign_in_url = testapiApiUrl + '/auth/signin'; + var sign_out_url = testapiApiUrl + '/auth/signout'; + var profile_url = testapiApiUrl + '/profile'; + + /** This function initiates a sign in. */ + function doSignIn() { + $window.location.href = sign_in_url; + } + + /** This function will initate a sign out. */ + function doSignOut() { + $rootScope.auth.currentUser = null; + $rootScope.auth.isAuthenticated = false; + $rootScope.auth.projectNames = []; + $window.location.href = sign_out_url; + } + + /** + * This function checks to see if a user is logged in and + * authenticated. + */ + function doSignCheck() { + return $http.get(profile_url, {withCredentials: true}). + success(function (data) { + $rootScope.auth.currentUser = data; + $rootScope.auth.isAuthenticated = true; + $rootScope.auth.projectNames = $rootScope.auth.doSubmitterCheck(data.groups); + }). + error(function () { + $rootScope.auth.currentUser = null; + $rootScope.auth.isAuthenticated = false; + $rootScope.auth.projectNames = []; + }); + } + + function doSubmitterCheck(groups){ + var projectNames = [] + for(var index=0;index=0){ + projectNames.push(groups[index].split('-')[2]) + } + } + return projectNames; + } + + $rootScope.auth.doSignCheck(); + } + + angular + .element(document) + .ready(loadConfig); + + /** + * Load config and start up the angular application. + */ + function loadConfig() { + + var $http = angular.injector(['ng']).get('$http'); + + /** + * Store config variables as constants, and start the app. + */ + function startApp(config) { + // Add config options as constants. + angular.forEach(config, function(value, key) { + angular.module('testapiApp').constant(key, value); + }); + + angular.bootstrap(document, ['testapiApp']); + } + + $http.get('testapi-ui/config.json').success(function (data) { + startApp(data); + }).error(function () { + startApp({}); + }); + } +})(); diff --git a/testapi/opnfv_testapi/ui/auth-failure/authFailureController.js b/testapi/opnfv_testapi/ui/auth-failure/authFailureController.js deleted file mode 100644 index 29d1d70..0000000 --- a/testapi/opnfv_testapi/ui/auth-failure/authFailureController.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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/testapi/opnfv_testapi/ui/components/about/about.html b/testapi/opnfv_testapi/ui/components/about/about.html new file mode 100644 index 0000000..65860a8 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/about/about.html @@ -0,0 +1,32 @@ +

TestAPI Documentation

+ +

TestAPI is a source of tools for test results collection of OPNFV clouds.

+

To learn more about TestAPI, visit the links below.

+ +
    +
  1. + + About TestAPI +
  2. +
  3. + + How do I declare project in TestAPI +
  4. +
  5. + + How do I declare test case in TestAPI +
  6. +
  7. + + How do I push my results to TestAPI +
  8. +
+ diff --git a/testapi/opnfv_testapi/ui/components/auth-failure/authFailureController.js b/testapi/opnfv_testapi/ui/components/auth-failure/authFailureController.js new file mode 100644 index 0000000..29d1d70 --- /dev/null +++ b/testapi/opnfv_testapi/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/testapi/opnfv_testapi/ui/components/home/home.html b/testapi/opnfv_testapi/ui/components/home/home.html new file mode 100644 index 0000000..47d747f --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/home/home.html @@ -0,0 +1,23 @@ +
+ +
+

Results Collection

+

TestAPI is a source of tools for OPNFV test results collection

+
+
+
+ +
+
+

What is TestAPI?

+
    +
  • Toolset for testing interoperability between OPNFV test projects.
  • +
  • Database backed website supporting collection and publication of + community test results for OPNFV.
  • +
  • User interface to display individual test run results.
  • +
+
+
+ diff --git a/testapi/opnfv_testapi/ui/components/logout/logout.html b/testapi/opnfv_testapi/ui/components/logout/logout.html new file mode 100644 index 0000000..38a5c36 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/logout/logout.html @@ -0,0 +1 @@ +
diff --git a/testapi/opnfv_testapi/ui/components/logout/logoutController.js b/testapi/opnfv_testapi/ui/components/logout/logoutController.js new file mode 100644 index 0000000..1b6d78c --- /dev/null +++ b/testapi/opnfv_testapi/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/testapi/opnfv_testapi/ui/components/pods/pods.html b/testapi/opnfv_testapi/ui/components/pods/pods.html new file mode 100644 index 0000000..22f2934 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/pods/pods.html @@ -0,0 +1,76 @@ +

Pods

+

This page is used to create or query pods.
+ Querying pods is open to everybody.
+ But only login users are granted the privilege to create the new pod. +

+ +
+ +
+ +
+

Filters

+
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + +
+ {{pod.name}} +
+

+ owner: {{pod.owner}}
+ role: {{pod.role}}
+ mode: {{pod.mode}}
+ create_date: {{pod.creation_date}}
+ details: {{pod.details}} +

+
+
+
+
+ diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js new file mode 100644 index 0000000..489fa8a --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js @@ -0,0 +1,122 @@ +/* + * 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('PodsController', PodsController); + + PodsController.$inject = [ + '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' + ]; + + /** + * TestAPI Pods Controller + * This controller is for the '/pods' page where a user can browse + * through pods declared in TestAPI. + */ + function PodsController($scope, $http, $filter, $state, testapiApiUrl, + raiseAlert) { + var ctrl = this; + ctrl.url = testapiApiUrl + '/pods'; + + ctrl.create = create; + ctrl.update = update; + ctrl.open = open; + ctrl.clearFilters = clearFilters; + + ctrl.roles = ['community-ci', 'production-ci']; + ctrl.modes = ['metal', 'virtual']; + ctrl.createRequirements = [ + {label: 'name', type: 'text', required: true}, + {label: 'mode', type: 'select', selects: ctrl.modes}, + {label: 'role', type: 'select', selects: ctrl.roles}, + {label: 'details', type: 'textarea', required: false} + ]; + + ctrl.name = ''; + ctrl.role = 'community-ci'; + ctrl.mode = 'metal'; + ctrl.details = ''; + + /** + * 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.update(); + } + + /** + * This will contact the TestAPI to create a new pod. + */ + function create() { + ctrl.showError = false; + + if(ctrl.name != ""){ + var pods_url = ctrl.url; + var body = { + name: ctrl.name, + mode: ctrl.mode, + role: ctrl.role, + details: ctrl.details + }; + ctrl.podsRequest = + $http.post(pods_url, body).error(function (data, status) { + ctrl.showError = true; + if(status == 403){ + ctrl.error = + 'Error creating the new pod from server: Pod\'s name already exists' + } + }); + } + else{ + ctrl.showError = true; + ctrl.error = 'Name is missing.' + } + } + + /** + * This will contact the TestAPI to get a listing of declared pods. + */ + function update() { + ctrl.showError = false; + ctrl.podsRequest = + $http.get(ctrl.url).success(function (data) { + ctrl.data = data; + }).error(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = + 'Error retrieving pods from server: ' + + angular.toJson(error); + }); + } + } +})(); diff --git a/testapi/opnfv_testapi/ui/components/profile/importPubKeyModal.html b/testapi/opnfv_testapi/ui/components/profile/importPubKeyModal.html new file mode 100644 index 0000000..0f55c27 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/profile/importPubKeyModal.html @@ -0,0 +1,27 @@ + + diff --git a/testapi/opnfv_testapi/ui/components/profile/profile.html b/testapi/opnfv_testapi/ui/components/profile/profile.html new file mode 100644 index 0000000..763f5d1 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/profile/profile.html @@ -0,0 +1,44 @@ +

User profile

+
+
+ + + + + + + + + +
User {{auth.currentUser.user}}
Fullname {{auth.currentUser.fullname}}
Email {{auth.currentUser.email}}
Groups +
+ {{group}}
+
+
+
+
+
+
+
+

User Public Keys

+
+
+ +
+
+
+ +
+ + + + + + + + +
{{pubKey.format}}{{pubKey.shortKey}}{{pubKey.comment}}
+
+
diff --git a/testapi/opnfv_testapi/ui/components/profile/profileController.js b/testapi/opnfv_testapi/ui/components/profile/profileController.js new file mode 100644 index 0000000..5dbdf7b --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/profile/profileController.js @@ -0,0 +1,219 @@ +/* + * + * 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') + .factory('PubKeys', PubKeys); + + PubKeys.$inject = ['$resource', 'testapiApiUrl']; + + /** + * This is a provider for the user's uploaded public keys. + */ + function PubKeys($resource, testapiApiUrl) { + return $resource(testapiApiUrl + '/user/pubkeys/:id', null, null); + } + + angular + .module('testapiApp') + .controller('ProfileController', ProfileController); + + ProfileController.$inject = [ + '$scope', '$http', 'testapiApiUrl', 'PubKeys', + '$uibModal', 'raiseAlert', '$state' + ]; + + /** + * TestAPI Profile Controller + * This controller handles user's profile page, where a user can view + * account-specific information. + */ + function ProfileController($scope, $http, testapiApiUrl, + PubKeys, $uibModal, raiseAlert, $state) { + + var ctrl = this; + + ctrl.updatePubKeys = updatePubKeys; + ctrl.openImportPubKeyModal = openImportPubKeyModal; + ctrl.openShowPubKeyModal = openShowPubKeyModal; + + // Must be authenticated to view this page. + if (!$scope.auth.isAuthenticated) { + $state.go('home'); + } + + /** + * This function will fetch all the user's public keys from the + * server and store them in an array. + */ + function updatePubKeys() { + var keys = PubKeys.query(function() { + ctrl.pubkeys = []; + angular.forEach(keys, function (key) { + ctrl.pubkeys.push({ + 'resource': key, + 'format': key.format, + 'shortKey': [ + key.pubkey.slice(0, 10), + '.', + key.pubkey.slice(-10) + ].join('.'), + 'pubkey': key.pubkey, + 'comment': key.comment + }); + }); + }); + } + + /** + * This function will open the modal that will give the user a form + * for importing a public key. + */ + function openImportPubKeyModal() { + $uibModal.open({ + templateUrl: '/components/profile/importPubKeyModal.html', + backdrop: true, + windowClass: 'modal', + controller: 'ImportPubKeyModalController as modal' + }).result.finally(function() { + ctrl.updatePubKeys(); + }); + } + + /** + * This function will open the modal that will give the full + * information regarding a specific public key. + * @param {Object} pubKey resource + */ + function openShowPubKeyModal(pubKey) { + $uibModal.open({ + templateUrl: '/components/profile/showPubKeyModal.html', + backdrop: true, + windowClass: 'modal', + controller: 'ShowPubKeyModalController as modal', + resolve: { + pubKey: function() { + return pubKey; + } + } + }).result.finally(function() { + ctrl.updatePubKeys(); + }); + } + + ctrl.authRequest = $scope.auth.doSignCheck().then(ctrl.updatePubKeys); + } + + angular + .module('testapiApp') + .controller('ImportPubKeyModalController', ImportPubKeyModalController); + + ImportPubKeyModalController.$inject = [ + '$uibModalInstance', 'PubKeys', 'raiseAlert' + ]; + + /** + * Import Pub Key Modal Controller + * This controller is for the modal that appears if a user wants to import + * a public key. + */ + function ImportPubKeyModalController($uibModalInstance, + PubKeys, raiseAlert) { + + var ctrl = this; + + ctrl.importPubKey = importPubKey; + ctrl.cancel = cancel; + + /** + * This function will save a new public key resource to the API server. + */ + function importPubKey() { + var newPubKey = new PubKeys( + {raw_key: ctrl.raw_key, self_signature: ctrl.self_signature} + ); + newPubKey.$save( + function(newPubKey_) { + raiseAlert('success', '', 'Public key saved successfully'); + $uibModalInstance.close(newPubKey_); + }, + function(httpResp) { + raiseAlert('danger', + httpResp.statusText, httpResp.data.title); + ctrl.cancel(); + } + ); + } + + /** + * This function will dismiss the modal. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } + + angular + .module('testapiApp') + .controller('ShowPubKeyModalController', ShowPubKeyModalController); + + ShowPubKeyModalController.$inject = [ + '$uibModalInstance', 'raiseAlert', 'pubKey' + ]; + + /** + * Show Pub Key Modal Controller + * This controller is for the modal that appears if a user wants to see the + * full details of one of their public keys. + */ + function ShowPubKeyModalController($uibModalInstance, raiseAlert, pubKey) { + var ctrl = this; + + ctrl.deletePubKey = deletePubKey; + ctrl.cancel = cancel; + + ctrl.pubKey = pubKey.resource; + ctrl.rawKey = [pubKey.format, pubKey.pubkey, pubKey.comment].join('\n'); + + /** + * This function will delete a public key resource. + */ + function deletePubKey() { + ctrl.pubKey.$remove( + {id: ctrl.pubKey.id}, + function() { + raiseAlert('success', + '', 'Public key deleted successfully'); + $uibModalInstance.close(ctrl.pubKey.id); + }, + function(httpResp) { + raiseAlert('danger', + httpResp.statusText, httpResp.data.title); + ctrl.cancel(); + } + ); + } + + /** + * This method will dismiss the modal. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } +})(); diff --git a/testapi/opnfv_testapi/ui/components/profile/showPubKeyModal.html b/testapi/opnfv_testapi/ui/components/profile/showPubKeyModal.html new file mode 100644 index 0000000..5f63a5e --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/profile/showPubKeyModal.html @@ -0,0 +1,11 @@ + + diff --git a/testapi/opnfv_testapi/ui/components/projects/project/project.html b/testapi/opnfv_testapi/ui/components/projects/project/project.html new file mode 100644 index 0000000..9d46364 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/project.html @@ -0,0 +1,25 @@ +
+ + + + + + +
Name {{ctrl.data.name}}
Description {{ctrl.data.description}}
Creation date {{ctrl.data.creation_date}}
+
+ +
+
+ + +
+ + \ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/project/projectController.js b/testapi/opnfv_testapi/ui/components/projects/project/projectController.js new file mode 100644 index 0000000..8f4bd20 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/projectController.js @@ -0,0 +1,183 @@ +/* + * 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('ProjectController', ProjectController); + + ProjectController.$inject = [ + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', + 'confirmModal' + ]; + + /** + * TestAPI Project Controller + * This controller is for the '/projects' page where a user can browse + * through projects declared in TestAPI. + */ + function ProjectController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { + var ctrl = this; + ctrl.name = $state.params['name']; + ctrl.url = testapiApiUrl + '/projects/' + ctrl.name; + + ctrl.loadDetails = loadDetails; + ctrl.deleteProject = deleteProject; + ctrl.openDeleteModal = openDeleteModal; + ctrl.openUpdateModal = openUpdateModal; + ctrl.updateProject = updateProject; + + + /** + * This will contact the TestAPI to update an existing project. + */ + function updateProject(name,description) { + ctrl.showError = false; + ctrl.showSuccess = false; + if(ctrl.name != ""){ + var projects_url = ctrl.url; + var body = { + name: name, + description: description + }; + ctrl.projectsRequest = + $http.put(projects_url, body).success(function (data){ + ctrl.showSuccess = true ; + }) + .error(function (data) { + ctrl.showError = true; + ctrl.error = 'Error updating the existing Project from server: ' + angular.toJson(data); + }); + ctrl.name = ""; + ctrl.description=""; + } + else{ + ctrl.showError = true; + ctrl.error = 'Name is missing.' + } + } + + /** + * This will contact the TestAPI to delete an existing project. + */ + function deleteProject() { + ctrl.showError = false; + ctrl.showSuccess = false; + ctrl.projectsRequest = + $http.delete(ctrl.url).success(function (data) { + $state.go('projects', {}, {reload: true}); + ctrl.showSuccess = true ; + + }).error(function (error) { + ctrl.showError = true; + ctrl.error = + 'Error deleting project from server: ' + + angular.toJson(error); + }); + } + + /** + * This will open the modal that will show the delete confirm + * message + */ + function openDeleteModal() { + confirmModal("Delete",ctrl.deleteProject); + } + + /** + * This will open the modal that will show the update + * view + */ + function openUpdateModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/projects/project/updateModal.html', + controller: 'ModalInstanceCtrl as updateModal', + size: 'md', + resolve: { + data: function () { + return { + text: "Update", + successHandler: ctrl.updateProject, + project: ctrl.data + }; + } + } + }); + } + + /** + * This will contact the TestAPI to get a listing of declared projects. + */ + function loadDetails() { + ctrl.showError = false; + ctrl.projectsRequest = + $http.get(ctrl.url).success(function (data) { + ctrl.data = data; + }).error(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = + 'Error retrieving projects from server: ' + + angular.toJson(error); + }); + } + ctrl.loadDetails(); + } + + + /** + * TestAPI Modal instance Controller + * This controller is for the update modal where a user can update + * the project information. + */ + angular.module('testapiApp').controller('ModalInstanceCtrl', ModalInstanceCtrl); + ModalInstanceCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function ModalInstanceCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + + ctrl.createRequirements = [ + {label: 'name', type: 'text', required: true}, + {label: 'description', type: 'textarea', required: false} + ]; + + ctrl.name = ctrl.data.project.name; + ctrl.description = ctrl.data.project.description; + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + $uibModalInstance.close(); + if (angular.isDefined(ctrl.data.successHandler)) { + ctrl.data.successHandler(ctrl.name,ctrl.description); + } + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } + + +})(); diff --git a/testapi/opnfv_testapi/ui/components/projects/project/updateModal.html b/testapi/opnfv_testapi/ui/components/projects/project/updateModal.html new file mode 100644 index 0000000..ab8d64e --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/updateModal.html @@ -0,0 +1,26 @@ + + + diff --git a/testapi/opnfv_testapi/ui/components/projects/projects.html b/testapi/opnfv_testapi/ui/components/projects/projects.html new file mode 100644 index 0000000..55f8683 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/projects.html @@ -0,0 +1,52 @@ +

Projects

+ +
+
+

Create

+
+
+
+

+ + + + + + + +

+
+
+
+ +
+
+ + +
+
+
+ + +
+ + + + + + + + +
+ {{project.name}} +
+
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/projectsController.js b/testapi/opnfv_testapi/ui/components/projects/projectsController.js new file mode 100644 index 0000000..16002f6 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/projectsController.js @@ -0,0 +1,94 @@ +/* + * 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('ProjectsController', ProjectsController); + + ProjectsController.$inject = [ + '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' + ]; + + /** + * TestAPI Project Controller + * This controller is for the '/projects' page where a user can browse + * through projects declared in TestAPI. + */ + function ProjectsController($scope, $http, $filter, $state, testapiApiUrl, + raiseAlert) { + var ctrl = this; + ctrl.url = testapiApiUrl + '/projects'; + ctrl.create = create; + ctrl.update = update; + + ctrl.createRequirements = [ + {label: 'name', type: 'text', required: true}, + {label: 'description', type: 'textarea', required: false} + ]; + + ctrl.name = ''; + ctrl.details = ''; + + /** + * This will contact the TestAPI to create a new project. + */ + function create() { + ctrl.showError = false; + ctrl.showSuccess = false; + if(ctrl.name != ""){ + var projects_url = ctrl.url; + var body = { + name: ctrl.name, + description: ctrl.description + }; + ctrl.projectsRequest = + $http.post(projects_url, body).success(function (data){ + ctrl.showSuccess = true ; + ctrl.update(); + }) + .error(function (data) { + ctrl.showError = true; + ctrl.error = 'Error creating the new Project from server:' + angular.toJson(data); + }); + ctrl.name = ""; + ctrl.description=""; + } + else{ + ctrl.showError = true; + ctrl.error = 'Name is missing.' + } + } + + /** + * This will contact the TestAPI to get a listing of declared projects. + */ + function update() { + ctrl.showError = false; + ctrl.projectsRequest = + $http.get(ctrl.url).success(function (data) { + ctrl.data = data; + }).error(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = + 'Error retrieving projects from server: ' + + angular.toJson(error); + }); + } + ctrl.update(); + } +})(); diff --git a/testapi/opnfv_testapi/ui/components/results-report/partials/editTestModal.html b/testapi/opnfv_testapi/ui/components/results-report/partials/editTestModal.html new file mode 100644 index 0000000..583c9b9 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results-report/partials/editTestModal.html @@ -0,0 +1,65 @@ + diff --git a/testapi/opnfv_testapi/ui/components/results-report/partials/fullTestListModal.html b/testapi/opnfv_testapi/ui/components/results-report/partials/fullTestListModal.html new file mode 100644 index 0000000..6db198b --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results-report/partials/fullTestListModal.html @@ -0,0 +1,13 @@ + diff --git a/testapi/opnfv_testapi/ui/components/results-report/partials/reportDetails.html b/testapi/opnfv_testapi/ui/components/results-report/partials/reportDetails.html new file mode 100644 index 0000000..517e569 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results-report/partials/reportDetails.html @@ -0,0 +1,87 @@ + + + + + {{status | capitalize}} + + (Total: {{ctrl.caps[status].caps.length}} capabilities, {{ctrl.caps[status].count}} tests) + + ({{ctrl.testStatus | capitalize}}: {{ctrl.getStatusTestCount(status)}} tests) + + + + + +
    +
  1. + + + {{capability.id}} + + + [{{ctrl.getCapabilityTestCount(capability)}}] + + + [{{capability.passedTests.length}}/{{capability.passedTests.length + + capability.notPassedTests.length}}] + + +
      + +
    • + + + + + {{test}} + — + [Aliases] +
      +
      • {{alias}}
      +
      +
      +
    • + + + +
    • + + + + + {{test}} + — + [Aliases] +
      +
      • {{alias}}
      +
      +
      +
    • + +
    +
  2. +
+
diff --git a/testapi/opnfv_testapi/ui/components/results-report/resultsReport.html b/testapi/opnfv_testapi/ui/components/results-report/resultsReport.html new file mode 100644 index 0000000..5527121 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results-report/resultsReport.html @@ -0,0 +1,185 @@ +

Test Run Results

+ +
+
+
+
+ Test ID: {{ctrl.testId}}
+
Cloud ID: {{ctrl.resultsData.cpid}}
+ Upload Date: {{ctrl.resultsData.created_at}} UTC
+ Duration: {{ctrl.resultsData.duration_seconds}} seconds
+ Total Number of Passed Tests: + + {{ctrl.resultsData.results.length}} + +
+
+
+ Publicly Shared: + Yes + No +
+
+
+ Product: + {{ctrl.resultsData.product_version.product_info.name}} + + ({{ctrl.resultsData.product_version.version}}) +
+
+
+ Associated Guideline: + {{ctrl.resultsData.meta.guideline.slice(0, -5)}} +
+
+ Associated Target Program: + {{ctrl.targetMappings[ctrl.resultsData.meta.target]}} +
+
+ Verified: + YES +
+
+
+ +
+
+ + +
+
+
+
+ +
+
+
+
+
+ +
+

See how these results stack up against Interop Working Group capabilities and OpenStack + target marketing programs. +

+ + +
+
+ Guideline Version: + + +
+
+ Target Program: + +
+
+ + +
+
+ Guideline Status: + {{ctrl.guidelineData.status | capitalize}} +
+ + Corresponding OpenStack Releases: +
    +
  • + {{release | capitalize}} +
  • +
+
+ +
+ Status: +

This cloud passes {{ctrl.requiredPassPercent | number:1}}% + ({{ctrl.caps.required.passedCount}}/{{ctrl.caps.required.count}}) + of the tests in the {{ctrl.version.slice(0, -5)}} required capabilities for the + {{ctrl.targetMappings[target]}} program.
+ Excluding flagged tests, this cloud passes + {{ctrl.nonFlagRequiredPassPercent | number:1}}% + ({{ctrl.nonFlagPassCount}}/{{ctrl.totalNonFlagCount}}) + of the required tests. +

+ +

Compliance with {{ctrl.version.slice(0, -5)}}: + + YES + NO + +

+ +
+

Capability Overview

+ + Test Filters:
+
+ + + + +
+ + + + + +
+ + +
+ + +
+ + +
+
+
+ +
+
+
+
+
+ + diff --git a/testapi/opnfv_testapi/ui/components/results-report/resultsReportController.js b/testapi/opnfv_testapi/ui/components/results-report/resultsReportController.js new file mode 100644 index 0000000..591ad40 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results-report/resultsReportController.js @@ -0,0 +1,869 @@ +/* + * 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 = [ + '$http', '$stateParams', '$window', + '$uibModal', 'testapiApiUrl', 'raiseAlert' + ]; + + /** + * TestAPI Results Report Controller + * This controller is for the '/results/' page where a user can + * view details for a specific test run. + */ + function ResultsReportController($http, $stateParams, $window, + $uibModal, testapiApiUrl, raiseAlert) { + + var ctrl = this; + + ctrl.getVersionList = getVersionList; + ctrl.getResults = getResults; + ctrl.isResultAdmin = isResultAdmin; + ctrl.isShared = isShared; + ctrl.shareTestRun = shareTestRun; + ctrl.deleteTestRun = deleteTestRun; + ctrl.updateVerificationStatus = updateVerificationStatus; + ctrl.updateGuidelines = updateGuidelines; + ctrl.getTargetCapabilities = getTargetCapabilities; + ctrl.buildCapabilityV1_2 = buildCapabilityV1_2; + ctrl.buildCapabilityV1_3 = buildCapabilityV1_3; + ctrl.buildCapabilitiesObject = buildCapabilitiesObject; + ctrl.isTestFlagged = isTestFlagged; + ctrl.getFlaggedReason = getFlaggedReason; + ctrl.isCapabilityShown = isCapabilityShown; + ctrl.isTestShown = isTestShown; + ctrl.getCapabilityTestCount = getCapabilityTestCount; + ctrl.getStatusTestCount = getStatusTestCount; + ctrl.openFullTestListModal = openFullTestListModal; + ctrl.openEditTestModal = openEditTestModal; + + /** The testID extracted from the URL route. */ + ctrl.testId = $stateParams.testID; + + /** The target OpenStack marketing program to compare against. */ + ctrl.target = 'platform'; + + /** Mappings of Interop WG components to marketing program names. */ + ctrl.targetMappings = { + 'platform': 'Openstack Powered Platform', + 'compute': 'OpenStack Powered Compute', + 'object': 'OpenStack Powered Object Storage' + }; + + /** The schema version of the currently selected guideline data. */ + ctrl.schemaVersion = null; + + /** The selected test status used for test filtering. */ + ctrl.testStatus = 'total'; + + /** The HTML template that all accordian groups will use. */ + ctrl.detailsTemplate = 'components/results-report/partials/' + + 'reportDetails.html'; + + /** + * Retrieve an array of available guideline files from the TestAPI + * API server, sort this array reverse-alphabetically, and store it in + * a scoped variable. The scope's selected version is initialized to + * the latest (i.e. first) version here as well. After a successful API + * call, the function to update the capabilities is called. + * Sample API return array: ["2015.03.json", "2015.04.json"] + */ + function getVersionList() { + var content_url = testapiApiUrl + '/guidelines'; + ctrl.versionsRequest = + $http.get(content_url).success(function (data) { + ctrl.versionList = data.sort().reverse(); + if (!ctrl.version) { + // Default to the first approved guideline which is + // expected to be at index 1. + ctrl.version = ctrl.versionList[1]; + } + ctrl.updateGuidelines(); + }).error(function (error) { + ctrl.showError = true; + ctrl.error = 'Error retrieving version list: ' + + angular.toJson(error); + }); + } + + /** + * Retrieve results from the TestAPI API server based on the test + * run id in the URL. This function is the first function that will + * be called from the controller. Upon successful retrieval of results, + * the function that gets the version list will be called. + */ + function getResults() { + var content_url = testapiApiUrl + '/results/' + ctrl.testId; + ctrl.resultsRequest = + $http.get(content_url).success(function (data) { + ctrl.resultsData = data; + ctrl.version = ctrl.resultsData.meta.guideline; + ctrl.isVerified = ctrl.resultsData.verification_status; + if (ctrl.resultsData.meta.target) { + ctrl.target = ctrl.resultsData.meta.target; + } + getVersionList(); + }).error(function (error) { + ctrl.showError = true; + ctrl.resultsData = null; + ctrl.error = 'Error retrieving results from server: ' + + angular.toJson(error); + }); + } + + /** + * This tells you whether the current user has administrative + * privileges for the test result. + * @returns {Boolean} true if the user has admin privileges. + */ + function isResultAdmin() { + return Boolean(ctrl.resultsData && + (ctrl.resultsData.user_role === 'owner' || + ctrl.resultsData.user_role === 'foundation')); + } + /** + * This tells you whether the current results are shared with the + * community or not. + * @returns {Boolean} true if the results are shared + */ + function isShared() { + return Boolean(ctrl.resultsData && + 'shared' in ctrl.resultsData.meta); + } + + /** + * This will send an API request in order to share or unshare the + * current results based on the passed in shareState. + * @param {Boolean} shareState - Whether to share or unshare results. + */ + function shareTestRun(shareState) { + var content_url = [ + testapiApiUrl, '/results/', ctrl.testId, '/meta/shared' + ].join(''); + if (shareState) { + ctrl.shareRequest = + $http.post(content_url, 'true').success(function () { + ctrl.resultsData.meta.shared = 'true'; + raiseAlert('success', '', 'Test run shared!'); + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } else { + ctrl.shareRequest = + $http.delete(content_url).success(function () { + delete ctrl.resultsData.meta.shared; + raiseAlert('success', '', 'Test run unshared!'); + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } + } + + /** + * This will send a request to the API to delete the current + * test results set. + */ + function deleteTestRun() { + var content_url = [ + testapiApiUrl, '/results/', ctrl.testId + ].join(''); + ctrl.deleteRequest = + $http.delete(content_url).success(function () { + $window.history.back(); + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } + + /** + * This will send a request to the API to delete the current + * test results set. + */ + function updateVerificationStatus() { + var content_url = [ + testapiApiUrl, '/results/', ctrl.testId + ].join(''); + var data = {'verification_status': ctrl.isVerified}; + ctrl.updateRequest = + $http.put(content_url, data).success( + function () { + ctrl.resultsData.verification_status = ctrl.isVerified; + raiseAlert('success', '', + 'Verification status changed!'); + }).error(function (error) { + ctrl.isVerified = ctrl.resultsData.verification_status; + raiseAlert('danger', error.title, error.detail); + }); + } + + /** + * This will contact the TestAPI API server to retrieve the JSON + * content of the guideline file corresponding to the selected + * version. A function to construct an object from the capability + * data will be called upon successful retrieval. + */ + function updateGuidelines() { + ctrl.guidelineData = null; + ctrl.showError = false; + var content_url = testapiApiUrl + '/guidelines/' + + ctrl.version; + ctrl.capsRequest = + $http.get(content_url).success(function (data) { + ctrl.guidelineData = data; + ctrl.schemaVersion = data.schema; + ctrl.buildCapabilitiesObject(); + }).error(function (error) { + ctrl.showError = true; + ctrl.guidelineData = null; + ctrl.error = 'Error retrieving guideline date: ' + + angular.toJson(error); + }); + } + + /** + * This will get all the capabilities relevant to the target and + * their corresponding statuses. + * @returns {Object} Object containing each capability and their status + */ + function getTargetCapabilities() { + var components = ctrl.guidelineData.components; + var targetCaps = {}; + + // The 'platform' target is comprised of multiple components, so + // we need to get the capabilities belonging to each of its + // components. + if (ctrl.target === 'platform') { + var platform_components = + ctrl.guidelineData.platform.required; + + // This will contain status priority values, where lower + // values mean higher priorities. + var statusMap = { + required: 1, + advisory: 2, + deprecated: 3, + removed: 4 + }; + + // For each component required for the platform program. + angular.forEach(platform_components, function (component) { + // Get each capability list belonging to each status. + angular.forEach(components[component], + function (caps, status) { + // For each capability. + angular.forEach(caps, function(cap) { + // If the capability has already been added. + if (cap in targetCaps) { + // If the status priority value is less + // than the saved priority value, update + // the value. + if (statusMap[status] < + statusMap[targetCaps[cap]]) { + targetCaps[cap] = status; + } + } + else { + targetCaps[cap] = status; + } + }); + }); + }); + } + else { + angular.forEach(components[ctrl.target], + function (caps, status) { + angular.forEach(caps, function(cap) { + targetCaps[cap] = status; + }); + }); + } + return targetCaps; + } + + /** + * This will build the a capability object for schema version 1.2. + * This object will contain the information needed to form a report in + * the HTML template. + * @param {String} capId capability ID + */ + function buildCapabilityV1_2(capId) { + var cap = { + 'id': capId, + 'passedTests': [], + 'notPassedTests': [], + 'passedFlagged': [], + 'notPassedFlagged': [] + }; + var capDetails = ctrl.guidelineData.capabilities[capId]; + // Loop through each test belonging to the capability. + angular.forEach(capDetails.tests, + function (testId) { + // If the test ID is in the results' test list, add + // it to the passedTests array. + if (ctrl.resultsData.results.indexOf(testId) > -1) { + cap.passedTests.push(testId); + if (capDetails.flagged.indexOf(testId) > -1) { + cap.passedFlagged.push(testId); + } + } + else { + cap.notPassedTests.push(testId); + if (capDetails.flagged.indexOf(testId) > -1) { + cap.notPassedFlagged.push(testId); + } + } + }); + return cap; + } + + /** + * This will build the a capability object for schema version 1.3 and + * above. This object will contain the information needed to form a + * report in the HTML template. + * @param {String} capId capability ID + */ + function buildCapabilityV1_3(capId) { + var cap = { + 'id': capId, + 'passedTests': [], + 'notPassedTests': [], + 'passedFlagged': [], + 'notPassedFlagged': [] + }; + + // For cases where a capability listed in components is not + // in the capabilities object. + if (!(capId in ctrl.guidelineData.capabilities)) { + return cap; + } + + // Loop through each test belonging to the capability. + angular.forEach(ctrl.guidelineData.capabilities[capId].tests, + function (details, testId) { + var passed = false; + + // If the test ID is in the results' test list. + if (ctrl.resultsData.results.indexOf(testId) > -1) { + passed = true; + } + else if ('aliases' in details) { + var len = details.aliases.length; + for (var i = 0; i < len; i++) { + var alias = details.aliases[i]; + if (ctrl.resultsData.results.indexOf(alias) > -1) { + passed = true; + break; + } + } + } + + // Add to correct array based on whether the test was + // passed or not. + if (passed) { + cap.passedTests.push(testId); + if ('flagged' in details) { + cap.passedFlagged.push(testId); + } + } + else { + cap.notPassedTests.push(testId); + if ('flagged' in details) { + cap.notPassedFlagged.push(testId); + } + } + }); + return cap; + } + + /** + * This will check the schema version of the current capabilities file, + * and will call the correct method to build an object based on the + * capability data retrieved from the TestAPI API server. + */ + function buildCapabilitiesObject() { + // This is the object template where 'count' is the number of + // total tests that fall under the given status, and 'passedCount' + // is the number of tests passed. The 'caps' array will contain + // objects with details regarding each capability. + ctrl.caps = { + 'required': {'caps': [], 'count': 0, 'passedCount': 0, + 'flagFailCount': 0, 'flagPassCount': 0}, + 'advisory': {'caps': [], 'count': 0, 'passedCount': 0, + 'flagFailCount': 0, 'flagPassCount': 0}, + 'deprecated': {'caps': [], 'count': 0, 'passedCount': 0, + 'flagFailCount': 0, 'flagPassCount': 0}, + 'removed': {'caps': [], 'count': 0, 'passedCount': 0, + 'flagFailCount': 0, 'flagPassCount': 0} + }; + + switch (ctrl.schemaVersion) { + case '1.2': + var capMethod = 'buildCapabilityV1_2'; + break; + case '1.3': + case '1.4': + case '1.5': + case '1.6': + capMethod = 'buildCapabilityV1_3'; + break; + default: + ctrl.showError = true; + ctrl.guidelineData = null; + ctrl.error = 'The schema version for the guideline ' + + 'file selected (' + ctrl.schemaVersion + + ') is currently not supported.'; + return; + } + + // Get test details for each relevant capability and store + // them in the scope's 'caps' object. + var targetCaps = ctrl.getTargetCapabilities(); + angular.forEach(targetCaps, function(status, capId) { + var cap = ctrl[capMethod](capId); + ctrl.caps[status].count += + cap.passedTests.length + cap.notPassedTests.length; + ctrl.caps[status].passedCount += cap.passedTests.length; + ctrl.caps[status].flagPassCount += cap.passedFlagged.length; + ctrl.caps[status].flagFailCount += + cap.notPassedFlagged.length; + ctrl.caps[status].caps.push(cap); + }); + + ctrl.requiredPassPercent = (ctrl.caps.required.passedCount * + 100 / ctrl.caps.required.count); + + ctrl.totalRequiredFailCount = ctrl.caps.required.count - + ctrl.caps.required.passedCount; + ctrl.totalRequiredFlagCount = + ctrl.caps.required.flagFailCount + + ctrl.caps.required.flagPassCount; + ctrl.totalNonFlagCount = ctrl.caps.required.count - + ctrl.totalRequiredFlagCount; + ctrl.nonFlagPassCount = ctrl.totalNonFlagCount - + (ctrl.totalRequiredFailCount - + ctrl.caps.required.flagFailCount); + + ctrl.nonFlagRequiredPassPercent = (ctrl.nonFlagPassCount * + 100 / ctrl.totalNonFlagCount); + } + + /** + * This will check if a given test is flagged. + * @param {String} test ID of the test to check + * @param {Object} capObj capability that test is under + * @returns {Boolean} truthy value if test is flagged + */ + function isTestFlagged(test, capObj) { + if (!capObj) { + return false; + } + return (((ctrl.schemaVersion === '1.2') && + (capObj.flagged.indexOf(test) > -1)) || + ((ctrl.schemaVersion >= '1.3') && + (capObj.tests[test].flagged))); + } + + /** + * This will return the reason a test is flagged. An empty string + * will be returned if the passed in test is not flagged. + * @param {String} test ID of the test to check + * @param {String} capObj capability that test is under + * @returns {String} reason + */ + function getFlaggedReason(test, capObj) { + if ((ctrl.schemaVersion === '1.2') && + (ctrl.isTestFlagged(test, capObj))) { + + // Return a generic message since schema 1.2 does not + // provide flag reasons. + return 'Interop Working Group has flagged this test.'; + } + else if ((ctrl.schemaVersion >= '1.3') && + (ctrl.isTestFlagged(test, capObj))) { + + return capObj.tests[test].flagged.reason; + } + else { + return ''; + } + } + + /** + * This will check the if a capability should be shown based on the + * test filter selected. If a capability does not have any tests + * belonging under the given filter, it should not be shown. + * @param {Object} capability Built object for capability + * @returns {Boolean} true if capability should be shown + */ + function isCapabilityShown(capability) { + return ((ctrl.testStatus === 'total') || + (ctrl.testStatus === 'passed' && + capability.passedTests.length > 0) || + (ctrl.testStatus === 'not passed' && + capability.notPassedTests.length > 0) || + (ctrl.testStatus === 'flagged' && + (capability.passedFlagged.length + + capability.notPassedFlagged.length > 0))); + } + + /** + * This will check the if a test should be shown based on the test + * filter selected. + * @param {String} test ID of the test + * @param {Object} capability Built object for capability + * @return {Boolean} true if test should be shown + */ + function isTestShown(test, capability) { + return ((ctrl.testStatus === 'total') || + (ctrl.testStatus === 'passed' && + capability.passedTests.indexOf(test) > -1) || + (ctrl.testStatus === 'not passed' && + capability.notPassedTests.indexOf(test) > -1) || + (ctrl.testStatus === 'flagged' && + (capability.passedFlagged.indexOf(test) > -1 || + capability.notPassedFlagged.indexOf(test) > -1))); + } + + /** + * This will give the number of tests belonging under the selected + * test filter for a given capability. + * @param {Object} capability Built object for capability + * @returns {Number} number of tests under filter + */ + function getCapabilityTestCount(capability) { + if (ctrl.testStatus === 'total') { + return capability.passedTests.length + + capability.notPassedTests.length; + } + else if (ctrl.testStatus === 'passed') { + return capability.passedTests.length; + } + else if (ctrl.testStatus === 'not passed') { + return capability.notPassedTests.length; + } + else if (ctrl.testStatus === 'flagged') { + return capability.passedFlagged.length + + capability.notPassedFlagged.length; + } + else { + return 0; + } + } + + /** + * This will give the number of tests belonging under the selected + * test filter for a given status. + * @param {String} capability status + * @returns {Number} number of tests for status under filter + */ + function getStatusTestCount(status) { + if (!ctrl.caps) { + return -1; + } + else if (ctrl.testStatus === 'total') { + return ctrl.caps[status].count; + } + else if (ctrl.testStatus === 'passed') { + return ctrl.caps[status].passedCount; + } + else if (ctrl.testStatus === 'not passed') { + return ctrl.caps[status].count - + ctrl.caps[status].passedCount; + } + else if (ctrl.testStatus === 'flagged') { + return ctrl.caps[status].flagFailCount + + ctrl.caps[status].flagPassCount; + } + else { + return -1; + } + } + + /** + * This will open the modal that will show the full list of passed + * tests for the current results. + */ + function openFullTestListModal() { + $uibModal.open({ + templateUrl: '/components/results-report/partials' + + '/fullTestListModal.html', + backdrop: true, + windowClass: 'modal', + animation: true, + controller: 'FullTestListModalController as modal', + size: 'lg', + resolve: { + tests: function () { + return ctrl.resultsData.results; + } + } + }); + } + + /** + * This will open the modal that will all a user to edit test run + * metadata. + */ + function openEditTestModal() { + $uibModal.open({ + templateUrl: '/components/results-report/partials' + + '/editTestModal.html', + backdrop: true, + windowClass: 'modal', + animation: true, + controller: 'EditTestModalController as modal', + size: 'lg', + resolve: { + resultsData: function () { + return ctrl.resultsData; + } + } + }); + } + + getResults(); + } + + angular + .module('testapiApp') + .controller('FullTestListModalController', FullTestListModalController); + + FullTestListModalController.$inject = ['$uibModalInstance', 'tests']; + + /** + * Full Test List Modal Controller + * This controller is for the modal that appears if a user wants to see the + * full list of passed tests on a report page. + */ + function FullTestListModalController($uibModalInstance, tests) { + var ctrl = this; + + ctrl.tests = tests; + + /** + * This function will close/dismiss the modal. + */ + ctrl.close = function () { + $uibModalInstance.dismiss('exit'); + }; + + /** + * This function will return a string representing the sorted + * tests list separated by newlines. + */ + ctrl.getTestListString = function () { + return ctrl.tests.sort().join('\n'); + }; + } + + angular + .module('testapiApp') + .controller('EditTestModalController', EditTestModalController); + + EditTestModalController.$inject = [ + '$uibModalInstance', '$http', '$state', 'raiseAlert', + 'testapiApiUrl', 'resultsData' + ]; + + /** + * Edit Test Modal Controller + * This controller is for the modal that appears if a user wants to edit + * test run metadata. + */ + function EditTestModalController($uibModalInstance, $http, $state, + raiseAlert, testapiApiUrl, resultsData) { + + var ctrl = this; + + ctrl.getVersionList = getVersionList; + ctrl.getUserProducts = getUserProducts; + ctrl.associateProductVersion = associateProductVersion; + ctrl.getProductVersions = getProductVersions; + ctrl.saveChanges = saveChanges; + + ctrl.resultsData = resultsData; + ctrl.metaCopy = angular.copy(resultsData.meta); + ctrl.prodVersionCopy = angular.copy(resultsData.product_version); + + ctrl.getVersionList(); + ctrl.getUserProducts(); + + /** + * Retrieve an array of available capability files from the TestAPI + * API server, sort this array reverse-alphabetically, and store it in + * a scoped variable. + * Sample API return array: ["2015.03.json", "2015.04.json"] + */ + function getVersionList() { + if (ctrl.versionList) { + return; + } + var content_url = testapiApiUrl + '/guidelines'; + ctrl.versionsRequest = + $http.get(content_url).success(function (data) { + ctrl.versionList = data.sort().reverse(); + }).error(function (error) { + raiseAlert('danger', error.title, + 'Unable to retrieve version list'); + }); + } + + /** + * Get products user has management rights to or all products depending + * on the passed in parameter value. + */ + function getUserProducts() { + var contentUrl = testapiApiUrl + '/products'; + ctrl.productsRequest = + $http.get(contentUrl).success(function (data) { + ctrl.products = {}; + angular.forEach(data.products, function(prod) { + if (prod.can_manage) { + ctrl.products[prod.id] = prod; + } + }); + if (ctrl.prodVersionCopy) { + ctrl.selectedProduct = ctrl.products[ + ctrl.prodVersionCopy.product_info.id + ]; + } + ctrl.getProductVersions(); + }).error(function (error) { + ctrl.products = null; + ctrl.showError = true; + ctrl.error = + 'Error retrieving Products listing from server: ' + + angular.toJson(error); + }); + } + + /** + * Send a PUT request to the API server to associate a product with + * a test result. + */ + function associateProductVersion() { + var verId = (ctrl.selectedVersion ? + ctrl.selectedVersion.id : null); + var testId = resultsData.id; + var url = testapiApiUrl + '/results/' + testId; + ctrl.associateRequest = $http.put(url, {'product_version_id': + verId}) + .error(function (error) { + ctrl.showError = true; + ctrl.showSuccess = false; + ctrl.error = + 'Error associating product version with test run: ' + + angular.toJson(error); + }); + } + + /** + * Get all versions for a product. + */ + function getProductVersions() { + if (!ctrl.selectedProduct) { + ctrl.productVersions = []; + ctrl.selectedVersion = null; + return; + } + + var url = testapiApiUrl + '/products/' + + ctrl.selectedProduct.id + '/versions'; + ctrl.getVersionsRequest = $http.get(url) + .success(function (data) { + ctrl.productVersions = data; + if (ctrl.prodVersionCopy && + ctrl.prodVersionCopy.product_info.id == + ctrl.selectedProduct.id) { + ctrl.selectedVersion = ctrl.prodVersionCopy; + } + else { + angular.forEach(data, function(ver) { + if (!ver.version) { + ctrl.selectedVersion = ver; + } + }); + } + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } + + /** + * Send a PUT request to the server with the changes. + */ + function saveChanges() { + ctrl.showError = false; + ctrl.showSuccess = false; + var metaBaseUrl = [ + testapiApiUrl, '/results/', resultsData.id, '/meta/' + ].join(''); + var metaFields = ['target', 'guideline', 'shared']; + var meta = ctrl.metaCopy; + angular.forEach(metaFields, function(field) { + var oldMetaValue = (field in ctrl.resultsData.meta) ? + ctrl.resultsData.meta[field] : ''; + if (field in meta && oldMetaValue != meta[field]) { + var metaUrl = metaBaseUrl + field; + if (meta[field]) { + ctrl.assocRequest = $http.post(metaUrl, meta[field]) + .success(function(data) { + ctrl.resultsData.meta[field] = meta[field]; + }) + .error(function (error) { + ctrl.showError = true; + ctrl.showSuccess = false; + ctrl.error = + 'Error associating metadata with ' + + 'test run: ' + angular.toJson(error); + }); + } + else { + ctrl.unassocRequest = $http.delete(metaUrl) + .success(function (data) { + delete ctrl.resultsData.meta[field]; + delete meta[field]; + }) + .error(function (error) { + ctrl.showError = true; + ctrl.showSuccess = false; + ctrl.error = + 'Error associating metadata with ' + + 'test run: ' + angular.toJson(error); + }); + } + } + }); + ctrl.associateProductVersion(); + if (!ctrl.showError) { + ctrl.showSuccess = true; + $state.reload(); + } + } + + /** + * This function will close/dismiss the modal. + */ + ctrl.close = function () { + $uibModalInstance.dismiss('exit'); + }; + } +})(); diff --git a/testapi/opnfv_testapi/ui/components/results/results.html b/testapi/opnfv_testapi/ui/components/results/results.html new file mode 100644 index 0000000..2ae5339 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results/results.html @@ -0,0 +1,115 @@ +

{{ctrl.pageHeader}}

+

{{ctrl.pageParagraph}}

+
+

Upload Results

+
+ +
+
+ +
+
+ +
+
+{{ctrl.uploadState}} +
+
+
+
+

Filters

+
+
+ +

+ + + + +

+
+
+ +

+ + + + +

+
+
+ + +
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDPodProjectTest CaseInstallerVersionScenarioCriteriaStart DateStop Date
{{ result._id }}{{ result.pod_name }}{{ result.project_name }}{{ result.case_name }}{{ result.installer }}{{ result.version }}{{ result.scenario }}{{ result.criteria }}{{ result.start_date }}{{ result.stop_date }}
+ +
+ + +
+
+ + diff --git a/testapi/opnfv_testapi/ui/components/results/resultsController.js b/testapi/opnfv_testapi/ui/components/results/resultsController.js new file mode 100644 index 0000000..cc6cc0b --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results/resultsController.js @@ -0,0 +1,370 @@ +/* + * 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]); + }); + }); + } + }; + }]); + + ResultsController.$inject = [ + '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' + ]; + + /** + * 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) { + var ctrl = this; + + ctrl.uploadFile=uploadFile; + ctrl.update = update; + ctrl.open = open; + ctrl.clearFilters = clearFilters; + ctrl.associateMeta = associateMeta; + ctrl.getVersionList = getVersionList; + ctrl.getUserProducts = getUserProducts; + ctrl.associateProductVersion = associateProductVersion; + ctrl.getProductVersions = getProductVersions; + ctrl.prepVersionEdit = prepVersionEdit; + + /** 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'; + + /** Check to see if this page should display user-specific results. */ + // ctrl.isUserResults = $state.current.name === 'userResults'; + // need auth to browse + ctrl.isUserResults = $state.current.name === 'userResults'; + + // Should only be on user-results-page if authenticated. + if (ctrl.isUserResults && !$scope.auth.isAuthenticated) { + $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.isPublic = false; + + if (ctrl.isUserResults) { + ctrl.authRequest = $scope.auth.doSignCheck() + .then(ctrl.update); + // ctrl.getUserProducts(); + } else { + ctrl.update(); + } + + + function uploadFileToUrl(file, uploadUrl){ + var fd = new FormData(); + fd.append('file', file); + fd.append('public', ctrl.isPublic) + + $http.post(uploadUrl, fd, { + transformRequest: angular.identity, + headers: {'Content-Type': undefined} + }) + + .success(function(data){ + var id = data.href.substr(data.href.lastIndexOf('/')+1); + ctrl.uploadState = "Upload succeed. Result id is " + id; + ctrl.update(); + }) + + .error(function(data, status){ + ctrl.uploadState = "Upload failed. Error code is " + status; + }); + } + + function uploadFile(){ + var file = $scope.resultFile; + console.log('file is ' ); + console.dir(file); + + var uploadUrl = testapiApiUrl + "/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 + '/results' + + '?page=' + ctrl.currentPage; + var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd'); + if (start) { + content_url = + content_url + '&from=' + start + ' 00:00:00'; + } + var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd'); + if (end) { + content_url = content_url + '&to=' + end + ' 23:59:59'; + } + if (ctrl.isUserResults) { + content_url = content_url + '&signed'; + } + 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; + }).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); + } + }); + } + } + + /** + * Retrieve an array of available capability files from the TestAPI + * API server, sort this array reverse-alphabetically, and store it in + * a scoped variable. + * Sample API return array: ["2015.03.json", "2015.04.json"] + */ + function getVersionList() { + if (ctrl.versionList) { + return; + } + var content_url = testapiApiUrl + '/guidelines'; + ctrl.versionsRequest = + $http.get(content_url).success(function (data) { + ctrl.versionList = data.sort().reverse(); + }).error(function (error) { + raiseAlert('danger', error.title, + 'Unable to retrieve version list'); + }); + } + + /** + * Get products user has management rights to or all products depending + * on the passed in parameter value. + */ + function getUserProducts() { + if (ctrl.products) { + return; + } + var contentUrl = testapiApiUrl + '/products'; + ctrl.productsRequest = + $http.get(contentUrl).success(function (data) { + ctrl.products = {}; + angular.forEach(data.products, function(prod) { + if (prod.can_manage) { + ctrl.products[prod.id] = prod; + } + }); + }).error(function (error) { + ctrl.products = null; + ctrl.showError = true; + ctrl.error = + 'Error retrieving Products listing from server: ' + + angular.toJson(error); + }); + } + + /** + * Send a PUT request to the API server to associate a product with + * a test result. + */ + function associateProductVersion(result) { + var verId = (result.selectedVersion ? + result.selectedVersion.id : null); + var testId = result.id; + var url = testapiApiUrl + '/results/' + testId; + ctrl.associateRequest = $http.put(url, {'product_version_id': + verId}) + .success(function (data) { + result.product_version = result.selectedVersion; + if (result.selectedVersion) { + result.product_version.product_info = + result.selectedProduct; + } + result.productEdit = false; + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } + + /** + * Get all versions for a product. + */ + function getProductVersions(result) { + if (!result.selectedProduct) { + result.productVersions = []; + result.selectedVersion = null; + return; + } + + var url = testapiApiUrl + '/products/' + + result.selectedProduct.id + '/versions'; + ctrl.getVersionsRequest = $http.get(url) + .success(function (data) { + result.productVersions = data; + + // If the test result isn't already associated to a + // version, default it to the null version. + if (!result.product_version) { + angular.forEach(data, function(ver) { + if (!ver.version) { + result.selectedVersion = ver; + } + }); + } + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } + + /** + * Instantiate variables needed for editing product/version + * associations. + */ + function prepVersionEdit(result) { + result.productEdit = true; + if (result.product_version) { + result.selectedProduct = + ctrl.products[result.product_version.product_info.id]; + } + result.selectedVersion = result.product_version; + ctrl.getProductVersions(result); + } + + } +})(); diff --git a/testapi/opnfv_testapi/ui/config.json b/testapi/opnfv_testapi/ui/config.json new file mode 100644 index 0000000..5d48c7b --- /dev/null +++ b/testapi/opnfv_testapi/ui/config.json @@ -0,0 +1 @@ +{"testapiApiUrl": "http://localhost:8000/api/v1"} diff --git a/testapi/opnfv_testapi/ui/favicon-16x16.png b/testapi/opnfv_testapi/ui/favicon-16x16.png new file mode 100755 index 0000000..e08c8a1 Binary files /dev/null and b/testapi/opnfv_testapi/ui/favicon-16x16.png differ diff --git a/testapi/opnfv_testapi/ui/favicon-32x32.png b/testapi/opnfv_testapi/ui/favicon-32x32.png new file mode 100755 index 0000000..7bf57e2 Binary files /dev/null and b/testapi/opnfv_testapi/ui/favicon-32x32.png differ diff --git a/testapi/opnfv_testapi/ui/favicon.ico b/testapi/opnfv_testapi/ui/favicon.ico new file mode 100644 index 0000000..156019a Binary files /dev/null and b/testapi/opnfv_testapi/ui/favicon.ico differ diff --git a/testapi/opnfv_testapi/ui/home/home.html b/testapi/opnfv_testapi/ui/home/home.html deleted file mode 100644 index 47d747f..0000000 --- a/testapi/opnfv_testapi/ui/home/home.html +++ /dev/null @@ -1,23 +0,0 @@ -
- -
-

Results Collection

-

TestAPI is a source of tools for OPNFV test results collection

-
-
-
- -
-
-

What is TestAPI?

-
    -
  • Toolset for testing interoperability between OPNFV test projects.
  • -
  • Database backed website supporting collection and publication of - community test results for OPNFV.
  • -
  • User interface to display individual test run results.
  • -
-
-
- diff --git a/testapi/opnfv_testapi/ui/index.html b/testapi/opnfv_testapi/ui/index.html new file mode 100644 index 0000000..ac29aca --- /dev/null +++ b/testapi/opnfv_testapi/ui/index.html @@ -0,0 +1,62 @@ + + + + + + + + TestAPI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + diff --git a/testapi/opnfv_testapi/ui/logout/logout.html b/testapi/opnfv_testapi/ui/logout/logout.html deleted file mode 100644 index 38a5c36..0000000 --- a/testapi/opnfv_testapi/ui/logout/logout.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/testapi/opnfv_testapi/ui/logout/logoutController.js b/testapi/opnfv_testapi/ui/logout/logoutController.js deleted file mode 100644 index 1b6d78c..0000000 --- a/testapi/opnfv_testapi/ui/logout/logoutController.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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/testapi/opnfv_testapi/ui/package.json b/testapi/opnfv_testapi/ui/package.json new file mode 100644 index 0000000..dc99239 --- /dev/null +++ b/testapi/opnfv_testapi/ui/package.json @@ -0,0 +1,18 @@ +{ + "devDependencies": { + "grunt": "~1.0.1", + "grunt-contrib-connect": "^1.0.2", + "grunt-contrib-copy": "^1.0.0", + "grunt-karma": "~2.0.0", + "grunt-protractor-coverage": "^0.2.18", + "grunt-protractor-runner": "~5.0.0", + "grunt-shell-spawn": "~0.3.10", + "grunt-wait": "~0.1.0", + "karma": "~1.7.1", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage": "~1.1.1", + "karma-jasmine": "~1.1.0", + "load-grunt-tasks": "~3.5.2", + "protractor-http-mock": "^0.10.0" + } +} diff --git a/testapi/opnfv_testapi/ui/pods/pods.html b/testapi/opnfv_testapi/ui/pods/pods.html deleted file mode 100644 index 22f2934..0000000 --- a/testapi/opnfv_testapi/ui/pods/pods.html +++ /dev/null @@ -1,76 +0,0 @@ -

Pods

-

This page is used to create or query pods.
- Querying pods is open to everybody.
- But only login users are granted the privilege to create the new pod. -

- -
- -
-

Create

-
-
-
-

- - - - - - - - - - -

-
-
- -
- -
-
-
- -
-

Filters

-
-
- - -
-
-
- -
-
- -
- - - - - - - - -
- {{pod.name}} -
-

- owner: {{pod.owner}}
- role: {{pod.role}}
- mode: {{pod.mode}}
- create_date: {{pod.creation_date}}
- details: {{pod.details}} -

-
-
-
-
- diff --git a/testapi/opnfv_testapi/ui/pods/podsController.js b/testapi/opnfv_testapi/ui/pods/podsController.js deleted file mode 100644 index 489fa8a..0000000 --- a/testapi/opnfv_testapi/ui/pods/podsController.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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('PodsController', PodsController); - - PodsController.$inject = [ - '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' - ]; - - /** - * TestAPI Pods Controller - * This controller is for the '/pods' page where a user can browse - * through pods declared in TestAPI. - */ - function PodsController($scope, $http, $filter, $state, testapiApiUrl, - raiseAlert) { - var ctrl = this; - ctrl.url = testapiApiUrl + '/pods'; - - ctrl.create = create; - ctrl.update = update; - ctrl.open = open; - ctrl.clearFilters = clearFilters; - - ctrl.roles = ['community-ci', 'production-ci']; - ctrl.modes = ['metal', 'virtual']; - ctrl.createRequirements = [ - {label: 'name', type: 'text', required: true}, - {label: 'mode', type: 'select', selects: ctrl.modes}, - {label: 'role', type: 'select', selects: ctrl.roles}, - {label: 'details', type: 'textarea', required: false} - ]; - - ctrl.name = ''; - ctrl.role = 'community-ci'; - ctrl.mode = 'metal'; - ctrl.details = ''; - - /** - * 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.update(); - } - - /** - * This will contact the TestAPI to create a new pod. - */ - function create() { - ctrl.showError = false; - - if(ctrl.name != ""){ - var pods_url = ctrl.url; - var body = { - name: ctrl.name, - mode: ctrl.mode, - role: ctrl.role, - details: ctrl.details - }; - ctrl.podsRequest = - $http.post(pods_url, body).error(function (data, status) { - ctrl.showError = true; - if(status == 403){ - ctrl.error = - 'Error creating the new pod from server: Pod\'s name already exists' - } - }); - } - else{ - ctrl.showError = true; - ctrl.error = 'Name is missing.' - } - } - - /** - * This will contact the TestAPI to get a listing of declared pods. - */ - function update() { - ctrl.showError = false; - ctrl.podsRequest = - $http.get(ctrl.url).success(function (data) { - ctrl.data = data; - }).error(function (error) { - ctrl.data = null; - ctrl.showError = true; - ctrl.error = - 'Error retrieving pods from server: ' + - angular.toJson(error); - }); - } - } -})(); diff --git a/testapi/opnfv_testapi/ui/profile/importPubKeyModal.html b/testapi/opnfv_testapi/ui/profile/importPubKeyModal.html deleted file mode 100644 index 0f55c27..0000000 --- a/testapi/opnfv_testapi/ui/profile/importPubKeyModal.html +++ /dev/null @@ -1,27 +0,0 @@ - - diff --git a/testapi/opnfv_testapi/ui/profile/profile.html b/testapi/opnfv_testapi/ui/profile/profile.html deleted file mode 100644 index 763f5d1..0000000 --- a/testapi/opnfv_testapi/ui/profile/profile.html +++ /dev/null @@ -1,44 +0,0 @@ -

User profile

-
-
- - - - - - - - - -
User {{auth.currentUser.user}}
Fullname {{auth.currentUser.fullname}}
Email {{auth.currentUser.email}}
Groups -
- {{group}}
-
-
-
-
-
-
-
-

User Public Keys

-
-
- -
-
-
- -
- - - - - - - - -
{{pubKey.format}}{{pubKey.shortKey}}{{pubKey.comment}}
-
-
diff --git a/testapi/opnfv_testapi/ui/profile/profileController.js b/testapi/opnfv_testapi/ui/profile/profileController.js deleted file mode 100644 index 5dbdf7b..0000000 --- a/testapi/opnfv_testapi/ui/profile/profileController.js +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * 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') - .factory('PubKeys', PubKeys); - - PubKeys.$inject = ['$resource', 'testapiApiUrl']; - - /** - * This is a provider for the user's uploaded public keys. - */ - function PubKeys($resource, testapiApiUrl) { - return $resource(testapiApiUrl + '/user/pubkeys/:id', null, null); - } - - angular - .module('testapiApp') - .controller('ProfileController', ProfileController); - - ProfileController.$inject = [ - '$scope', '$http', 'testapiApiUrl', 'PubKeys', - '$uibModal', 'raiseAlert', '$state' - ]; - - /** - * TestAPI Profile Controller - * This controller handles user's profile page, where a user can view - * account-specific information. - */ - function ProfileController($scope, $http, testapiApiUrl, - PubKeys, $uibModal, raiseAlert, $state) { - - var ctrl = this; - - ctrl.updatePubKeys = updatePubKeys; - ctrl.openImportPubKeyModal = openImportPubKeyModal; - ctrl.openShowPubKeyModal = openShowPubKeyModal; - - // Must be authenticated to view this page. - if (!$scope.auth.isAuthenticated) { - $state.go('home'); - } - - /** - * This function will fetch all the user's public keys from the - * server and store them in an array. - */ - function updatePubKeys() { - var keys = PubKeys.query(function() { - ctrl.pubkeys = []; - angular.forEach(keys, function (key) { - ctrl.pubkeys.push({ - 'resource': key, - 'format': key.format, - 'shortKey': [ - key.pubkey.slice(0, 10), - '.', - key.pubkey.slice(-10) - ].join('.'), - 'pubkey': key.pubkey, - 'comment': key.comment - }); - }); - }); - } - - /** - * This function will open the modal that will give the user a form - * for importing a public key. - */ - function openImportPubKeyModal() { - $uibModal.open({ - templateUrl: '/components/profile/importPubKeyModal.html', - backdrop: true, - windowClass: 'modal', - controller: 'ImportPubKeyModalController as modal' - }).result.finally(function() { - ctrl.updatePubKeys(); - }); - } - - /** - * This function will open the modal that will give the full - * information regarding a specific public key. - * @param {Object} pubKey resource - */ - function openShowPubKeyModal(pubKey) { - $uibModal.open({ - templateUrl: '/components/profile/showPubKeyModal.html', - backdrop: true, - windowClass: 'modal', - controller: 'ShowPubKeyModalController as modal', - resolve: { - pubKey: function() { - return pubKey; - } - } - }).result.finally(function() { - ctrl.updatePubKeys(); - }); - } - - ctrl.authRequest = $scope.auth.doSignCheck().then(ctrl.updatePubKeys); - } - - angular - .module('testapiApp') - .controller('ImportPubKeyModalController', ImportPubKeyModalController); - - ImportPubKeyModalController.$inject = [ - '$uibModalInstance', 'PubKeys', 'raiseAlert' - ]; - - /** - * Import Pub Key Modal Controller - * This controller is for the modal that appears if a user wants to import - * a public key. - */ - function ImportPubKeyModalController($uibModalInstance, - PubKeys, raiseAlert) { - - var ctrl = this; - - ctrl.importPubKey = importPubKey; - ctrl.cancel = cancel; - - /** - * This function will save a new public key resource to the API server. - */ - function importPubKey() { - var newPubKey = new PubKeys( - {raw_key: ctrl.raw_key, self_signature: ctrl.self_signature} - ); - newPubKey.$save( - function(newPubKey_) { - raiseAlert('success', '', 'Public key saved successfully'); - $uibModalInstance.close(newPubKey_); - }, - function(httpResp) { - raiseAlert('danger', - httpResp.statusText, httpResp.data.title); - ctrl.cancel(); - } - ); - } - - /** - * This function will dismiss the modal. - */ - function cancel() { - $uibModalInstance.dismiss('cancel'); - } - } - - angular - .module('testapiApp') - .controller('ShowPubKeyModalController', ShowPubKeyModalController); - - ShowPubKeyModalController.$inject = [ - '$uibModalInstance', 'raiseAlert', 'pubKey' - ]; - - /** - * Show Pub Key Modal Controller - * This controller is for the modal that appears if a user wants to see the - * full details of one of their public keys. - */ - function ShowPubKeyModalController($uibModalInstance, raiseAlert, pubKey) { - var ctrl = this; - - ctrl.deletePubKey = deletePubKey; - ctrl.cancel = cancel; - - ctrl.pubKey = pubKey.resource; - ctrl.rawKey = [pubKey.format, pubKey.pubkey, pubKey.comment].join('\n'); - - /** - * This function will delete a public key resource. - */ - function deletePubKey() { - ctrl.pubKey.$remove( - {id: ctrl.pubKey.id}, - function() { - raiseAlert('success', - '', 'Public key deleted successfully'); - $uibModalInstance.close(ctrl.pubKey.id); - }, - function(httpResp) { - raiseAlert('danger', - httpResp.statusText, httpResp.data.title); - ctrl.cancel(); - } - ); - } - - /** - * This method will dismiss the modal. - */ - function cancel() { - $uibModalInstance.dismiss('cancel'); - } - } -})(); diff --git a/testapi/opnfv_testapi/ui/profile/showPubKeyModal.html b/testapi/opnfv_testapi/ui/profile/showPubKeyModal.html deleted file mode 100644 index 5f63a5e..0000000 --- a/testapi/opnfv_testapi/ui/profile/showPubKeyModal.html +++ /dev/null @@ -1,11 +0,0 @@ - - diff --git a/testapi/opnfv_testapi/ui/projects/project/project.html b/testapi/opnfv_testapi/ui/projects/project/project.html deleted file mode 100644 index 9d46364..0000000 --- a/testapi/opnfv_testapi/ui/projects/project/project.html +++ /dev/null @@ -1,25 +0,0 @@ -
- - - - - - -
Name {{ctrl.data.name}}
Description {{ctrl.data.description}}
Creation date {{ctrl.data.creation_date}}
-
- -
-
- - -
- - \ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/projects/project/projectController.js b/testapi/opnfv_testapi/ui/projects/project/projectController.js deleted file mode 100644 index 8f4bd20..0000000 --- a/testapi/opnfv_testapi/ui/projects/project/projectController.js +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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('ProjectController', ProjectController); - - ProjectController.$inject = [ - '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', - 'confirmModal' - ]; - - /** - * TestAPI Project Controller - * This controller is for the '/projects' page where a user can browse - * through projects declared in TestAPI. - */ - function ProjectController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal) { - var ctrl = this; - ctrl.name = $state.params['name']; - ctrl.url = testapiApiUrl + '/projects/' + ctrl.name; - - ctrl.loadDetails = loadDetails; - ctrl.deleteProject = deleteProject; - ctrl.openDeleteModal = openDeleteModal; - ctrl.openUpdateModal = openUpdateModal; - ctrl.updateProject = updateProject; - - - /** - * This will contact the TestAPI to update an existing project. - */ - function updateProject(name,description) { - ctrl.showError = false; - ctrl.showSuccess = false; - if(ctrl.name != ""){ - var projects_url = ctrl.url; - var body = { - name: name, - description: description - }; - ctrl.projectsRequest = - $http.put(projects_url, body).success(function (data){ - ctrl.showSuccess = true ; - }) - .error(function (data) { - ctrl.showError = true; - ctrl.error = 'Error updating the existing Project from server: ' + angular.toJson(data); - }); - ctrl.name = ""; - ctrl.description=""; - } - else{ - ctrl.showError = true; - ctrl.error = 'Name is missing.' - } - } - - /** - * This will contact the TestAPI to delete an existing project. - */ - function deleteProject() { - ctrl.showError = false; - ctrl.showSuccess = false; - ctrl.projectsRequest = - $http.delete(ctrl.url).success(function (data) { - $state.go('projects', {}, {reload: true}); - ctrl.showSuccess = true ; - - }).error(function (error) { - ctrl.showError = true; - ctrl.error = - 'Error deleting project from server: ' + - angular.toJson(error); - }); - } - - /** - * This will open the modal that will show the delete confirm - * message - */ - function openDeleteModal() { - confirmModal("Delete",ctrl.deleteProject); - } - - /** - * This will open the modal that will show the update - * view - */ - function openUpdateModal(){ - $uibModal.open({ - templateUrl: 'testapi-ui/components/projects/project/updateModal.html', - controller: 'ModalInstanceCtrl as updateModal', - size: 'md', - resolve: { - data: function () { - return { - text: "Update", - successHandler: ctrl.updateProject, - project: ctrl.data - }; - } - } - }); - } - - /** - * This will contact the TestAPI to get a listing of declared projects. - */ - function loadDetails() { - ctrl.showError = false; - ctrl.projectsRequest = - $http.get(ctrl.url).success(function (data) { - ctrl.data = data; - }).error(function (error) { - ctrl.data = null; - ctrl.showError = true; - ctrl.error = - 'Error retrieving projects from server: ' + - angular.toJson(error); - }); - } - ctrl.loadDetails(); - } - - - /** - * TestAPI Modal instance Controller - * This controller is for the update modal where a user can update - * the project information. - */ - angular.module('testapiApp').controller('ModalInstanceCtrl', ModalInstanceCtrl); - ModalInstanceCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; - function ModalInstanceCtrl($scope, $uibModalInstance, data) { - var ctrl = this; - ctrl.confirm = confirm; - ctrl.cancel = cancel; - ctrl.data = angular.copy(data); - - ctrl.createRequirements = [ - {label: 'name', type: 'text', required: true}, - {label: 'description', type: 'textarea', required: false} - ]; - - ctrl.name = ctrl.data.project.name; - ctrl.description = ctrl.data.project.description; - - /** - * Initiate confirmation and call the success handler with the - * inputs. - */ - function confirm() { - $uibModalInstance.close(); - if (angular.isDefined(ctrl.data.successHandler)) { - ctrl.data.successHandler(ctrl.name,ctrl.description); - } - } - - /** - * Close the confirm modal without initiating changes. - */ - function cancel() { - $uibModalInstance.dismiss('cancel'); - } - } - - -})(); diff --git a/testapi/opnfv_testapi/ui/projects/project/updateModal.html b/testapi/opnfv_testapi/ui/projects/project/updateModal.html deleted file mode 100644 index ab8d64e..0000000 --- a/testapi/opnfv_testapi/ui/projects/project/updateModal.html +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/testapi/opnfv_testapi/ui/projects/projects.html b/testapi/opnfv_testapi/ui/projects/projects.html deleted file mode 100644 index 55f8683..0000000 --- a/testapi/opnfv_testapi/ui/projects/projects.html +++ /dev/null @@ -1,52 +0,0 @@ -

Projects

- -
-
-

Create

-
-
-
-

- - - - - - - -

-
-
-
- -
-
- - -
-
-
- - -
- - - - - - - - -
- {{project.name}} -
-
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/projects/projectsController.js b/testapi/opnfv_testapi/ui/projects/projectsController.js deleted file mode 100644 index 16002f6..0000000 --- a/testapi/opnfv_testapi/ui/projects/projectsController.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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('ProjectsController', ProjectsController); - - ProjectsController.$inject = [ - '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' - ]; - - /** - * TestAPI Project Controller - * This controller is for the '/projects' page where a user can browse - * through projects declared in TestAPI. - */ - function ProjectsController($scope, $http, $filter, $state, testapiApiUrl, - raiseAlert) { - var ctrl = this; - ctrl.url = testapiApiUrl + '/projects'; - ctrl.create = create; - ctrl.update = update; - - ctrl.createRequirements = [ - {label: 'name', type: 'text', required: true}, - {label: 'description', type: 'textarea', required: false} - ]; - - ctrl.name = ''; - ctrl.details = ''; - - /** - * This will contact the TestAPI to create a new project. - */ - function create() { - ctrl.showError = false; - ctrl.showSuccess = false; - if(ctrl.name != ""){ - var projects_url = ctrl.url; - var body = { - name: ctrl.name, - description: ctrl.description - }; - ctrl.projectsRequest = - $http.post(projects_url, body).success(function (data){ - ctrl.showSuccess = true ; - ctrl.update(); - }) - .error(function (data) { - ctrl.showError = true; - ctrl.error = 'Error creating the new Project from server:' + angular.toJson(data); - }); - ctrl.name = ""; - ctrl.description=""; - } - else{ - ctrl.showError = true; - ctrl.error = 'Name is missing.' - } - } - - /** - * This will contact the TestAPI to get a listing of declared projects. - */ - function update() { - ctrl.showError = false; - ctrl.projectsRequest = - $http.get(ctrl.url).success(function (data) { - ctrl.data = data; - }).error(function (error) { - ctrl.data = null; - ctrl.showError = true; - ctrl.error = - 'Error retrieving projects from server: ' + - angular.toJson(error); - }); - } - ctrl.update(); - } -})(); diff --git a/testapi/opnfv_testapi/ui/results-report/partials/editTestModal.html b/testapi/opnfv_testapi/ui/results-report/partials/editTestModal.html deleted file mode 100644 index 583c9b9..0000000 --- a/testapi/opnfv_testapi/ui/results-report/partials/editTestModal.html +++ /dev/null @@ -1,65 +0,0 @@ - diff --git a/testapi/opnfv_testapi/ui/results-report/partials/fullTestListModal.html b/testapi/opnfv_testapi/ui/results-report/partials/fullTestListModal.html deleted file mode 100644 index 6db198b..0000000 --- a/testapi/opnfv_testapi/ui/results-report/partials/fullTestListModal.html +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/testapi/opnfv_testapi/ui/results-report/partials/reportDetails.html b/testapi/opnfv_testapi/ui/results-report/partials/reportDetails.html deleted file mode 100644 index 517e569..0000000 --- a/testapi/opnfv_testapi/ui/results-report/partials/reportDetails.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - {{status | capitalize}} - - (Total: {{ctrl.caps[status].caps.length}} capabilities, {{ctrl.caps[status].count}} tests) - - ({{ctrl.testStatus | capitalize}}: {{ctrl.getStatusTestCount(status)}} tests) - - - - - -
    -
  1. - - - {{capability.id}} - - - [{{ctrl.getCapabilityTestCount(capability)}}] - - - [{{capability.passedTests.length}}/{{capability.passedTests.length + - capability.notPassedTests.length}}] - - -
      - -
    • - - - - - {{test}} - — - [Aliases] -
      -
      • {{alias}}
      -
      -
      -
    • - - - -
    • - - - - - {{test}} - — - [Aliases] -
      -
      • {{alias}}
      -
      -
      -
    • - -
    -
  2. -
-
diff --git a/testapi/opnfv_testapi/ui/results-report/resultsReport.html b/testapi/opnfv_testapi/ui/results-report/resultsReport.html deleted file mode 100644 index 5527121..0000000 --- a/testapi/opnfv_testapi/ui/results-report/resultsReport.html +++ /dev/null @@ -1,185 +0,0 @@ -

Test Run Results

- -
-
-
-
- Test ID: {{ctrl.testId}}
-
Cloud ID: {{ctrl.resultsData.cpid}}
- Upload Date: {{ctrl.resultsData.created_at}} UTC
- Duration: {{ctrl.resultsData.duration_seconds}} seconds
- Total Number of Passed Tests: - - {{ctrl.resultsData.results.length}} - -
-
-
- Publicly Shared: - Yes - No -
-
-
- Product: - {{ctrl.resultsData.product_version.product_info.name}} - - ({{ctrl.resultsData.product_version.version}}) -
-
-
- Associated Guideline: - {{ctrl.resultsData.meta.guideline.slice(0, -5)}} -
-
- Associated Target Program: - {{ctrl.targetMappings[ctrl.resultsData.meta.target]}} -
-
- Verified: - YES -
-
-
- -
-
- - -
-
-
-
- -
-
-
-
-
- -
-

See how these results stack up against Interop Working Group capabilities and OpenStack - target marketing programs. -

- - -
-
- Guideline Version: - - -
-
- Target Program: - -
-
- - -
-
- Guideline Status: - {{ctrl.guidelineData.status | capitalize}} -
- - Corresponding OpenStack Releases: -
    -
  • - {{release | capitalize}} -
  • -
-
- -
- Status: -

This cloud passes {{ctrl.requiredPassPercent | number:1}}% - ({{ctrl.caps.required.passedCount}}/{{ctrl.caps.required.count}}) - of the tests in the {{ctrl.version.slice(0, -5)}} required capabilities for the - {{ctrl.targetMappings[target]}} program.
- Excluding flagged tests, this cloud passes - {{ctrl.nonFlagRequiredPassPercent | number:1}}% - ({{ctrl.nonFlagPassCount}}/{{ctrl.totalNonFlagCount}}) - of the required tests. -

- -

Compliance with {{ctrl.version.slice(0, -5)}}: - - YES - NO - -

- -
-

Capability Overview

- - Test Filters:
-
- - - - -
- - - - - -
- - -
- - -
- - -
-
-
- -
-
-
-
-
- - diff --git a/testapi/opnfv_testapi/ui/results-report/resultsReportController.js b/testapi/opnfv_testapi/ui/results-report/resultsReportController.js deleted file mode 100644 index 591ad40..0000000 --- a/testapi/opnfv_testapi/ui/results-report/resultsReportController.js +++ /dev/null @@ -1,869 +0,0 @@ -/* - * 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 = [ - '$http', '$stateParams', '$window', - '$uibModal', 'testapiApiUrl', 'raiseAlert' - ]; - - /** - * TestAPI Results Report Controller - * This controller is for the '/results/' page where a user can - * view details for a specific test run. - */ - function ResultsReportController($http, $stateParams, $window, - $uibModal, testapiApiUrl, raiseAlert) { - - var ctrl = this; - - ctrl.getVersionList = getVersionList; - ctrl.getResults = getResults; - ctrl.isResultAdmin = isResultAdmin; - ctrl.isShared = isShared; - ctrl.shareTestRun = shareTestRun; - ctrl.deleteTestRun = deleteTestRun; - ctrl.updateVerificationStatus = updateVerificationStatus; - ctrl.updateGuidelines = updateGuidelines; - ctrl.getTargetCapabilities = getTargetCapabilities; - ctrl.buildCapabilityV1_2 = buildCapabilityV1_2; - ctrl.buildCapabilityV1_3 = buildCapabilityV1_3; - ctrl.buildCapabilitiesObject = buildCapabilitiesObject; - ctrl.isTestFlagged = isTestFlagged; - ctrl.getFlaggedReason = getFlaggedReason; - ctrl.isCapabilityShown = isCapabilityShown; - ctrl.isTestShown = isTestShown; - ctrl.getCapabilityTestCount = getCapabilityTestCount; - ctrl.getStatusTestCount = getStatusTestCount; - ctrl.openFullTestListModal = openFullTestListModal; - ctrl.openEditTestModal = openEditTestModal; - - /** The testID extracted from the URL route. */ - ctrl.testId = $stateParams.testID; - - /** The target OpenStack marketing program to compare against. */ - ctrl.target = 'platform'; - - /** Mappings of Interop WG components to marketing program names. */ - ctrl.targetMappings = { - 'platform': 'Openstack Powered Platform', - 'compute': 'OpenStack Powered Compute', - 'object': 'OpenStack Powered Object Storage' - }; - - /** The schema version of the currently selected guideline data. */ - ctrl.schemaVersion = null; - - /** The selected test status used for test filtering. */ - ctrl.testStatus = 'total'; - - /** The HTML template that all accordian groups will use. */ - ctrl.detailsTemplate = 'components/results-report/partials/' + - 'reportDetails.html'; - - /** - * Retrieve an array of available guideline files from the TestAPI - * API server, sort this array reverse-alphabetically, and store it in - * a scoped variable. The scope's selected version is initialized to - * the latest (i.e. first) version here as well. After a successful API - * call, the function to update the capabilities is called. - * Sample API return array: ["2015.03.json", "2015.04.json"] - */ - function getVersionList() { - var content_url = testapiApiUrl + '/guidelines'; - ctrl.versionsRequest = - $http.get(content_url).success(function (data) { - ctrl.versionList = data.sort().reverse(); - if (!ctrl.version) { - // Default to the first approved guideline which is - // expected to be at index 1. - ctrl.version = ctrl.versionList[1]; - } - ctrl.updateGuidelines(); - }).error(function (error) { - ctrl.showError = true; - ctrl.error = 'Error retrieving version list: ' + - angular.toJson(error); - }); - } - - /** - * Retrieve results from the TestAPI API server based on the test - * run id in the URL. This function is the first function that will - * be called from the controller. Upon successful retrieval of results, - * the function that gets the version list will be called. - */ - function getResults() { - var content_url = testapiApiUrl + '/results/' + ctrl.testId; - ctrl.resultsRequest = - $http.get(content_url).success(function (data) { - ctrl.resultsData = data; - ctrl.version = ctrl.resultsData.meta.guideline; - ctrl.isVerified = ctrl.resultsData.verification_status; - if (ctrl.resultsData.meta.target) { - ctrl.target = ctrl.resultsData.meta.target; - } - getVersionList(); - }).error(function (error) { - ctrl.showError = true; - ctrl.resultsData = null; - ctrl.error = 'Error retrieving results from server: ' + - angular.toJson(error); - }); - } - - /** - * This tells you whether the current user has administrative - * privileges for the test result. - * @returns {Boolean} true if the user has admin privileges. - */ - function isResultAdmin() { - return Boolean(ctrl.resultsData && - (ctrl.resultsData.user_role === 'owner' || - ctrl.resultsData.user_role === 'foundation')); - } - /** - * This tells you whether the current results are shared with the - * community or not. - * @returns {Boolean} true if the results are shared - */ - function isShared() { - return Boolean(ctrl.resultsData && - 'shared' in ctrl.resultsData.meta); - } - - /** - * This will send an API request in order to share or unshare the - * current results based on the passed in shareState. - * @param {Boolean} shareState - Whether to share or unshare results. - */ - function shareTestRun(shareState) { - var content_url = [ - testapiApiUrl, '/results/', ctrl.testId, '/meta/shared' - ].join(''); - if (shareState) { - ctrl.shareRequest = - $http.post(content_url, 'true').success(function () { - ctrl.resultsData.meta.shared = 'true'; - raiseAlert('success', '', 'Test run shared!'); - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } else { - ctrl.shareRequest = - $http.delete(content_url).success(function () { - delete ctrl.resultsData.meta.shared; - raiseAlert('success', '', 'Test run unshared!'); - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - } - - /** - * This will send a request to the API to delete the current - * test results set. - */ - function deleteTestRun() { - var content_url = [ - testapiApiUrl, '/results/', ctrl.testId - ].join(''); - ctrl.deleteRequest = - $http.delete(content_url).success(function () { - $window.history.back(); - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * This will send a request to the API to delete the current - * test results set. - */ - function updateVerificationStatus() { - var content_url = [ - testapiApiUrl, '/results/', ctrl.testId - ].join(''); - var data = {'verification_status': ctrl.isVerified}; - ctrl.updateRequest = - $http.put(content_url, data).success( - function () { - ctrl.resultsData.verification_status = ctrl.isVerified; - raiseAlert('success', '', - 'Verification status changed!'); - }).error(function (error) { - ctrl.isVerified = ctrl.resultsData.verification_status; - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * This will contact the TestAPI API server to retrieve the JSON - * content of the guideline file corresponding to the selected - * version. A function to construct an object from the capability - * data will be called upon successful retrieval. - */ - function updateGuidelines() { - ctrl.guidelineData = null; - ctrl.showError = false; - var content_url = testapiApiUrl + '/guidelines/' + - ctrl.version; - ctrl.capsRequest = - $http.get(content_url).success(function (data) { - ctrl.guidelineData = data; - ctrl.schemaVersion = data.schema; - ctrl.buildCapabilitiesObject(); - }).error(function (error) { - ctrl.showError = true; - ctrl.guidelineData = null; - ctrl.error = 'Error retrieving guideline date: ' + - angular.toJson(error); - }); - } - - /** - * This will get all the capabilities relevant to the target and - * their corresponding statuses. - * @returns {Object} Object containing each capability and their status - */ - function getTargetCapabilities() { - var components = ctrl.guidelineData.components; - var targetCaps = {}; - - // The 'platform' target is comprised of multiple components, so - // we need to get the capabilities belonging to each of its - // components. - if (ctrl.target === 'platform') { - var platform_components = - ctrl.guidelineData.platform.required; - - // This will contain status priority values, where lower - // values mean higher priorities. - var statusMap = { - required: 1, - advisory: 2, - deprecated: 3, - removed: 4 - }; - - // For each component required for the platform program. - angular.forEach(platform_components, function (component) { - // Get each capability list belonging to each status. - angular.forEach(components[component], - function (caps, status) { - // For each capability. - angular.forEach(caps, function(cap) { - // If the capability has already been added. - if (cap in targetCaps) { - // If the status priority value is less - // than the saved priority value, update - // the value. - if (statusMap[status] < - statusMap[targetCaps[cap]]) { - targetCaps[cap] = status; - } - } - else { - targetCaps[cap] = status; - } - }); - }); - }); - } - else { - angular.forEach(components[ctrl.target], - function (caps, status) { - angular.forEach(caps, function(cap) { - targetCaps[cap] = status; - }); - }); - } - return targetCaps; - } - - /** - * This will build the a capability object for schema version 1.2. - * This object will contain the information needed to form a report in - * the HTML template. - * @param {String} capId capability ID - */ - function buildCapabilityV1_2(capId) { - var cap = { - 'id': capId, - 'passedTests': [], - 'notPassedTests': [], - 'passedFlagged': [], - 'notPassedFlagged': [] - }; - var capDetails = ctrl.guidelineData.capabilities[capId]; - // Loop through each test belonging to the capability. - angular.forEach(capDetails.tests, - function (testId) { - // If the test ID is in the results' test list, add - // it to the passedTests array. - if (ctrl.resultsData.results.indexOf(testId) > -1) { - cap.passedTests.push(testId); - if (capDetails.flagged.indexOf(testId) > -1) { - cap.passedFlagged.push(testId); - } - } - else { - cap.notPassedTests.push(testId); - if (capDetails.flagged.indexOf(testId) > -1) { - cap.notPassedFlagged.push(testId); - } - } - }); - return cap; - } - - /** - * This will build the a capability object for schema version 1.3 and - * above. This object will contain the information needed to form a - * report in the HTML template. - * @param {String} capId capability ID - */ - function buildCapabilityV1_3(capId) { - var cap = { - 'id': capId, - 'passedTests': [], - 'notPassedTests': [], - 'passedFlagged': [], - 'notPassedFlagged': [] - }; - - // For cases where a capability listed in components is not - // in the capabilities object. - if (!(capId in ctrl.guidelineData.capabilities)) { - return cap; - } - - // Loop through each test belonging to the capability. - angular.forEach(ctrl.guidelineData.capabilities[capId].tests, - function (details, testId) { - var passed = false; - - // If the test ID is in the results' test list. - if (ctrl.resultsData.results.indexOf(testId) > -1) { - passed = true; - } - else if ('aliases' in details) { - var len = details.aliases.length; - for (var i = 0; i < len; i++) { - var alias = details.aliases[i]; - if (ctrl.resultsData.results.indexOf(alias) > -1) { - passed = true; - break; - } - } - } - - // Add to correct array based on whether the test was - // passed or not. - if (passed) { - cap.passedTests.push(testId); - if ('flagged' in details) { - cap.passedFlagged.push(testId); - } - } - else { - cap.notPassedTests.push(testId); - if ('flagged' in details) { - cap.notPassedFlagged.push(testId); - } - } - }); - return cap; - } - - /** - * This will check the schema version of the current capabilities file, - * and will call the correct method to build an object based on the - * capability data retrieved from the TestAPI API server. - */ - function buildCapabilitiesObject() { - // This is the object template where 'count' is the number of - // total tests that fall under the given status, and 'passedCount' - // is the number of tests passed. The 'caps' array will contain - // objects with details regarding each capability. - ctrl.caps = { - 'required': {'caps': [], 'count': 0, 'passedCount': 0, - 'flagFailCount': 0, 'flagPassCount': 0}, - 'advisory': {'caps': [], 'count': 0, 'passedCount': 0, - 'flagFailCount': 0, 'flagPassCount': 0}, - 'deprecated': {'caps': [], 'count': 0, 'passedCount': 0, - 'flagFailCount': 0, 'flagPassCount': 0}, - 'removed': {'caps': [], 'count': 0, 'passedCount': 0, - 'flagFailCount': 0, 'flagPassCount': 0} - }; - - switch (ctrl.schemaVersion) { - case '1.2': - var capMethod = 'buildCapabilityV1_2'; - break; - case '1.3': - case '1.4': - case '1.5': - case '1.6': - capMethod = 'buildCapabilityV1_3'; - break; - default: - ctrl.showError = true; - ctrl.guidelineData = null; - ctrl.error = 'The schema version for the guideline ' + - 'file selected (' + ctrl.schemaVersion + - ') is currently not supported.'; - return; - } - - // Get test details for each relevant capability and store - // them in the scope's 'caps' object. - var targetCaps = ctrl.getTargetCapabilities(); - angular.forEach(targetCaps, function(status, capId) { - var cap = ctrl[capMethod](capId); - ctrl.caps[status].count += - cap.passedTests.length + cap.notPassedTests.length; - ctrl.caps[status].passedCount += cap.passedTests.length; - ctrl.caps[status].flagPassCount += cap.passedFlagged.length; - ctrl.caps[status].flagFailCount += - cap.notPassedFlagged.length; - ctrl.caps[status].caps.push(cap); - }); - - ctrl.requiredPassPercent = (ctrl.caps.required.passedCount * - 100 / ctrl.caps.required.count); - - ctrl.totalRequiredFailCount = ctrl.caps.required.count - - ctrl.caps.required.passedCount; - ctrl.totalRequiredFlagCount = - ctrl.caps.required.flagFailCount + - ctrl.caps.required.flagPassCount; - ctrl.totalNonFlagCount = ctrl.caps.required.count - - ctrl.totalRequiredFlagCount; - ctrl.nonFlagPassCount = ctrl.totalNonFlagCount - - (ctrl.totalRequiredFailCount - - ctrl.caps.required.flagFailCount); - - ctrl.nonFlagRequiredPassPercent = (ctrl.nonFlagPassCount * - 100 / ctrl.totalNonFlagCount); - } - - /** - * This will check if a given test is flagged. - * @param {String} test ID of the test to check - * @param {Object} capObj capability that test is under - * @returns {Boolean} truthy value if test is flagged - */ - function isTestFlagged(test, capObj) { - if (!capObj) { - return false; - } - return (((ctrl.schemaVersion === '1.2') && - (capObj.flagged.indexOf(test) > -1)) || - ((ctrl.schemaVersion >= '1.3') && - (capObj.tests[test].flagged))); - } - - /** - * This will return the reason a test is flagged. An empty string - * will be returned if the passed in test is not flagged. - * @param {String} test ID of the test to check - * @param {String} capObj capability that test is under - * @returns {String} reason - */ - function getFlaggedReason(test, capObj) { - if ((ctrl.schemaVersion === '1.2') && - (ctrl.isTestFlagged(test, capObj))) { - - // Return a generic message since schema 1.2 does not - // provide flag reasons. - return 'Interop Working Group has flagged this test.'; - } - else if ((ctrl.schemaVersion >= '1.3') && - (ctrl.isTestFlagged(test, capObj))) { - - return capObj.tests[test].flagged.reason; - } - else { - return ''; - } - } - - /** - * This will check the if a capability should be shown based on the - * test filter selected. If a capability does not have any tests - * belonging under the given filter, it should not be shown. - * @param {Object} capability Built object for capability - * @returns {Boolean} true if capability should be shown - */ - function isCapabilityShown(capability) { - return ((ctrl.testStatus === 'total') || - (ctrl.testStatus === 'passed' && - capability.passedTests.length > 0) || - (ctrl.testStatus === 'not passed' && - capability.notPassedTests.length > 0) || - (ctrl.testStatus === 'flagged' && - (capability.passedFlagged.length + - capability.notPassedFlagged.length > 0))); - } - - /** - * This will check the if a test should be shown based on the test - * filter selected. - * @param {String} test ID of the test - * @param {Object} capability Built object for capability - * @return {Boolean} true if test should be shown - */ - function isTestShown(test, capability) { - return ((ctrl.testStatus === 'total') || - (ctrl.testStatus === 'passed' && - capability.passedTests.indexOf(test) > -1) || - (ctrl.testStatus === 'not passed' && - capability.notPassedTests.indexOf(test) > -1) || - (ctrl.testStatus === 'flagged' && - (capability.passedFlagged.indexOf(test) > -1 || - capability.notPassedFlagged.indexOf(test) > -1))); - } - - /** - * This will give the number of tests belonging under the selected - * test filter for a given capability. - * @param {Object} capability Built object for capability - * @returns {Number} number of tests under filter - */ - function getCapabilityTestCount(capability) { - if (ctrl.testStatus === 'total') { - return capability.passedTests.length + - capability.notPassedTests.length; - } - else if (ctrl.testStatus === 'passed') { - return capability.passedTests.length; - } - else if (ctrl.testStatus === 'not passed') { - return capability.notPassedTests.length; - } - else if (ctrl.testStatus === 'flagged') { - return capability.passedFlagged.length + - capability.notPassedFlagged.length; - } - else { - return 0; - } - } - - /** - * This will give the number of tests belonging under the selected - * test filter for a given status. - * @param {String} capability status - * @returns {Number} number of tests for status under filter - */ - function getStatusTestCount(status) { - if (!ctrl.caps) { - return -1; - } - else if (ctrl.testStatus === 'total') { - return ctrl.caps[status].count; - } - else if (ctrl.testStatus === 'passed') { - return ctrl.caps[status].passedCount; - } - else if (ctrl.testStatus === 'not passed') { - return ctrl.caps[status].count - - ctrl.caps[status].passedCount; - } - else if (ctrl.testStatus === 'flagged') { - return ctrl.caps[status].flagFailCount + - ctrl.caps[status].flagPassCount; - } - else { - return -1; - } - } - - /** - * This will open the modal that will show the full list of passed - * tests for the current results. - */ - function openFullTestListModal() { - $uibModal.open({ - templateUrl: '/components/results-report/partials' + - '/fullTestListModal.html', - backdrop: true, - windowClass: 'modal', - animation: true, - controller: 'FullTestListModalController as modal', - size: 'lg', - resolve: { - tests: function () { - return ctrl.resultsData.results; - } - } - }); - } - - /** - * This will open the modal that will all a user to edit test run - * metadata. - */ - function openEditTestModal() { - $uibModal.open({ - templateUrl: '/components/results-report/partials' + - '/editTestModal.html', - backdrop: true, - windowClass: 'modal', - animation: true, - controller: 'EditTestModalController as modal', - size: 'lg', - resolve: { - resultsData: function () { - return ctrl.resultsData; - } - } - }); - } - - getResults(); - } - - angular - .module('testapiApp') - .controller('FullTestListModalController', FullTestListModalController); - - FullTestListModalController.$inject = ['$uibModalInstance', 'tests']; - - /** - * Full Test List Modal Controller - * This controller is for the modal that appears if a user wants to see the - * full list of passed tests on a report page. - */ - function FullTestListModalController($uibModalInstance, tests) { - var ctrl = this; - - ctrl.tests = tests; - - /** - * This function will close/dismiss the modal. - */ - ctrl.close = function () { - $uibModalInstance.dismiss('exit'); - }; - - /** - * This function will return a string representing the sorted - * tests list separated by newlines. - */ - ctrl.getTestListString = function () { - return ctrl.tests.sort().join('\n'); - }; - } - - angular - .module('testapiApp') - .controller('EditTestModalController', EditTestModalController); - - EditTestModalController.$inject = [ - '$uibModalInstance', '$http', '$state', 'raiseAlert', - 'testapiApiUrl', 'resultsData' - ]; - - /** - * Edit Test Modal Controller - * This controller is for the modal that appears if a user wants to edit - * test run metadata. - */ - function EditTestModalController($uibModalInstance, $http, $state, - raiseAlert, testapiApiUrl, resultsData) { - - var ctrl = this; - - ctrl.getVersionList = getVersionList; - ctrl.getUserProducts = getUserProducts; - ctrl.associateProductVersion = associateProductVersion; - ctrl.getProductVersions = getProductVersions; - ctrl.saveChanges = saveChanges; - - ctrl.resultsData = resultsData; - ctrl.metaCopy = angular.copy(resultsData.meta); - ctrl.prodVersionCopy = angular.copy(resultsData.product_version); - - ctrl.getVersionList(); - ctrl.getUserProducts(); - - /** - * Retrieve an array of available capability files from the TestAPI - * API server, sort this array reverse-alphabetically, and store it in - * a scoped variable. - * Sample API return array: ["2015.03.json", "2015.04.json"] - */ - function getVersionList() { - if (ctrl.versionList) { - return; - } - var content_url = testapiApiUrl + '/guidelines'; - ctrl.versionsRequest = - $http.get(content_url).success(function (data) { - ctrl.versionList = data.sort().reverse(); - }).error(function (error) { - raiseAlert('danger', error.title, - 'Unable to retrieve version list'); - }); - } - - /** - * Get products user has management rights to or all products depending - * on the passed in parameter value. - */ - function getUserProducts() { - var contentUrl = testapiApiUrl + '/products'; - ctrl.productsRequest = - $http.get(contentUrl).success(function (data) { - ctrl.products = {}; - angular.forEach(data.products, function(prod) { - if (prod.can_manage) { - ctrl.products[prod.id] = prod; - } - }); - if (ctrl.prodVersionCopy) { - ctrl.selectedProduct = ctrl.products[ - ctrl.prodVersionCopy.product_info.id - ]; - } - ctrl.getProductVersions(); - }).error(function (error) { - ctrl.products = null; - ctrl.showError = true; - ctrl.error = - 'Error retrieving Products listing from server: ' + - angular.toJson(error); - }); - } - - /** - * Send a PUT request to the API server to associate a product with - * a test result. - */ - function associateProductVersion() { - var verId = (ctrl.selectedVersion ? - ctrl.selectedVersion.id : null); - var testId = resultsData.id; - var url = testapiApiUrl + '/results/' + testId; - ctrl.associateRequest = $http.put(url, {'product_version_id': - verId}) - .error(function (error) { - ctrl.showError = true; - ctrl.showSuccess = false; - ctrl.error = - 'Error associating product version with test run: ' + - angular.toJson(error); - }); - } - - /** - * Get all versions for a product. - */ - function getProductVersions() { - if (!ctrl.selectedProduct) { - ctrl.productVersions = []; - ctrl.selectedVersion = null; - return; - } - - var url = testapiApiUrl + '/products/' + - ctrl.selectedProduct.id + '/versions'; - ctrl.getVersionsRequest = $http.get(url) - .success(function (data) { - ctrl.productVersions = data; - if (ctrl.prodVersionCopy && - ctrl.prodVersionCopy.product_info.id == - ctrl.selectedProduct.id) { - ctrl.selectedVersion = ctrl.prodVersionCopy; - } - else { - angular.forEach(data, function(ver) { - if (!ver.version) { - ctrl.selectedVersion = ver; - } - }); - } - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * Send a PUT request to the server with the changes. - */ - function saveChanges() { - ctrl.showError = false; - ctrl.showSuccess = false; - var metaBaseUrl = [ - testapiApiUrl, '/results/', resultsData.id, '/meta/' - ].join(''); - var metaFields = ['target', 'guideline', 'shared']; - var meta = ctrl.metaCopy; - angular.forEach(metaFields, function(field) { - var oldMetaValue = (field in ctrl.resultsData.meta) ? - ctrl.resultsData.meta[field] : ''; - if (field in meta && oldMetaValue != meta[field]) { - var metaUrl = metaBaseUrl + field; - if (meta[field]) { - ctrl.assocRequest = $http.post(metaUrl, meta[field]) - .success(function(data) { - ctrl.resultsData.meta[field] = meta[field]; - }) - .error(function (error) { - ctrl.showError = true; - ctrl.showSuccess = false; - ctrl.error = - 'Error associating metadata with ' + - 'test run: ' + angular.toJson(error); - }); - } - else { - ctrl.unassocRequest = $http.delete(metaUrl) - .success(function (data) { - delete ctrl.resultsData.meta[field]; - delete meta[field]; - }) - .error(function (error) { - ctrl.showError = true; - ctrl.showSuccess = false; - ctrl.error = - 'Error associating metadata with ' + - 'test run: ' + angular.toJson(error); - }); - } - } - }); - ctrl.associateProductVersion(); - if (!ctrl.showError) { - ctrl.showSuccess = true; - $state.reload(); - } - } - - /** - * This function will close/dismiss the modal. - */ - ctrl.close = function () { - $uibModalInstance.dismiss('exit'); - }; - } -})(); diff --git a/testapi/opnfv_testapi/ui/results/results.html b/testapi/opnfv_testapi/ui/results/results.html deleted file mode 100644 index 2ae5339..0000000 --- a/testapi/opnfv_testapi/ui/results/results.html +++ /dev/null @@ -1,115 +0,0 @@ -

{{ctrl.pageHeader}}

-

{{ctrl.pageParagraph}}

-
-

Upload Results

-
- -
-
- -
-
- -
-
-{{ctrl.uploadState}} -
-
-
-
-

Filters

-
-
- -

- - - - -

-
-
- -

- - - - -

-
-
- - -
-
-
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IDPodProjectTest CaseInstallerVersionScenarioCriteriaStart DateStop Date
{{ result._id }}{{ result.pod_name }}{{ result.project_name }}{{ result.case_name }}{{ result.installer }}{{ result.version }}{{ result.scenario }}{{ result.criteria }}{{ result.start_date }}{{ result.stop_date }}
- -
- - -
-
- - diff --git a/testapi/opnfv_testapi/ui/results/resultsController.js b/testapi/opnfv_testapi/ui/results/resultsController.js deleted file mode 100644 index cc6cc0b..0000000 --- a/testapi/opnfv_testapi/ui/results/resultsController.js +++ /dev/null @@ -1,370 +0,0 @@ -/* - * 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]); - }); - }); - } - }; - }]); - - ResultsController.$inject = [ - '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' - ]; - - /** - * 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) { - var ctrl = this; - - ctrl.uploadFile=uploadFile; - ctrl.update = update; - ctrl.open = open; - ctrl.clearFilters = clearFilters; - ctrl.associateMeta = associateMeta; - ctrl.getVersionList = getVersionList; - ctrl.getUserProducts = getUserProducts; - ctrl.associateProductVersion = associateProductVersion; - ctrl.getProductVersions = getProductVersions; - ctrl.prepVersionEdit = prepVersionEdit; - - /** 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'; - - /** Check to see if this page should display user-specific results. */ - // ctrl.isUserResults = $state.current.name === 'userResults'; - // need auth to browse - ctrl.isUserResults = $state.current.name === 'userResults'; - - // Should only be on user-results-page if authenticated. - if (ctrl.isUserResults && !$scope.auth.isAuthenticated) { - $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.isPublic = false; - - if (ctrl.isUserResults) { - ctrl.authRequest = $scope.auth.doSignCheck() - .then(ctrl.update); - // ctrl.getUserProducts(); - } else { - ctrl.update(); - } - - - function uploadFileToUrl(file, uploadUrl){ - var fd = new FormData(); - fd.append('file', file); - fd.append('public', ctrl.isPublic) - - $http.post(uploadUrl, fd, { - transformRequest: angular.identity, - headers: {'Content-Type': undefined} - }) - - .success(function(data){ - var id = data.href.substr(data.href.lastIndexOf('/')+1); - ctrl.uploadState = "Upload succeed. Result id is " + id; - ctrl.update(); - }) - - .error(function(data, status){ - ctrl.uploadState = "Upload failed. Error code is " + status; - }); - } - - function uploadFile(){ - var file = $scope.resultFile; - console.log('file is ' ); - console.dir(file); - - var uploadUrl = testapiApiUrl + "/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 + '/results' + - '?page=' + ctrl.currentPage; - var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd'); - if (start) { - content_url = - content_url + '&from=' + start + ' 00:00:00'; - } - var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd'); - if (end) { - content_url = content_url + '&to=' + end + ' 23:59:59'; - } - if (ctrl.isUserResults) { - content_url = content_url + '&signed'; - } - 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; - }).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); - } - }); - } - } - - /** - * Retrieve an array of available capability files from the TestAPI - * API server, sort this array reverse-alphabetically, and store it in - * a scoped variable. - * Sample API return array: ["2015.03.json", "2015.04.json"] - */ - function getVersionList() { - if (ctrl.versionList) { - return; - } - var content_url = testapiApiUrl + '/guidelines'; - ctrl.versionsRequest = - $http.get(content_url).success(function (data) { - ctrl.versionList = data.sort().reverse(); - }).error(function (error) { - raiseAlert('danger', error.title, - 'Unable to retrieve version list'); - }); - } - - /** - * Get products user has management rights to or all products depending - * on the passed in parameter value. - */ - function getUserProducts() { - if (ctrl.products) { - return; - } - var contentUrl = testapiApiUrl + '/products'; - ctrl.productsRequest = - $http.get(contentUrl).success(function (data) { - ctrl.products = {}; - angular.forEach(data.products, function(prod) { - if (prod.can_manage) { - ctrl.products[prod.id] = prod; - } - }); - }).error(function (error) { - ctrl.products = null; - ctrl.showError = true; - ctrl.error = - 'Error retrieving Products listing from server: ' + - angular.toJson(error); - }); - } - - /** - * Send a PUT request to the API server to associate a product with - * a test result. - */ - function associateProductVersion(result) { - var verId = (result.selectedVersion ? - result.selectedVersion.id : null); - var testId = result.id; - var url = testapiApiUrl + '/results/' + testId; - ctrl.associateRequest = $http.put(url, {'product_version_id': - verId}) - .success(function (data) { - result.product_version = result.selectedVersion; - if (result.selectedVersion) { - result.product_version.product_info = - result.selectedProduct; - } - result.productEdit = false; - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * Get all versions for a product. - */ - function getProductVersions(result) { - if (!result.selectedProduct) { - result.productVersions = []; - result.selectedVersion = null; - return; - } - - var url = testapiApiUrl + '/products/' + - result.selectedProduct.id + '/versions'; - ctrl.getVersionsRequest = $http.get(url) - .success(function (data) { - result.productVersions = data; - - // If the test result isn't already associated to a - // version, default it to the null version. - if (!result.product_version) { - angular.forEach(data, function(ver) { - if (!ver.version) { - result.selectedVersion = ver; - } - }); - } - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * Instantiate variables needed for editing product/version - * associations. - */ - function prepVersionEdit(result) { - result.productEdit = true; - if (result.product_version) { - result.selectedProduct = - ctrl.products[result.product_version.product_info.id]; - } - result.selectedVersion = result.product_version; - ctrl.getProductVersions(result); - } - - } -})(); diff --git a/testapi/opnfv_testapi/ui/robots.txt b/testapi/opnfv_testapi/ui/robots.txt new file mode 100644 index 0000000..93c4420 --- /dev/null +++ b/testapi/opnfv_testapi/ui/robots.txt @@ -0,0 +1,4 @@ +# robotstxt.org + +User-agent: * + diff --git a/testapi/opnfv_testapi/ui/shared/alerts/alertModal.html b/testapi/opnfv_testapi/ui/shared/alerts/alertModal.html new file mode 100644 index 0000000..59fd500 --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/alerts/alertModal.html @@ -0,0 +1,8 @@ + diff --git a/testapi/opnfv_testapi/ui/shared/alerts/alertModalFactory.js b/testapi/opnfv_testapi/ui/shared/alerts/alertModalFactory.js new file mode 100644 index 0000000..929f543 --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/alerts/alertModalFactory.js @@ -0,0 +1,74 @@ +/* + * 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') + .factory('raiseAlert', raiseAlert); + + raiseAlert.$inject = ['$uibModal']; + + /** + * This allows alert pop-ups to be raised. Just inject it as a dependency + * in the calling controller. + */ + function raiseAlert($uibModal) { + return function(mode, title, text) { + $uibModal.open({ + templateUrl: 'testapi-ui/shared/alerts/alertModal.html', + controller: 'RaiseAlertModalController as alert', + backdrop: true, + keyboard: true, + backdropClick: true, + size: 'md', + resolve: { + data: function () { + return { + mode: mode, + title: title, + text: text + }; + } + } + }); + }; + } + + angular + .module('testapiApp') + .controller('RaiseAlertModalController', RaiseAlertModalController); + + RaiseAlertModalController.$inject = ['$uibModalInstance', 'data']; + + /** + * This is the controller for the alert pop-up. + */ + function RaiseAlertModalController($uibModalInstance, data) { + var ctrl = this; + + ctrl.close = close; + ctrl.data = data; + + /** + * This method will close the alert modal. The modal will close + * when the user clicks the close button or clicks outside of the + * modal. + */ + function close() { + $uibModalInstance.close(); + } + } +})(); diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html b/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html new file mode 100644 index 0000000..e5397e0 --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html @@ -0,0 +1,23 @@ + + + diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js new file mode 100644 index 0000000..aba205e --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js @@ -0,0 +1,67 @@ +(function () { + 'use strict'; + + angular + .module('testapiApp') + .factory('confirmModal', confirmModal); + + confirmModal.$inject = ['$uibModal']; + + /** + * Opens confirm modal dialog with input textbox + */ + function confirmModal($uibModal) { + return function(text, successHandler) { + $uibModal.open({ + templateUrl: '/testapi-ui/shared/alerts/confirmModal.html', + controller: 'CustomConfirmModalController as confirmModal', + size: 'md', + resolve: { + data: function () { + return { + text: text, + successHandler: successHandler + }; + } + } + }); + }; + } + + angular + .module('testapiApp') + .controller('CustomConfirmModalController', + CustomConfirmModalController); + + CustomConfirmModalController.$inject = ['$uibModalInstance', 'data']; + + /** + * This is the controller for the alert pop-up. + */ + function CustomConfirmModalController($uibModalInstance, data) { + var ctrl = this; + + ctrl.confirm = confirm; + ctrl.cancel = cancel; + + ctrl.data = angular.copy(data); + + /** + * Initiate confirmation and call the success handler with the + * input text. + */ + function confirm() { + $uibModalInstance.close(); + if (angular.isDefined(ctrl.data.successHandler)) { + ctrl.data.successHandler(ctrl.inputText); + } + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } +})(); diff --git a/testapi/opnfv_testapi/ui/shared/filters.js b/testapi/opnfv_testapi/ui/shared/filters.js new file mode 100644 index 0000000..4a4b7bd --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/filters.js @@ -0,0 +1,55 @@ +/* + * 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'; + + /** + * Convert an object of objects to an array of objects to use with ng-repeat + * filters. + */ + angular + .module('testapiApp') + .filter('arrayConverter', arrayConverter); + + /** + * Convert an object of objects to an array of objects to use with ng-repeat + * filters. + */ + function arrayConverter() { + return function (objects) { + var array = []; + angular.forEach(objects, function (object, key) { + if (!('id' in object)) { + object.id = key; + } + array.push(object); + }); + return array; + }; + } + + angular + .module('testapiApp') + .filter('capitalize', capitalize); + + /** + * Angular filter that will capitalize the first letter of a string. + */ + function capitalize() { + return function (string) { + return string.substring(0, 1).toUpperCase() + string.substring(1); + }; + } +})(); diff --git a/testapi/opnfv_testapi/ui/shared/header/header.html b/testapi/opnfv_testapi/ui/shared/header/header.html new file mode 100644 index 0000000..4b3f8dd --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/header/header.html @@ -0,0 +1,55 @@ +
TestAPI +TestAPI +
+ + diff --git a/testapi/opnfv_testapi/ui/shared/header/headerController.js b/testapi/opnfv_testapi/ui/shared/header/headerController.js new file mode 100644 index 0000000..0a14a41 --- /dev/null +++ b/testapi/opnfv_testapi/ui/shared/header/headerController.js @@ -0,0 +1,63 @@ +/* + * 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('HeaderController', HeaderController); + + HeaderController.$inject = ['$location']; + + /** + * TestAPI Header Controller + * This controller is for the header template which contains the site + * navigation. + */ + function HeaderController($location) { + var ctrl = this; + + ctrl.isActive = isActive; + ctrl.isCatalogActive = isCatalogActive; + + /** Whether the Navbar is collapsed for small displays. */ + ctrl.navbarCollapsed = true; + + /** + * This determines whether a button should be in the active state based + * on the URL. + */ + function isActive(viewLocation) { + var path = $location.path().substr(0, viewLocation.length); + if (path === viewLocation) { + // Make sure "/" only matches when viewLocation is "/". + if (!($location.path().substr(0).length > 1 && + viewLocation.length === 1 )) { + return true; + } + } + return false; + } + + /** This determines the active state for the catalog dropdown. Type + * parameter should be passed in to specify if the catalog is the + * public or user one. + */ + function isCatalogActive(type) { + return ctrl.isActive('/' + type + '_vendors') + || ctrl.isActive('/' + type + '_products'); + } + } +})(); diff --git a/testapi/setup.cfg b/testapi/setup.cfg index b3394d4..e83da5e 100644 --- a/testapi/setup.cfg +++ b/testapi/setup.cfg @@ -26,7 +26,7 @@ packages = data_files = /etc/opnfv_testapi = etc/config.ini /usr/local/share/opnfv_testapi = 3rd_party/static/* - /usr/local/share/opnfv_testapi/testapi-ui/components = opnfv_testapi/ui/* + /usr/local/share/opnfv_testapi/testapi-ui = opnfv_testapi/ui/* [entry_points] console_scripts = -- cgit 1.2.3-korg