Skip to content

Commit 2820f91

Browse files
Merge pull request #1697 from ral-facilities/bugfix/fix-default-filtering
Fix default filter on my data DLS table
2 parents a60c317 + c024c3a commit 2820f91

15 files changed

+493
-58
lines changed

packages/datagateway-common/src/api/index.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,11 @@ export const useSingleSort = (): ((
364364
);
365365
};
366366

367-
export const usePushFilter = (
367+
const useFilter = (
368+
updateMethod: UpdateMethod,
368369
filterPrefix?: string
369370
): ((filterKey: string, filter: Filter | null) => void) => {
370-
const { push } = useHistory();
371+
const { push, replace } = useHistory();
371372

372373
return React.useCallback(
373374
(filterKey: string, filter: Filter | null) => {
@@ -394,12 +395,26 @@ export const usePushFilter = (
394395
},
395396
};
396397
}
397-
push({ search: `?${parseQueryToSearch(query).toString()}` });
398+
(updateMethod === 'push' ? push : replace)({
399+
search: `?${parseQueryToSearch(query).toString()}`,
400+
});
398401
},
399-
[filterPrefix, push]
402+
[filterPrefix, push, replace, updateMethod]
400403
);
401404
};
402405

406+
export const usePushFilter = (
407+
filterPrefix?: string
408+
): ((filterKey: string, filter: Filter | null) => void) => {
409+
return useFilter('push', filterPrefix);
410+
};
411+
412+
export const useReplaceFilter = (
413+
filterPrefix?: string
414+
): ((filterKey: string, filter: Filter | null) => void) => {
415+
return useFilter('replace', filterPrefix);
416+
};
417+
403418
export const usePushInvestigationFilter = (): ((
404419
filterKey: string,
405420
filter: Filter | null

packages/datagateway-common/src/table/columnFilters/__snapshots__/dateColumnFilter.component.test.tsx.snap

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,98 @@ exports[`Date filter component renders correctly 1`] = `
189189
</form>
190190
</DocumentFragment>
191191
`;
192+
193+
exports[`Date filter component renders correctly with default values 1`] = `
194+
<DocumentFragment>
195+
<form>
196+
<div
197+
class="MuiFormControl-root MuiTextField-root css-1u3bzj6-MuiFormControl-root-MuiTextField-root"
198+
>
199+
<div
200+
class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-adornedEnd css-1ptx2yq-MuiInputBase-root-MuiInput-root"
201+
>
202+
<input
203+
aria-invalid="false"
204+
aria-label="test filter from"
205+
autocomplete="off"
206+
class="MuiInputBase-input MuiInput-input MuiInputBase-inputAdornedEnd css-1x51dt5-MuiInputBase-input-MuiInput-input"
207+
id="test filter from"
208+
inputmode="text"
209+
placeholder="From..."
210+
type="text"
211+
value="1999-01-01"
212+
/>
213+
<div
214+
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-standard MuiInputAdornment-sizeMedium css-1laqsz7-MuiInputAdornment-root"
215+
>
216+
<button
217+
aria-label="test filter from, date picker"
218+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-edgeEnd MuiIconButton-sizeSmall css-1bkxqye-MuiButtonBase-root-MuiIconButton-root"
219+
tabindex="0"
220+
type="button"
221+
>
222+
<svg
223+
aria-hidden="true"
224+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
225+
data-testid="CalendarIcon"
226+
focusable="false"
227+
viewBox="0 0 24 24"
228+
>
229+
<path
230+
d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"
231+
/>
232+
</svg>
233+
<span
234+
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
235+
/>
236+
</button>
237+
</div>
238+
</div>
239+
</div>
240+
<div
241+
class="MuiFormControl-root MuiTextField-root css-1u3bzj6-MuiFormControl-root-MuiTextField-root"
242+
>
243+
<div
244+
class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-adornedEnd css-1ptx2yq-MuiInputBase-root-MuiInput-root"
245+
>
246+
<input
247+
aria-invalid="false"
248+
aria-label="test filter to"
249+
autocomplete="off"
250+
class="MuiInputBase-input MuiInput-input MuiInputBase-inputAdornedEnd css-1x51dt5-MuiInputBase-input-MuiInput-input"
251+
id="test filter to"
252+
inputmode="text"
253+
placeholder="To..."
254+
type="text"
255+
value="2000-01-01"
256+
/>
257+
<div
258+
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-standard MuiInputAdornment-sizeMedium css-1laqsz7-MuiInputAdornment-root"
259+
>
260+
<button
261+
aria-label="test filter to, date picker"
262+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-edgeEnd MuiIconButton-sizeSmall css-1bkxqye-MuiButtonBase-root-MuiIconButton-root"
263+
tabindex="0"
264+
type="button"
265+
>
266+
<svg
267+
aria-hidden="true"
268+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
269+
data-testid="CalendarIcon"
270+
focusable="false"
271+
viewBox="0 0 24 24"
272+
>
273+
<path
274+
d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"
275+
/>
276+
</svg>
277+
<span
278+
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
279+
/>
280+
</button>
281+
</div>
282+
</div>
283+
</div>
284+
</form>
285+
</DocumentFragment>
286+
`;

packages/datagateway-common/src/table/columnFilters/__snapshots__/textColumnFilter.component.test.tsx.snap

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,79 @@ exports[`Text filter component renders correctly 1`] = `
7373
</DocumentFragment>
7474
`;
7575

76+
exports[`Text filter component renders correctly with default value 1`] = `
77+
<DocumentFragment>
78+
<div>
79+
<div
80+
class="MuiFormControl-root MuiFormControl-marginDense MuiFormControl-fullWidth css-zevgu-MuiFormControl-root"
81+
id="test-filter"
82+
>
83+
<label
84+
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-standard MuiFormLabel-colorSecondary MuiFormLabel-filled MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-standard css-1o0voyd-MuiFormLabel-root-MuiInputLabel-root"
85+
data-shrink="true"
86+
id="test-filter"
87+
>
88+
Include
89+
</label>
90+
<div
91+
aria-hidden="true"
92+
class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-colorSecondary MuiInputBase-formControl MuiInputBase-adornedEnd css-89bi5l-MuiInputBase-root-MuiInput-root"
93+
>
94+
<input
95+
aria-invalid="false"
96+
aria-label="Filter by test"
97+
class="MuiInputBase-input MuiInput-input MuiInputBase-inputAdornedEnd css-1x51dt5-MuiInputBase-input-MuiInput-input"
98+
id="test-filter"
99+
type="text"
100+
value="test default value"
101+
/>
102+
<div
103+
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-standard MuiInputAdornment-sizeMedium css-1laqsz7-MuiInputAdornment-root"
104+
>
105+
<div
106+
class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-colorPrimary css-4u4t8f-MuiInputBase-root-MuiInput-root-MuiSelect-root"
107+
>
108+
<div
109+
aria-expanded="false"
110+
aria-haspopup="listbox"
111+
aria-label="include, exclude or exact"
112+
aria-labelledby="test-select-filter-type"
113+
class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input css-1rxz5jq-MuiSelect-select-MuiInputBase-input-MuiInput-input"
114+
id="test-select-filter-type"
115+
role="button"
116+
tabindex="0"
117+
>
118+
<span
119+
class="notranslate"
120+
>
121+
122+
</span>
123+
</div>
124+
<input
125+
aria-hidden="true"
126+
class="MuiSelect-nativeInput css-yf8vq0-MuiSelect-nativeInput"
127+
tabindex="-1"
128+
value="include"
129+
/>
130+
<svg
131+
aria-hidden="true"
132+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconStandard css-pqjvzy-MuiSvgIcon-root-MuiSelect-icon"
133+
data-testid="SettingsIcon"
134+
focusable="false"
135+
viewBox="0 0 24 24"
136+
>
137+
<path
138+
d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"
139+
/>
140+
</svg>
141+
</div>
142+
</div>
143+
</div>
144+
</div>
145+
</div>
146+
</DocumentFragment>
147+
`;
148+
76149
exports[`Text filter component usePrincipalExperimenterFilter hook returns a function which can generate a working PI filter 1`] = `
77150
<DocumentFragment>
78151
<div>

packages/datagateway-common/src/table/columnFilters/dateColumnFilter.component.test.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ import DateColumnFilter, {
55
useDateFilter,
66
} from './dateColumnFilter.component';
77
import { renderHook } from '@testing-library/react-hooks';
8-
import { act } from 'react-test-renderer';
98
import { usePushFilter } from '../../api';
109
import {
1110
applyDatePickerWorkaround,
1211
cleanupDatePickerWorkaround,
1312
} from '../../setupTests';
14-
import { render, screen } from '@testing-library/react';
13+
import { render, screen, act } from '@testing-library/react';
1514
import { UserEvent } from '@testing-library/user-event/setup/setup';
1615
import userEvent from '@testing-library/user-event';
1716

@@ -41,6 +40,21 @@ describe('Date filter component', () => {
4140
expect(asFragment()).toMatchSnapshot();
4241
});
4342

43+
it('renders correctly with default values', () => {
44+
const { asFragment } = render(
45+
<DateColumnFilter
46+
value={{}}
47+
defaultFilter={{
48+
startDate: '1999-01-01T00:00:00.000Z',
49+
endDate: '2000-01-01T00:00:00.000Z',
50+
}}
51+
label="test"
52+
onChange={jest.fn()}
53+
/>
54+
);
55+
expect(asFragment()).toMatchSnapshot();
56+
});
57+
4458
describe('datesEqual function', () => {
4559
it('returns true if both dates are null', () => {
4660
const date1 = null;

packages/datagateway-common/src/table/columnFilters/dateColumnFilter.component.tsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState } from 'react';
22
import { format, isValid, isEqual, isBefore } from 'date-fns';
3-
import { FiltersType, DateFilter } from '../../app.types';
3+
import { FiltersType, DateFilter, Filter } from '../../app.types';
44
import { usePushFilter } from '../../api';
55
import {
66
TextField,
@@ -76,6 +76,7 @@ interface DateColumnFilterProps {
7676
onChange: (value: { startDate?: string; endDate?: string } | null) => void;
7777
value: { startDate?: string; endDate?: string } | undefined;
7878
filterByTime?: boolean;
79+
defaultFilter?: DateFilter;
7980
}
8081

8182
const CustomTextField: React.FC<TextFieldProps> = (renderProps) => {
@@ -110,10 +111,18 @@ const CustomTextField: React.FC<TextFieldProps> = (renderProps) => {
110111
const DateColumnFilter = (props: DateColumnFilterProps): React.ReactElement => {
111112
//Need state to change otherwise wont update error messages for an invalid date
112113
const [startDate, setStartDate] = useState(
113-
props.value?.startDate ? new Date(props.value.startDate) : null
114+
props.defaultFilter?.startDate
115+
? new Date(props.defaultFilter.startDate)
116+
: props.value?.startDate
117+
? new Date(props.value.startDate)
118+
: null
114119
);
115120
const [endDate, setEndDate] = useState(
116-
props.value?.endDate ? new Date(props.value.endDate) : null
121+
props.defaultFilter?.endDate
122+
? new Date(props.defaultFilter.endDate)
123+
: props.value?.endDate
124+
? new Date(props.value.endDate)
125+
: null
117126
);
118127

119128
const invalidDateRange = startDate && endDate && isBefore(endDate, startDate);
@@ -316,16 +325,25 @@ export default DateColumnFilter;
316325

317326
export const useDateFilter = (
318327
filters: FiltersType
319-
): ((label: string, dataKey: string) => React.ReactElement) => {
328+
): ((
329+
label: string,
330+
dataKey: string,
331+
defaultFilter?: Filter
332+
) => React.ReactElement) => {
320333
const pushFilter = usePushFilter();
321334
return React.useMemo(() => {
322-
const dateFilter = (label: string, dataKey: string): React.ReactElement => (
335+
const dateFilter = (
336+
label: string,
337+
dataKey: string,
338+
defaultFilter?: Filter
339+
): React.ReactElement => (
323340
<DateColumnFilter
324341
label={label}
325342
value={filters[dataKey] as DateFilter}
326343
onChange={(value: { startDate?: string; endDate?: string } | null) =>
327344
pushFilter(dataKey, value ? value : null)
328345
}
346+
defaultFilter={defaultFilter as DateFilter}
329347
/>
330348
);
331349
return dateFilter;

packages/datagateway-common/src/table/columnFilters/textColumnFilter.component.test.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import TextColumnFilter, {
44
useTextFilter,
55
DEBOUNCE_DELAY,
66
} from './textColumnFilter.component';
7-
import { act } from 'react-dom/test-utils';
87
import { usePushFilter, usePushFilters } from '../../api';
9-
import { render, screen } from '@testing-library/react';
8+
import { render, screen, act } from '@testing-library/react';
109
import { renderHook } from '@testing-library/react-hooks';
1110
import { UserEvent } from '@testing-library/user-event/setup/setup';
1211
import userEvent from '@testing-library/user-event';
1312

1413
jest.mock('../../api');
15-
jest.useFakeTimers('modern');
14+
jest.useFakeTimers();
1615

1716
describe('Text filter component', () => {
1817
let user: UserEvent;
@@ -32,6 +31,18 @@ describe('Text filter component', () => {
3231
expect(asFragment()).toMatchSnapshot();
3332
});
3433

34+
it('renders correctly with default value', () => {
35+
const { asFragment } = render(
36+
<TextColumnFilter
37+
value={{ value: undefined, type: 'include' }}
38+
defaultFilter={{ value: 'test default value', type: 'include' }}
39+
label="test"
40+
onChange={jest.fn()}
41+
/>
42+
);
43+
expect(asFragment()).toMatchSnapshot();
44+
});
45+
3546
it('calls the onChange method once when input is typed while include filter type is selected and calls again by debounced function after timeout', async () => {
3647
const onChange = jest.fn();
3748

0 commit comments

Comments
 (0)