From a60abe38a8c7b58cb36fa8da98b20dd629b9570f Mon Sep 17 00:00:00 2001 From: nixocio Date: Tue, 15 Jun 2021 17:04:17 -0400 Subject: [PATCH] Allow space on host filter for smart inventory Allow space on host filter for smart inventory Fix: https://github.com/ansible/tower/issues/4874 --- .../Lookup/shared/HostFilterUtils.jsx | 33 +++++++++++++++++-- .../Lookup/shared/HostFilterUtils.test.jsx | 12 +++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx index 309ca24339..6f5786e7ba 100644 --- a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx +++ b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx @@ -17,13 +17,19 @@ export function toSearchParams(string = '') { }); } + const unescapeString = v => { + // This is necessary when editing a string that was initially + // escaped to allow white space + return v.replace(/"/g, ''); + }; + return orArr .join(' and ') .split(/ and | or /) .map(s => s.split('=')) .reduce((searchParams, [k, v]) => { const key = decodeURIComponent(k); - const value = decodeURIComponent(v); + const value = decodeURIComponent(unescapeString(v)); if (searchParams[key] === undefined) { searchParams[key] = value; } else if (Array.isArray(searchParams[key])) { @@ -61,6 +67,27 @@ export function toQueryString(config, searchParams = {}) { .join('&'); } +/** + * Escape a string with double quote in case there was a white space + * @param {string} value A string to be parsed + * @return {string} string + */ +const escapeString = value => { + if (verifySpace(value)) { + return `"${value}"`; + } + return value; +}; + +/** + * Verify whether a string has white spaces + * @param {string} value A string to be parsed + * @return {bool} true if a string has white spaces + */ +const verifySpace = value => { + return value.trim().indexOf(' ') >= 0; +}; + /** * Convert params object to host filter string * @param {object} searchParams A string or array of strings keyed by query param key @@ -71,9 +98,9 @@ export function toHostFilter(searchParams = {}) { .sort() .flatMap(key => { if (Array.isArray(searchParams[key])) { - return searchParams[key].map(val => `${key}=${val}`); + return searchParams[key].map(val => `${key}=${escapeString(val)}`); } - return `${key}=${searchParams[key]}`; + return `${key}=${escapeString(searchParams[key])}`; }); const filteredSearchParams = flattenSearchParams.filter( diff --git a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.test.jsx b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.test.jsx index 653f8750fe..cb41fbde15 100644 --- a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.test.jsx +++ b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.test.jsx @@ -104,6 +104,18 @@ describe('toHostFilter', () => { ); }); + test('should return a host filter with escaped string', () => { + const object = { + or__description__contains: 'bar biz', + enabled: 'true', + name__contains: 'x', + or__name: 'foo', + }; + expect(toHostFilter(object)).toEqual( + 'enabled=true and name__contains=x or description__contains="bar biz" or name=foo' + ); + }); + test('should return a host filter with and conditional', () => { const object = { enabled: 'true',