From 06abf29d5071144811560204b8b235eb015bd81a Mon Sep 17 00:00:00 2001 From: chris Houseknecht Date: Thu, 16 Jan 2014 05:00:22 -0500 Subject: [PATCH] Activity stream: implemented new search. Fixed a bunch of things related to the new data structure. Fixed /home/groups page. --- awx/ui/static/js/controllers/Home.js | 16 ++++--- awx/ui/static/js/helpers/Groups.js | 11 ++--- awx/ui/static/js/helpers/search.js | 33 +++++++++++---- awx/ui/static/js/lists/HomeGroups.js | 11 ++--- awx/ui/static/js/lists/Streams.js | 45 ++++++++++---------- awx/ui/static/js/widgets/Stream.js | 46 +++++++++++++-------- awx/ui/static/less/ansible-ui.less | 1 + awx/ui/static/lib/ansible/list-generator.js | 2 +- 8 files changed, 97 insertions(+), 68 deletions(-) diff --git a/awx/ui/static/js/controllers/Home.js b/awx/ui/static/js/controllers/Home.js index be3c741807..993f6638d9 100644 --- a/awx/ui/static/js/controllers/Home.js +++ b/awx/ui/static/js/controllers/Home.js @@ -95,7 +95,7 @@ Home.$inject=['$scope', '$compile', '$routeParams', '$rootScope', '$location', ' function HomeGroups ($location, $routeParams, HomeGroupList, GenerateList, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, - GetBasePath, SearchInit, PaginateInit, FormatDate, HostsStatusMsg, GetSyncStatusMsg, ViewUpdateStatus, Stream) { + GetBasePath, SearchInit, PaginateInit, FormatDate, GetHostsStatusMsg, GetSyncStatusMsg, ViewUpdateStatus, Stream) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -122,7 +122,7 @@ function HomeGroups ($location, $routeParams, HomeGroupList, GenerateList, Proce // Set values for Failed Hosts column scope.home_groups[i].failed_hosts = scope.home_groups[i].hosts_with_active_failures + ' / ' + scope.home_groups[i].total_hosts; - msg = HostsStatusMsg({ + msg = GetHostsStatusMsg({ active_failures: scope.home_groups[i].hosts_with_active_failures, total_hosts: scope.home_groups[i].total_hosts, inventory_id: scope.home_groups[i].inventory, @@ -135,7 +135,8 @@ function HomeGroups ($location, $routeParams, HomeGroupList, GenerateList, Proce scope.home_groups[i].failed_hosts_link = msg['url']; scope.home_groups[i].failed_hosts_class = msg['class']; scope.home_groups[i].status = update_status['status']; - scope.home_groups[i].source = scope.groups[i].summary_fields.inventory_source.source; + scope.home_groups[i].source = (scope.home_groups[i].summary_fields.inventory_source) ? + scope.home_groups[i].summary_fields.inventory_source.source : null; scope.home_groups[i].last_updated = last_update; scope.home_groups[i].status_badge_class = update_status['class']; scope.home_groups[i].status_badge_tooltip = update_status['tooltip']; @@ -205,12 +206,17 @@ function HomeGroups ($location, $routeParams, HomeGroupList, GenerateList, Proce LoadBreadCrumbs(); scope.showActivity = function() { Stream(); } - scope.viewUpdateStatus = function(id) { ViewUpdateStatus({ scope: scope, group_id: id }) }; + + scope.viewUpdateStatus = function(id) { + scope.groups = scope.home_groups; + ViewUpdateStatus({ scope: scope, tree_id: id }) + }; } HomeGroups.$inject = [ '$location', '$routeParams', 'HomeGroupList', 'GenerateList', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', - 'ClearScope', 'GetBasePath', 'SearchInit', 'PaginateInit', 'FormatDate', 'HostsStatusMsg', 'GetSyncStatusMsg', 'ViewUpdateStatus', 'Stream' + 'ClearScope', 'GetBasePath', 'SearchInit', 'PaginateInit', 'FormatDate', 'GetHostsStatusMsg', 'GetSyncStatusMsg', 'ViewUpdateStatus', + 'Stream' ]; diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 8caf3a9720..41017e3ac7 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -93,7 +93,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' var found = false; var group = Find({ list: scope.groups, key: 'id', val: tree_id }); - scope.showHosts(tree_id, group_id, false); + if (scope.showHosts) { + if (scope.selected_tree_id !== tree_id) + scope.showHosts(tree_id, group_id, false); + } if (group) { if (Empty(group.source)) { @@ -141,9 +144,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' // Return values for use on host status indicator if (active_failures > 0) { - tip = active_failures + - [ (active_failures == 1) ? ' host' : ' hosts' ] + ' with failed jobs.' + - [ (active_failures == 1) ? ' host' : ' hosts' ] + '.'; + tip = total_hosts + ( (total_hosts == 1) ? ' host' : ' hosts' ) + '. ' + active_failures + ' with failed jobs.'; html_class = 'true'; failures = true; } @@ -156,7 +157,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } else { // many hosts with 0 failures - tip = 'No job failures'; + tip = total_hosts + ( (total_hosts == 1) ? ' host' : ' hosts' ) + '. No job failures'; html_class = 'false'; } } diff --git a/awx/ui/static/js/helpers/search.js b/awx/ui/static/js/helpers/search.js index ec96e43a6d..c235675787 100644 --- a/awx/ui/static/js/helpers/search.js +++ b/awx/ui/static/js/helpers/search.js @@ -249,7 +249,8 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) } Refresh({ scope: scope, set: set, iterator: iterator, url: url }); }); - + + /* if (scope.removeFoundObject) { scope.removeFoundObject(); } @@ -269,8 +270,9 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) scope.$emit('prepareSearch2', iterator, page, load, spin); } }); + */ - if (scope.removeResultWarning) { + /*if (scope.removeResultWarning) { scope.removeResultWarning(); } scope.removeResultWarning = scope.$on('resultWarning', function(e, objs, length) { @@ -278,6 +280,7 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) var label = (objs == 'inventory') ? 'inventories' : objs.replace(/s$/,''); Alert('Warning', 'The number of matching ' + label + ' was too large. We limited your search to the first 30.', 'alert-info'); }); + */ if (scope.removePrepareSearch) { scope.removePrepareSearch(); @@ -293,6 +296,7 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) var modifier; // Determine how many object values we're dealing with. + /* expected_objects = 0; found_objects = 0; for (var i=1; i <= widgets; i++) { @@ -305,18 +309,27 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) expected_objects++; } } + */ for (var i=1; i <= widgets; i++) { var modifier = (i == 1) ? '' : i; if ( $('#search-widget-container' + modifier) ) { if (list.fields[scope[iterator + 'SearchField' + modifier]] && list.fields[scope[iterator + 'SearchField' + modifier]].searchObject) { + // Search field of object type if (list.fields[scope[iterator + 'SearchField' + modifier]].searchObject !== 'all') { + // An object type is selected scope[iterator + 'HideAllStartBtn' + modifier] = false; if (scope[iterator + 'SearchValue' + modifier]) { + // A search value was entered scope[iterator + 'ShowStartBtn' + modifier] = false; - var objs = list.fields[scope[iterator + 'SearchField' + modifier]].searchObject; - var objUrl = GetBasePath('base') + objs + '/?name__icontains=' + scope[iterator + 'SearchValue' + modifier]; + scope[iterator + 'SearchParams'] += '&' + + list.fields[scope[iterator + 'SearchField' + modifier]].searchObject + + '__name__icontains=' + + scope[iterator + 'SearchValue' + modifier]; + + //var objUrl = GetBasePath('base') + objs + '/?name__icontains=' + scope[iterator + 'SearchValue' + modifier]; + /* Rest.setUrl(objUrl); Rest.setHeader({ widget: i }); Rest.setHeader({ object: objs }); @@ -340,10 +353,11 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) { hdr: 'Error!', msg: 'Retrieving list of ' + objs + ' where name contains: ' + scope[iterator + 'SearchValue' + modifier] + ' GET returned status: ' + status }); }); - } + */ + } else { scope[iterator + 'ShowStartBtn' + modifier] = true; - scope.$emit('foundObject', iterator, page, load, spin, i, null); + //scope.$emit('foundObject', iterator, page, load, spin, i, null); } } else { @@ -353,10 +367,11 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) } } } - if (expected_objects == 0) { + scope.$emit('prepareSearch2', iterator, page, load, spin); + //if (expected_objects == 0) { // No search widgets contain objects - scope.$emit('prepareSearch2', iterator, page, load, spin); - } + // scope.$emit('prepareSearch2', iterator, page, load, spin); + //} }); if (scope.removePrepareSearch2) { diff --git a/awx/ui/static/js/lists/HomeGroups.js b/awx/ui/static/js/lists/HomeGroups.js index 8e66c5fce4..48d763c512 100644 --- a/awx/ui/static/js/lists/HomeGroups.js +++ b/awx/ui/static/js/lists/HomeGroups.js @@ -24,7 +24,7 @@ angular.module('HomeGroupListDefinition', []) label: 'Group', ngClick: "\{\{ 'GroupsEdit(' + group.id + ')' \}\}", columnClass: 'col-lg-3 col-md3 col-sm-2', - linkTo: "\{\{ '/#/inventories/' + group.inventory + '/groups/?name=' + group.name \}\}" + linkTo: "\{\{ '/#/inventories/' + group.inventory + '/' \}\}" }, inventory_name: { label: 'Inventory', @@ -36,7 +36,7 @@ angular.module('HomeGroupListDefinition', []) failed_hosts: { label: 'Failed Hosts', ngHref: "\{\{ group.failed_hosts_link \}\}", - badgeIcon: "\{\{ 'icon-failures-' + group.failed_hosts_class \}\}", + badgeIcon: "\{\{ 'fa icon-failures-' + group.failed_hosts_class \}\}", badgeNgHref: "\{\{ group.failed_hosts_link \}\}", badgePlacement: 'left', badgeToolTip: "\{\{ group.failed_hosts_tip \}\}", @@ -51,7 +51,7 @@ angular.module('HomeGroupListDefinition', []) label: 'Status', ngClick: "viewUpdateStatus(\{\{ group.id \}\})", searchType: 'select', - badgeIcon: "\{\{ 'icon-cloud-' + group.status_badge_class \}\}", + badgeIcon: "\{\{ 'fa fa-cloud ' + group.status_badge_class \}\}", badgeToolTip: "\{\{ group.status_badge_tooltip \}\}", awToolTip: "\{\{ group.status_badge_tooltip \}\}", dataPlacement: 'top', @@ -117,9 +117,6 @@ angular.module('HomeGroupListDefinition', []) mode: 'all', ngShow: "user_is_superuser" } - }, - - fieldActions: { - } + }); diff --git a/awx/ui/static/js/lists/Streams.js b/awx/ui/static/js/lists/Streams.js index 1b7b6fdb02..c2b90aed83 100644 --- a/awx/ui/static/js/lists/Streams.js +++ b/awx/ui/static/js/lists/Streams.js @@ -29,12 +29,12 @@ angular.module('StreamListDefinition', []) }, user: { label: 'Initiated by', - ngBindHtml: 'activity.user', - sourceModel: 'user', + //ngBindHtml: 'activity.user', + sourceModel: 'actor', sourceField: 'username', - awToolTip: "\{\{ userToolTip \}\}", - dataPlacement: 'top', - searchPlaceholder: 'Initiated by username', + //awToolTip: "\{\{ userToolTip \}\}", + //dataPlacement: 'top', + searchPlaceholder: 'Username', searchWidget: 1 }, description: { @@ -47,7 +47,7 @@ angular.module('StreamListDefinition', []) label: 'System event', searchOnly: true, searchType: 'isnull', - sourceModel: 'user', + sourceModel: 'actor', sourceField: 'username', searchWidget: 1 }, @@ -60,12 +60,11 @@ angular.module('StreamListDefinition', []) searchObject: 'all', searchPlaceholder: 'All resources', searchWidget: 2, - searchField: 'object1' }, credential_search: { label: 'Credential', searchOnly: true, - searchObject: 'credentials', + searchObject: 'credential', searchPlaceholder: 'Credential name', searchWidget: 2, searchField: 'object1' @@ -73,7 +72,7 @@ angular.module('StreamListDefinition', []) group_search: { label: 'Group', searchOnly: true, - searchObject: 'groups', + searchObject: 'group', searchPlaceholder: 'Group name', searchWidget: 2, searchField: 'object1' @@ -81,7 +80,7 @@ angular.module('StreamListDefinition', []) host_search: { label: 'Host', searchOnly: true, - searchObject: 'hosts', + searchObject: 'host', searchPlaceholder: 'Host name', searchWidget: 2, searchField: 'object1' @@ -89,7 +88,7 @@ angular.module('StreamListDefinition', []) inventory_search: { label: 'Inventory', searchOnly: true, - searchObject: 'inventories', + searchObject: 'inventory', searchPlaceholder: 'Inventory name', searchWidget: 2, searchField: 'object1' @@ -97,7 +96,7 @@ angular.module('StreamListDefinition', []) job_template_search: { label: 'Job Template', searchOnly: true, - searchObject: 'job_templates', + searchObject: 'job_template', searchPlaceholder: 'Job template name', searchWidget: 2, searchField: 'object1' @@ -105,7 +104,7 @@ angular.module('StreamListDefinition', []) organization_search: { label: 'Organization', searchOnly: true, - searchObject: 'organizations', + searchObject: 'organization', searchPlaceholder: 'Organization name', searchWidget: 2, searchField: 'object1' @@ -113,7 +112,7 @@ angular.module('StreamListDefinition', []) project_search: { label: 'Project', searchOnly: true, - searchObject: 'projects', + searchObject: 'project', searchPlaceholder: 'Project name', searchWidget: 2, searchField: 'object1' @@ -121,7 +120,7 @@ angular.module('StreamListDefinition', []) user_search: { label: 'User', searchOnly: true, - searchObject: 'users', + searchObject: 'user', searchPlaceholder: 'Primary username', searchWidget: 2, searchField: 'object1' @@ -140,7 +139,7 @@ angular.module('StreamListDefinition', []) credential_search3: { label: 'Credential', searchOnly: true, - searchObject: 'credentials', + searchObject: 'credential', searchPlaceholder: 'Related credential name', searchWidget: 3, searchField: 'object2' @@ -148,7 +147,7 @@ angular.module('StreamListDefinition', []) group_search3: { label: 'Group', searchOnly: true, - searchObject: 'groups', + searchObject: 'group', searchPlaceholder: 'Related group name', searchWidget: 3, searchField: 'object2' @@ -156,7 +155,7 @@ angular.module('StreamListDefinition', []) host_search3: { label: 'Host', searchOnly: true, - searchObject: 'hosts', + searchObject: 'host', searchPlaceholder: 'Related host name', searchWidget: 3, searchField: 'object2' @@ -164,7 +163,7 @@ angular.module('StreamListDefinition', []) inventory_search3: { label: 'Inventory', searchOnly: true, - searchObject: 'inventories', + searchObject: 'inventory', searchPlaceholder: 'Related inventory name', searchWidget: 3, searchField: 'object2' @@ -172,7 +171,7 @@ angular.module('StreamListDefinition', []) job_template_search3: { label: 'Job Template', searchOnly: true, - searchObject: 'job_templates', + searchObject: 'job_template', searchPlaceholder: 'Related job template name', searchWidget: 3, searchField: 'object2' @@ -180,7 +179,7 @@ angular.module('StreamListDefinition', []) organization_search3: { label: 'Organization', searchOnly: true, - searchObject: 'organizations', + searchObject: 'organization', searchPlaceholder: 'Related organization name', searchWidget: 3, searchField: 'object2' @@ -188,7 +187,7 @@ angular.module('StreamListDefinition', []) project_search3: { label: 'Project', searchOnly: true, - searchObject: 'projects', + searchObject: 'project', searchPlaceholder: 'Related project name', searchWidget: 3, searchField: 'object2' @@ -196,7 +195,7 @@ angular.module('StreamListDefinition', []) user_search3: { label: 'User', searchOnly: true, - searchObject: 'users', + searchObject: 'user', searchPlaceholder: 'Related username', searchWidget: 3, searchField: 'object2' diff --git a/awx/ui/static/js/widgets/Stream.js b/awx/ui/static/js/widgets/Stream.js index b156a14ebb..acee785101 100644 --- a/awx/ui/static/js/widgets/Stream.js +++ b/awx/ui/static/js/widgets/Stream.js @@ -146,16 +146,20 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti }*/ descr += activity.operation; descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed '; - if (activity.summary_fields.object2 && activity.summary_fields.object2.name) { - descr += activity.summary_fields.object2.base + ' ' - + activity.summary_fields.object2.name + '' + [ (activity.operation == 'disassociate') ? ' from ' : ' to ']; + var obj1 = activity.object1; + var obj2 = activity.object2; + if (activity.summary_fields[obj2] && activity.summary_fields[obj2][0].name) { + activity.summary_fields[obj2][0].base = obj2; + descr += obj2 + ' ' + + activity.summary_fields[obj2][0].name + '' + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' ); } else if (activity.object2) { - descr += activity.object2 + [ (activity.operation == 'disassociate') ? ' from ' : ' to ']; + descr += activity.object2[0] + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' ); } - if (activity.summary_fields.object1 && activity.summary_fields.object1.name) { - descr += activity.summary_fields.object1.base + ' ' - + activity.summary_fields.object1.name + ''; + if (activity.summary_fields[obj1] && activity.summary_fields[obj1][0].name) { + activity.summary_fields[obj1][0].base = obj2; + descr += obj1 + ' ' + + activity.summary_fields[obj1][0].name + ''; } else if (activity.object1) { descr += activity.object1; @@ -222,8 +226,6 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti scope.formModalCancelShow = false; scope.formModalInfo = false; //scope.formModalHeader = results.summary_fields.project.name + ' - SCM Status'; - $('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none'); - $('#form-modal').addClass('skinny-modal'); if (!scope.$$phase) { scope.$digest(); } @@ -311,40 +313,48 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti scope['activities'][i].timestamp = FormatDate(cDate); // Display username - scope['activities'][i].user = (scope['activities'][i].summary_fields.user) ? scope['activities'][i].summary_fields.user.username : + /*scope['activities'][i].user = (scope['activities'][i].summary_fields.user) ? scope['activities'][i].summary_fields.user.username : 'system'; if (scope['activities'][i].user !== 'system') { // turn user into a link when not 'system' scope['activities'][i].user = "" + scope['activities'][i].user + ""; + }*/ + if (scope['activities'][i]['summary_fields']['actor']) { + scope['activities'][i]['user'] = scope['activities'][i]['summary_fields']['actor']['username']; + } + else { + scope['activities'][i]['user'] = 'system'; } // Objects var href; var deleted = /^\_delete/; - if (scope['activities'][i].summary_fields.object1 && scope['activities'][i].summary_fields.object1.name) { - if ( !deleted.test(scope['activities'][i].summary_fields.object1.name) ) { + var obj1 = scope['activities'][i].object1; + var obj2 = scope['activities'][i].object2; + if ( obj1 && scope['activities'][i].summary_fields[obj1] && scope['activities'][i].summary_fields[obj1].name) { + if ( !deleted.test(scope['activities'][i].summary_fields[obj1].name) ) { href = BuildUrl(scope['activities'][i].summary_fields.object1); - scope['activities'][i].objects = "" + scope['activities'][i].summary_fields.object1.name + ""; + scope['activities'][i].objects = "" + scope['activities'][i].summary_fields[obj1].name + ""; } else { - scope['activities'][i].objects = scope['activities'][i].summary_fields.object1.name; + scope['activities'][i].objects = scope['activities'][i].summary_fields[obj1].name; } } else if (scope['activities'][i].object1) { scope['activities'][i].objects = scope['activities'][i].object1; } - if (scope['activities'][i].summary_fields.object2 && scope['activities'][i].summary_fields.object2.name) { + if (obj2 && scope['activities'][i].summary_fields[obj2] && scope['activities'][i].summary_fields[obj2].name) { if ( !deleted.test(scope['activities'][i].summary_fields.object2.name) ) { href = BuildUrl(scope['activities'][i].summary_fields.object2); - scope['activities'][i].objects += ", " + scope['activities'][i].summary_fields.object2.name + ""; + scope['activities'][i].objects += ", " + scope['activities'][i].summary_fields[obj2].name + ""; } else { - scope['activities'][i].objects += "," + scope['activities'][i].summary_fields.object2.name; + scope['activities'][i].objects += "," + scope['activities'][i].summary_fields[obj2].name; } } else if (scope['activities'][i].object2) { - scope['activities'][i].objects += ", " + scope['activities'][i].object1; + scope['activities'][i].objects += ", " + scope['activities'][i].object2; } // Description diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index fd54a093f1..d892a03dbf 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -959,6 +959,7 @@ input[type="checkbox"].checkbox-no-label { .field-badge { font-size: 12px; + margin-right: 3px; } .license-warning, diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js index 5d6c9e65cf..1a374f2dfd 100644 --- a/awx/ui/static/lib/ansible/list-generator.js +++ b/awx/ui/static/lib/ansible/list-generator.js @@ -289,7 +289,7 @@ angular.module('ListGenerator', ['GeneratorHelpers']) if (options.mode == 'select' || options.mode == 'lookup') { html += "Select"; } - else if (options.mode == 'edit') { + else if (options.mode == 'edit' && list.fieldActions) { html += "Actions\n";