From 44c6bca6f0ab8ec3fc3fb02ab570db29f24423a4 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Thu, 26 Sep 2013 01:50:01 -0400 Subject: [PATCH] Fixed 'refresh' routine to refresh on the current url (which includes current page, sort and search criteria). In other words refresh now respects the current page state rather than resetting it back to thebeginning. Also added first attempt at a dashboard and widget. --- awx/ui/static/js/app.js | 22 +-- .../static/js/controllers/Authentication.js | 2 +- awx/ui/static/js/controllers/Home.js | 29 ++++ awx/ui/static/js/controllers/Jobs.js | 8 +- awx/ui/static/js/controllers/Projects.js | 8 +- awx/ui/static/js/helpers/refresh.js | 1 + awx/ui/static/js/widgets/ObjectCount.js | 131 ++++++++++++++++++ awx/ui/static/less/ansible-ui.less | 7 + awx/ui/static/partials/home.html | 10 ++ awx/ui/templates/ui/index.html | 5 +- 10 files changed, 205 insertions(+), 18 deletions(-) create mode 100644 awx/ui/static/js/controllers/Home.js create mode 100644 awx/ui/static/js/widgets/ObjectCount.js create mode 100644 awx/ui/static/partials/home.html diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index bf11eb7130..2a02013c9d 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -68,7 +68,8 @@ angular.module('ansible', [ 'SelectionHelper', 'LicenseFormDefinition', 'License', - 'HostGroupsFormDefinition' + 'HostGroupsFormDefinition', + 'ObjectCountWidget' ]) .config(['$routeProvider', function($routeProvider) { $routeProvider. @@ -228,13 +229,15 @@ angular.module('ansible', [ when('/login', { templateUrl: urlPrefix + 'partials/organizations.html', controller: Authenticate }). when('/logout', { templateUrl: urlPrefix + 'partials/organizations.html', controller: Authenticate }). + + when('/home', { templateUrl: urlPrefix + 'partials/home.html', controller: Home }). - otherwise({redirectTo: '/'}); + otherwise({redirectTo: '/home'}); }]) .run(['$cookieStore', '$rootScope', 'CheckLicense', '$location', 'Authorization','LoadBasePaths', 'ViewLicense', function($cookieStore, $rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense) { - LoadBasePaths(); + LoadBasePaths(); if ( !(typeof $AnsibleConfig.refresh_rate == 'number' && $AnsibleConfig.refresh_rate >= 3 && $AnsibleConfig.refresh_rate <= 99) ) { @@ -266,12 +269,12 @@ angular.module('ansible', [ // Make the correct tab active var base = $location.path().replace(/^\//,'').split('/')[0]; if (base == '') { - $('.nav-tabs a[href="#' + 'organizations' + '"]').tab('show'); + base = 'home'; } else { - base.replace(/\_/g,' '); - $('.nav-tabs a[href="#' + base + '"]').tab('show'); + base.replace(/\_/g,' '); } + $('.nav-tabs a[href="#' + base + '"]').tab('show'); }); if (!Authorization.getToken()) { @@ -284,14 +287,13 @@ angular.module('ansible', [ // If browser refresh, activate the correct tab var base = ($location.path().replace(/^\//,'').split('/')[0]); if (base == '') { - base = 'organizations'; - $location.path('/organizations'); - $('.nav-tabs a[href="#' + base + '"]').tab('show'); + base = 'home'; + $location.path('/home'); } else { base.replace(/\_/g,' '); - $('.nav-tabs a[href="#' + base + '"]').tab('show'); } + $('.nav-tabs a[href="#' + base + '"]').tab('show'); $rootScope.viewCurrentUser = function() { $location.path('/users/' + $rootScope.current_user.id); diff --git a/awx/ui/static/js/controllers/Authentication.js b/awx/ui/static/js/controllers/Authentication.js index 4d45cfd054..27614053fc 100644 --- a/awx/ui/static/js/controllers/Authentication.js +++ b/awx/ui/static/js/controllers/Authentication.js @@ -74,7 +74,7 @@ function Authenticate($cookieStore, $window, $scope, $rootScope, $location, Auth Authorization.getLicense() .success(function(data, status, headers, config) { Authorization.setLicense(data['license_info']); - $location.path('/organizations'); + $location.url('/home?login=true'); }) .error(function(data, status, headers, config) { Alert('Error', 'Failed to access user information. GET returned status: ' + status, 'alert-danger', setLoginFocus); diff --git a/awx/ui/static/js/controllers/Home.js b/awx/ui/static/js/controllers/Home.js new file mode 100644 index 0000000000..3d3e142cd8 --- /dev/null +++ b/awx/ui/static/js/controllers/Home.js @@ -0,0 +1,29 @@ +/************************************ + * Copyright (c) 2013 AnsibleWorks, Inc. + * + * + * Home.js + * + * Controller functions for Home tab + * + */ + +'use strict'; + +function Home ($routeParams, $scope, $rootScope, $location, Wait, ObjectCount, ClearScope) +{ + //ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior + //scope. + if (!$routeParams['login']) { + Wait('start'); + } + + ObjectCount({ target: 'container1' }); + + if (!$routeParams['login']) { + Wait('stop'); + } + +} + +Home.$inject=[ '$routeParams', '$scope', '$rootScope', '$location', 'Wait', 'ObjectCount', 'ClearScope']; \ No newline at end of file diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index 81b533291d..08a6639462 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -12,7 +12,7 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, - ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate) + ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh) { ClearScope('htmlTemplate'); var list = JobList; @@ -71,7 +71,9 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, LoadBreadCrumbs(); scope.refresh = function() { - scope.search(list.iterator); + scope['jobSearchSpin'] = true; + scope['jobLoading'] = true; + Refresh({ scope: scope, set: 'jobs', iterator: 'job', url: scope['current_url'] }); } scope.refreshJob = scope.refresh; @@ -155,7 +157,7 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, JobsListCtrl.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList', 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', - 'ProcessErrors','GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate' + 'ProcessErrors','GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh' ]; diff --git a/awx/ui/static/js/controllers/Projects.js b/awx/ui/static/js/controllers/Projects.js index 6b09db4f8d..dfa65db951 100644 --- a/awx/ui/static/js/controllers/Projects.js +++ b/awx/ui/static/js/controllers/Projects.js @@ -13,7 +13,7 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, ProjectList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, ProjectStatus, - FormatDate) + FormatDate, Refresh) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -136,7 +136,9 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, } scope.refresh = function() { - scope.search(list.iterator); + scope['projectSearchSpin'] = true; + scope['projectLoading'] = true; + Refresh({ scope: scope, set: 'projects', iterator: 'project', url: scope['current_url'] }); } scope.SCMUpdate = function(project_id) { @@ -158,7 +160,7 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, ProjectsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'ProjectList', 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', - 'GetBasePath', 'SelectionInit', 'ProjectUpdate', 'ProjectStatus', 'FormatDate' ]; + 'GetBasePath', 'SelectionInit', 'ProjectUpdate', 'ProjectStatus', 'FormatDate', 'Refresh' ]; function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, ProjectsForm, diff --git a/awx/ui/static/js/helpers/refresh.js b/awx/ui/static/js/helpers/refresh.js index 6983678a51..0a6c29d0c1 100644 --- a/awx/ui/static/js/helpers/refresh.js +++ b/awx/ui/static/js/helpers/refresh.js @@ -23,6 +23,7 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities']) var iterator = params.iterator; var url = params.url; + scope.current_url = url; Rest.setUrl(url); Rest.get() .success( function(data, status, headers, config) { diff --git a/awx/ui/static/js/widgets/ObjectCount.js b/awx/ui/static/js/widgets/ObjectCount.js new file mode 100644 index 0000000000..16689b6473 --- /dev/null +++ b/awx/ui/static/js/widgets/ObjectCount.js @@ -0,0 +1,131 @@ +/********************************************* + * Copyright (c) 2013 AnsibleWorks, Inc. + * + * ObjectCount.js + * + * Dashboard widget showing object counts and license availability. + * + */ + + +angular.module('ObjectCountWidget', ['RestServices', 'Utilities']) + .factory('ObjectCount', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', + function($rootScope, $compile, Rest, GetBasePath, ProcessErrors, Wait) { + return function(params) { + + var current_version; + var scope = $rootScope.$new(); + var counts = []; + var target = params.target; + + scope.$on('countReady', function(e, obj, count) { + var keys=[]; + var hash = {}; + if (counts.length == 10) { + // sort the list of objs + for (var i=0; i < counts.length; i++) { + for (var key in counts[i]) { + if (key !== 'hosts' && key !== 'groups') { + keys.push(key); + } + hash[key] = counts[i][key]; + } + } + // sort the keys, forcing groups and hosts to appear directlry after inventory + keys.sort(); + var new_keys = []; + for (var i=0; i < keys.length; i++) { + if (keys[i] == 'inventory') { + new_keys.push('inventory'); + new_keys.push('groups'); + new_keys.push('hosts'); + } + else { + new_keys.push(keys[i]); + } + } + keys = new_keys; + + var html = "
\n"; + html += "
System Summary
\n"; + html += "
\n"; + html += "\n"; + html += "
\n"; + html += "
\n"; + + var element = angular.element(document.getElementById(target)); + element.html(html); + //scope = element.scope(); // Set scope specific to the element we're compiling, avoids circular reference + // From here use 'scope' to manipulate the form, as the form is not in '$scope' + $compile(element)(scope); + } + }); + + var getCount = function (obj) { + scope.collection = (obj == 'inventory') ? 'inventories' : obj; + var url = current_version + scope.collection + '/'; + Rest.setUrl(url); + Rest.get() + .success( function(data, status, headers, config) { + var count = {}; + count[obj] = data.count; + counts.push(count); + scope.$emit('countReady'); + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to get count for ' + obj + '. GET status: ' + status }); + }); + } + + Rest.setUrl('/api/'); + Rest.get() + .success( function(data, status, headers, config) { + + current_version = data.current_version; + + Rest.setUrl(current_version); + Rest.get() + .success( function(data, status, headers, config) { + for (obj in data) { + if (obj !== 'me' && obj !== 'authtoken' && obj !== 'config') { + getCount(obj); + } + } + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to get ' + current_version + '. GET status: ' + status }); + }) + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to get /api/. GET status: ' + status }); + }); + } + }]); diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index da323a429a..986b070f0c 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -25,10 +25,17 @@ body { /* Helper Classes */ .pad-right-sm { padding-right: 10px; } +.pad-left-md { padding-left: 30px; } .pad-left-lg { padding-left: 50px; } .normal-weight { font-weight: normal; } .no-bullets { list-style: none; } +.capitalize { text-transform: capitalize; } +.grey-txt { color: @grey; } +.success-badge { + color: #ffffff; + background-color: #5cb85c; +} .bold-text .checkbox-inline { font-weight: bold; diff --git a/awx/ui/static/partials/home.html b/awx/ui/static/partials/home.html new file mode 100644 index 0000000000..62dda61343 --- /dev/null +++ b/awx/ui/static/partials/home.html @@ -0,0 +1,10 @@ +
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 1bfbae090f..db89e31f6a 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -42,6 +42,7 @@ + @@ -104,6 +105,7 @@ + @@ -140,7 +142,8 @@