From d23adad7f655f7c5ba9ed634d44c126c829e5498 Mon Sep 17 00:00:00 2001 From: Paul Van Eck <pvaneck@us.ibm.com> Date: Wed, 30 Sep 2015 12:31:32 -0700 Subject: [PATCH] Update eslint and update angular style to match With an updated eslint version and the addition of eslint-config-openstack and eslint-plugin-angular, there are several more stylistic guidelines to follow. However, this is what other OpenStack angular projects follow such as Horizon. Some notable changes are: * Wrapped javascript content in anonymous functions. This is a safeguard to keep the code from conflicting with other variables with the same name in other scripts on the same page. * Explicitly inject dependencies and have controllers, factories, etc as explicitly declared functions. * Use angular "controller as" syntax instead of assigning variables to $scope. * Added eslint rule that requires JSDoc for every function declaration. Note these are mainly stylistic changes and all the functionality of RefStack should remain the same. Change-Id: I044b1f473d589681a2ae9d2704700dd85687cbb6 --- .eslintrc | 17 +- package.json | 10 +- refstack-ui/app/app.js | 154 ++- .../auth-failure/authFailureController.js | 42 +- .../components/capabilities/capabilities.html | 26 +- .../capabilities/capabilitiesController.js | 333 +++--- .../partials/capabilityDetailsV1.2.html | 22 +- .../partials/capabilityDetailsV1.3.html | 22 +- .../components/profile/importPubKeyModal.html | 14 +- .../app/components/profile/profile.html | 14 +- .../components/profile/profileController.js | 318 +++-- .../components/profile/showPubKeyModal.html | 10 +- .../partials/fullTestListModal.html | 6 +- .../partials/reportDetails.html | 42 +- .../results-report/resultsReport.html | 76 +- .../results-report/resultsReportController.js | 1050 +++++++++-------- .../app/components/results/results.html | 50 +- .../components/results/resultsController.js | 231 ++-- refstack-ui/app/shared/alerts/alertModal.html | 8 +- .../app/shared/alerts/alertModalFactory.js | 69 +- refstack-ui/app/shared/filters.js | 74 +- refstack-ui/app/shared/header/header.html | 14 +- .../app/shared/header/headerController.js | 49 +- refstack-ui/tests/unit/ControllerSpec.js | 352 +++--- 24 files changed, 1666 insertions(+), 1337 deletions(-) diff --git a/.eslintrc b/.eslintrc index fea13b0f..6c08851d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -32,6 +32,8 @@ "shelljs": false }, + "extends": "openstack", + "globals": { "require": false, "exports": false, @@ -43,16 +45,25 @@ "browser": false }, + "plugins": [ + "angular" + ], + "rules": { "quotes": [2, "single"], "eol-last": 2, "no-trailing-spaces": 2, "camelcase": 0, "no-extra-boolean-cast": 0, + "operator-linebreak": 0, + "require-jsdoc": 2, // Stylistic - "indent": [2, 4], + "indent": [2, 4, {SwitchCase: 1}], "max-len": [2, 80], - "no-undefined": 2 + "no-undefined": 2, + + // Angular Plugin + "angular/controller-as-vm": [1, "ctrl"] } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 1794822a..d2e9bb28 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,13 @@ "version": "0.0.1", "private": true, "name": "refstack-ui", - "description": "A user interface for Refstack", + "description": "A user interface for RefStack", "license": "Apache2", "devDependencies": { "bower": "1.3.12", - "eslint": "^0.21.2", + "eslint": "1.5.1", + "eslint-config-openstack": "1.2.1", + "eslint-plugin-angular": "0.12.0", "http-server": "^0.6.1", "karma": "^0.12.23", "karma-chrome-launcher": "^0.1.5", @@ -15,9 +17,7 @@ "karma-jasmine": "^0.2.2", "karma-phantomjs-launcher": "0.2.0", "phantomjs": "1.9.17", - "protractor": "~1.0.0", - "shelljs": "^0.2.6", - "tmp": "0.0.23" + "protractor": "~1.0.0" }, "scripts": { "postinstall": "bower install --config.interactive=false", diff --git a/refstack-ui/app/app.js b/refstack-ui/app/app.js index 7824143d..471f4517 100644 --- a/refstack-ui/app/app.js +++ b/refstack-ui/app/app.js @@ -1,16 +1,38 @@ -/** Main app module where application dependencies are listed. */ -var refstackApp = angular.module('refstackApp', [ - 'ui.router', 'ui.bootstrap', 'cgBusy', 'ngResource', 'angular-confirm']); - -/** - * Handle application routing. Specific templates and controllers will be - * used based on the URL route. +/* + * 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. */ -refstackApp.config([ - '$stateProvider', '$urlRouterProvider', - function ($stateProvider, $urlRouterProvider) { - 'use strict'; +(function () { + 'use strict'; + + /** Main app module where application dependencies are listed. */ + angular + .module('refstackApp', [ + 'ui.router','ui.bootstrap', 'cgBusy', + 'ngResource', 'angular-confirm' + ]); + + angular + .module('refstackApp') + .config(configureRoutes); + + 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', { @@ -24,70 +46,80 @@ refstackApp.config([ state('capabilities', { url: '/capabilities', templateUrl: '/components/capabilities/capabilities.html', - controller: 'capabilitiesController' + controller: 'CapabilitiesController as ctrl' }). state('communityResults', { url: '/community_results', templateUrl: '/components/results/results.html', - controller: 'resultsController' + controller: 'ResultsController as ctrl' }). state('userResults', { url: '/user_results', templateUrl: '/components/results/results.html', - controller: 'resultsController' + controller: 'ResultsController as ctrl' }). state('resultsDetail', { url: '/results/:testID', - templateUrl: '/components/results-report/resultsReport.html', - controller: 'resultsReportController' + templateUrl: '/components/results-report' + + '/resultsReport.html', + controller: 'ResultsReportController as ctrl' }). state('profile', { url: '/profile', templateUrl: '/components/profile/profile.html', - controller: 'profileController' + controller: 'ProfileController as ctrl' }). state('authFailure', { url: '/auth_failure/:message', templateUrl: '/components/home/home.html', - controller: 'authFailureController' + controller: 'AuthFailureController as ctrl' }); } -]); -/** - * Injections in $rootscope - */ + angular + .module('refstackApp') + .run(setup); -refstackApp.run(['$http', '$rootScope', '$window', '$state', 'refstackApiUrl', - function($http, $rootScope, $window, $state, refstackApiUrl) { - 'use strict'; + setup.$inject = [ + '$http', '$rootScope', '$window', '$state', 'refstackApiUrl' + ]; + + /** + * Set up the app with injections into $rootscope. This is mainly for auth + * functions. + */ + function setup($http, $rootScope, $window, $state, refstackApiUrl) { /** * This function injects sign in function in all scopes */ $rootScope.auth = {}; + $rootScope.auth.doSignIn = doSignIn; + $rootScope.auth.doSignOut = doSignOut; + $rootScope.auth.doSignCheck = doSignCheck; var sign_in_url = refstackApiUrl + '/auth/signin'; - $rootScope.auth.doSignIn = function () { - $window.location.href = sign_in_url; - }; - - /** - * This function injects sign out function in all scopes - */ var sign_out_url = refstackApiUrl + '/auth/signout'; - $rootScope.auth.doSignOut = function () { + var profile_url = refstackApiUrl + '/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.currentUser = null; $rootScope.isAuthenticated = false; $window.location.href = sign_out_url; - }; + } /** - * This block tries to authenticate user + * This function checks to see if a user is logged in and + * authenticated. */ - var profile_url = refstackApiUrl + '/profile'; - $rootScope.auth.doSignCheck = function () { + function doSignCheck() { return $http.get(profile_url, {withCredentials: true}). success(function (data) { $rootScope.auth.currentUser = data; @@ -97,30 +129,38 @@ refstackApp.run(['$http', '$rootScope', '$window', '$state', 'refstackApiUrl', $rootScope.auth.currentUser = null; $rootScope.auth.isAuthenticated = false; }); - }; + } + $rootScope.auth.doSignCheck(); } -]); -/** - * Load config and start up the angular application. - */ -angular.element(document).ready(function () { - 'use strict'; + angular + .element(document) + .ready(loadConfig); - var $http = angular.injector(['ng']).get('$http'); + /** + * Load config and start up the angular application. + */ + function loadConfig() { - function startApp(config) { - // Add config options as constants. - for (var key in config) { - angular.module('refstackApp').constant(key, config[key]); + 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('refstackApp').constant(key, value); + }); + + angular.bootstrap(document, ['refstackApp']); } - angular.bootstrap(document, ['refstackApp']); - } - $http.get('config.json').success(function (data) { - startApp(data); - }).error(function () { - startApp({}); - }); -}); + $http.get('config.json').success(function (data) { + startApp(data); + }).error(function () { + startApp({}); + }); + } +})(); diff --git a/refstack-ui/app/components/auth-failure/authFailureController.js b/refstack-ui/app/components/auth-failure/authFailureController.js index 597f1578..51ea8f29 100644 --- a/refstack-ui/app/components/auth-failure/authFailureController.js +++ b/refstack-ui/app/components/auth-failure/authFailureController.js @@ -1,17 +1,31 @@ -/** - * Refstack Auth Failure Controller - * This controller handles messages from Refstack API if user auth fails. +/* + * 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. */ -var refstackApp = angular.module('refstackApp'); +(function () { + 'use strict'; -refstackApp.controller('authFailureController', - [ - '$stateParams', '$state', 'raiseAlert', - function($stateParams, $state, raiseAlert) { - 'use strict'; - raiseAlert('danger', 'Authentication Failure:', - $stateParams.message); - $state.go('home'); - } - ]); + angular + .module('refstackApp') + .controller('AuthFailureController', AuthFailureController); + + AuthFailureController.$inject = ['$stateParams', '$state', 'raiseAlert']; + /** + * Refstack Auth Failure Controller + * This controller handles messages from Refstack API if user auth fails. + */ + function AuthFailureController($stateParams, $state, raiseAlert) { + raiseAlert('danger', 'Authentication Failure:', $stateParams.message); + $state.go('home'); + } +})(); diff --git a/refstack-ui/app/components/capabilities/capabilities.html b/refstack-ui/app/components/capabilities/capabilities.html index 26b42d6e..e4cdeb7a 100644 --- a/refstack-ui/app/components/capabilities/capabilities.html +++ b/refstack-ui/app/components/capabilities/capabilities.html @@ -4,15 +4,15 @@ <div class="row"> <div class="col-md-3"> <strong>Version:</strong> - <select ng-model="version" ng-change="update()" class="form-control"> + <select ng-model="ctrl.version" ng-change="ctrl.update()" class="form-control"> <!-- Slicing the version file name here gets rid of the '.json' file extension. --> - <option ng-repeat="versionFile in versionList" value="{{versionFile}}">{{versionFile.slice(0, -5)}}</option> + <option ng-repeat="versionFile in ctrl.versionList" value="{{versionFile}}">{{versionFile.slice(0, -5)}}</option> </select> </div> <div class="col-md-4"> <strong>Target Program:</strong> <span class="program-about"><a target="_blank" href="http://www.openstack.org/brand/interop/">About</a></span> - <select ng-model="target" class="form-control" ng-change="updateTargetCapabilities()"> + <select ng-model="ctrl.target" class="form-control" ng-change="ctrl.updateTargetCapabilities()"> <option value="platform">OpenStack Powered Platform</option> <option value="compute">OpenStack Powered Compute</option> <option value="object">OpenStack Powered Object Storage</option> @@ -21,10 +21,10 @@ </div> <br /> -<div ng-show="capabilities"> +<div ng-show="ctrl.capabilities"> <strong>Corresponding OpenStack Releases:</strong> <ul class="list-inline"> - <li ng-repeat="release in capabilities.releases"> + <li ng-repeat="release in ctrl.capabilities.releases"> {{release | capitalize}} </li> </ul> @@ -33,19 +33,19 @@ <strong>Capability Status:</strong> <div class="checkbox"> <label> - <input type="checkbox" ng-model="status.required"> + <input type="checkbox" ng-model="ctrl.status.required"> <span class="required">Required</span> </label> <label> - <input type="checkbox" ng-model="status.advisory"> + <input type="checkbox" ng-model="ctrl.status.advisory"> <span class="advisory">Advisory</span> </label> <label> - <input type="checkbox" ng-model="status.deprecated"> + <input type="checkbox" ng-model="ctrl.status.deprecated"> <span class="deprecated">Deprecated</span> </label> <label> - <input type="checkbox" ng-model="status.removed"> + <input type="checkbox" ng-model="ctrl.status.removed"> <span class="removed">Removed</span> </label> </div> @@ -54,14 +54,14 @@ <p><small>Tests marked with <span class="glyphicon glyphicon-flag text-warning"></span> are tests flagged by DefCore.</small></p> <!-- Loading animation divs --> -<div cg-busy="{promise:versionsRequest,message:'Loading versions'}"></div> -<div cg-busy="{promise:capsRequest,message:'Loading capabilities'}"></div> +<div cg-busy="{promise:ctrl.versionsRequest,message:'Loading versions'}"></div> +<div cg-busy="{promise:ctrl.capsRequest,message:'Loading capabilities'}"></div> <!-- Get the version-specific template --> -<div ng-include src="detailsTemplate"></div> +<div ng-include src="ctrl.detailsTemplate"></div> <div ng-show="showError" class="alert alert-danger" role="alert"> <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <span class="sr-only">Error:</span> - {{error}} + {{ctrl.error}} </div> diff --git a/refstack-ui/app/components/capabilities/capabilitiesController.js b/refstack-ui/app/components/capabilities/capabilitiesController.js index f955ba78..2068b83e 100644 --- a/refstack-ui/app/components/capabilities/capabilitiesController.js +++ b/refstack-ui/app/components/capabilities/capabilitiesController.js @@ -1,172 +1,191 @@ -var refstackApp = angular.module('refstackApp'); - -/** - * Refstack Capabilities Controller - * This controller is for the '/capabilities' page where a user can browse - * through tests belonging to DefCore-defined capabilities. +/* + * 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. */ -refstackApp.controller('capabilitiesController', - ['$scope', '$http', 'refstackApiUrl', - function ($scope, $http, refstackApiUrl) { - 'use strict'; - /** Whether to hide/collapse the achievements for each capability. */ - $scope.hideAchievements = true; +(function () { + 'use strict'; - /** Whether to hide/collapse the tests for each capability. */ - $scope.hideTests = true; + angular + .module('refstackApp') + .controller('CapabilitiesController', CapabilitiesController); - /** The target OpenStack marketing program to show capabilities for. */ - $scope.target = 'platform'; + CapabilitiesController.$inject = ['$http', 'refstackApiUrl']; - /** The various possible capability statuses. */ - $scope.status = { - required: true, - advisory: false, - deprecated: false, - removed: false - }; + /** + * RefStack Capabilities Controller + * This controller is for the '/capabilities' page where a user can browse + * through tests belonging to DefCore-defined capabilities. + */ + function CapabilitiesController($http, refstackApiUrl) { + var ctrl = this; - /** - * The template to load for displaying capability details. The value - * of this depends on the schema version of the capabilities file. - */ - $scope.detailsTemplate = null; + ctrl.getVersionList = getVersionList; + ctrl.update = update; + ctrl.updateTargetCapabilities = updateTargetCapabilities; + ctrl.filterStatus = filterStatus; + ctrl.getObjectLength = getObjectLength; - /** - * Retrieve an array of available capability files from the Refstack - * 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"] - */ - $scope.getVersionList = function () { - var content_url = refstackApiUrl + '/capabilities'; - $scope.versionsRequest = - $http.get(content_url).success(function (data) { - $scope.versionList = data.sort().reverse(); - $scope.version = $scope.versionList[0]; - $scope.update(); - }).error(function (error) { - $scope.showError = true; - $scope.error = 'Error retrieving version list: ' + - JSON.stringify(error); - }); - }; + /** The target OpenStack marketing program to show capabilities for. */ + ctrl.target = 'platform'; - /** - * This will contact the Refstack API server to retrieve the JSON - * content of the capability file corresponding to the selected - * version. - */ - $scope.update = function () { - var content_url = refstackApiUrl + '/capabilities/' + - $scope.version; - $scope.capsRequest = - $http.get(content_url).success(function (data) { - $scope.capabilities = data; - $scope.detailsTemplate = 'components/capabilities/' + - 'partials/capabilityDetailsV' + - data.schema + '.html'; - $scope.updateTargetCapabilities(); - }).error(function (error) { - $scope.showError = true; - $scope.capabilities = null; - $scope.error = 'Error retrieving capabilities: ' + - JSON.stringify(error); - }); - }; + /** The various possible capability statuses. */ + ctrl.status = { + required: true, + advisory: false, + deprecated: false, + removed: false + }; - /** - * This will update the scope's 'targetCapabilities' object with - * capabilities belonging to the selected OpenStack marketing program - * (programs typically correspond to 'components' in the DefCore - * schema). Each capability will have its status mapped to it. - */ - $scope.updateTargetCapabilities = function () { - $scope.targetCapabilities = {}; - var components = $scope.capabilities.components; - var targetCaps = $scope.targetCapabilities; + /** + * The template to load for displaying capability details. The value + * of this depends on the schema version of the capabilities file. + */ + ctrl.detailsTemplate = null; - // The 'platform' target is comprised of multiple components, so - // we need to get the capabilities belonging to each of its - // components. - if ($scope.target === 'platform') { - var platform_components = - $scope.capabilities.platform.required; + /** + * Retrieve an array of available capability files from the Refstack + * 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 = refstackApiUrl + '/capabilities'; + ctrl.versionsRequest = + $http.get(content_url).success(function (data) { + ctrl.versionList = data.sort().reverse(); + ctrl.version = ctrl.versionList[0]; + ctrl.update(); + }).error(function (error) { + ctrl.showError = true; + ctrl.error = 'Error retrieving version list: ' + + angular.toJson(error); + }); + } - // This will contain status priority values, where lower - // values mean higher priorities. - var statusMap = { - required: 1, - advisory: 2, - deprecated: 3, - removed: 4 - }; + /** + * This will contact the Refstack API server to retrieve the JSON + * content of the capability file corresponding to the selected + * version. + */ + function update() { + var content_url = refstackApiUrl + '/capabilities/' + + ctrl.version; + ctrl.capsRequest = + $http.get(content_url).success(function (data) { + ctrl.capabilities = data; + ctrl.detailsTemplate = 'components/capabilities/' + + 'partials/capabilityDetailsV' + + data.schema + '.html'; + ctrl.updateTargetCapabilities(); + }).error(function (error) { + ctrl.showError = true; + ctrl.capabilities = null; + ctrl.error = 'Error retrieving capabilities: ' + + angular.toJson(error); + }); + } - // 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[$scope.target], - function (caps, status) { - angular.forEach(caps, function(cap) { - targetCaps[cap] = status; - }); - }); - } - }; + /** + * This will update the scope's 'targetCapabilities' object with + * capabilities belonging to the selected OpenStack marketing program + * (programs typically correspond to 'components' in the DefCore + * schema). Each capability will have its status mapped to it. + */ + function updateTargetCapabilities() { + ctrl.targetCapabilities = {}; + var components = ctrl.capabilities.components; + var targetCaps = ctrl.targetCapabilities; - $scope.getVersionList(); + // 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.capabilities.platform.required; - /** - * This filter will check if a capability's status corresponds - * to a status that is checked/selected in the UI. This filter - * is meant to be used with the ng-repeat directive. - * @param {Object} capability - * @returns {Boolean} True if capability's status is selected - */ - $scope.filterStatus = function (capability) { - var caps = $scope.targetCapabilities; - return ($scope.status.required && - caps[capability.id] === 'required') || - ($scope.status.advisory && - caps[capability.id] === 'advisory') || - ($scope.status.deprecated && - caps[capability.id] === 'deprecated') || - ($scope.status.removed && - caps[capability.id] === 'removed'); - }; + // This will contain status priority values, where lower + // values mean higher priorities. + var statusMap = { + required: 1, + advisory: 2, + deprecated: 3, + removed: 4 + }; - /** - * This function will get the length of an Object/dict based on - * the number of keys it has. - * @param {Object} object - * @returns {Number} length of object - */ - $scope.getObjectLength = function (object) { - return Object.keys(object).length; - }; - }]); + // 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; + }); + }); + } + } + + /** + * This filter will check if a capability's status corresponds + * to a status that is checked/selected in the UI. This filter + * is meant to be used with the ng-repeat directive. + * @param {Object} capability + * @returns {Boolean} True if capability's status is selected + */ + function filterStatus(capability) { + var caps = ctrl.targetCapabilities; + return (ctrl.status.required && + caps[capability.id] === 'required') || + (ctrl.status.advisory && + caps[capability.id] === 'advisory') || + (ctrl.status.deprecated && + caps[capability.id] === 'deprecated') || + (ctrl.status.removed && + caps[capability.id] === 'removed'); + } + + /** + * This function will get the length of an Object/dict based on + * the number of keys it has. + * @param {Object} object + * @returns {Number} length of object + */ + function getObjectLength(object) { + return Object.keys(object).length; + } + + ctrl.getVersionList(); + } +})(); diff --git a/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.2.html b/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.2.html index 0e24c804..22f33e41 100644 --- a/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.2.html +++ b/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.2.html @@ -4,20 +4,20 @@ This expects the JSON data of the capability file to be stored in scope variable 'capabilities'. --> -<ol ng-show="capabilities" class="capabilities"> - <li class="capability-list-item" ng-repeat="capability in capabilities.capabilities | arrayConverter | filter:filterStatus"> +<ol ng-show="ctrl.capabilities" class="capabilities"> + <li class="capability-list-item" ng-repeat="capability in ctrl.capabilities.capabilities | arrayConverter | filter:ctrl.filterStatus | orderBy:'id'"> <span class="capability-name">{{capability.id}}</span><br /> <em>{{capability.description}}</em><br /> - Status: <span class="{{targetCapabilities[capability.id]}}">{{targetCapabilities[capability.id]}}</span><br /> - <a ng-click="hideAchievements = !hideAchievements">Achievements ({{capability.achievements.length}})</a><br /> - <ol collapse="hideAchievements" class="list-inline"> + Status: <span class="{{ctrl.targetCapabilities[capability.id]}}">{{ctrl.targetCapabilities[capability.id]}}</span><br /> + <a ng-click="showAchievements = !showAchievements">Achievements ({{capability.achievements.length}})</a><br /> + <ol collapse="!showAchievements" class="list-inline"> <li ng-repeat="achievement in capability.achievements"> {{achievement}} </li> </ol> - <a ng-click="hideTests = !hideTests">Tests ({{capability.tests.length}})</a> - <ul collapse="hideTests"> + <a ng-click="showTests = !showTests">Tests ({{capability.tests.length}})</a> + <ul collapse="!showTests"> <li ng-repeat="test in capability.tests"> <span ng-class="{'glyphicon glyphicon-flag text-warning': capability.flagged.indexOf(test) > -1}"></span> {{test}} @@ -26,12 +26,12 @@ variable 'capabilities'. </li> </ol> -<div ng-show="capabilities" class="criteria"> +<div ng-show="ctrl.capabilities" class="criteria"> <hr> - <h4><a ng-click="hideCriteria = !hideCriteria">Criteria</a></h4> - <div collapse="hideCriteria"> + <h4><a ng-click="showCriteria = !showCriteria">Criteria</a></h4> + <div collapse="showCriteria"> <ul> - <li ng-repeat="(key, criterion) in capabilities.criteria"> + <li ng-repeat="(key, criterion) in ctrl.capabilities.criteria"> <span class="criterion-name">{{criterion.name}}</span><br /> <em>{{criterion.Description}}</em><br /> Weight: {{criterion.weight}} diff --git a/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.3.html b/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.3.html index db44813a..cb075632 100644 --- a/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.3.html +++ b/refstack-ui/app/components/capabilities/partials/capabilityDetailsV1.3.html @@ -4,21 +4,21 @@ This expects the JSON data of the capability file to be stored in scope variable 'capabilities'. --> -<ol ng-show="capabilities" class="capabilities"> - <li class="capability-list-item" ng-repeat="capability in capabilities.capabilities | arrayConverter | filter:filterStatus"> +<ol ng-show="ctrl.capabilities" class="capabilities"> + <li class="capability-list-item" ng-repeat="capability in ctrl.capabilities.capabilities | arrayConverter | filter:ctrl.filterStatus | orderBy:'id'"> <span class="capability-name">{{capability.id}}</span><br /> <em>{{capability.description}}</em><br /> - Status: <span class="{{targetCapabilities[capability.id]}}">{{targetCapabilities[capability.id]}}</span><br /> + Status: <span class="{{ctrl.targetCapabilities[capability.id]}}">{{ctrl.targetCapabilities[capability.id]}}</span><br /> Project: {{capability.project | capitalize}}<br /> - <a ng-click="hideAchievements = !hideAchievements">Achievements ({{capability.achievements.length}})</a><br /> - <ol collapse="hideAchievements" class="list-inline"> + <a ng-click="showAchievements = !hshowAchievements">Achievements ({{capability.achievements.length}})</a><br /> + <ol collapse="!showAchievements" class="list-inline"> <li ng-repeat="achievement in capability.achievements"> {{achievement}} </li> </ol> - <a ng-click="hideTests = !hideTests">Tests ({{getObjectLength(capability.tests)}})</a> - <ul collapse="hideTests"> + <a ng-click="showTests = !showTests">Tests ({{ctrl.getObjectLength(capability.tests)}})</a> + <ul collapse="!showTests"> <li ng-repeat="(testName, testDetails) in capability.tests"> <span ng-class="{'glyphicon glyphicon-flag text-warning': testDetails.flagged}" title="{{testDetails.flagged.reason}}"></span> {{testName}} @@ -27,12 +27,12 @@ variable 'capabilities'. </li> </ol> -<div ng-show="capabilities" class="criteria"> +<div ng-show="ctrl.capabilities" class="criteria"> <hr> - <h4><a ng-click="hideCriteria = !hideCriteria">Criteria</a></h4> - <div collapse="hideCriteria"> + <h4><a ng-click="showCriteria = !showCriteria">Criteria</a></h4> + <div collapse="showCriteria"> <ul> - <li ng-repeat="(key, criterion) in capabilities.criteria"> + <li ng-repeat="(key, criterion) in ctrl.capabilities.criteria"> <span class="criterion-name">{{criterion.name}}</span><br /> <em>{{criterion.Description}}</em><br /> Weight: {{criterion.weight}} diff --git a/refstack-ui/app/components/profile/importPubKeyModal.html b/refstack-ui/app/components/profile/importPubKeyModal.html index d9b1107a..e86e3a5b 100644 --- a/refstack-ui/app/components/profile/importPubKeyModal.html +++ b/refstack-ui/app/components/profile/importPubKeyModal.html @@ -1,21 +1,21 @@ <div class="modal-header"> - <h4>Import public key</h4> + <h4>Import Public Key</h4> </div> <div class="modal-body container-fluid"> <div class="row"> - <div class="col-md-2">Public key</div> + <div class="col-md-2">Public Key</div> <div class="col-md-9 pull-right"> - <textarea type="text" rows="11" cols="42" ng-model="raw_key" required></textarea> + <textarea type="text" rows="11" cols="42" ng-model="modal.raw_key" required></textarea> </div> </div> <div class="row"> <div class="col-md-2">Signature</div> <div class="col-md-9 pull-right"> - <textarea type="text" rows="11" cols="42" ng-model="self_signature" required></textarea> + <textarea type="text" rows="11" cols="42" ng-model="modal.self_signature" required></textarea> </div> </div> <div class="modal-footer"> - <button class="btn btn-warning" ng-click="cancel()">Cancel</button> - <button type="button" class="btn btn-default btn-sm" ng-click="importPubKey()">Import public key</button> + <button class="btn btn-warning" ng-click="modal.cancel()">Cancel</button> + <button type="button" class="btn btn-default btn-sm" ng-click="modal.importPubKey()">Import Public Key</button> </div> -</div> \ No newline at end of file +</div> diff --git a/refstack-ui/app/components/profile/profile.html b/refstack-ui/app/components/profile/profile.html index 3d1e275f..dc97c41e 100644 --- a/refstack-ui/app/components/profile/profile.html +++ b/refstack-ui/app/components/profile/profile.html @@ -1,5 +1,5 @@ <h3>User profile</h3> -<div cg-busy="{promise:authRequest,message:'Loading'}"></div> +<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div> <div> <table class="table table-striped table-hover"> <tbody> @@ -9,15 +9,15 @@ </tbody> </table> </div> -<div ng-show="pubkeys"> +<div ng-show="ctrl.pubkeys"> <div class="container-fluid"> <div class="row"> <div class="col-md-4"> - <h4>User public keys</h4> + <h4>User Public Keys</h4> </div> <div class="col-md-2 pull-right"> - <button type="button" class="btn btn-default btn-sm" ng-click="openImportPubKeyModal()"> - <span class="glyphicon glyphicon-plus"></span> Import public key + <button type="button" class="btn btn-default btn-sm" ng-click="ctrl.openImportPubKeyModal()"> + <span class="glyphicon glyphicon-plus"></span> Import Public Key </button> </div> </div> @@ -26,7 +26,7 @@ <div> <table class="table table-striped table-hover"> <tbody> - <tr ng-repeat="pubKey in pubkeys" ng-click="openShowPubKeyModal(pubKey)"> + <tr ng-repeat="pubKey in ctrl.pubkeys" ng-click="ctrl.openShowPubKeyModal(pubKey)"> <td>{{pubKey.format}}</td> <td>{{pubKey.shortKey}}</td> <td>{{pubKey.comment}}</td> @@ -34,4 +34,4 @@ </tbody> </table> </div> -</div> \ No newline at end of file +</div> diff --git a/refstack-ui/app/components/profile/profileController.js b/refstack-ui/app/components/profile/profileController.js index 8383e246..2a8bb69d 100644 --- a/refstack-ui/app/components/profile/profileController.js +++ b/refstack-ui/app/components/profile/profileController.js @@ -1,133 +1,217 @@ -/** - * Refstack User Profile Controller - * This controller handles user's profile page, where a user can view - * account-specific information. +/* + * + * 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. */ -var refstackApp = angular.module('refstackApp'); +(function () { + 'use strict'; -refstackApp.factory('PubKeys', - ['$resource', 'refstackApiUrl', function($resource, refstackApiUrl) { - 'use strict'; + angular + .module('refstackApp') + .factory('PubKeys', PubKeys); + + PubKeys.$inject = ['$resource', 'refstackApiUrl']; + + /** + * This is a provider for the user's uploaded public keys. + */ + function PubKeys($resource, refstackApiUrl) { return $resource(refstackApiUrl + '/profile/pubkeys/:id', null, null); - }]); + } -refstackApp.controller('profileController', - [ + angular + .module('refstackApp') + .controller('ProfileController', ProfileController); + + ProfileController.$inject = [ '$scope', '$http', 'refstackApiUrl', 'PubKeys', - '$modal', 'raiseAlert', '$state', - function($scope, $http, refstackApiUrl, - PubKeys, $modal, raiseAlert, $state) { - 'use strict'; + '$modal', 'raiseAlert', '$state' + ]; - if (!$scope.auth.isAuthenticated) { - $state.go('home'); - } + /** + * RefStack Profile Controller + * This controller handles user's profile page, where a user can view + * account-specific information. + */ + function ProfileController($scope, $http, refstackApiUrl, + PubKeys, $modal, raiseAlert, $state) { - $scope.updatePubKeys = function (){ - var keys = PubKeys.query(function(){ - $scope.pubkeys = []; - angular.forEach(keys, function (key) { - $scope.pubkeys.push({ - 'resource': key, - 'format': key.format, - 'shortKey': [ - key.pubkey.slice(0, 10), - '.', - key.pubkey.slice(-10, -1) - ].join('.'), - 'pubkey': key.pubkey, - 'comment': key.comment - }); + 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, -1) + ].join('.'), + 'pubkey': key.pubkey, + 'comment': key.comment }); }); - }; - $scope.openImportPubKeyModal = function () { - $modal.open({ - templateUrl: '/components/profile/importPubKeyModal.html', - backdrop: true, - windowClass: 'modal', - controller: 'importPubKeyModalController' - }).result.finally(function() { - $scope.updatePubKeys(); - }); - }; - - $scope.openShowPubKeyModal = function (pubKey) { - $modal.open({ - templateUrl: '/components/profile/showPubKeyModal.html', - backdrop: true, - windowClass: 'modal', - controller: 'showPubKeyModalController', - resolve: { - pubKey: function(){ - return pubKey; - } - } - }).result.finally(function() { - $scope.updatePubKeys(); - }); - }; - $scope.showRes = function(pubKey){ - raiseAlert('success', '', pubKey.pubkey); - }; - $scope.authRequest = $scope.auth.doSignCheck() - .then($scope.updatePubKeys); + }); } - ]); -refstackApp.controller('importPubKeyModalController', - ['$scope', '$modalInstance', 'PubKeys', 'raiseAlert', - function ($scope, $modalInstance, PubKeys, raiseAlert) { - 'use strict'; - $scope.importPubKey = function () { - var newPubKey = new PubKeys( - {raw_key: $scope.raw_key, - self_signature: $scope.self_signature} - ); - newPubKey.$save(function(newPubKey_){ - raiseAlert('success', - '', 'Public key saved successfully'); - $modalInstance.close(newPubKey_); - }, - function(httpResp){ - raiseAlert('danger', - httpResp.statusText, httpResp.data.title); - $scope.cancel(); - } - ); - }; - $scope.cancel = function () { - $modalInstance.dismiss('cancel'); - }; + /** + * This function will open the modal that will give the user a form + * for importing a public key. + */ + function openImportPubKeyModal() { + $modal.open({ + templateUrl: '/components/profile/importPubKeyModal.html', + backdrop: true, + windowClass: 'modal', + controller: 'ImportPubKeyModalController as modal' + }).result.finally(function() { + ctrl.updatePubKeys(); + }); } - ]); -refstackApp.controller('showPubKeyModalController', - ['$scope', '$modalInstance', 'raiseAlert', 'pubKey', - function ($scope, $modalInstance, raiseAlert, pubKey) { - 'use strict'; - $scope.pubKey = pubKey.resource; - $scope.rawKey = [pubKey.format, - pubKey.pubkey, pubKey.comment].join('\n'); - $scope.deletePubKey = function () { - $scope.pubKey.$remove( - {id: $scope.pubKey.id}, - function(){ - raiseAlert('success', - '', 'Public key deleted successfully'); - $modalInstance.close($scope.pubKey.id); - }, - function(httpResp){ - raiseAlert('danger', - httpResp.statusText, httpResp.data.title); - $scope.cancel(); + /** + * This function will open the modal that will give the full + * information regarding a specific public key. + * @param {Object} pubKey resource + */ + function openShowPubKeyModal(pubKey) { + $modal.open({ + templateUrl: '/components/profile/showPubKeyModal.html', + backdrop: true, + windowClass: 'modal', + controller: 'ShowPubKeyModalController as modal', + resolve: { + pubKey: function() { + return pubKey; } - ); - }; - $scope.cancel = function () { - $modalInstance.dismiss('cancel'); - }; + } + }).result.finally(function() { + ctrl.updatePubKeys(); + }); } - ] -); + + ctrl.authRequest = $scope.auth.doSignCheck().then(ctrl.updatePubKeys); + } + + angular + .module('refstackApp') + .controller('ImportPubKeyModalController', ImportPubKeyModalController); + + ImportPubKeyModalController.$inject = [ + '$modalInstance', '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($modalInstance, 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'); + $modalInstance.close(newPubKey_); + }, + function(httpResp) { + raiseAlert('danger', + httpResp.statusText, httpResp.data.title); + ctrl.cancel(); + } + ); + } + + /** + * This function will dismiss the modal. + */ + function cancel() { + $modalInstance.dismiss('cancel'); + } + } + + angular + .module('refstackApp') + .controller('ShowPubKeyModalController', ShowPubKeyModalController); + + ShowPubKeyModalController.$inject = [ + '$modalInstance', '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($modalInstance, 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'); + $modalInstance.close(ctrl.pubKey.id); + }, + function(httpResp) { + raiseAlert('danger', + httpResp.statusText, httpResp.data.title); + ctrl.cancel(); + } + ); + } + + /** + * This method will dismiss the modal. + */ + function cancel() { + $modalInstance.dismiss('cancel'); + } + } +})(); diff --git a/refstack-ui/app/components/profile/showPubKeyModal.html b/refstack-ui/app/components/profile/showPubKeyModal.html index d2dbf2f2..5f63a5ef 100644 --- a/refstack-ui/app/components/profile/showPubKeyModal.html +++ b/refstack-ui/app/components/profile/showPubKeyModal.html @@ -1,11 +1,11 @@ <div class="modal-header"> - <h4>Public key</h4> + <h4>Public Key</h4> </div> <div class="modal-body container-fluid"> - <textarea type="text" rows="10" cols="67" readonly="readonly">{{::rawKey}}</textarea> + <textarea type="text" rows="10" cols="67" readonly="readonly">{{modal.rawKey}}</textarea> <div class="modal-footer"> - <button class="btn btn-warning" ng-click="cancel()">Cancel</button> - <button type="button" class="btn btn-danger btn-sm" ng-click="deletePubKey() " + <button class="btn btn-warning" ng-click="modal.cancel()">Cancel</button> + <button type="button" class="btn btn-danger btn-sm" ng-click="modal.deletePubKey() " confirm="Are you sure you want to delete this public key? You will lose management access to any test results signed with this key.">Delete</button> </div> -</div> \ No newline at end of file +</div> diff --git a/refstack-ui/app/components/results-report/partials/fullTestListModal.html b/refstack-ui/app/components/results-report/partials/fullTestListModal.html index 2ac7de77..6db198b0 100644 --- a/refstack-ui/app/components/results-report/partials/fullTestListModal.html +++ b/refstack-ui/app/components/results-report/partials/fullTestListModal.html @@ -1,13 +1,13 @@ <div class="modal-content"> <div class="modal-header"> - <h4>All Passed Tests ({{tests.length}})</h4> + <h4>All Passed Tests ({{modal.tests.length}})</h4> </div> <div class="modal-body tests-modal-content"> <div class="form-group"> - <textarea class="form-control" rows="20" id="tests" wrap="off">{{getTestListString()}}</textarea> + <textarea class="form-control" rows="20" id="tests" wrap="off">{{modal.getTestListString()}}</textarea> </div> </div> <div class="modal-footer"> - <button class="btn btn-primary" type="button" ng-click="close()">Close</button> + <button class="btn btn-primary" type="button" ng-click="modal.close()">Close</button> </div> </div> diff --git a/refstack-ui/app/components/results-report/partials/reportDetails.html b/refstack-ui/app/components/results-report/partials/reportDetails.html index 3548660e..7f603a1f 100644 --- a/refstack-ui/app/components/results-report/partials/reportDetails.html +++ b/refstack-ui/app/components/results-report/partials/reportDetails.html @@ -3,13 +3,13 @@ HTML for each accordion group that separates the status types on the results report page. --> -<accordion-group is-open="isOpen" is-disabled="caps[status].caps.length == 0"> +<accordion-group is-open="isOpen" is-disabled="ctrl.caps[status].caps.length == 0"> <accordion-heading> {{status | capitalize}} <small> - (<strong>Total:</strong> {{caps[status].caps.length}} capabilities, {{caps[status].count}} tests) - <span ng-if="testStatus !== 'total'"> - (<strong>{{testStatus | capitalize}}:</strong> {{getStatusTestCount(status)}} tests) + (<strong>Total:</strong> {{ctrl.caps[status].caps.length}} capabilities, {{ctrl.caps[status].count}} tests) + <span ng-if="ctrl.testStatus !== 'total'"> + (<strong>{{ctrl.testStatus | capitalize}}:</strong> {{ctrl.getStatusTestCount(status)}} tests) </span> </small> <i class="pull-right glyphicon" @@ -17,18 +17,18 @@ report page. </i> </accordion-heading> <ol class="capabilities"> - <li ng-repeat="capability in caps[status].caps | orderBy:'id'" - ng-if="isCapabilityShown(capability)"> + <li ng-repeat="capability in ctrl.caps[status].caps | orderBy:'id'" + ng-if="ctrl.isCapabilityShown(capability)"> - <a ng-click="hideTests = !hideTests" - title="{{capabilityData.capabilities[capability.id].description}}"> + <a ng-click="ctrl.hideTests = !ctrl.hideTests" + title="{{ctrl.capabilityData.capabilities[capability.id].description}}"> {{capability.id}} </a> - <span ng-class="{'text-success': testStatus === 'passed', - 'text-danger': testStatus === 'not passed', - 'text-warning': testStatus === 'flagged'}" - ng-if="testStatus !== 'total'"> - [{{getCapabilityTestCount(capability)}}] + <span ng-class="{'text-success': ctrl.testStatus === 'passed', + 'text-danger': ctrl.testStatus === 'not passed', + 'text-warning': ctrl.testStatus === 'flagged'}" + ng-if="ctrl.testStatus !== 'total'"> + [{{ctrl.getCapabilityTestCount(capability)}}] </span> <span ng-class="{'text-success': (capability.passedTests.length > 0 && capability.notPassedTests.length == 0), @@ -36,31 +36,31 @@ report page. capability.notPassedTests.length > 0), 'text-warning': (capability.passedTests.length > 0 && capability.notPassedTests.length > 0)}" - ng-if="testStatus === 'total'"> + ng-if="ctrl.testStatus === 'total'"> [{{capability.passedTests.length}}/{{capability.passedTests.length + capability.notPassedTests.length}}] </span> - <ul class="list-unstyled" collapse="hideTests"> + <ul class="list-unstyled" collapse="ctrl.hideTests"> <li ng-repeat="test in capability.passedTests | orderBy:'toString()'" - ng-if="isTestShown(test, capability)"> + ng-if="ctrl.isTestShown(test, capability)"> <span class="glyphicon glyphicon-ok text-success" aria-hidden="true"> </span> <span ng-class="{'glyphicon glyphicon-flag text-warning': - isTestFlagged(test, capabilityData.capabilities[capability.id])}" - title="{{getFlaggedReason(test, capabilityData.capabilities[capability.id])}}"> + ctrl.isTestFlagged(test, ctrl.capabilityData.capabilities[capability.id])}" + title="{{ctrl.getFlaggedReason(test, ctrl.capabilityData.capabilities[capability.id])}}"> </span> {{test}} </li> <li ng-repeat="test in capability.notPassedTests | orderBy:'toString()'" - ng-if="isTestShown(test, capability)"> + ng-if="ctrl.isTestShown(test, capability)"> <span class="glyphicon glyphicon-remove text-danger" aria-hidden="true"></span> <span ng-class="{'glyphicon glyphicon-flag text-warning': - isTestFlagged(test, capabilityData.capabilities[capability.id])}" - title="{{getFlaggedReason(test, capabilityData.capabilities[capability.id])}}"> + ctrl.isTestFlagged(test, ctrl.capabilityData.capabilities[capability.id])}" + title="{{ctrl.getFlaggedReason(test, ctrl.capabilityData.capabilities[capability.id])}}"> </span> {{test}} </li> diff --git a/refstack-ui/app/components/results-report/resultsReport.html b/refstack-ui/app/components/results-report/resultsReport.html index 166c9947..cdd42f6a 100644 --- a/refstack-ui/app/components/results-report/resultsReport.html +++ b/refstack-ui/app/components/results-report/resultsReport.html @@ -1,31 +1,31 @@ <h3>Test Run Results</h3> -<div ng-show="resultsData" class="container-fluid"> +<div ng-show="ctrl.resultsData" class="container-fluid"> <div class="row"> <div class="pull-left"> <div class="test-report"> - <strong>Test ID:</strong> {{testId}}<br /> - <div ng-if="isEditingAllowed()"><strong>Cloud ID:</strong> {{resultsData.cpid}}<br /></div> - <strong>Upload Date:</strong> {{resultsData.created_at}} UTC<br /> - <strong>Duration:</strong> {{resultsData.duration_seconds}} seconds<br /> + <strong>Test ID:</strong> {{ctrl.testId}}<br /> + <div ng-if="ctrl.isEditingAllowed()"><strong>Cloud ID:</strong> {{ctrl.resultsData.cpid}}<br /></div> + <strong>Upload Date:</strong> {{ctrl.resultsData.created_at}} UTC<br /> + <strong>Duration:</strong> {{ctrl.resultsData.duration_seconds}} seconds<br /> <strong>Total Number of Passed Tests:</strong> - <a title="See all passed tests" ng-click="openFullTestListModal()"> - {{resultsData.results.length}} + <a title="See all passed tests" ng-click="ctrl.openFullTestListModal()"> + {{ctrl.resultsData.results.length}} </a><br /> <hr> </div> </div> <div class="pull-right"> - <div ng-show="isEditingAllowed()"> - <button class="btn btn-warning" ng-hide="isShared()" ng-click="shareTestRun(true)" confirm="Are you sure you want to share these test run results with the community?">Share</button> - <button class="btn btn-success" ng-show="isShared()" ng-click="shareTestRun(false)">Unshare</button> - <button type="button" class="btn btn-danger" ng-click="deleteTestRun()" confirm="Are you sure you want to delete these test run results?">Delete</button> + <div ng-show="ctrl.isEditingAllowed()"> + <button class="btn btn-warning" ng-hide="ctrl.isShared()" ng-click="ctrl.shareTestRun(true)" confirm="Are you sure you want to share these test run results with the community?">Share</button> + <button class="btn btn-success" ng-show="ctrl.isShared()" ng-click="ctrl.shareTestRun(false)">Unshare</button> + <button type="button" class="btn btn-danger" ng-click="ctrl.deleteTestRun()" confirm="Are you sure you want to delete these test run results?">Delete</button> </div> </div> </div> </div> -<div ng-show="resultsData"> +<div ng-show="ctrl.resultsData"> <p>See how these results stack up against DefCore capabilities and OpenStack <a target="_blank" href="http://www.openstack.org/brand/interop/">target marketing programs.</a> </p> @@ -34,14 +34,14 @@ <div class="row"> <div class="col-md-3"> <strong>Capabilities Version:</strong> - <select ng-model="version" ng-change="updateCapabilities()" class="form-control"> + <select ng-model="ctrl.version" ng-change="ctrl.updateCapabilities()" class="form-control"> <!-- Slicing the version file name here gets rid of the '.json' file extension --> - <option ng-repeat="versionFile in versionList" value="{{versionFile}}">{{versionFile.slice(0, -5)}}</option> + <option ng-repeat="versionFile in ctrl.versionList" value="{{versionFile}}">{{versionFile.slice(0, -5)}}</option> </select> </div> <div class="col-md-4"> <strong>Target Program:</strong> - <select ng-model="target" class="form-control" ng-change="buildCapabilitiesObject()"> + <select ng-model="ctrl.target" class="form-control" ng-change="ctrl.buildCapabilitiesObject()"> <option value="platform">OpenStack Powered Platform</option> <option value="compute">OpenStack Powered Compute</option> <option value="object">OpenStack Powered Object Storage</option> @@ -53,28 +53,28 @@ <br /> <strong>Corresponding OpenStack Releases:</strong> <ul class="list-inline"> - <li ng-repeat="release in capabilityData.releases"> + <li ng-repeat="release in ctrl.capabilityData.releases"> {{release | capitalize}} </li> </ul> <hr > - <div ng-show="capabilityData"> + <div ng-show="ctrl.capabilityData"> <strong>Status:</strong> - <p>This cloud passes <strong>{{requiredPassPercent | number:1}}% </strong> - ({{caps.required.passedCount}}/{{caps.required.count}}) - of the tests in the <strong>{{version.slice(0, -5)}}</strong> <em>required</em> capabilities for the - <strong>{{targetMappings[target]}}</strong> program. <br /> + <p>This cloud passes <strong>{{ctrl.requiredPassPercent | number:1}}% </strong> + ({{ctrl.caps.required.passedCount}}/{{ctrl.caps.required.count}}) + of the tests in the <strong>{{ctrl.version.slice(0, -5)}}</strong> <em>required</em> capabilities for the + <strong>{{ctrl.targetMappings[target]}}</strong> program. <br /> Excluding flagged tests, this cloud passes - <strong>{{nonFlagRequiredPassPercent | number:1}}%</strong> - ({{nonFlagPassCount}}/{{totalNonFlagCount}}) + <strong>{{ctrl.nonFlagRequiredPassPercent | number:1}}%</strong> + ({{ctrl.nonFlagPassCount}}/{{ctrl.totalNonFlagCount}}) of the <em>required</em> tests. </p> - <p>Compliance with <strong>{{version.slice(0, -5)}}</strong>: + <p>Compliance with <strong>{{ctrl.version.slice(0, -5)}}</strong>: <strong> - <span ng-if="nonFlagPassCount === totalNonFlagCount" class="yes">YES</span> - <span ng-if="nonFlagPassCount !== totalNonFlagCount" class="no">NO</span> + <span ng-if="ctrl.nonFlagPassCount === ctrl.totalNonFlagCount" class="yes">YES</span> + <span ng-if="ctrl.nonFlagPassCount !== ctrl.totalNonFlagCount" class="no">NO</span> </strong> </p> @@ -83,20 +83,20 @@ Test Filters:<br /> <div class="btn-group button-margin" data-toggle="buttons"> - <label class="btn btn-default" ng-class="{'active': testStatus === 'total'}"> - <input type="radio" ng-model="testStatus" value="total"> + <label class="btn btn-default" ng-class="{'active': ctrl.testStatus === 'total'}"> + <input type="radio" ng-model="ctrl.testStatus" value="total"> <span class="text-primary">All</span> </label> - <label class="btn btn-default" ng-class="{'active': testStatus === 'passed'}"> - <input type="radio" ng-model="testStatus" value="passed"> + <label class="btn btn-default" ng-class="{'active': ctrl.testStatus === 'passed'}"> + <input type="radio" ng-model="ctrl.testStatus" value="passed"> <span class="text-success">Passed</span> </label> - <label class="btn btn-default" ng-class="{'active': testStatus === 'not passed'}"> - <input type="radio" ng-model="testStatus" value="not passed"> + <label class="btn btn-default" ng-class="{'active': ctrl.testStatus === 'not passed'}"> + <input type="radio" ng-model="ctrl.testStatus" value="not passed"> <span class="text-danger">Not Passed</span> </label> - <label class="btn btn-default" ng-class="{'active': testStatus === 'flagged'}"> - <input type="radio" ng-model="testStatus" value="flagged"> + <label class="btn btn-default" ng-class="{'active': ctrl.testStatus === 'flagged'}"> + <input type="radio" ng-model="ctrl.testStatus" value="flagged"> <span class="text-warning">Flagged</span> </label> </div> @@ -105,23 +105,23 @@ <!-- The ng-repeat is used to pass in a local variable to the template. --> <ng-include ng-repeat="status in ['required']" - src="detailsTemplate" + src="ctrl.detailsTemplate" onload="isOpen = true"> </ng-include> <br /> <ng-include ng-repeat="status in ['advisory']" - src="detailsTemplate"> + src="ctrl.detailsTemplate"> </ng-include> <br /> <ng-include ng-repeat="status in ['deprecated']" - src="detailsTemplate"> + src="ctrl.detailsTemplate"> </ng-include> <br /> <ng-include ng-repeat="status in ['removed']" - src="detailsTemplate"> + src="ctrl.detailsTemplate"> </ng-include> </accordion> </div> diff --git a/refstack-ui/app/components/results-report/resultsReportController.js b/refstack-ui/app/components/results-report/resultsReportController.js index 04514e4d..1166c110 100644 --- a/refstack-ui/app/components/results-report/resultsReportController.js +++ b/refstack-ui/app/components/results-report/resultsReportController.js @@ -1,538 +1,598 @@ -var refstackApp = angular.module('refstackApp'); - -/** - * Refstack Results Report Controller - * This controller is for the '/results/<test run ID>' page where a user can - * view details for a specific test run. +/* + * 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. */ -refstackApp.controller('resultsReportController', - ['$scope', '$http', '$stateParams', - '$window', '$modal', 'refstackApiUrl', 'raiseAlert', - function ($scope, $http, $stateParams, $window, $modal, - refstackApiUrl, raiseAlert) { - 'use strict'; - /** The testID extracted from the URL route. */ - $scope.testId = $stateParams.testID; +(function () { + 'use strict'; - /** Whether to hide tests on start.*/ - $scope.hideTests = true; + angular + .module('refstackApp') + .controller('ResultsReportController', ResultsReportController); - /** The target OpenStack marketing program to compare against. */ - $scope.target = 'platform'; + ResultsReportController.$inject = [ + '$http', '$stateParams', '$window', + '$modal', 'refstackApiUrl', 'raiseAlert' + ]; - /** Mappings of DefCore components to marketing program names. */ - $scope.targetMappings = { - 'platform': 'Openstack Powered Platform', - 'compute': 'OpenStack Powered Compute', - 'object': 'OpenStack Powered Object Storage' - }; + /** + * RefStack Results Report Controller + * This controller is for the '/results/<test run ID>' page where a user can + * view details for a specific test run. + */ + function ResultsReportController($http, $stateParams, $window, + $modal, refstackApiUrl, raiseAlert) { - /** The schema version of the currently selected capabilities data. */ - $scope.schemaVersion = null; + var ctrl = this; - /** The selected test status used for test filtering. */ - $scope.testStatus = 'total'; + ctrl.getVersionList = getVersionList; + ctrl.getResults = getResults; + ctrl.isEditingAllowed = isEditingAllowed; + ctrl.isShared = isShared; + ctrl.shareTestRun = shareTestRun; + ctrl.deleteTestRun = deleteTestRun; + ctrl.updateCapabilities = updateCapabilities; + 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; - /** The HTML template that all accordian groups will use. */ - $scope.detailsTemplate = 'components/results-report/partials/' + - 'reportDetails.html'; + /** The testID extracted from the URL route. */ + ctrl.testId = $stateParams.testID; - /** - * Retrieve an array of available capability files from the Refstack - * 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"] - */ - var getVersionList = function () { - var content_url = refstackApiUrl + '/capabilities'; - $scope.versionsRequest = - $http.get(content_url).success(function (data) { - $scope.versionList = data.sort().reverse(); - $scope.version = $scope.versionList[0]; - $scope.updateCapabilities(); - }).error(function (error) { - $scope.showError = true; - $scope.error = 'Error retrieving version list: ' + - JSON.stringify(error); - }); - }; + /** Whether to hide tests on start.*/ + ctrl.hideTests = true; - /** - * Retrieve results from the Refstack 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. - */ - var getResults = function () { - var content_url = refstackApiUrl + '/results/' + $scope.testId; - $scope.resultsRequest = - $http.get(content_url).success(function (data) { - $scope.resultsData = data; - getVersionList(); - }).error(function (error) { - $scope.showError = true; - $scope.resultsData = null; - $scope.error = 'Error retrieving results from server: ' + - JSON.stringify(error); + /** The target OpenStack marketing program to compare against. */ + ctrl.target = 'platform'; - }); - }; + /** Mappings of DefCore components to marketing program names. */ + ctrl.targetMappings = { + 'platform': 'Openstack Powered Platform', + 'compute': 'OpenStack Powered Compute', + 'object': 'OpenStack Powered Object Storage' + }; - $scope.isEditingAllowed = function () { - return Boolean($scope.resultsData && - $scope.resultsData.user_role === 'owner'); - }; + /** The schema version of the currently selected capabilities data. */ + ctrl.schemaVersion = null; - $scope.isShared = function () { - return Boolean($scope.resultsData && - 'shared' in $scope.resultsData.meta); - }; + /** The selected test status used for test filtering. */ + ctrl.testStatus = 'total'; - $scope.shareTestRun = function (shareState) { - var content_url = [ - refstackApiUrl, '/results/', $scope.testId, '/meta/shared' - ].join(''); - if (shareState) { - $scope.shareRequest = - $http.post(content_url, 'true').success(function () { - $scope.resultsData.meta.shared = 'true'; - raiseAlert('success', '', 'Test run shared!'); - }).error(function (error) { - raiseAlert('danger', - error.title, error.detail); - }); - } else { - $scope.shareRequest = - $http.delete(content_url).success(function () { - delete $scope.resultsData.meta.shared; - raiseAlert('success', '', 'Test run unshared!'); - }).error(function (error) { - raiseAlert('danger', - error.title, error.detail); - }); - } - }; + /** The HTML template that all accordian groups will use. */ + ctrl.detailsTemplate = 'components/results-report/partials/' + + 'reportDetails.html'; - $scope.deleteTestRun = function () { - var content_url = [ - refstackApiUrl, '/results/', $scope.testId - ].join(''); - $scope.deleteRequest = - $http.delete(content_url).success(function () { - $window.history.back(); - }).error(function (error) { - raiseAlert('danger', - error.title, error.detail); - }); - }; + /** + * Retrieve an array of available capability files from the Refstack + * 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 = refstackApiUrl + '/capabilities'; + ctrl.versionsRequest = + $http.get(content_url).success(function (data) { + ctrl.versionList = data.sort().reverse(); + ctrl.version = ctrl.versionList[0]; + ctrl.updateCapabilities(); + }).error(function (error) { + ctrl.showError = true; + ctrl.error = 'Error retrieving version list: ' + + angular.toJson(error); + }); + } - /** - * This will contact the Refstack API server to retrieve the JSON - * content of the capability file corresponding to the selected - * version. A function to construct an object from the capability - * date will be called upon successful retrieval. - */ - $scope.updateCapabilities = function () { - $scope.capabilityData = null; - $scope.showError = false; - var content_url = refstackApiUrl + '/capabilities/' + - $scope.version; - $scope.capsRequest = - $http.get(content_url).success(function (data) { - $scope.capabilityData = data; - $scope.schemaVersion = data.schema; - $scope.buildCapabilitiesObject(); - }).error(function (error) { - $scope.showError = true; - $scope.capabilityData = null; - $scope.error = 'Error retrieving capabilities: ' + - JSON.stringify(error); - }); - }; + /** + * Retrieve results from the Refstack 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 = refstackApiUrl + '/results/' + ctrl.testId; + ctrl.resultsRequest = + $http.get(content_url).success(function (data) { + ctrl.resultsData = data; + getVersionList(); + }).error(function (error) { + ctrl.showError = true; + ctrl.resultsData = null; + ctrl.error = 'Error retrieving results from server: ' + + 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 - */ - $scope.getTargetCapabilities = function () { - var components = $scope.capabilityData.components; - var targetCaps = {}; + /** + * This tells you whether the current results can be edited/managed + * based on if the current user is the owner of the results set. + * @returns {Boolean} true if editing is allowed + */ + function isEditingAllowed() { + return Boolean(ctrl.resultsData && + ctrl.resultsData.user_role === 'owner'); + } + /** + * 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); + } - // The 'platform' target is comprised of multiple components, so - // we need to get the capabilities belonging to each of its - // components. - if ($scope.target === 'platform') { - var platform_components = - $scope.capabilityData.platform.required; + /** + * 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 = [ + refstackApiUrl, '/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 contain status priority values, where lower - // values mean higher priorities. - var statusMap = { - required: 1, - advisory: 2, - deprecated: 3, - removed: 4 - }; + /** + * This will send a request to the API to delete the current + * test results set. + */ + function deleteTestRun() { + var content_url = [ + refstackApiUrl, '/results/', ctrl.testId + ].join(''); + ctrl.deleteRequest = + $http.delete(content_url).success(function () { + $window.history.back(); + }).error(function (error) { + raiseAlert('danger', error.title, error.detail); + }); + } - // 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[$scope.target], - function (caps, status) { - angular.forEach(caps, function(cap) { - targetCaps[cap] = status; - }); - }); - } - return targetCaps; - }; + /** + * This will contact the Refstack API server to retrieve the JSON + * content of the capability file corresponding to the selected + * version. A function to construct an object from the capability + * date will be called upon successful retrieval. + */ + function updateCapabilities() { + ctrl.capabilityData = null; + ctrl.showError = false; + var content_url = refstackApiUrl + '/capabilities/' + + ctrl.version; + ctrl.capsRequest = + $http.get(content_url).success(function (data) { + ctrl.capabilityData = data; + ctrl.schemaVersion = data.schema; + ctrl.buildCapabilitiesObject(); + }).error(function (error) { + ctrl.showError = true; + ctrl.capabilityData = null; + ctrl.error = 'Error retrieving capabilities: ' + + angular.toJson(error); + }); + } - /** - * 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 - */ - $scope.buildCapabilityV1_2 = function (capId) { - var cap = { - 'id': capId, - 'passedTests': [], - 'notPassedTests': [], - 'passedFlagged': [], - 'notPassedFlagged': [] - }; - var capDetails = $scope.capabilityData.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 ($scope.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 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.capabilityData.components; + var targetCaps = {}; - /** - * This will build the a capability object for schema version 1.3. - * This object will contain the information needed to form a report in - * the HTML template. - * @param {String} capId capability ID - */ - $scope.buildCapabilityV1_3 = function (capId) { - var cap = { - 'id': capId, - 'passedTests': [], - 'notPassedTests': [], - 'passedFlagged': [], - 'notPassedFlagged': [] - }; - // Loop through each test belonging to the capability. - angular.forEach($scope.capabilityData.capabilities[capId].tests, - function (details, testId) { - // If the test ID is in the results' test list, add - // it to the passedTests array. - if ($scope.resultsData.results.indexOf(testId) > -1) { - 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; - }; + // 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.capabilityData.platform.required; - /** - * 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 Refstack API server. - */ - $scope.buildCapabilitiesObject = function () { - // 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. - $scope.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} - }; + // This will contain status priority values, where lower + // values mean higher priorities. + var statusMap = { + required: 1, + advisory: 2, + deprecated: 3, + removed: 4 + }; - switch ($scope.schemaVersion) { - case '1.2': - var capMethod = 'buildCapabilityV1_2'; - break; - case '1.3': - capMethod = 'buildCapabilityV1_3'; - break; - default: - $scope.showError = true; - $scope.capabilityData = null; - $scope.error = 'The schema version for the capabilities ' + - 'file selected (' + $scope.schemaVersion + - ') is currently not supported.'; - return; - } + // 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; + } - // Get test details for each relevant capability and store - // them in the scope's 'caps' object. - var targetCaps = $scope.getTargetCapabilities(); - angular.forEach(targetCaps, function(status, capId) { - var cap = $scope[capMethod](capId); - $scope.caps[status].count += - cap.passedTests.length + cap.notPassedTests.length; - $scope.caps[status].passedCount += cap.passedTests.length; - $scope.caps[status].flagPassCount += cap.passedFlagged.length; - $scope.caps[status].flagFailCount += - cap.notPassedFlagged.length; - $scope.caps[status].caps.push(cap); - }); + /** + * 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.capabilityData.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; + } - $scope.requiredPassPercent = ($scope.caps.required.passedCount * - 100 / $scope.caps.required.count); + /** + * This will build the a capability object for schema version 1.3. + * 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': [] + }; + // Loop through each test belonging to the capability. + angular.forEach(ctrl.capabilityData.capabilities[capId].tests, + function (details, 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 ('flagged' in details) { + cap.passedFlagged.push(testId); + } + } + else { + cap.notPassedTests.push(testId); + if ('flagged' in details) { + cap.notPassedFlagged.push(testId); + } + } + }); + return cap; + } - $scope.totalRequiredFailCount = $scope.caps.required.count - - $scope.caps.required.passedCount; - $scope.totalRequiredFlagCount = - $scope.caps.required.flagFailCount + - $scope.caps.required.flagPassCount; - $scope.totalNonFlagCount = $scope.caps.required.count - - $scope.totalRequiredFlagCount; - $scope.nonFlagPassCount = $scope.totalNonFlagCount - - ($scope.totalRequiredFailCount - - $scope.caps.required.flagFailCount); + /** + * 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 Refstack 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} + }; - $scope.nonFlagRequiredPassPercent = ($scope.nonFlagPassCount * - 100 / $scope.totalNonFlagCount); - }; + switch (ctrl.schemaVersion) { + case '1.2': + var capMethod = 'buildCapabilityV1_2'; + break; + case '1.3': + capMethod = 'buildCapabilityV1_3'; + break; + default: + ctrl.showError = true; + ctrl.capabilityData = null; + ctrl.error = 'The schema version for the capabilities ' + + 'file selected (' + ctrl.schemaVersion + + ') is currently not supported.'; + return; + } - /** - * 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 - */ - $scope.isTestFlagged = function (test, capObj) { - if (!capObj) { - return false; - } - return ((($scope.schemaVersion === '1.2') && - (capObj.flagged.indexOf(test) > -1)) || - (($scope.schemaVersion === '1.3') && - (capObj.tests[test].flagged))); - }; + // 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); + }); - /** - * 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 - */ - $scope.getFlaggedReason = function (test, capObj) { - if (($scope.schemaVersion === '1.2') && - ($scope.isTestFlagged(test, capObj))){ + ctrl.requiredPassPercent = (ctrl.caps.required.passedCount * + 100 / ctrl.caps.required.count); - // Return a generic message since schema 1.2 does not - // provide flag reasons. - return 'DefCore has flagged this test.'; - } - else if (($scope.schemaVersion === '1.3') && - ($scope.isTestFlagged(test, capObj))){ + 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); - return capObj.tests[test].flagged.reason; - } - else { - return ''; - } - }; + ctrl.nonFlagRequiredPassPercent = (ctrl.nonFlagPassCount * + 100 / ctrl.totalNonFlagCount); + } - /** - * 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 - */ - $scope.isCapabilityShown = function (capability) { - return (($scope.testStatus === 'total') || - ($scope.testStatus === 'passed' && - capability.passedTests.length > 0) || - ($scope.testStatus === 'not passed' && - capability.notPassedTests.length > 0) || - ($scope.testStatus === 'flagged' && - (capability.passedFlagged.length + - capability.notPassedFlagged.length > 0))); - }; + /** + * 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 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 - */ - $scope.isTestShown = function (test, capability) { - return (($scope.testStatus === 'total') || - ($scope.testStatus === 'passed' && - capability.passedTests.indexOf(test) > -1) || - ($scope.testStatus === 'not passed' && - capability.notPassedTests.indexOf(test) > -1) || - ($scope.testStatus === 'flagged' && - (capability.passedFlagged.indexOf(test) > -1 || - capability.notPassedFlagged.indexOf(test) > -1))); - }; + /** + * 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))) { - /** - * 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 - */ - $scope.getCapabilityTestCount = function (capability) { - if ($scope.testStatus === 'total') { - return capability.passedTests.length + - capability.notPassedTests.length; - } - else if ($scope.testStatus === 'passed') { - return capability.passedTests.length; - } - else if ($scope.testStatus === 'not passed') { - return capability.notPassedTests.length; - } - else if ($scope.testStatus === 'flagged') { - return capability.passedFlagged.length + - capability.notPassedFlagged.length; - } - else { - return 0; - } - }; + // Return a generic message since schema 1.2 does not + // provide flag reasons. + return 'DefCore has flagged this test.'; + } + else if ((ctrl.schemaVersion === '1.3') && + (ctrl.isTestFlagged(test, capObj))) { - /** - * 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 - */ - $scope.getStatusTestCount = function (status) { - if (!$scope.caps) { - return -1; - } - else if ($scope.testStatus === 'total') { - return $scope.caps[status].count; - } - else if ($scope.testStatus === 'passed') { - return $scope.caps[status].passedCount; - } - else if ($scope.testStatus === 'not passed') { - return $scope.caps[status].count - - $scope.caps[status].passedCount; - } - else if ($scope.testStatus === 'flagged') { - return $scope.caps[status].flagFailCount + - $scope.caps[status].flagPassCount; - } - else { - return -1; - } - }; + return capObj.tests[test].flagged.reason; + } + else { + return ''; + } + } - $scope.openFullTestListModal = function () { - $modal.open({ - templateUrl: '/components/results-report/partials' + - '/fullTestListModal.html', - backdrop: true, - windowClass: 'modal', - animation: true, - controller: 'fullTestListModalController', - size: 'lg', - resolve: { - tests: function () { - return $scope.resultsData.results; - } - } - }); - }; + /** + * 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))); + } - getResults(); - } - ] -); + /** + * 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; + } + } -/** - * 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. - */ -refstackApp.controller('fullTestListModalController', - ['$scope', '$modalInstance', 'tests', - function ($scope, $modalInstance, tests) { - 'use strict'; + /** + * 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; + } + } - $scope.tests = tests; + /** + * This will open the modal that will show the full list of passed + * tests for the current results. + */ + function openFullTestListModal() { + $modal.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 function will close/dismiss the modal. - */ - $scope.close = function () { - $modalInstance.dismiss('exit'); - }; + getResults(); + } - /** - * This function will return a string representing the sorted - * tests list separated by newlines. - */ - $scope.getTestListString = function () { - return $scope.tests.sort().join('\n'); - }; - }] -); + angular + .module('refstackApp') + .controller('FullTestListModalController', FullTestListModalController); + + FullTestListModalController.$inject = ['$modalInstance', '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($modalInstance, tests) { + var ctrl = this; + + ctrl.tests = tests; + + /** + * This function will close/dismiss the modal. + */ + ctrl.close = function () { + $modalInstance.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'); + }; + } +})(); diff --git a/refstack-ui/app/components/results/results.html b/refstack-ui/app/components/results/results.html index c4b98bd8..e04e13f2 100644 --- a/refstack-ui/app/components/results/results.html +++ b/refstack-ui/app/components/results/results.html @@ -1,4 +1,4 @@ -<h3>{{pageHeader}}</h3> +<h3>{{ctrl.pageHeader}}</h3> <p>The most recently uploaded community test results are listed here.</p> <div class="result-filters"> @@ -8,12 +8,11 @@ <label for="cpid">Start Date</label> <p class="input-group"> <input type="text" class="form-control" - datepicker-popup="{{format}}" - ng-model="startDate" is-open="startOpen" - datepicker-options="dateOptions" + datepicker-popup="{{ctrl.format}}" + ng-model="ctrl.startDate" is-open="ctrl.startOpen" close-text="Close" /> <span class="input-group-btn"> - <button type="button" class="btn btn-default" ng-click="open($event, 'startOpen')"> + <button type="button" class="btn btn-default" ng-click="ctrl.open($event, 'startOpen')"> <i class="glyphicon glyphicon-calendar"></i> </button> </span> @@ -23,62 +22,61 @@ <label for="cpid">End Date</label> <p class="input-group"> <input type="text" class="form-control" - datepicker-popup="{{format}}" - ng-model="endDate" is-open="endOpen" - datepicker-options="dateOptions" + datepicker-popup="{{ctrl.format}}" + ng-model="ctrl.endDate" is-open="ctrl.endOpen" close-text="Close" /> <span class="input-group-btn"> - <button type="button" class="btn btn-default" ng-click="open($event, 'endOpen')"> + <button type="button" class="btn btn-default" ng-click="ctrl.open($event, 'endOpen')"> <i class="glyphicon glyphicon-calendar"></i> </button> </span> </p> </div> <div class="col-md-3"style="margin-top:24px;"> - <button type="submit" class="btn btn-primary" ng-click="update()">Filter</button> - <button type="submit" class="btn btn-primary btn-danger" ng-click="clearFilters()">Clear</button> + <button type="submit" class="btn btn-primary" ng-click="ctrl.update()">Filter</button> + <button type="submit" class="btn btn-primary btn-danger" ng-click="ctrl.clearFilters()">Clear</button> </div> </div> </div> -<div cg-busy="{promise:authRequest,message:'Loading'}"></div> -<div cg-busy="{promise:resultsRequest,message:'Loading'}"></div> -<div ng-show="data" class="results-table"> - <table ng-show="data" class="table table-striped table-hover"> +<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div> +<div cg-busy="{promise:ctrl.resultsRequest,message:'Loading'}"></div> +<div ng-show="ctrl.data" class="results-table"> + <table ng-show="ctrl.data" class="table table-striped table-hover"> <thead> <tr> <th>Upload Date</th> <th>Test Run ID</th> - <th ng-if="::isUserResults">Shared</th> + <th ng-if="ctrl.isUserResults">Shared</th> </tr> </thead> <tbody> - <tr ng-repeat="result in data.results"> + <tr ng-repeat="result in ctrl.data.results"> <td>{{result.created_at}}</td> <td><a ui-sref="resultsDetail({testID: result.id})">{{result.id}}</a></td> - <td ng-if="::isUserResults"><span ng-show="result.meta.shared" class="glyphicon glyphicon-share"></span></td> + <td ng-if="ctrl.isUserResults"><span ng-show="result.meta.shared" class="glyphicon glyphicon-share"></span></td> </tr> </tbody> </table> <div class="pages"> <pagination - total-items="totalItems" - ng-model="currentPage" - items-per-page="itemsPerPage" - max-size="maxSize" + total-items="ctrl.totalItems" + ng-model="ctrl.currentPage" + items-per-page="ctrl.itemsPerPage" + max-size="ctrl.maxSize" class="pagination-sm" boundary-links="true" rotate="false" - num-pages="numPages" - ng-change="update()"> + num-pages="ctrl.numPages" + ng-change="ctrl.update()"> </pagination> </div> </div> -<div ng-show="showError" class="alert alert-danger" role="alert"> +<div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <span class="sr-only">Error:</span> - {{error}} + {{ctrl.error}} </div> diff --git a/refstack-ui/app/components/results/resultsController.js b/refstack-ui/app/components/results/resultsController.js index f74fb92b..5ccccb09 100644 --- a/refstack-ui/app/components/results/resultsController.js +++ b/refstack-ui/app/components/results/resultsController.js @@ -1,107 +1,142 @@ -var refstackApp = angular.module('refstackApp'); - -/** - * Refstack Results Controller - * This controller is for the '/results' page where a user can browse - * a listing of community uploaded results. +/* + * 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. */ -refstackApp.controller('resultsController', - ['$scope', '$http', '$filter', '$state', 'refstackApiUrl', - function ($scope, $http, $filter, $state, refstackApiUrl) { - 'use strict'; - /** Initial page to be on. */ - $scope.currentPage = 1; +(function () { + 'use strict'; - /** - * 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 Refstack server which - * defaults to 20. - */ - $scope.itemsPerPage = 20; + angular + .module('refstackApp') + .controller('ResultsController', ResultsController); - /** - * How many page buttons should be displayed at max before adding - * the '...' button. - */ - $scope.maxSize = 5; + ResultsController.$inject = [ + '$scope', '$http', '$filter', '$state', 'refstackApiUrl' + ]; - /** The upload date lower limit to be used in filtering results. */ - $scope.startDate = ''; + /** + * RefStack 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, refstackApiUrl) { + var ctrl = this; - /** The upload date upper limit to be used in filtering results. */ - $scope.endDate = ''; + ctrl.update = update; + ctrl.open = open; + ctrl.clearFilters = clearFilters; - $scope.isUserResults = $state.current.name === 'userResults'; - if ($scope.isUserResults && !$scope.auth.isAuthenticated) { - $state.go('home'); - } - $scope.pageHeader = $scope.isUserResults ? - 'Private test results' : 'Community test results'; - /** - * This will contact the Refstack API to get a listing of test run - * results. - */ - $scope.update = function () { - $scope.showError = false; - // Construct the API URL based on user-specified filters. - var content_url = refstackApiUrl + '/results?page=' + - $scope.currentPage; - var start = $filter('date')($scope.startDate, 'yyyy-MM-dd'); - if (start) { - content_url = - content_url + '&start_date=' + start + ' 00:00:00'; - } - var end = $filter('date')($scope.endDate, 'yyyy-MM-dd'); - if (end) { - content_url = content_url + '&end_date=' + end + ' 23:59:59'; - } - if ($scope.isUserResults) { - content_url = content_url + '&signed'; - } - $scope.resultsRequest = - $http.get(content_url).success(function (data) { - $scope.data = data; - $scope.totalItems = $scope.data.pagination.total_pages * - $scope.itemsPerPage; - $scope.currentPage = $scope.data.pagination.current_page; - }).error(function (error) { - $scope.data = null; - $scope.totalItems = 0; - $scope.showError = true; - $scope.error = - 'Error retrieving results listing from server: ' + - JSON.stringify(error); - }); - }; - if ($scope.isUserResults) { - $scope.authRequest = $scope.auth.doSignCheck() - .then($scope.update); - } else { - $scope.update(); - } + /** Initial page to be on. */ + ctrl.currentPage = 1; - /** - * 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 - */ - $scope.open = function ($event, openVar) { - $event.preventDefault(); - $event.stopPropagation(); - $scope[openVar] = true; - }; + /** + * 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 Refstack server which + * defaults to 20. + */ + ctrl.itemsPerPage = 20; - /** - * This function will clear all filters and update the results - * listing. - */ - $scope.clearFilters = function () { - $scope.startDate = null; - $scope.endDate = null; - $scope.update(); - }; - }]); + /** + * 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'; + + // 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'; + + if (ctrl.isUserResults) { + ctrl.authRequest = $scope.auth.doSignCheck() + .then(ctrl.update); + } else { + ctrl.update(); + } + + /** + * This will contact the Refstack 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 = refstackApiUrl + '/results' + + '?page=' + ctrl.currentPage; + var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd'); + if (start) { + content_url = + content_url + '&start_date=' + start + ' 00:00:00'; + } + var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd'); + if (end) { + content_url = content_url + '&end_date=' + 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(); + } + } +})(); diff --git a/refstack-ui/app/shared/alerts/alertModal.html b/refstack-ui/app/shared/alerts/alertModal.html index 7aee7921..59fd5001 100644 --- a/refstack-ui/app/shared/alerts/alertModal.html +++ b/refstack-ui/app/shared/alerts/alertModal.html @@ -1,8 +1,8 @@ <div class="modal-body" style="padding:0px"> - <div class="alert alert-{{::data.mode}}" style="margin-bottom:0px"> - <button type="button" class="close" data-ng-click="close()" > + <div class="alert alert-{{alert.data.mode}}" style="margin-bottom:0px"> + <button type="button" class="close" data-ng-click="alert.close()" > <span class="glyphicon glyphicon-remove-circle"></span> </button> - <strong>{{::data.title}}</strong> {{::data.text}} + <strong>{{alert.data.title}}</strong> {{alert.data.text}} </div> -</div> \ No newline at end of file +</div> diff --git a/refstack-ui/app/shared/alerts/alertModalFactory.js b/refstack-ui/app/shared/alerts/alertModalFactory.js index abeff4ae..f2a6a6b1 100644 --- a/refstack-ui/app/shared/alerts/alertModalFactory.js +++ b/refstack-ui/app/shared/alerts/alertModalFactory.js @@ -1,12 +1,35 @@ -var refstackApp = angular.module('refstackApp'); +/* + * 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. + */ -refstackApp.factory('raiseAlert', - ['$modal', function($modal) { - 'use strict'; +(function () { + 'use strict'; + + angular + .module('refstackApp') + .factory('raiseAlert', raiseAlert); + + raiseAlert.$inject = ['$modal']; + + /** + * This allows alert pop-ups to be raised. Just inject it as a dependency + * in the calling controller. + */ + function raiseAlert($modal) { return function(mode, title, text) { $modal.open({ templateUrl: '/shared/alerts/alertModal.html', - controller: 'raiseAlertModalController', + controller: 'RaiseAlertModalController as alert', backdrop: true, keyboard: true, backdropClick: true, @@ -22,20 +45,30 @@ refstackApp.factory('raiseAlert', } }); }; - }] -); + } + angular + .module('refstackApp') + .controller('RaiseAlertModalController', RaiseAlertModalController); -refstackApp.controller('raiseAlertModalController', - ['$scope', '$modalInstance', 'data', - function ($scope, $modalInstance, data) { - 'use strict'; - $scope.data = data; + RaiseAlertModalController.$inject = ['$modalInstance', 'data']; - //wait for users click to close the pop up window. - $scope.close = function() { - $modalInstance.close(); - }; + /** + * This is the controller for the alert pop-up. + */ + function RaiseAlertModalController($modalInstance, 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() { + $modalInstance.close(); } - ] -); + } +})(); diff --git a/refstack-ui/app/shared/filters.js b/refstack-ui/app/shared/filters.js index 6b3cb9a5..84b171b6 100644 --- a/refstack-ui/app/shared/filters.js +++ b/refstack-ui/app/shared/filters.js @@ -1,31 +1,53 @@ -var refstackApp = angular.module('refstackApp'); - -/** Refstack AngularJS Filters */ - -/** - * Convert an object of objects to an array of objects to use with ng-repeat - * filters. +/* + * 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. */ -refstackApp.filter('arrayConverter', function () { + +(function () { 'use strict'; - return function (objects) { - var array = []; - angular.forEach(objects, function (object, key) { - object.id = key; - array.push(object); - }); - return array; - }; -}); + /** + * Convert an object of objects to an array of objects to use with ng-repeat + * filters. + */ + angular + .module('refstackApp') + .filter('arrayConverter', arrayConverter); -/** - * Angular filter that will capitalize the first letter of a string. - */ -refstackApp.filter('capitalize', function() { - 'use strict'; + /** + * 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) { + object.id = key; + array.push(object); + }); + return array; + }; + } - return function (string) { - return string.substring(0, 1).toUpperCase() + string.substring(1); - }; -}); + angular + .module('refstackApp') + .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/refstack-ui/app/shared/header/header.html b/refstack-ui/app/shared/header/header.html index 2809563c..16f67d99 100644 --- a/refstack-ui/app/shared/header/header.html +++ b/refstack-ui/app/shared/header/header.html @@ -1,11 +1,11 @@ <div class="heading"><a ui-sref="home"><img src="assets/img/refstack-logo.png" alt="RefStack"></a> RefStack </div> -<nav class="navbar navbar-default" role="navigation" ng-controller="headerController"> +<nav class="navbar navbar-default" role="navigation" ng-controller="HeaderController as header"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> - <button type="button" class="navbar-toggle collapsed" ng-click="navbarCollapsed = !navbarCollapsed"> + <button type="button" class="navbar-toggle collapsed" ng-click="header.navbarCollapsed = !header.navbarCollapsed"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> @@ -13,12 +13,12 @@ RefStack </button> </div> - <div class="collapse navbar-collapse" id="navbar" collapse="navbarCollapsed"> + <div class="collapse navbar-collapse" id="navbar" collapse="header.navbarCollapsed"> <ul class="nav navbar-nav"> - <li ng-class="{ active: isActive('/')}"><a ui-sref="home">Home</a></li> - <li ng-class="{ active: isActive('/about')}"><a ui-sref="about">About</a></li> - <li ng-class="{ active: isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li> - <li ng-class="{ active: isActive('/community_results')}"><a ui-sref="communityResults">Community Results</a></li> + <li ng-class="{ active: header.isActive('/')}"><a ui-sref="home">Home</a></li> + <li ng-class="{ active: header.isActive('/about')}"><a ui-sref="about">About</a></li> + <li ng-class="{ active: header.isActive('/capabilities')}"><a ui-sref="capabilities">DefCore Capabilities</a></li> + <li ng-class="{ active: header.isActive('/community_results')}"><a ui-sref="communityResults">Community Results</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li ng-class="{ active: isActive('/user_results')}" ng-if="auth.isAuthenticated"><a ui-sref="userResults">My Results</a></li> diff --git a/refstack-ui/app/shared/header/headerController.js b/refstack-ui/app/shared/header/headerController.js index a3235b0d..56b632aa 100644 --- a/refstack-ui/app/shared/header/headerController.js +++ b/refstack-ui/app/shared/header/headerController.js @@ -1,22 +1,44 @@ -var refstackApp = angular.module('refstackApp'); - -/** - * Refstack Header Controller - * This controller is for the header template which contains the site - * navigation. +/* + * 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. */ -refstackApp.controller('headerController', - ['$scope', '$location', function ($scope, $location) { - 'use strict'; + +(function () { + 'use strict'; + + angular + .module('refstackApp') + .controller('HeaderController', HeaderController); + + HeaderController.$inject = ['$location']; + + /** + * Refstack Header Controller + * This controller is for the header template which contains the site + * navigation. + */ + function HeaderController($location) { + var ctrl = this; + + ctrl.isActive = isActive; /** Whether the Navbar is collapsed for small displays. */ - $scope.navbarCollapsed = true; + ctrl.navbarCollapsed = true; /** * This determines whether a button should be in the active state based * on the URL. */ - $scope.isActive = function (viewLocation) { + function isActive(viewLocation) { var path = $location.path().substr(0, viewLocation.length); if (path === viewLocation) { // Make sure "/" only matches when viewLocation is "/". @@ -26,5 +48,6 @@ refstackApp.controller('headerController', } } return false; - }; - }]); + } + } +})(); diff --git a/refstack-ui/tests/unit/ControllerSpec.js b/refstack-ui/tests/unit/ControllerSpec.js index 0318f3dd..784dddf6 100644 --- a/refstack-ui/tests/unit/ControllerSpec.js +++ b/refstack-ui/tests/unit/ControllerSpec.js @@ -9,7 +9,7 @@ describe('Refstack controllers', function () { $provide.constant('refstackApiUrl', fakeApiUrl); }); module('refstackApp'); - inject(function(_$httpBackend_){ + inject(function(_$httpBackend_) { $httpBackend = _$httpBackend_; }); $httpBackend.whenGET(fakeApiUrl + '/profile').respond(401); @@ -17,45 +17,41 @@ describe('Refstack controllers', function () { .respond('<div>mock template</div>'); }); - describe('headerController', function () { - var scope, $location; + describe('HeaderController', function () { + var $location, ctrl; - beforeEach(inject(function ($rootScope, $controller, _$location_) { - scope = $rootScope.$new(); + beforeEach(inject(function ($controller, _$location_) { $location = _$location_; - $controller('headerController', {$scope: scope}); + ctrl = $controller('HeaderController', {}); })); it('should set "navbarCollapsed" to true', function () { - expect(scope.navbarCollapsed).toBe(true); + expect(ctrl.navbarCollapsed).toBe(true); }); it('should have a function to check if the URL path is active', function () { $location.path('/'); expect($location.path()).toBe('/'); - expect(scope.isActive('/')).toBe(true); - expect(scope.isActive('/about')).toBe(false); + expect(ctrl.isActive('/')).toBe(true); + expect(ctrl.isActive('/about')).toBe(false); $location.path('/results?cpid=123&foo=bar'); expect($location.path()).toBe('/results?cpid=123&foo=bar'); - expect(scope.isActive('/results')).toBe(true); + expect(ctrl.isActive('/results')).toBe(true); }); }); - describe('capabilitiesController', function () { - var scope; + describe('CapabilitiesController', function () { + var ctrl; - beforeEach(inject(function ($rootScope, $controller) { - scope = $rootScope.$new(); - $controller('capabilitiesController', {$scope: scope}); + beforeEach(inject(function ($controller) { + ctrl = $controller('CapabilitiesController', {}); })); it('should set default states', function () { - expect(scope.hideAchievements).toBe(true); - expect(scope.hideTests).toBe(true); - expect(scope.target).toBe('platform'); - expect(scope.status).toEqual({ + expect(ctrl.target).toBe('platform'); + expect(ctrl.status).toEqual({ required: true, advisory: false, deprecated: false, removed: false }); @@ -84,24 +80,24 @@ describe('Refstack controllers', function () { '/capabilities/2015.04.json').respond(fakeCaps); $httpBackend.flush(); // The version list should be sorted latest first. - expect(scope.versionList).toEqual(['2015.04.json', + expect(ctrl.versionList).toEqual(['2015.04.json', '2015.03.json']); - expect(scope.capabilities).toEqual(fakeCaps); + expect(ctrl.capabilities).toEqual(fakeCaps); var expectedTemplate = 'components/capabilities/partials/' + 'capabilityDetailsV1.3.html'; - expect(scope.detailsTemplate).toEqual(expectedTemplate); + expect(ctrl.detailsTemplate).toEqual(expectedTemplate); var expectedTargetCaps = { 'cap_id_1': 'required', 'cap_id_2': 'advisory', 'cap_id_3': 'deprecated', 'cap_id_4': 'removed' }; - expect(scope.targetCapabilities).toEqual(expectedTargetCaps); + expect(ctrl.targetCapabilities).toEqual(expectedTargetCaps); }); it('should have a function to check if a capability status is selected', function () { - scope.targetCapabilities = { + ctrl.targetCapabilities = { 'cap_id_1': 'required', 'cap_id_2': 'advisory', 'cap_id_3': 'deprecated', @@ -109,12 +105,12 @@ describe('Refstack controllers', function () { }; // Expect only the required capability to return true. - expect(scope.filterStatus({'id': 'cap_id_1'})).toBe(true); - expect(scope.filterStatus({'id': 'cap_id_2'})).toBe(false); - expect(scope.filterStatus({'id': 'cap_id_3'})).toBe(false); - expect(scope.filterStatus({'id': 'cap_id_4'})).toBe(false); + expect(ctrl.filterStatus({'id': 'cap_id_1'})).toBe(true); + expect(ctrl.filterStatus({'id': 'cap_id_2'})).toBe(false); + expect(ctrl.filterStatus({'id': 'cap_id_3'})).toBe(false); + expect(ctrl.filterStatus({'id': 'cap_id_4'})).toBe(false); - scope.status = { + ctrl.status = { required: true, advisory: true, deprecated: true, @@ -122,10 +118,10 @@ describe('Refstack controllers', function () { }; // Every capability should return true now. - expect(scope.filterStatus({'id': 'cap_id_1'})).toBe(true); - expect(scope.filterStatus({'id': 'cap_id_2'})).toBe(true); - expect(scope.filterStatus({'id': 'cap_id_3'})).toBe(true); - expect(scope.filterStatus({'id': 'cap_id_4'})).toBe(true); + expect(ctrl.filterStatus({'id': 'cap_id_1'})).toBe(true); + expect(ctrl.filterStatus({'id': 'cap_id_2'})).toBe(true); + expect(ctrl.filterStatus({'id': 'cap_id_3'})).toBe(true); + expect(ctrl.filterStatus({'id': 'cap_id_4'})).toBe(true); }); it('should have a function to get the length of an object/dict', @@ -138,12 +134,12 @@ describe('Refstack controllers', function () { 'idempotent_id': 'id-5678' } }; - expect(scope.getObjectLength(testObject)).toBe(2); + expect(ctrl.getObjectLength(testObject)).toBe(2); }); }); describe('resultsController', function () { - var scope; + var scope, ctrl; var fakeResponse = { 'pagination': {'current_page': 1, 'total_pages': 2}, 'results': [{ @@ -155,7 +151,7 @@ describe('Refstack controllers', function () { beforeEach(inject(function ($rootScope, $controller) { scope = $rootScope.$new(); - $controller('resultsController', {$scope: scope}); + ctrl = $controller('ResultsController', {$scope: scope}); })); it('should fetch the first page of results with proper URL args', @@ -164,46 +160,46 @@ describe('Refstack controllers', function () { $httpBackend.expectGET(fakeApiUrl + '/results?page=1') .respond(fakeResponse); $httpBackend.flush(); - expect(scope.data).toEqual(fakeResponse); - expect(scope.currentPage).toBe(1); + expect(ctrl.data).toEqual(fakeResponse); + expect(ctrl.currentPage).toBe(1); // Simulate the user adding date filters. - scope.startDate = new Date('2015-03-10T11:51:00'); - scope.endDate = new Date('2015-04-10T11:51:00'); - scope.update(); + ctrl.startDate = new Date('2015-03-10T11:51:00'); + ctrl.endDate = new Date('2015-04-10T11:51:00'); + ctrl.update(); $httpBackend.expectGET(fakeApiUrl + '/results?page=1' + '&start_date=2015-03-10 00:00:00' + '&end_date=2015-04-10 23:59:59') .respond(fakeResponse); $httpBackend.flush(); - expect(scope.data).toEqual(fakeResponse); - expect(scope.currentPage).toBe(1); + expect(ctrl.data).toEqual(fakeResponse); + expect(ctrl.currentPage).toBe(1); }); it('should set an error when results cannot be retrieved', function () { $httpBackend.expectGET(fakeApiUrl + '/results?page=1').respond(404, {'detail': 'Not Found'}); $httpBackend.flush(); - expect(scope.data).toBe(null); - expect(scope.error).toEqual('Error retrieving results listing ' + + expect(ctrl.data).toBe(null); + expect(ctrl.error).toEqual('Error retrieving results listing ' + 'from server: {"detail":"Not Found"}'); - expect(scope.totalItems).toBe(0); - expect(scope.showError).toBe(true); + expect(ctrl.totalItems).toBe(0); + expect(ctrl.showError).toBe(true); }); it('should have an function to clear filters and update the view', function () { - scope.startDate = 'some date'; - scope.endDate = 'some other date'; - scope.clearFilters(); - expect(scope.startDate).toBe(null); - expect(scope.endDate).toBe(null); + ctrl.startDate = 'some date'; + ctrl.endDate = 'some other date'; + ctrl.clearFilters(); + expect(ctrl.startDate).toBe(null); + expect(ctrl.endDate).toBe(null); }); }); - describe('resultsReportController', function () { - var scope, stateparams; + describe('ResultsReportController', function () { + var stateparams, ctrl; var fakeResultResponse = {'results': ['test_id_1']}; var fakeCapabilityResponse = { 'platform': {'required': ['compute']}, @@ -224,11 +220,11 @@ describe('Refstack controllers', function () { } }; - beforeEach(inject(function ($rootScope, $controller) { + beforeEach(inject(function ($controller) { stateparams = {testID: 1234}; - scope = $rootScope.$new(); - $controller('resultsReportController', - {$scope: scope, $stateParams: stateparams}); + ctrl = $controller('ResultsReportController', + {$stateParams: stateparams} + ); })); it('should make all necessary API requests to get results ' + @@ -242,18 +238,18 @@ describe('Refstack controllers', function () { $httpBackend.expectGET(fakeApiUrl + '/capabilities/2015.04.json').respond(fakeCapabilityResponse); $httpBackend.flush(); - expect(scope.resultsData).toEqual(fakeResultResponse); + expect(ctrl.resultsData).toEqual(fakeResultResponse); // The version list should be sorted latest first. - expect(scope.versionList).toEqual(['2015.04.json', + expect(ctrl.versionList).toEqual(['2015.04.json', '2015.03.json']); - expect(scope.capabilityData).toEqual(fakeCapabilityResponse); - expect(scope.schemaVersion).toEqual('1.2'); + expect(ctrl.capabilityData).toEqual(fakeCapabilityResponse); + expect(ctrl.schemaVersion).toEqual('1.2'); }); it('should have a method that creates an object containing each ' + 'relevant capability and its highest priority status', function () { - scope.capabilityData = { + ctrl.capabilityData = { 'schema': '1.3', 'platform': {'required': ['compute', 'object']}, 'components': { @@ -276,16 +272,16 @@ describe('Refstack controllers', function () { 'cap_id_2': 'required', 'cap_id_3': 'advisory' }; - expect(scope.getTargetCapabilities()).toEqual(expected); + expect(ctrl.getTargetCapabilities()).toEqual(expected); }); it('should be able to sort the results into a capability object for ' + 'schema version 1.2', function () { - scope.resultsData = fakeResultResponse; - scope.capabilityData = fakeCapabilityResponse; - scope.schemaVersion = '1.2'; - scope.buildCapabilitiesObject(); + ctrl.resultsData = fakeResultResponse; + ctrl.capabilityData = fakeCapabilityResponse; + ctrl.schemaVersion = '1.2'; + ctrl.buildCapabilitiesObject(); var expectedCapsObject = { 'required': { 'caps': [{ @@ -305,16 +301,16 @@ describe('Refstack controllers', function () { 'removed': {'caps': [], 'count': 0, 'passedCount': 0, 'flagFailCount': 0, 'flagPassCount': 0} }; - expect(scope.caps).toEqual(expectedCapsObject); - expect(scope.requiredPassPercent).toEqual(50); - expect(scope.nonFlagPassCount).toEqual(0); + expect(ctrl.caps).toEqual(expectedCapsObject); + expect(ctrl.requiredPassPercent).toEqual(50); + expect(ctrl.nonFlagPassCount).toEqual(0); }); it('should be able to sort the results into a capability object for ' + 'schema version 1.3', function () { - scope.resultsData = fakeResultResponse; - scope.capabilityData = { + ctrl.resultsData = fakeResultResponse; + ctrl.capabilityData = { 'platform': {'required': ['compute']}, 'schema': '1.3', 'components': { @@ -333,7 +329,7 @@ describe('Refstack controllers', function () { 'action': 'foo', 'date': '2015-03-24', 'reason': 'bar' - }, + }, 'idempotent_id': 'id-1234' }, 'test_id_2': { @@ -343,8 +339,8 @@ describe('Refstack controllers', function () { } } }; - scope.schemaVersion = '1.3'; - scope.buildCapabilitiesObject(); + ctrl.schemaVersion = '1.3'; + ctrl.buildCapabilitiesObject(); var expectedCapsObject = { 'required': { 'caps': [{ @@ -364,9 +360,9 @@ describe('Refstack controllers', function () { 'removed': {'caps': [], 'count': 0, 'passedCount': 0, 'flagFailCount': 0, 'flagPassCount': 0} }; - expect(scope.caps).toEqual(expectedCapsObject); - expect(scope.requiredPassPercent).toEqual(50); - expect(scope.nonFlagPassCount).toEqual(0); + expect(ctrl.caps).toEqual(expectedCapsObject); + expect(ctrl.requiredPassPercent).toEqual(50); + expect(ctrl.nonFlagPassCount).toEqual(0); }); it('should have a method to determine if a test is flagged', @@ -374,30 +370,31 @@ describe('Refstack controllers', function () { var capObj = {'flagged': [ 'test1'], 'tests': ['test1', 'test2']}; - scope.schemaVersion = '1.2'; - expect(scope.isTestFlagged('test1', capObj)).toEqual(true); - expect(scope.isTestFlagged('test2', capObj)).toEqual(false); + ctrl.schemaVersion = '1.2'; + expect(ctrl.isTestFlagged('test1', capObj)).toEqual(true); + expect(ctrl.isTestFlagged('test2', capObj)).toEqual(false); - capObj = {'tests': { - 'test1': { - 'flagged': { - 'action': 'foo', - 'date': '2015-03-24', - 'reason': 'bar' - }, - 'idempotent_id': 'id-1234' - }, - 'test2': { - 'idempotent_id': 'id-5678' - } - } - }; + capObj = { + 'tests': { + 'test1': { + 'flagged': { + 'action': 'foo', + 'date': '2015-03-24', + 'reason': 'bar' + }, + 'idempotent_id': 'id-1234' + }, + 'test2': { + 'idempotent_id': 'id-5678' + } + } + }; - scope.schemaVersion = '1.3'; - expect(scope.isTestFlagged('test1', capObj)).toBeTruthy(); - expect(scope.isTestFlagged('test2', capObj)).toBeFalsy(); + ctrl.schemaVersion = '1.3'; + expect(ctrl.isTestFlagged('test1', capObj)).toBeTruthy(); + expect(ctrl.isTestFlagged('test2', capObj)).toBeFalsy(); - expect(scope.isTestFlagged('test2', null)).toEqual(false); + expect(ctrl.isTestFlagged('test2', null)).toEqual(false); }); it('should have a method to get the reason a flagged test is flagged', @@ -405,27 +402,28 @@ describe('Refstack controllers', function () { var capObj = {'flagged': [ 'test1'], 'tests': ['test1', 'test2']}; - scope.schemaVersion = '1.2'; - expect(scope.getFlaggedReason('test1', capObj)).toEqual( + ctrl.schemaVersion = '1.2'; + expect(ctrl.getFlaggedReason('test1', capObj)).toEqual( 'DefCore has flagged this test.'); // Check that non-flagged test returns empty string. - expect(scope.getFlaggedReason('test2', capObj)).toEqual(''); + expect(ctrl.getFlaggedReason('test2', capObj)).toEqual(''); - capObj = {'tests': { - 'test1': { - 'flagged': { - 'action': 'foo', - 'date': '2015-03-24', - 'reason': 'bar' - }, - 'idempotent_id': 'id-1234' - } - } - }; + capObj = { + 'tests': { + 'test1': { + 'flagged': { + 'action': 'foo', + 'date': '2015-03-24', + 'reason': 'bar' + }, + 'idempotent_id': 'id-1234' + } + } + }; - scope.schemaVersion = '1.3'; - expect(scope.getFlaggedReason('test1', capObj)).toEqual('bar'); + ctrl.schemaVersion = '1.3'; + expect(ctrl.getFlaggedReason('test1', capObj)).toEqual('bar'); }); it('should have a method to determine whether a capability should ' + @@ -445,23 +443,23 @@ describe('Refstack controllers', function () { }]; // Check that all capabilities are shown by default. - expect(scope.isCapabilityShown(caps[0])).toEqual(true); - expect(scope.isCapabilityShown(caps[1])).toEqual(true); + expect(ctrl.isCapabilityShown(caps[0])).toEqual(true); + expect(ctrl.isCapabilityShown(caps[1])).toEqual(true); // Check that only capabilities with passed tests are shown. - scope.testStatus = 'passed'; - expect(scope.isCapabilityShown(caps[0])).toEqual(true); - expect(scope.isCapabilityShown(caps[1])).toEqual(false); + ctrl.testStatus = 'passed'; + expect(ctrl.isCapabilityShown(caps[0])).toEqual(true); + expect(ctrl.isCapabilityShown(caps[1])).toEqual(false); // Check that only capabilities with passed tests are shown. - scope.testStatus = 'not passed'; - expect(scope.isCapabilityShown(caps[0])).toEqual(false); - expect(scope.isCapabilityShown(caps[1])).toEqual(true); + ctrl.testStatus = 'not passed'; + expect(ctrl.isCapabilityShown(caps[0])).toEqual(false); + expect(ctrl.isCapabilityShown(caps[1])).toEqual(true); // Check that only capabilities with flagged tests are shown. - scope.testStatus = 'flagged'; - expect(scope.isCapabilityShown(caps[0])).toEqual(true); - expect(scope.isCapabilityShown(caps[1])).toEqual(false); + ctrl.testStatus = 'flagged'; + expect(ctrl.isCapabilityShown(caps[0])).toEqual(true); + expect(ctrl.isCapabilityShown(caps[1])).toEqual(false); }); it('should have a method to determine whether a test should be shown', @@ -473,13 +471,13 @@ describe('Refstack controllers', function () { 'notPassedFlagged': [] }; - expect(scope.isTestShown('test_id_1', cap)).toEqual(true); - scope.testStatus = 'passed'; - expect(scope.isTestShown('test_id_1', cap)).toEqual(true); - scope.testStatus = 'not passed'; - expect(scope.isTestShown('test_id_1', cap)).toEqual(false); - scope.testStatus = 'flagged'; - expect(scope.isTestShown('test_id_1', cap)).toEqual(true); + expect(ctrl.isTestShown('test_id_1', cap)).toEqual(true); + ctrl.testStatus = 'passed'; + expect(ctrl.isTestShown('test_id_1', cap)).toEqual(true); + ctrl.testStatus = 'not passed'; + expect(ctrl.isTestShown('test_id_1', cap)).toEqual(false); + ctrl.testStatus = 'flagged'; + expect(ctrl.isTestShown('test_id_1', cap)).toEqual(true); }); it('should have a method to determine how many tests in a ' + @@ -493,48 +491,48 @@ describe('Refstack controllers', function () { }; // Should return the count of all tests. - expect(scope.getCapabilityTestCount(cap)).toEqual(7); + expect(ctrl.getCapabilityTestCount(cap)).toEqual(7); // Should return the count of passed tests. - scope.testStatus = 'passed'; - expect(scope.getCapabilityTestCount(cap)).toEqual(3); + ctrl.testStatus = 'passed'; + expect(ctrl.getCapabilityTestCount(cap)).toEqual(3); // Should return the count of failed tests. - scope.testStatus = 'not passed'; - expect(scope.getCapabilityTestCount(cap)).toEqual(4); + ctrl.testStatus = 'not passed'; + expect(ctrl.getCapabilityTestCount(cap)).toEqual(4); // Should return the count of flagged tests. - scope.testStatus = 'flagged'; - expect(scope.getCapabilityTestCount(cap)).toEqual(3); + ctrl.testStatus = 'flagged'; + expect(ctrl.getCapabilityTestCount(cap)).toEqual(3); }); it('should have a method to determine how many tests in a status ' + 'belong under the current test filter', function () { - scope.caps = {'required': {'caps': [], 'count': 10, + ctrl.caps = {'required': {'caps': [], 'count': 10, 'passedCount': 6, 'flagFailCount': 3, 'flagPassCount': 2}}; // Should return the count of all tests (count). - expect(scope.getStatusTestCount('required')).toEqual(10); + expect(ctrl.getStatusTestCount('required')).toEqual(10); // Should return the count of passed tests (passedCount). - scope.testStatus = 'passed'; - expect(scope.getStatusTestCount('required')).toEqual(6); + ctrl.testStatus = 'passed'; + expect(ctrl.getStatusTestCount('required')).toEqual(6); // Should return the count of failed tests // (count - passedCount). - scope.testStatus = 'not passed'; - expect(scope.getStatusTestCount('required')).toEqual(4); + ctrl.testStatus = 'not passed'; + expect(ctrl.getStatusTestCount('required')).toEqual(4); // Should return the count of flagged tests // (flagFailCount + flagPassCount). - scope.testStatus = 'flagged'; - expect(scope.getStatusTestCount('required')).toEqual(5); + ctrl.testStatus = 'flagged'; + expect(ctrl.getStatusTestCount('required')).toEqual(5); // Test when caps has not been set yet. - scope.caps = null; - expect(scope.getStatusTestCount('required')).toEqual(-1); + ctrl.caps = null; + expect(ctrl.getStatusTestCount('required')).toEqual(-1); }); it('should have a method to open a modal for the full passed test list', @@ -544,71 +542,63 @@ describe('Refstack controllers', function () { modal = $modal; }); spyOn(modal, 'open'); - scope.openFullTestListModal(); + ctrl.openFullTestListModal(); expect(modal.open).toHaveBeenCalled(); }); }); - describe('fullTestListModalController', function () { - var scope; - var modalInstance; + describe('FullTestListModalController', function () { + var modalInstance, ctrl; - beforeEach(inject(function ($rootScope, $controller) { - scope = $rootScope.$new(); + beforeEach(inject(function ($controller) { modalInstance = { dismiss: jasmine.createSpy('modalInstance.dismiss') }; - $controller('fullTestListModalController', { - $scope: scope, - $modalInstance: modalInstance, - tests: ['t1', 't2'] - }); + ctrl = $controller('FullTestListModalController', + {$modalInstance: modalInstance, tests: ['t1', 't2']} + ); })); it('should set a scope variable to the passed in tests', function () { - expect(scope.tests).toEqual(['t1', 't2']); + expect(ctrl.tests).toEqual(['t1', 't2']); }); it('should have a method to close the modal', function () { - scope.close(); + ctrl.close(); expect(modalInstance.dismiss).toHaveBeenCalledWith('exit'); }); it('should have a method to convert the tests to a string', function () { - scope.tests = ['t2', 't1', 't3']; + ctrl.tests = ['t2', 't1', 't3']; var expectedString = 't1\nt2\nt3'; - expect(scope.getTestListString()).toEqual(expectedString); + expect(ctrl.getTestListString()).toEqual(expectedString); }); }); - describe('testRaiseAlertModalController', function() { - var data; - var scope, modalInstance; + describe('TestRaiseAlertModalController', function() { + var data, modalInstance, ctrl; data = { - mode: 'success', - title: '', - text: 'operation successful' - }; + mode: 'success', + title: '', + text: 'operation successful' + }; - beforeEach(inject(function ($rootScope, $controller) { - scope = $rootScope.$new(); + beforeEach(inject(function ($controller) { modalInstance = { dismiss: jasmine.createSpy('modalInstance.dismiss'), close: jasmine.createSpy('modalInstance.close') }; - $controller('raiseAlertModalController', { - $scope: scope, - $modalInstance: modalInstance, - data: data - }); + ctrl = $controller('RaiseAlertModalController', + {$modalInstance: modalInstance, data: data} + ); })); it('should close', function () { - scope.close(); + ctrl.close(); expect(modalInstance.close).toHaveBeenCalledWith(); }); });