From 66c044daca578070ad3c5a16f1d9c2f7f4be0daf Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Fri, 4 Apr 2014 15:41:19 -0400 Subject: [PATCH] Applied status field changes to home/groups page. --- awx/ui/static/js/controllers/Home.js | 168 +++++++++++++++++- awx/ui/static/js/helpers/Groups.js | 6 + awx/ui/static/js/lists/CompletedJobs.js | 5 - awx/ui/static/js/lists/HomeGroups.js | 24 +++ awx/ui/static/js/lists/Inventories.js | 2 +- awx/ui/static/js/lists/QueuedJobs.js | 8 +- awx/ui/static/js/lists/RunningJobs.js | 8 +- awx/ui/static/less/ansible-ui.less | 3 +- .../static/lib/ansible/generator-helpers.js | 1 + awx/ui/static/partials/subhome.html | 41 ++++- 10 files changed, 241 insertions(+), 25 deletions(-) diff --git a/awx/ui/static/js/controllers/Home.js b/awx/ui/static/js/controllers/Home.js index 66b97e22ab..09475cfe90 100644 --- a/awx/ui/static/js/controllers/Home.js +++ b/awx/ui/static/js/controllers/Home.js @@ -122,7 +122,7 @@ Home.$inject = ['$scope', '$compile', '$routeParams', '$rootScope', '$location', ]; -function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, +function HomeGroups($filter, $compile, $location, $routeParams, LogViewer, HomeGroupList, GenerateList, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GetBasePath, SearchInit, PaginateInit, FormatDate, GetHostsStatusMsg, GetSyncStatusMsg, ViewUpdateStatus, Stream, GroupsEdit, Wait, Alert, Rest, Empty, InventoryUpdate, Find) { @@ -135,6 +135,35 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces scope = generator.inject(list, { mode: 'edit' }), opt; + function ellipsis(a) { + if (a.length > 20) { + return a.substr(0,20) + '...'; + } + return a; + } + + function attachElem(event, html, title) { + var elem = $(event.target).parent(); + try { + elem.tooltip('hide'); + elem.popover('destroy'); + } + catch(err) { + //ignore + } + elem.attr({ "aw-pop-over": html, "data-title": title, "data-placement": "right" }); + $compile(elem)(scope); + elem.on('shown.bs.popover', function() { + $('.popover').each(function() { + $compile($(this))(scope); //make nested directives work! + }); + $('.popover-content, .popover-title').click(function() { + elem.popover('hide'); + }); + }); + elem.popover('show'); + } + if (scope.removePostRefresh) { scope.removePostRefresh(); } @@ -145,7 +174,9 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces scope.home_groups[i].inventory_name = scope.home_groups[i].summary_fields.inventory.name; stat = GetSyncStatusMsg({ - status: scope.home_groups[i].summary_fields.inventory_source.status + status: scope.home_groups[i].summary_fields.inventory_source.status, + source: scope.home_groups[i].summary_fields.inventory_source.source, + has_inventory_sources: scope.home_groups[i].has_inventory_sources }); // from helpers/Groups.js hosts_status = GetHostsStatusMsg({ @@ -174,6 +205,7 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces list: list, url: defaultUrl }); + PaginateInit({ scope: scope, list: list, @@ -258,7 +290,8 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces scope: scope, group_id: group_id, inventory_id: inventory_id, - groups_reload: false + groups_reload: false, + mode: 'edit' }); }; @@ -306,9 +339,136 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces scope.search(list.iterator, null, false, true); }; + + if (scope.removeHostSummaryReady) { + scope.removeHostSummaryReady(); + } + scope.removeHostSummaryReady = scope.$on('HostSummaryReady', function(e, event, data) { + var html, title = "Recent Jobs", url = GetBasePath('jobs'); + Wait('stop'); + if (data.length > 0) { + html = "\n"; + html += "\n"; + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + html += "\n"; + html += "\n"; + data.forEach(function(row) { + html += "\n"; + html += "\n"; + //html += ""; + html += ""; + html += ""; + html += "\n"; + }); + html += "\n"; + html += "
StatusViewName
" + ($filter('date')(row.finished,'MM/dd HH:mm:ss')).replace(/ /,'
') + "
Events
" + + "Hosts
" + ellipsis(row.name) + "
\n"; + html += "
esc or click to close
\n"; + } + else { + html = "

No recent job data available for this inventory.

\n" + + "
esc or click to close
\n"; + } + attachElem(event, html, title); + }); + + if (scope.removeGroupSummaryReady) { + scope.removeGroupSummaryReady(); + } + scope.removeGroupSummaryReady = scope.$on('GroupSummaryReady', function(e, event, inventory, data) { + var html, title; + + Wait('stop'); + + // Build the html for our popover + html = "\n"; + html += "\n"; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + html += "\n"; + data.results.forEach( function(row) { + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + }); + html += "\n"; + html += "
StatusLast SyncGroup
" + ($filter('date')(row.last_updated,'MM/dd HH:mm:ss')).replace(/ /,'
') + "
" + ellipsis(row.summary_fields.group.name) + "
\n"; + html += "
esc or click to close
\n"; + title = "Sync Status"; + attachElem(event, html, title); + }); + + scope.showGroupSummary = function(event, id) { + var group, status; + if (!Empty(id)) { + group = Find({ list: scope.home_groups, key: 'id', val: id }); + status = group.summary_fields.inventory_source.status; + if (status === 'failed' || status === 'error' || status === 'successful') { + Wait('start'); + Rest.setUrl(group.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5'); + Rest.get() + .success(function(data) { + scope.$emit('GroupSummaryReady', event, group, data); + }) + .error(function(data, status) { + ProcessErrors( scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + group.related.inventory_sources + ' failed. GET returned status: ' + status + }); + }); + } + } + }; + + scope.showHostSummary = function(event, id) { + var url, jobs = []; + if (!Empty(id)) { + Wait('start'); + url = GetBasePath('hosts') + "?groups__id=" + id + "&last_job__isnull=false&order_by=-last_job&page_size=5"; + Rest.setUrl(url); + Rest.get() + .success( function(data) { + data.results.forEach(function(host) { + host.summary_fields.recent_jobs.every(function(job) { + if (job.id === host.last_job) { + jobs.push(job); + return false; + } + return true; + }); + }); + scope.$emit('HostSummaryReady', event, jobs); + }) + .error( function(data, status) { + ProcessErrors( scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. GET returned: ' + status + }); + }); + } + }; + + scope.viewJob = function(url) { + LogViewer({ + scope: scope, + url: url + }); + }; + + } -HomeGroups.$inject = ['$location', '$routeParams', 'HomeGroupList', 'GenerateList', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', +HomeGroups.$inject = ['$filter', '$compile', '$location', '$routeParams', 'LogViewer', 'HomeGroupList', 'GenerateList', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'SearchInit', 'PaginateInit', 'FormatDate', 'GetHostsStatusMsg', 'GetSyncStatusMsg', 'ViewUpdateStatus', 'Stream', 'GroupsEdit', 'Wait', 'Alert', 'Rest', 'Empty', 'InventoryUpdate', 'Find' ]; diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 1400764b25..069e0386e3 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -175,6 +175,12 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' launch_tip = 'Can only be updated by running a sync on the parent group.'; } + if (has_inventory_sources === false && Empty(source)) { + launch_class = 'btn-disabled'; + status_tip = 'Cloud source not configured. Click to update.'; + launch_tip = 'Cloud source not configured.'; + } + return { "class": stat_class, "tooltip": status_tip, diff --git a/awx/ui/static/js/lists/CompletedJobs.js b/awx/ui/static/js/lists/CompletedJobs.js index df2d6fca8a..c4689e7645 100644 --- a/awx/ui/static/js/lists/CompletedJobs.js +++ b/awx/ui/static/js/lists/CompletedJobs.js @@ -45,11 +45,6 @@ angular.module('CompletedJobsDefinition', []) { name: "Canceled", value: "canceled" } ] }, - inventory: { - label: 'Inventory ID', - searchType: 'int', - searchOnly: true - }, finished: { label: 'Finished On', noLink: true, diff --git a/awx/ui/static/js/lists/HomeGroups.js b/awx/ui/static/js/lists/HomeGroups.js index 8229c9840d..2dfe3c6e9d 100644 --- a/awx/ui/static/js/lists/HomeGroups.js +++ b/awx/ui/static/js/lists/HomeGroups.js @@ -21,6 +21,28 @@ angular.module('HomeGroupListDefinition', []) well: true, fields: { + status: { + label: 'Status', + columnClass: 'col-md-2 col-sm-2 col-xs-2', + searchable: false, + nosort: true, + ngClick: "null", + iconOnly: true, + icons: [{ + icon: "{{ 'icon-cloud-' + group.status_class }}", + awToolTip: "{{ group.status_tooltip }}", + dataTipWatch: "group.launch_tooltip", + awTipPlacement: "top", + ngClick: "showGroupSummary($event, group.id)", + ngClass: "group.launch_class" + },{ + icon: "{{ 'icon-job-' + group.hosts_status_class }}", + awToolTip: "{{ group.hosts_status_tip }}", + awTipPlacement: "top", + ngClick: "showHostSummary($event, group.id)", + ngClass: "" + }] + }, name: { key: true, label: 'Group', @@ -82,6 +104,7 @@ angular.module('HomeGroupListDefinition', []) }, fieldActions: { + /* sync_status: { mode: 'all', ngClick: "viewUpdateStatus(group.id, group.group_id)", @@ -96,6 +119,7 @@ angular.module('HomeGroupListDefinition', []) ngHref: "/#/inventories/{{ group.inventory }}/", iconClass: "{{ 'fa icon-failures-' + group.hosts_status_class }}" }, + */ group_update: { //label: 'Sync', mode: 'all', diff --git a/awx/ui/static/js/lists/Inventories.js b/awx/ui/static/js/lists/Inventories.js index 202d0253ba..1f6b18a411 100644 --- a/awx/ui/static/js/lists/Inventories.js +++ b/awx/ui/static/js/lists/Inventories.js @@ -27,7 +27,7 @@ angular.module('InventoriesListDefinition', []) searchable: false, nosort: true, ngClick: "null", - dataTitle: "Sync Status", + iconOnly: true, icons: [{ icon: "{{ 'icon-cloud-' + inventory.syncStatus }}", awToolTip: "{{ inventory.syncTip }}", diff --git a/awx/ui/static/js/lists/QueuedJobs.js b/awx/ui/static/js/lists/QueuedJobs.js index a4b2dbeb8f..ca7b6da22e 100644 --- a/awx/ui/static/js/lists/QueuedJobs.js +++ b/awx/ui/static/js/lists/QueuedJobs.js @@ -36,12 +36,8 @@ angular.module('QueuedJobsDefinition', []) dataTitle: "{{ queued_job.status_popover_title }}", icon: 'icon-job-{{ queued_job.status }}', iconOnly: true, - ngClick:"viewJobLog(queued_job.id)" - }, - inventory: { - label: 'Inventory ID', - searchType: 'int', - searchOnly: true + ngClick:"viewJobLog(queued_job.id)", + searchable: false }, created: { label: 'Created On', diff --git a/awx/ui/static/js/lists/RunningJobs.js b/awx/ui/static/js/lists/RunningJobs.js index a25bc71d6c..fd80aa9701 100644 --- a/awx/ui/static/js/lists/RunningJobs.js +++ b/awx/ui/static/js/lists/RunningJobs.js @@ -36,12 +36,8 @@ angular.module('RunningJobsDefinition', []) dataTitle: "{{ running_job.status_popover_title }}", icon: 'icon-job-{{ running_job.status }}', iconOnly: true, - ngClick:"viewJobLog(running_job.id)" - }, - inventory: { - label: 'Inventory ID', - searchType: 'int', - searchOnly: true + ngClick:"viewJobLog(running_job.id)", + searchable: false }, started: { label: 'Started On', diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 23f04b5152..cf2c6829b5 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -1249,7 +1249,8 @@ input[type="checkbox"].checkbox-no-label { /* Inventory Edit */ - #inventories_table i[class*="icon-job-"] { + #inventories_table i[class*="icon-job-"], + #home_groups_table i[class*="icon-job-"] { margin-left: 8px; } diff --git a/awx/ui/static/lib/ansible/generator-helpers.js b/awx/ui/static/lib/ansible/generator-helpers.js index 05fe0a3e7f..bec62420f2 100644 --- a/awx/ui/static/lib/ansible/generator-helpers.js +++ b/awx/ui/static/lib/ansible/generator-helpers.js @@ -483,6 +483,7 @@ angular.module('GeneratorHelpers', []) html += "aw-pop-over=\"" + field.awPopOver + "\" "; html += (field.dataPlacement) ? "data-placement=\"" + field.dataPlacement + "\" " : ""; } + html += (field.ngClass) ? Attr(field, 'ngClass') : ''; html += ">"; // Add icon: diff --git a/awx/ui/static/partials/subhome.html b/awx/ui/static/partials/subhome.html index 204e551564..61e0bc9f0f 100644 --- a/awx/ui/static/partials/subhome.html +++ b/awx/ui/static/partials/subhome.html @@ -1,4 +1,41 @@
-
-
+
+
+ + + +
\ No newline at end of file