diff --git a/awx/ui/client/src/shared/smart-search/smart-search.controller.js b/awx/ui/client/src/shared/smart-search/smart-search.controller.js index c3898dac41..6f5488ad1d 100644 --- a/awx/ui/client/src/shared/smart-search/smart-search.controller.js +++ b/awx/ui/client/src/shared/smart-search/smart-search.controller.js @@ -164,7 +164,7 @@ export default ['$stateParams', '$scope', '$state', 'GetBasePath', 'QuerySet', ' let splitTerms; if ($scope.singleSearchParam === 'host_filter') { - splitTerms = SmartSearchService.splitHostIntoTerms(terms); + splitTerms = SmartSearchService.splitFilterIntoTerms(terms); } else { splitTerms = SmartSearchService.splitSearchIntoTerms(terms); } diff --git a/awx/ui/client/src/shared/smart-search/smart-search.service.js b/awx/ui/client/src/shared/smart-search/smart-search.service.js index 1fea6ab4c6..3e97ec45e3 100644 --- a/awx/ui/client/src/shared/smart-search/smart-search.service.js +++ b/awx/ui/client/src/shared/smart-search/smart-search.service.js @@ -6,10 +6,14 @@ export default [function() { * work is done to encode quotes in quoted values and the spaces within those quoted * values before calling to `splitSearchIntoTerms`. */ - splitHostIntoTerms (searchString) { + splitFilterIntoTerms (searchString) { let groups = []; let quoted; + if (!searchString.includes(' ')) { + return this.splitSearchIntoTerms(this.encode(searchString)); + } + searchString.split(' ').forEach(substring => { if (substring.includes(':"')) { quoted = substring; @@ -17,9 +21,7 @@ export default [function() { quoted += ` ${substring}`; if (substring.includes('"')) { - quoted = quoted.replace(/"/g, encodeURIComponent('"')); - quoted = quoted.replace(/ /g, encodeURIComponent(' ')); - groups.push(quoted); + groups.push(this.encode(quoted)); quoted = undefined; } } else { @@ -29,6 +31,11 @@ export default [function() { return this.splitSearchIntoTerms(groups.join(' ')); }, + encode (string) { + string = string.replace(/'/g, '%27'); + + return string.replace(/("| )/g, match => encodeURIComponent(match)); + }, splitSearchIntoTerms(searchString) { return searchString.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g); }, diff --git a/awx/ui/tests/spec/smart-search/smart-search.service-test.js b/awx/ui/tests/spec/smart-search/smart-search.service-test.js index 13af06e51c..a6441719f1 100644 --- a/awx/ui/tests/spec/smart-search/smart-search.service-test.js +++ b/awx/ui/tests/spec/smart-search/smart-search.service-test.js @@ -42,4 +42,19 @@ describe('Service: SmartSearch', () => { }); }); + describe('fn splitFilterIntoTerms', () => { + it('should convert the filter term to a key and value with encode quotes and spaces', () => { + expect(SmartSearchService.splitFilterIntoTerms('foo')).toEqual(["foo"]); + expect(SmartSearchService.splitFilterIntoTerms('foo bar')).toEqual(["foo", "bar"]); + expect(SmartSearchService.splitFilterIntoTerms('name:foo bar')).toEqual(["name:foo", "bar"]); + expect(SmartSearchService.splitFilterIntoTerms('name:foo description:bar')).toEqual(["name:foo", "description:bar"]); + expect(SmartSearchService.splitFilterIntoTerms('name:"foo bar"')).toEqual(["name:%22foo%20bar%22"]); + expect(SmartSearchService.splitFilterIntoTerms('name:"foo bar" description:"bar foo"')).toEqual(["name:%22foo%20bar%22", "description:%22bar%20foo%22"]); + expect(SmartSearchService.splitFilterIntoTerms('name:"foo bar" a b c')).toEqual(["name:%22foo%20bar%22", 'a', 'b', 'c']); + expect(SmartSearchService.splitFilterIntoTerms('name:"1"')).toEqual(["name:%221%22"]); + expect(SmartSearchService.splitFilterIntoTerms('name:1')).toEqual(["name:1"]); + expect(SmartSearchService.splitFilterIntoTerms(`name:"foo ba'r" a b c`)).toEqual(["name:%22foo%20ba%27r%22", 'a', 'b', 'c']); + }); + }); + });