mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
fix: broken filters (#294)
This commit is contained in:
@@ -90,7 +90,14 @@ const ListingsGrid = () => {
|
||||
loadData();
|
||||
}, [page, sortField, sortDir, freeTextFilter, providerFilter, activityFilter, jobNameFilter, watchListFilter]);
|
||||
|
||||
const handleFilterChange = useMemo(() => debounce((value) => setFreeTextFilter(value || null), 500), []);
|
||||
const handleFilterChange = useMemo(
|
||||
() =>
|
||||
debounce((value) => {
|
||||
setFreeTextFilter(value || null);
|
||||
setPage(1);
|
||||
}, 500),
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@@ -152,6 +159,7 @@ const ListingsGrid = () => {
|
||||
onChange={(e) => {
|
||||
const v = e.target.value;
|
||||
setActivityFilter(v === 'all' ? null : v === 'true');
|
||||
setPage(1);
|
||||
}}
|
||||
>
|
||||
<Radio value="all">All</Radio>
|
||||
@@ -166,6 +174,7 @@ const ListingsGrid = () => {
|
||||
onChange={(e) => {
|
||||
const v = e.target.value;
|
||||
setWatchListFilter(v === 'all' ? null : v === 'true');
|
||||
setPage(1);
|
||||
}}
|
||||
>
|
||||
<Radio value="all">All</Radio>
|
||||
@@ -176,7 +185,10 @@ const ListingsGrid = () => {
|
||||
<Select
|
||||
placeholder="Provider"
|
||||
showClear
|
||||
onChange={(val) => setProviderFilter(val)}
|
||||
onChange={(val) => {
|
||||
setProviderFilter(val);
|
||||
setPage(1);
|
||||
}}
|
||||
value={providerFilter}
|
||||
style={{ width: 130 }}
|
||||
>
|
||||
@@ -190,7 +202,10 @@ const ListingsGrid = () => {
|
||||
<Select
|
||||
placeholder="Job"
|
||||
showClear
|
||||
onChange={(val) => setJobNameFilter(val)}
|
||||
onChange={(val) => {
|
||||
setJobNameFilter(val);
|
||||
setPage(1);
|
||||
}}
|
||||
value={jobNameFilter}
|
||||
style={{ width: 130 }}
|
||||
>
|
||||
|
||||
@@ -40,6 +40,12 @@ export const parseNullableBoolean = {
|
||||
* @param {*} defaultValue - value when param is absent
|
||||
* @param {{ parse: (s: string) => *, stringify: (v: *) => string|null }} [options]
|
||||
*/
|
||||
// WeakMap to store pending batched updates per setSearchParams function.
|
||||
// This lets multiple useSearchParamState hooks on the same component batch
|
||||
// their changes into a single setSearchParams call, preventing them from
|
||||
// overwriting each other.
|
||||
const pendingUpdates = new WeakMap();
|
||||
|
||||
export function useSearchParamState([searchParams, setSearchParams], key, defaultValue, options = {}) {
|
||||
const { parse = (v) => v, stringify = (v) => String(v) } = options;
|
||||
|
||||
@@ -48,21 +54,42 @@ export function useSearchParamState([searchParams, setSearchParams], key, defaul
|
||||
|
||||
const setValue = useCallback(
|
||||
(newValue) => {
|
||||
setSearchParams(
|
||||
(prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
const serialized = stringify(newValue);
|
||||
if (newValue === defaultValue || newValue === null || newValue === undefined || serialized === null) {
|
||||
next.delete(key);
|
||||
} else {
|
||||
next.set(key, serialized);
|
||||
}
|
||||
return next;
|
||||
},
|
||||
{ replace: true },
|
||||
);
|
||||
// Collect the change
|
||||
if (!pendingUpdates.has(setSearchParams)) {
|
||||
pendingUpdates.set(setSearchParams, new Map());
|
||||
|
||||
// Schedule a single flush at the end of the current microtask
|
||||
queueMicrotask(() => {
|
||||
const updates = pendingUpdates.get(setSearchParams);
|
||||
pendingUpdates.delete(setSearchParams);
|
||||
if (!updates || updates.size === 0) return;
|
||||
|
||||
setSearchParams(
|
||||
(prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
for (const [k, entry] of updates) {
|
||||
if (entry.remove) {
|
||||
next.delete(k);
|
||||
} else {
|
||||
next.set(k, entry.serialized);
|
||||
}
|
||||
}
|
||||
return next;
|
||||
},
|
||||
{ replace: true },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const batch = pendingUpdates.get(setSearchParams);
|
||||
const serialized = stringify(newValue);
|
||||
if (newValue === defaultValue || newValue === null || newValue === undefined || serialized === null) {
|
||||
batch.set(key, { remove: true });
|
||||
} else {
|
||||
batch.set(key, { remove: false, serialized });
|
||||
}
|
||||
},
|
||||
[key, defaultValue, stringify],
|
||||
[key, defaultValue, stringify, setSearchParams],
|
||||
);
|
||||
|
||||
return [value, setValue];
|
||||
|
||||
@@ -207,14 +207,17 @@ export const useFredyState = create(
|
||||
filter,
|
||||
}) {
|
||||
try {
|
||||
const qryString = queryString.stringify({
|
||||
page,
|
||||
pageSize,
|
||||
freeTextFilter,
|
||||
sortfield,
|
||||
sortdir,
|
||||
...filter,
|
||||
});
|
||||
const qryString = queryString.stringify(
|
||||
{
|
||||
page,
|
||||
pageSize,
|
||||
freeTextFilter,
|
||||
sortfield,
|
||||
sortdir,
|
||||
...filter,
|
||||
},
|
||||
{ skipNull: true, skipEmptyString: true },
|
||||
);
|
||||
const response = await xhrGet(`/api/listings/table?${qryString}`);
|
||||
set((state) => ({
|
||||
listingsData: { ...state.listingsData, ...response.json },
|
||||
|
||||
Reference in New Issue
Block a user