From 735da6bff691d322c65953b5d0bcb746d8f302ad Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Tue, 19 Nov 2013 04:35:26 +0000 Subject: [PATCH] Related search now works with new search features. Only searches after user stops typing. Disables the input field while search is executing. Moved refresh button to the right side of list page. Fixed bugs: was using contains rather than icontains. Not sure that old refresh button worked. It does now. --- awx/ui/static/js/forms/JobTemplates.js | 11 ++- awx/ui/static/js/forms/Organizations.js | 18 +++++ awx/ui/static/js/forms/Projects.js | 9 +++ awx/ui/static/js/forms/Teams.js | 36 +++++++++ awx/ui/static/js/forms/Users.js | 66 +++++++++++++++++ awx/ui/static/js/helpers/refresh-related.js | 3 +- awx/ui/static/js/helpers/related-search.js | 82 +++++++++++++-------- awx/ui/static/js/helpers/search.js | 1 - awx/ui/static/js/lists/Organizations.js | 9 +++ awx/ui/static/js/widgets/Stream.js | 8 +- 10 files changed, 209 insertions(+), 34 deletions(-) diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index 0a3e07a969..788883c1ba 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -257,7 +257,16 @@ angular.module('JobTemplateFormDefinition', []) index: false, open: false, - actions: { + actions: { + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('job')", + iconSize: 'large' + } }, fields: { diff --git a/awx/ui/static/js/forms/Organizations.js b/awx/ui/static/js/forms/Organizations.js index 273c678552..1cc07304cc 100644 --- a/awx/ui/static/js/forms/Organizations.js +++ b/awx/ui/static/js/forms/Organizations.js @@ -62,6 +62,15 @@ angular.module('OrganizationFormDefinition', []) label: 'Add', icon: 'icon-plus', awToolTip: 'Add a new user' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('user')", + iconSize: 'large' } }, @@ -108,6 +117,15 @@ angular.module('OrganizationFormDefinition', []) icon: 'icon-plus', label: 'Add', awToolTip: 'Add new administrator' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('admin')", + iconSize: 'large' } }, fields: { diff --git a/awx/ui/static/js/forms/Projects.js b/awx/ui/static/js/forms/Projects.js index 4e15fb1154..778f7d30ad 100644 --- a/awx/ui/static/js/forms/Projects.js +++ b/awx/ui/static/js/forms/Projects.js @@ -215,6 +215,15 @@ angular.module('ProjectFormDefinition', []) icon: 'icon-plus', label: 'Add', awToolTip: 'Add an organization' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('organization')", + iconSize: 'large' } }, diff --git a/awx/ui/static/js/forms/Teams.js b/awx/ui/static/js/forms/Teams.js index d2ae7d2696..17056307ab 100644 --- a/awx/ui/static/js/forms/Teams.js +++ b/awx/ui/static/js/forms/Teams.js @@ -74,6 +74,15 @@ angular.module('TeamFormDefinition', []) icon: 'icon-plus', label: 'Add', add: 'Add a new credential' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('credential')", + iconSize: 'large' } }, @@ -118,6 +127,15 @@ angular.module('TeamFormDefinition', []) label: 'Add', awToolTip: 'Add a permission for this user', ngShow: 'PermissionAddAllowed' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('permission')", + iconSize: 'large' } }, @@ -176,6 +194,15 @@ angular.module('TeamFormDefinition', []) ngClick: "add('projects')", icon: 'icon-plus', label: 'Add' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('project')", + iconSize: 'large' } }, @@ -219,6 +246,15 @@ angular.module('TeamFormDefinition', []) icon: 'icon-plus', label: 'Add', awToolTip: 'Add a user' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('user')", + iconSize: 'large' } }, diff --git a/awx/ui/static/js/forms/Users.js b/awx/ui/static/js/forms/Users.js index 25cbf7a86e..ec04dd9326 100644 --- a/awx/ui/static/js/forms/Users.js +++ b/awx/ui/static/js/forms/Users.js @@ -122,6 +122,15 @@ angular.module('UserFormDefinition', []) icon: 'icon-plus', label: 'Add', awToolTip: 'Add a credential for this user' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('credential')", + iconSize: 'large' } }, @@ -166,6 +175,15 @@ angular.module('UserFormDefinition', []) label: 'Add', awToolTip: 'Add a permission for this user', ngShow: 'PermissionAddAllowed' + }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('permission')", + iconSize: 'large' } }, @@ -221,6 +239,18 @@ angular.module('UserFormDefinition', []) open: false, // Open accordion on load? base: '/organizations', + actions: { + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('adminof')", + iconSize: 'large' + } + }, + fields: { name: { key: true, @@ -238,6 +268,18 @@ angular.module('UserFormDefinition', []) iterator: 'organization', open: false, + actions: { + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('organization')", + iconSize: 'large' + } + }, + fields: { name: { key: true, @@ -255,6 +297,18 @@ angular.module('UserFormDefinition', []) iterator: 'team', open: false, + actions: { + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('team')", + iconSize: 'large' + } + }, + fields: { name: { key: true, @@ -272,6 +326,18 @@ angular.module('UserFormDefinition', []) iterator: 'project', open: false, + actions: { + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch('project')", + iconSize: 'large' + } + }, + fields: { name: { key: true, diff --git a/awx/ui/static/js/helpers/refresh-related.js b/awx/ui/static/js/helpers/refresh-related.js index 1b6122971e..ffb968c51e 100644 --- a/awx/ui/static/js/helpers/refresh-related.js +++ b/awx/ui/static/js/helpers/refresh-related.js @@ -22,7 +22,7 @@ angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities']) var set = params.set; var iterator = params.iterator; var url = params.url; - + Rest.setUrl(url); Rest.get() .success( function(data, status, headers, config) { @@ -33,6 +33,7 @@ angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities']) scope[iterator + 'PageCount'] = Math.ceil((data.count / scope[iterator + 'PageSize'])); scope[iterator + 'SearchSpin'] = false; scope[iterator + 'Loading'] = false; + scope[iterator + 'HoldInput'] = false; scope.$emit('related' + set); if (!params.scope.$$phase) { params.scope.$digest(); diff --git a/awx/ui/static/js/helpers/related-search.js b/awx/ui/static/js/helpers/related-search.js index b0e75f98cf..7df0d59c49 100644 --- a/awx/ui/static/js/helpers/related-search.js +++ b/awx/ui/static/js/helpers/related-search.js @@ -16,7 +16,7 @@ */ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelatedHelper']) - .factory('RelatedSearchInit', ['Alert', 'Rest', 'RefreshRelated', function(Alert, Rest, RefreshRelated) { + .factory('RelatedSearchInit', ['$timeout', 'Alert', 'Rest', 'RefreshRelated', function($timeout, Alert, Rest, RefreshRelated) { return function(params) { var scope = params.scope; @@ -24,36 +24,46 @@ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelat var form = params.form; // Set default values - var iterator, f; - for (var set in form.related) { - if (form.related[set].type != 'tree') { - iterator = form.related[set].iterator; - for (var fld in form.related[set].fields) { - if (form.related[set].fields[fld].key) { - scope[iterator + 'SearchField'] = fld - scope[iterator + 'SearchFieldLabel'] = form.related[set].fields[fld].label; - break; + function setDefaults(inIterator) { + var iterator, f; + for (var set in form.related) { + if (form.related[set].type != 'tree' && (inIterator === undefined || inIterator == form.related[set].iterator)) { + iterator = form.related[set].iterator; + for (var fld in form.related[set].fields) { + if (form.related[set].fields[fld].key) { + scope[iterator + 'SearchField'] = fld + scope[iterator + 'SearchFieldLabel'] = form.related[set].fields[fld].label; + break; + } + } + scope[iterator + 'SortOrder'] = null; + scope[iterator + 'SearchType'] = 'icontains'; + scope[iterator + 'SearchTypeLabel'] = 'Contains'; + scope[iterator + 'SearchValue'] = null; + scope[iterator + 'SelectShow'] = false; + scope[iterator + 'HideSearchType'] = false; + f = scope[iterator + 'SearchField'] + if (form.related[set].fields[f].searchType && ( form.related[set].fields[f].searchType == 'boolean' + || form.related[set].fields[f].searchType == 'select')) { + scope[iterator + 'SelectShow'] = true; + scope[iterator + 'SearchSelectOpts'] = list.fields[f].searchOptions; + } + if (form.related[set].fields[f].searchType && form.related[set].fields[f].searchType == 'int') { + scope[iterator + 'HideSearchType'] = true; + } + if (form.related[set].fields[f].searchType && form.related[set].fields[f].searchType == 'gtzero') { + scope[iterator + "InputHide"] = true; } } - scope[iterator + 'SortOrder'] = null; - scope[iterator + 'SearchType'] = 'contains'; - scope[iterator + 'SearchTypeLabel'] = 'Contains'; - scope[iterator + 'SelectShow'] = false; - scope[iterator + 'HideSearchType'] = false; - f = scope[iterator + 'SearchField'] - if (form.related[set].fields[f].searchType && ( form.related[set].fields[f].searchType == 'boolean' - || form.related[set].fields[f].searchType == 'select')) { - scope[iterator + 'SelectShow'] = true; - scope[iterator + 'SearchSelectOpts'] = list.fields[f].searchOptions; - } - if (form.related[set].fields[f].searchType && form.related[set].fields[f].searchType == 'int') { - scope[iterator + 'HideSearchType'] = true; - } - if (form.related[set].fields[f].searchType && form.related[set].fields[f].searchType == 'gtzero') { - scope[iterator + "InputHide"] = true; - } + } + } + + setDefaults(); + + scope.resetSearch = function(iterator) { + setDefaults(iterator); + scope.search(iterator); } - } // Functions to handle search widget changes scope.setSearchField = function(iterator, fld, label) { @@ -93,9 +103,23 @@ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelat scope.search(model); } + scope.startSearch = function(iterator) { + //Called on each keydown event for seachValue field. Using a timer + //to prevent executing a search until user is finished typing. + if (scope.searchTimer) { + $timeout.cancel(scope.searchTimer); + } + scope.searchTimer = $timeout( + function() { + scope.search(iterator); + } + , 1000); + } + scope.search = function(iterator) { scope[iterator + 'SearchSpin'] = true; scope[iterator + 'Loading'] = true; + scope[iterator + 'HoldInput'] = true; if (iterator == 'host') { if (scope['hostSearchField'] == 'has_active_failures') { @@ -126,7 +150,7 @@ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelat break; } } - + sort_order = (scope[iterator + 'SortOrder'] == null) ? sort_order : scope[iterator + 'SortOrder']; var f = form.related[set].fields[scope[iterator + 'SearchField']]; diff --git a/awx/ui/static/js/helpers/search.js b/awx/ui/static/js/helpers/search.js index f3edabcdfc..8806aba8e4 100644 --- a/awx/ui/static/js/helpers/search.js +++ b/awx/ui/static/js/helpers/search.js @@ -182,7 +182,6 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) window.location = '/#' + $location.path(); scope.search(iterator); } - if (scope.removeDoSearch) { scope.removeDoSearch(); diff --git a/awx/ui/static/js/lists/Organizations.js b/awx/ui/static/js/lists/Organizations.js index 39c6501faa..6241625515 100644 --- a/awx/ui/static/js/lists/Organizations.js +++ b/awx/ui/static/js/lists/Organizations.js @@ -36,6 +36,15 @@ angular.module('OrganizationListDefinition', []) "class": 'btn-success btn-xs', awToolTip: 'Create a new organization' }, + reset: { + dataPlacement: 'top', + icon: "icon-undo", + mode: 'all', + 'class': 'btn-xs btn-primary', + awToolTip: "Reset the search filter", + ngClick: "resetSearch()", + iconSize: 'large' + }, stream: { 'class': "btn-primary btn-xs activity-btn", ngClick: "showActivity()", diff --git a/awx/ui/static/js/widgets/Stream.js b/awx/ui/static/js/widgets/Stream.js index 3274f19947..433a5a0879 100644 --- a/awx/ui/static/js/widgets/Stream.js +++ b/awx/ui/static/js/widgets/Stream.js @@ -184,9 +184,9 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti .factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit', 'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl', - 'ShowDetail', + 'ShowDetail', 'LoadBreadCrumbs', function($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList, - FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail) { + FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail, LoadBreadCrumbs) { return function(params) { var list = StreamList; @@ -207,6 +207,10 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti $('#tab-content-container').append('
'); ShowStream(); + if ($rootScope.breadcrumbs.length == 0) { + var title = base.substr(0,1).toUpperCase() + base.substr(1); + $rootScope.breadcrumbs.push({ path: $location.path(), title: title}); + } // Generate the list var scope = view.inject(list, {