From 1b224f64ac38b20ee290a1d95a2ae878616ce903 Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Mon, 18 Nov 2013 20:03:26 +0000 Subject: [PATCH] Added support for many (unlimited) search widgets on a page. Activity widget now has 2 object search widgets. Adding a setHeader function to Rest.js library. --- awx/ui/static/js/forms/ActivityDetail.js | 5 +- awx/ui/static/js/helpers/search.js | 261 ++++++++++-------- awx/ui/static/js/lists/Streams.js | 127 +++++++-- awx/ui/static/js/widgets/Stream.js | 24 +- awx/ui/static/lib/ansible/RestServices.js | 12 +- .../static/lib/ansible/generator-helpers.js | 119 +++----- awx/ui/static/lib/ansible/list-generator.js | 7 +- 7 files changed, 332 insertions(+), 223 deletions(-) diff --git a/awx/ui/static/js/forms/ActivityDetail.js b/awx/ui/static/js/forms/ActivityDetail.js index b5cadc53d3..b228382f2e 100644 --- a/awx/ui/static/js/forms/ActivityDetail.js +++ b/awx/ui/static/js/forms/ActivityDetail.js @@ -39,7 +39,7 @@ angular.module('ActivityDetailDefinition', []) object1_name: { label: 'Name', type: 'text', - ngHide: '!object1', + ngHide: '!object1_name', readonly: true }, object2: { @@ -51,12 +51,13 @@ angular.module('ActivityDetailDefinition', []) object2_name: { label: 'Name', type: 'text', - ngHide: '!object2', + ngHide: '!object2_name', readonly: true }, changes: { label: 'Changes', type: 'textarea', + ngHide: '!changes', readonly: true } } diff --git a/awx/ui/static/js/helpers/search.js b/awx/ui/static/js/helpers/search.js index a638c524c3..bca7bf816d 100644 --- a/awx/ui/static/js/helpers/search.js +++ b/awx/ui/static/js/helpers/search.js @@ -25,7 +25,9 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) var defaultUrl = params.url; var list = params.list; var iterator = (params.iterator) ? params.iterator : list.iterator; - var sort_order; + var sort_order; + var expected_objects=0; + var found_objects=0; if (scope.searchTimer) { $timeout.cancel(scope.searchTimer); @@ -114,74 +116,68 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) // Functions to handle search widget changes scope.setSearchField = function(iterator, fld, label, widget) { - var modifier = (widget == undefined || widget == 1) ? '' : widget; - scope[iterator + 'SearchFieldLabel' + modifier] = label; - scope[iterator + 'SearchField' + modifier] = fld; - scope[iterator + 'SearchValue' + modifier] = ''; - scope[iterator + 'SelectShow' + modifier] = false; - scope[iterator + 'HideSearchType' + modifier] = false; - scope[iterator + 'InputHide' + modifier] = false; - scope[iterator + 'SearchType' + modifier] = 'icontains'; - scope[iterator + 'SearchPlaceholder' + modifier] = (list.fields[fld].searchPlaceholder) ? list.fields[fld].searchPlaceholder : 'Search'; - scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject == 'all') ? true : false; - - if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') { - scope[iterator + "InputDisable" + modifier] = true; - } - else if (list.fields[fld].searchSingleValue){ - // Query a specific attribute for one specific value - // searchSingleValue: true - // searchType: 'boolean|int|etc.' - // searchValue: < value to match for boolean use 'true'|'false' > - scope[iterator + 'InputDisable' + modifier] = true; - scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue; - // For boolean type, SearchValue must be an object - if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'true') { - scope[iterator + "SearchSelectValue" + modifier] = { value: 1 }; - } - else if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'false') { - scope[iterator + "SearchSelectValue" + modifier] = { value: 0 }; - } - else { - scope[iterator + "SearchSelectValue" + modifier] = { value: list.fields[fld].searchValue }; - } - } - else if (list.fields[fld].searchType == 'in') { - scope[iterator + "SearchType" + modifier] = 'in'; - scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue; - scope[iterator + "InputDisable" + modifier] = true; - } - else if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean' + var modifier = (widget == undefined || widget == 1) ? '' : widget; + scope[iterator + 'SearchFieldLabel' + modifier] = label; + scope[iterator + 'SearchField' + modifier] = fld; + scope[iterator + 'SearchValue' + modifier] = ''; + scope[iterator + 'SelectShow' + modifier] = false; + scope[iterator + 'HideSearchType' + modifier] = false; + scope[iterator + 'InputHide' + modifier] = false; + scope[iterator + 'SearchType' + modifier] = 'icontains'; + scope[iterator + 'SearchPlaceholder' + modifier] = (list.fields[fld].searchPlaceholder) ? list.fields[fld].searchPlaceholder : 'Search'; + scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject == 'all') ? true : false; + + if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') { + scope[iterator + "InputDisable" + modifier] = true; + } + else if (list.fields[fld].searchSingleValue){ + // Query a specific attribute for one specific value + // searchSingleValue: true + // searchType: 'boolean|int|etc.' + // searchValue: < value to match for boolean use 'true'|'false' > + scope[iterator + 'InputDisable' + modifier] = true; + scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue; + // For boolean type, SearchValue must be an object + if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'true') { + scope[iterator + "SearchSelectValue" + modifier] = { value: 1 }; + } + else if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'false') { + scope[iterator + "SearchSelectValue" + modifier] = { value: 0 }; + } + else { + scope[iterator + "SearchSelectValue" + modifier] = { value: list.fields[fld].searchValue }; + } + } + else if (list.fields[fld].searchType == 'in') { + scope[iterator + "SearchType" + modifier] = 'in'; + scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue; + scope[iterator + "InputDisable" + modifier] = true; + } + else if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean' || list.fields[fld].searchType == 'select' || list.fields[fld].searchType == 'select_or')) { - scope[iterator + 'SelectShow' + modifier] = true; - scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[fld].searchOptions; - } - else if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') { - scope[iterator + 'HideSearchType' + modifier] = true; - } - else if (list.fields[fld].searchType && list.fields[fld].searchType == 'isnull') { - scope[iterator + 'SearchType' + modifier] = 'isnull'; - scope[iterator + 'InputDisable' + modifier] = true; - scope[iterator + 'SearchValue' + modifier] = 'true'; - } - scope.search(iterator); - } + scope[iterator + 'SelectShow' + modifier] = true; + scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[fld].searchOptions; + } + else if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') { + scope[iterator + 'HideSearchType' + modifier] = true; + } + else if (list.fields[fld].searchType && list.fields[fld].searchType == 'isnull') { + scope[iterator + 'SearchType' + modifier] = 'isnull'; + scope[iterator + 'InputDisable' + modifier] = true; + scope[iterator + 'SearchValue' + modifier] = 'true'; + } + scope.search(iterator); + } scope.resetSearch = function(iterator, widget) { - // Respdond to click of reset button - setDefaults(widget); - // Force removal of search keys from the URL - window.location = '/#' + $location.path(); - scope.search(iterator); - } - - //scope.setSearchType = function(iterator, type, label) { - // scope[iterator + 'SearchTypeLabel'] = label; - // scope[iterator + 'SearchType'] = type; - // scope.search(iterator); - // } - + // Respdond to click of reset button + setDefaults(widget); + // Force removal of search keys from the URL + window.location = '/#' + $location.path(); + scope.search(iterator); + } + if (scope.removeDoSearch) { scope.removeDoSearch(); } @@ -212,85 +208,126 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) Refresh({ scope: scope, set: set, iterator: iterator, url: url }); }); - + if (scope.removeFoundObject) { + scope.removeFoundObject(); + } + scope.removeFoundObject = scope.$on('foundObject', function(e, iterator, page, load, spin, widget, pk) { + found_objects++; + // Add new criteria to search params + var modifier = (widget == 1) ? '' : widget; + var objs = list.fields[scope[iterator + 'SearchField' + modifier]].searchObject; + var o = (objs == 'inventories') ? 'inventory' : objs.replace(/s$/,''); + var searchFld = list.fields[scope[iterator + 'SearchField' + modifier]].searchField; + scope[iterator + 'SearchParams'] += '&' + searchFld + '__icontains=' + o; + if (!Empty(pk)) { + scope[iterator + 'SearchParams'] += '&' + searchFld + '_id__in=' + pk; + } + // Move to the next phase once all object types are processed + if (found_objects == expected_objects) { + scope.$emit('prepareSearch2', iterator, page, load, spin); + } + }); + if (scope.removePrepareSearch) { scope.removePrepareSearch(); } scope.removePrepareSearch = scope.$on('prepareSearch', function(e, iterator, page, load, spin) { // - // Start build the search key/value pairs. This will process the first search widget, if the + // Start build the search key/value pairs. This will process search widget, if the // selected field is an object type (used on activity stream). // - scope[iterator + 'HoldInput'] = true; scope[iterator + 'SearchParams'] = ''; - if (list.fields[scope[iterator + 'SearchField']].searchObject && - list.fields[scope[iterator + 'SearchField']].searchObject !== 'all') { - //This is specifically for activity stream. We need to identify which type of object is being searched - //and then provide a list of PK values corresponding to the list of objects the user is interested in. - var objs = list.fields[scope[iterator + 'SearchField']].searchObject; - var o = (objs == 'inventories') ? 'inventory' : objs.replace(/s$/,''); - scope[iterator + 'SearchParams'] = 'or__object1=' + o + '&or__object2=' + o; - if (scope[iterator + 'SearchValue']) { - var objUrl = GetBasePath('base') + objs + '/?name__icontains=' + scope[iterator + 'SearchValue']; - Rest.setUrl(objUrl); - Rest.get() - .success( function(data, status, headers, config) { - var list=''; - for (var i=0; i < data.results.length; i++) { - list += "," + data.results[i].id; - } - list = list.replace(/^\,/,''); - if (!Empty(list)) { - scope[iterator + 'SearchParams'] += '&or__object1_id__in=' + list + '&or__object2_id__in=' + list; - } - //scope[iterator + 'SearchParams'] += (sort_order) ? '&order_by=' + escape(sort_order) : ""; - scope.$emit('prepareSearch2', iterator, page, load, spin, 2); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Retrieving list of ' + obj + ' where name contains: ' + scope[iterator + 'SearchValue'] + - ' GET returned status: ' + status }); - }); - } - else { - scope.$emit('prepareSearch2', iterator, page, load, spin, 2); + var widgets = (list.searchWidgets) ? list.searchWidgets : 1; + var modifier; + + // Determine how many object values we're dealing with. + expected_objects = 0; + found_objects = 0; + for (var i=1; i <= widgets; i++) { + modifier = (i == 1) ? '' : i; + if ($('#search-widget-container' + modifier) && + list.fields[scope[iterator + 'SearchField' + modifier]] && + list.fields[scope[iterator + 'SearchField' + modifier]].searchObject && + list.fields[scope[iterator + 'SearchField' + modifier]].searchObject !== 'all') { + expected_objects++; } } - else { - scope.$emit('prepareSearch2', iterator, page, load, spin, 1); + + 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 && + list.fields[scope[iterator + 'SearchField' + modifier]].searchObject !== 'all') { + scope[iterator + 'HoldInput' + modifier] = true; + if (scope[iterator + 'SearchValue' + modifier]) { + var objs = list.fields[scope[iterator + 'SearchField' + modifier]].searchObject; + var objUrl = GetBasePath('base') + objs + '/?name__icontains=' + scope[iterator + 'SearchValue']; + Rest.setUrl(objUrl); + Rest.get() + .success( function(data, status, headers, config) { + var pk=''; + for (var j=0; j < data.results.length; j++) { + pk += "," + data.results[j].id; + } + pk = pk.replace(/^\,/,''); + console.log(config); + scope.$emit('foundObject', iterator, page, load, spin, i, pk); + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Retrieving list of ' + obj + ' where name contains: ' + scope[iterator + 'SearchValue'] + + ' GET returned status: ' + status }); + }); + } + else { + scope.$emit('foundObject', iterator, page, load, spin, i, null); + } + } + } + } + if (expected_objects == 0) { + // No search widgets contain objects + scope.$emit('prepareSearch2', iterator, page, load, spin); } }); if (scope.removePrepareSearch2) { scope.removePrepareSearch2(); } - scope.removePrepareSearch2 = scope.$on('prepareSearch2', function(e, iterator, page, load, spin, startingWidget) { + scope.removePrepareSearch2 = scope.$on('prepareSearch2', function(e, iterator, page, load, spin) { // Continue building the search by examining the remaining search widgets. If we're looking at activity_stream, // there's more than one. - for (var i=startingWidget; i <= 3; i++) { - var modifier = (i == 1) ? '' : i; + var widgets = (list.searchWidgets) ? list.searchWidgets : 1; + var modifier; + for (var i=1; i <= widgets; i++) { + modifier = (i == 1) ? '' : i; scope[iterator + 'HoldInput' + modifier] = true; - if ( $('#search-widget-container' + modifier) ) { - // if the search widget exists, add its parameters to the query + if ($('#search-widget-container' + modifier) && + list.fields[scope[iterator + 'SearchField' + modifier]] && + !list.fields[scope[iterator + 'SearchField' + modifier]].searchObject) { + + // if the search widget exists and its value is not an object, add its parameters to the query + if ( (!scope[iterator + 'SelectShow' + modifier] && !Empty(scope[iterator + 'SearchValue' + modifier])) || (scope[iterator + 'SelectShow' + modifier] && scope[iterator + 'SearchSelectValue' + modifier]) || (list.fields[scope[iterator + 'SearchField' + modifier]] && list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'gtzero') ) { if (list.fields[scope[iterator + 'SearchField' + modifier]].searchField) { - scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField' + modifier]].searchField + '__'; + scope[iterator + 'SearchParams'] += '&' + list.fields[scope[iterator + 'SearchField' + modifier]].searchField + '__'; } else if (list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel) { // handle fields whose source is a related model e.g. inventories.organization - scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel + '__' + + scope[iterator + 'SearchParams'] += '&' + list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel + '__' + list.fields[scope[iterator + 'SearchField' + modifier]].sourceField + '__'; } else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'select') && (scope[iterator + 'SearchSelectValue' + modifier].value == '' || scope[iterator + 'SearchSelectValue' + modifier].value == null) ) { - scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField' + modifier]; + scope[iterator + 'SearchParams'] += '&' + scope[iterator + 'SearchField' + modifier]; } else { - scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField' + modifier] + '__'; + scope[iterator + 'SearchParams'] += '&' + scope[iterator + 'SearchField' + modifier] + '__'; } if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType && @@ -307,7 +344,7 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) scope[iterator + 'SearchSelectValue' + modifier].value == null) ) { scope[iterator + 'SearchParams'] += 'iexact='; } - else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType && + /*else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType && (list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'or')) ) { scope[iterator + 'SearchParams'] = ''; //start over var val = scope[iterator + 'SearchValue' + modifier]; @@ -317,7 +354,7 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) '__icontains=' + escape(val); } scope[iterator + 'SearchParams'].replace(/^\&/,''); - } + }*/ else { scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType' + modifier] + '='; } diff --git a/awx/ui/static/js/lists/Streams.js b/awx/ui/static/js/lists/Streams.js index 7ed2bf2d06..9e83071d74 100644 --- a/awx/ui/static/js/lists/Streams.js +++ b/awx/ui/static/js/lists/Streams.js @@ -17,8 +17,7 @@ angular.module('StreamListDefinition', []) index: false, hover: true, "class": "table-condensed", - searchWidgetLabel: 'Object', - searchWidgetLabel2: 'Modified by', + searchWidgets: 3, fields: { timestamp: { @@ -29,14 +28,14 @@ angular.module('StreamListDefinition', []) searchable: false }, user: { - label: 'User', + label: 'Initiated by', ngBindHtml: 'activity.user', sourceModel: 'user', sourceField: 'username', awToolTip: "\{\{ userToolTip \}\}", dataPlacement: 'top', - searchPlaceholder: 'Username', - searchWidget: 2 + searchPlaceholder: 'Initiated by username', + searchWidget: 1 }, objects: { label: 'Objects', @@ -51,68 +50,162 @@ angular.module('StreamListDefinition', []) searchable: false }, system_event: { - label: 'System', + label: 'System event', searchOnly: true, searchType: 'isnull', sourceModel: 'user', sourceField: 'username', - searchWidget: 2 + searchWidget: 1 }, - // The following fields exist to forces loading each type of object into the search + + // The following fields exist to force loading each type of object into the search // dropdown all_objects: { label: 'All', searchOnly: true, searchObject: 'all', - searchPlaceholder: ' ' + searchPlaceholder: 'All primary objects', + searchWidget: 2, + searchField: 'object1' }, credential_search: { label: 'Credential', searchOnly: true, searchObject: 'credentials', - searchPlaceholder: 'Credential name' + searchPlaceholder: 'Primary credential name', + searchWidget: 2, + searchField: 'object1' }, group_search: { label: 'Group', searchOnly: true, searchObject: 'groups', - searchPlaceholder: 'Group name' + searchPlaceholder: 'Primary group name', + searchWidget: 2, + searchField: 'object1' }, host_search: { label: 'Host', searchOnly: true, searchObject: 'hosts', - searchPlaceholder: 'Host name' + searchPlaceholder: 'Primary host name', + searchWidget: 2, + searchField: 'object1' }, inventory_search: { label: 'Inventory', searchOnly: true, searchObject: 'inventories', - searchPlaceholder: 'Inventory name' + searchPlaceholder: 'Primary inventory name', + searchWidget: 2, + searchField: 'object1' }, job_template_search: { label: 'Job Template', searchOnly: true, searchObject: 'job_templates', - searchPlaceholder: 'Job template name' + searchPlaceholder: 'Primary job template name', + searchWidget: 2, + searchField: 'object1' }, organization_search: { label: 'Organization', searchOnly: true, searchObject: 'organizations', - searchPlaceholder: 'Organization name' + searchPlaceholder: 'Primary organization name', + searchWidget: 2, + searchField: 'object1' }, project_search: { label: 'Project', searchOnly: true, searchObject: 'projects', - searchPlaceholder: 'Project name' + searchPlaceholder: 'Primary project name', + searchWidget: 2, + searchField: 'object1' }, user_search: { label: 'User', searchOnly: true, searchObject: 'users', - searchPlaceholder: 'Username' + searchPlaceholder: 'Primary username', + searchWidget: 2, + searchField: 'object1' + }, + + // The following fields exist to force loading each type of object into the search + // dropdown + all_objects3: { + label: 'All', + searchOnly: true, + searchObject: 'all', + searchPlaceholder: 'All related objects', + searchWidget: 3, + searchField: 'object2' + }, + credential_search3: { + label: 'Credential', + searchOnly: true, + searchObject: 'credentials', + searchPlaceholder: 'Related credential name', + searchWidget: 3, + searchField: 'object2' + }, + group_search3: { + label: 'Group', + searchOnly: true, + searchObject: 'groups', + searchPlaceholder: 'Related group name', + searchWidget: 3, + searchField: 'object2' + }, + host_search3: { + label: 'Host', + searchOnly: true, + searchObject: 'hosts', + searchPlaceholder: 'Related host name', + searchWidget: 3, + searchField: 'object2' + }, + inventory_search3: { + label: 'Inventory', + searchOnly: true, + searchObject: 'inventories', + searchPlaceholder: 'Related inventory name', + searchWidget: 3, + searchField: 'object2' + }, + job_template_search3: { + label: 'Job Template', + searchOnly: true, + searchObject: 'job_templates', + searchPlaceholder: 'Related job template name', + searchWidget: 3, + searchField: 'object2' + }, + organization_search3: { + label: 'Organization', + searchOnly: true, + searchObject: 'organizations', + searchPlaceholder: 'Related organization name', + searchWidget: 3, + searchField: 'object2' + }, + project_search3: { + label: 'Project', + searchOnly: true, + searchObject: 'projects', + searchPlaceholder: 'Related project name', + searchWidget: 3, + searchField: 'object2' + }, + user_search3: { + label: 'User', + searchOnly: true, + searchObject: 'users', + 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 32bd4f33ed..84a2dd3a88 100644 --- a/awx/ui/static/js/widgets/Stream.js +++ b/awx/ui/static/js/widgets/Stream.js @@ -92,14 +92,20 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti } descr += activity.operation; descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed '; - if (activity.summary_fields.object2) { + 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 ']; } - if (activity.summary_fields.object1) { + else if (activity.object2) { + descr += activity.object2 + [ (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 + ''; } + else if (activity.object1) { + descr += activity.object1; + } return descr; } }]) @@ -241,7 +247,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti // Objects var href; var deleted = /^\_delete/; - if (scope['activities'][i].summary_fields.object1) { + if (scope['activities'][i].summary_fields.object1 && scope['activities'][i].summary_fields.object1.name) { if ( !deleted.test(scope['activities'][i].summary_fields.object1.name) ) { href = BuildUrl(scope['activities'][i].summary_fields.object1); scope['activities'][i].objects = "" + scope['activities'][i].summary_fields.object1.name + ""; @@ -250,15 +256,23 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti scope['activities'][i].objects = scope['activities'][i].summary_fields.object1.name; } } - if (scope['activities'][i].summary_fields.object2) { + 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 ( !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 + ""; } else { - scope['activities'][i].objects += scope['activities'][i].summary_fields.object2.name; + scope['activities'][i].objects += "," + scope['activities'][i].summary_fields.object2.name; } } + else if (scope['activities'][i].object2) { + scope['activities'][i].objects += ", " + scope['activities'][i].object1; + } + + // Description scope['activities'][i].description = BuildDescription(scope['activities'][i]); } }); diff --git a/awx/ui/static/lib/ansible/RestServices.js b/awx/ui/static/lib/ansible/RestServices.js index 2ef2ed2926..489d86e8e4 100644 --- a/awx/ui/static/lib/ansible/RestServices.js +++ b/awx/ui/static/lib/ansible/RestServices.js @@ -8,6 +8,8 @@ angular.module('RestServices',['ngCookies','AuthService']) .factory('Rest', ['$http','$rootScope','$cookieStore', '$q', 'Authorization', function($http, $rootScope, $cookieStore, $q, Authorization) { return { + + headers: {}, setUrl: function (url) { this.url = url; @@ -42,6 +44,13 @@ function($http, $rootScope, $cookieStore, $q, Authorization) { }; return promise; }, + + setHeader: function(hdr) { + // Passin in { key: value } pairs to be added to the header + for (var h in hdr) { + this.headers[h] = hdr.h; + } + }, get: function(args) { args = (args) ? args : {}; this.params = (args.params) ? args.params : null; @@ -52,9 +61,10 @@ function($http, $rootScope, $cookieStore, $q, Authorization) { return this.createResponse({ detail: 'Token is expired' }, 401); } else if (token) { + this.setHeader({ Authorization: 'Token ' + token }); return $http({method: 'GET', url: this.url, - headers: { 'Authorization': 'Token ' + token }, + headers: this.headers, params: this.params }); } diff --git a/awx/ui/static/lib/ansible/generator-helpers.js b/awx/ui/static/lib/ansible/generator-helpers.js index 0b61efb61c..19f3b83f19 100644 --- a/awx/ui/static/lib/ansible/generator-helpers.js +++ b/awx/ui/static/lib/ansible/generator-helpers.js @@ -477,110 +477,63 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers']) var iterator = params.iterator; var form = params.template; var useMini = params.mini; - //var label = (params.label) ? params.label : null; var html= ''; - var secondWidget = params.secondWidget; - + var searchWidgets = (params.searchWidgets) ? params.searchWidgets : 1; html += "
\n"; - html += "
\n"; - html += (form.searchWidgetLabel) ? "" : ""; - html += "
\n"; - html += "
\n"; - - html += "\n"; - - html += "
    \n"; - for ( var fld in form.fields) { - if ( (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) - && (form.fields[fld].searchWidget == undefined || form.fields[fld].searchWidget == 1) ) { - html += "
  • " + - form.fields[fld].searchLabel + "
  • \n"; - } - else { - html += form.fields[fld].label.replace(/\/g,' ') + "')\">" + - form.fields[fld].label.replace(/\/g,' ') + "\n"; - } - } - } - html += "
