diff --git a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx index 27be7b3c99..a7d7bd0f61 100644 --- a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx +++ b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.jsx @@ -35,7 +35,6 @@ export function toSearchParams(string = '') { */ export function toQueryString(config, searchParams = {}) { if (Object.keys(searchParams).length === 0) return ''; - return Object.keys(searchParams) .flatMap(key => { if (Array.isArray(searchParams[key])) { @@ -59,14 +58,40 @@ export function toQueryString(config, searchParams = {}) { * @return {string} Host filter string */ export function toHostFilter(searchParams = {}) { - return Object.keys(searchParams) + const flattenSearchParams = Object.keys(searchParams) + .sort() .flatMap(key => { if (Array.isArray(searchParams[key])) { return searchParams[key].map(val => `${key}=${val}`); } return `${key}=${searchParams[key]}`; - }) - .join(' and '); + }); + + const filteredSearchParams = flattenSearchParams.filter( + el => el.indexOf('or__') === -1 + ); + + const conditionalSearchParams = flattenSearchParams.filter( + el => !filteredSearchParams.includes(el) + ); + + const conditionalQuery = conditionalSearchParams + .map(el => el.replace('or__', 'or ')) + .join(' ') + .trim(); + + if (filteredSearchParams.length === 0 && conditionalQuery) { + // when there are just or operators the first one should be removed from the query + // `name=foo or name__contains=bar or name__iexact=foo` instead of + // `or name=foo or name__contains=bar or name__iexact=foo` that is the reason of the slice(3) + return conditionalQuery.slice(3); + } + + if (conditionalQuery) { + return filteredSearchParams.join(' and ').concat(' ', conditionalQuery); + } + + return filteredSearchParams.join(' and ').trim(); } /** 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 c381ec4082..157830d29e 100644 --- a/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.test.jsx +++ b/awx/ui_next/src/components/Lookup/shared/HostFilterUtils.test.jsx @@ -77,6 +77,37 @@ describe('toHostFilter', () => { 'isa=2 and tatlo=foo and tatlo=bar and tatlo=baz' ); }); + test('should return a host filter with mixed conditionals', () => { + const object = { + or__name__contains: 'bar', + or__name__iexact: 'foo', + enabled: 'true', + name__contains: 'x', + or__name: 'foo', + }; + expect(toHostFilter(object)).toEqual( + 'enabled=true and name__contains=x or name=foo or name__contains=bar or name__iexact=foo' + ); + }); + + test('should return a host filter with and conditional', () => { + const object = { + enabled: 'true', + name__contains: 'x', + }; + expect(toHostFilter(object)).toEqual('enabled=true and name__contains=x'); + }); + + test('should return a host filter with or conditional', () => { + const object = { + or__name__contains: 'bar', + or__name__iexact: 'foo', + or__name: 'foo', + }; + expect(toHostFilter(object)).toEqual( + 'name=foo or name__contains=bar or name__iexact=foo' + ); + }); }); describe('removeNamespacedKeys', () => {