From 2f136064f98ef12332b312d631de75804b50ecfb Mon Sep 17 00:00:00 2001 From: stdavis Date: Fri, 22 Nov 2024 09:51:01 -0700 Subject: [PATCH] fix: allow multiple filters to be selected for a query layer Fixes #705 --- src/components/search-wizard/QueryLayer.jsx | 50 ++-------------- .../search-wizard/SpecialFilter.stories.jsx | 20 +++++++ src/utah-design-system/RadioGroup.jsx | 8 ++- src/utils.js | 58 ++++++++++--------- src/utils.test.js | 28 ++++++++- 5 files changed, 90 insertions(+), 74 deletions(-) diff --git a/src/components/search-wizard/QueryLayer.jsx b/src/components/search-wizard/QueryLayer.jsx index 1d074bce..f72803b9 100644 --- a/src/components/search-wizard/QueryLayer.jsx +++ b/src/components/search-wizard/QueryLayer.jsx @@ -15,33 +15,6 @@ import Button from '../../utah-design-system/Button'; * @typedef {import('../../contexts/SearchMachineProvider').LayerFilterValue} LayerFilterValue */ -/** - * @param {FieldFilterConfig - * | import('../../../functions/common/config').CheckboxRadioQueriesFilterConfig - * | import('../../../functions/common/config').DateFilterConfig} filterConfig - * @param {LayerFilterValue[]} filterValues - * @returns {number} - */ -function getFilterValueIndex(filterConfig, filterValues) { - if (!filterValues) { - return -1; - } - - const index = filterValues.findIndex((filter) => { - const typesMatch = filter.type === filterConfig.type; - if (/** @type {FieldFilterConfig} */ (filterConfig).field) { - return ( - typesMatch && - filter.field === /** @type {FieldFilterConfig} */ (filterConfig).field - ); - } - - return typesMatch; - }); - - return index; -} - /** * @param {Object} props * @param {import('../../../functions/common/config').QueryLayerConfig} props.config @@ -119,29 +92,18 @@ export default function QueryLayer({ */ filterConfig, /** @type {number} */ index, ) => { - const filterValueIndex = getFilterValueIndex( - filterConfig, - filterValues, - ); return ( {index > 0 &&
} { - if (filterValueIndex === -1) { - onFiltersChange([newValue]); - } else { - filterValues.splice( - filterValueIndex, - 1, - newValue, - ); - onFiltersChange(filterValues); - } + const newFilterValues = filterValues?.length + ? [...filterValues] + : []; + newFilterValues[index] = newValue; + onFiltersChange(newFilterValues); }} />
diff --git a/src/components/search-wizard/SpecialFilter.stories.jsx b/src/components/search-wizard/SpecialFilter.stories.jsx index 404604ce..ca754666 100644 --- a/src/components/search-wizard/SpecialFilter.stories.jsx +++ b/src/components/search-wizard/SpecialFilter.stories.jsx @@ -16,6 +16,7 @@ export const Default = () => { }, checkbox: null, radio: null, + radio2: null, date: null, }); @@ -90,6 +91,25 @@ export const Default = () => { onChange={getOnChange('radio')} />
+ [Radio 2] + +
[Date] {items.map((item) => { const id = `${ariaLabel}-${item.value}`; @@ -44,7 +48,7 @@ export default function RadioGroup({ > { - switch (layerFilter.type) { - case 'field': { - const paddedValues = - layerFilter.fieldType === 'text' - ? layerFilter.values.map((value) => `'${value}'`) - : layerFilter.values; - - return `${layerFilter.field} IN (${paddedValues.join(',')})`; + return ( + layerFilterValues + .map((layerFilter) => { + switch (layerFilter.type) { + case 'field': { + const paddedValues = + layerFilter.fieldType === 'text' + ? layerFilter.values.map((value) => `'${value}'`) + : layerFilter.values; + + return `${layerFilter.field} IN (${paddedValues.join(',')})`; + } + case 'radio': { + return layerFilter.values[0]; + } + case 'checkbox': { + const paddedValues = layerFilter.values.map( + (value) => `(${value})`, + ); + + return `(${paddedValues.join(' OR ')})`; + } + case 'date': { + return `${layerFilter.field} >= '${layerFilter.values[0]}' AND ${layerFilter.field} <= '${layerFilter.values[1]}'`; + } + default: + throw new Error(`Invalid filter type: ${layerFilter.type}`); } - case 'radio': { - return layerFilter.values[0]; - } - case 'checkbox': { - const paddedValues = layerFilter.values.map((value) => `(${value})`); - - return `(${paddedValues.join(' OR ')})`; - } - case 'date': { - return `${layerFilter.field} >= '${layerFilter.values[0]}' AND ${layerFilter.field} <= '${layerFilter.values[1]}'`; - } - default: - throw new Error(`Invalid filter type: ${layerFilter.type}`); - } - }) - .join(' AND '); + }) + // filter out empty values (this can happen if a filter has multiple filters) + .filter((value) => value) + .join(' AND ') + ); } /** @typedef {import('./contexts/SearchMachineProvider').LayerFilterValue} LayerFilterValue */ diff --git a/src/utils.test.js b/src/utils.test.js index 17a3cca1..d2ab4860 100644 --- a/src/utils.test.js +++ b/src/utils.test.js @@ -94,7 +94,11 @@ describe('getDefQueryFromLayerFilterValues', () => { }, { type: 'radio', - values: ["Field = 'Value1'"], + values: ["RadioField = 'RadioValue'"], + }, + { + type: 'radio', + values: ["AnotherRadioField = 'AnotherRadioValue'"], }, { type: 'date', @@ -106,7 +110,7 @@ describe('getDefQueryFromLayerFilterValues', () => { const result = getDefQueryFromLayerFilterValues(values); expect(result).toEqual( - "FieldName IN ('Value1','Value2') AND FieldName IN (1,2) AND ((Field = 'Value1') OR (Field = 'Value2')) AND Field = 'Value1' AND FieldName >= '2020-01-01' AND FieldName <= '2020-01-02'", + "FieldName IN ('Value1','Value2') AND FieldName IN (1,2) AND ((Field = 'Value1') OR (Field = 'Value2')) AND RadioField = 'RadioValue' AND AnotherRadioField = 'AnotherRadioValue' AND FieldName >= '2020-01-01' AND FieldName <= '2020-01-02'", ); }); @@ -114,6 +118,26 @@ describe('getDefQueryFromLayerFilterValues', () => { expect(getDefQueryFromLayerFilterValues([])).toEqual(null); expect(getDefQueryFromLayerFilterValues(undefined)).toEqual(null); }); + + it('skips empty values', () => { + /** @type {import('./contexts/SearchMachineProvider').LayerFilterValue[]} */ + const values = [ + { + type: 'radio', + values: ["RadioField = 'RadioValue'"], + }, + ]; + values[2] = { + type: 'radio', + values: ["AnotherRadioField = 'AnotherRadioValue'"], + }; + + const result = getDefQueryFromLayerFilterValues(values); + + expect(result).toEqual( + "RadioField = 'RadioValue' AND AnotherRadioField = 'AnotherRadioValue'", + ); + }); }); describe('getDefaultLayerFilterValues', () => {