\n"; - html += "
\n"; - - html += "\n"; - - html += "\n"; - - // Reset button - html += "
\n"; - html += "\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - - // Search Widget 2 - // Used on activity stream. Set 'searchWidget2: true' on fields to be included. - if (secondWidget) { - html += "
\n"; - html += (form.searchWidgetLabel2) ? "" : ""; - html += "
\n"; - html += "
\n"; + for (var i=1; i <= searchWidgets; i++) { + var modifier = (i == 1) ? '' : i; + html += "
\n"; + //html += (form.searchWidgetLabel) ? "" : ""; + html += "
\n"; + html += "
\n"; html += "\n"; - - html += "
    \n"; + html += "
      \n"; for ( var fld in form.fields) { - if ( (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) - && form.fields[fld].searchWidget == 2 ) { + if ( (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) + && (((form.fields[fld].searchWidget == undefined || form.fields[fld].searchWidget == 1) && i == 1 ) || + (form.fields[fld].searchWidget == i)) ) { html += "
    • " + + html += form.fields[fld].searchLabel + "', " + i + ")\">" + form.fields[fld].searchLabel + "
    • \n"; } else { - html += form.fields[fld].label.replace(/\/g,' ') + "', 2)\">" + + html += form.fields[fld].label.replace(/\/g,' ') + "', " + i + ")\">" + form.fields[fld].label.replace(/\/g,' ') + "\n"; } } } html += "
    \n"; html += "
\n"; + + html += "\n"; - html += "\n"; + html += "\n"; // Reset button - html += "
\n"; - html += "\n"; - html += "
\n"; + //html += "
\n"; + //html += "\n"; + //html += "
\n"; html += "
\n"; html += "
\n"; } diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js index 39ddf3a8ce..cd7760a4e9 100644 --- a/awx/ui/static/lib/ansible/list-generator.js +++ b/awx/ui/static/lib/ansible/list-generator.js @@ -195,7 +195,7 @@ angular.module('ListGenerator', ['GeneratorHelpers']) if (options.searchSize) { html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize, - secondWidget: options.secondWidget }); + searchWidgets: list.searchWidgets }); } else if (options.mode == 'summary') { html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' }); @@ -215,8 +215,9 @@ angular.module('ListGenerator', ['GeneratorHelpers']) if (options.searchSize) { // User supplied searchSize, calc the remaining var size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g,'')); - size += (options.secondWidget) ? 3 : 0; - html += 'col-lg-' + (11 - size); + size = (list.searchWidgets) ? list.searchWidgets * size : size; + console.log('size: ' + (12 - size - 1)); + html += 'col-lg-' + (12 - size - 1); } else if (options.mode == 'summary') { html += 'col-lg-5';