Skip to content

Commit 2f21965

Browse files
committed
useSavedQueries doc
1 parent c3323a8 commit 2f21965

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

docs_headless/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export default defineConfig({
123123
'uselist',
124124
'uselistcontext',
125125
'uselistcontroller',
126+
'usesavedqueries',
126127
'useunselect',
127128
'useunselectall',
128129
],
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
title: "useSavedQueries"
3+
storybook_path: ra-core-list-filter-usesavedqueries--basic
4+
---
5+
6+
This hook allows to read and write saved queries for a specific resource. Saved queries store a combination of filters, sort order, page size, and displayed filters that users can save and reuse later. The data is persisted in the [Store](./Store.md).
7+
8+
## Usage
9+
10+
```jsx
11+
import { useSavedQueries } from 'ra-core';
12+
13+
const [savedQueries, setSavedQueries] = useSavedQueries(resource);
14+
```
15+
16+
The `resource` parameter should be a string representing the resource name (e.g., 'posts', 'users').
17+
18+
The hook returns a tuple with:
19+
- `savedQueries`: an array of `SavedQuery` objects for the specified resource
20+
- `setSavedQueries`: a function to update the saved queries array
21+
22+
This hook is typically used within a list context where filter values, sort order, and pagination state are available. It's commonly used to implement saved query functionality in filter sidebars:
23+
24+
```jsx
25+
import { ListBase, useSavedQueries, useListContext } from 'ra-core';
26+
27+
const MyListComponent = () => (
28+
<ListBase>
29+
<SavedQueriesComponent />
30+
{/* Other list components */}
31+
</ListBase>
32+
);
33+
```
34+
35+
The saved queries are stored per resource using the pattern `${resource}.savedQueries` in the store, ensuring that each resource maintains its own set of saved queries.
36+
37+
## SavedQuery Interface
38+
39+
```typescript
40+
interface SavedQuery {
41+
label: string;
42+
value: {
43+
filter?: any;
44+
displayedFilters?: any[];
45+
sort?: SortPayload;
46+
perPage?: number;
47+
};
48+
}
49+
```
50+
51+
## Example Component Implementation
52+
53+
```jsx
54+
import { useSavedQueries, useListContext, extractValidSavedQueries } from 'ra-core';
55+
import isEqual from 'lodash/isEqual.js';
56+
57+
const SavedQueriesComponent = () => {
58+
const { resource, filterValues, displayedFilters, sort, perPage } = useListContext();
59+
const [savedQueries, setSavedQueries] = useSavedQueries(resource);
60+
const validSavedQueries = extractValidSavedQueries(savedQueries);
61+
62+
const hasFilterValues = !isEqual(filterValues, {});
63+
const hasSavedCurrentQuery = validSavedQueries.some(savedQuery =>
64+
isEqual(savedQuery.value, {
65+
filter: filterValues,
66+
sort,
67+
perPage,
68+
displayedFilters,
69+
})
70+
);
71+
72+
const addQuery = () => {
73+
const newSavedQuery = {
74+
label: 'My Custom Query',
75+
value: {
76+
filter: filterValues,
77+
sort,
78+
perPage,
79+
displayedFilters,
80+
},
81+
};
82+
const newSavedQueries = extractValidSavedQueries(savedQueries);
83+
setSavedQueries(newSavedQueries.concat(newSavedQuery));
84+
};
85+
86+
const removeQuery = () => {
87+
const savedQueryToRemove = {
88+
filter: filterValues,
89+
sort,
90+
perPage,
91+
displayedFilters,
92+
};
93+
const newSavedQueries = extractValidSavedQueries(savedQueries);
94+
const index = newSavedQueries.findIndex(savedQuery =>
95+
isEqual(savedQuery.value, savedQueryToRemove)
96+
);
97+
setSavedQueries([
98+
...newSavedQueries.slice(0, index),
99+
...newSavedQueries.slice(index + 1),
100+
]);
101+
};
102+
103+
return (
104+
<div>
105+
<h3>Saved Queries</h3>
106+
{validSavedQueries.length === 0 && (
107+
<p>No saved queries yet. Set a filter to save it.</p>
108+
)}
109+
<ul>
110+
{validSavedQueries.map((savedQuery, index) => (
111+
<li key={index}>
112+
{savedQuery.label}
113+
</li>
114+
))}
115+
</ul>
116+
{hasFilterValues && !hasSavedCurrentQuery && (
117+
<button onClick={addQuery}>
118+
Save current query
119+
</button>
120+
)}
121+
{hasSavedCurrentQuery && (
122+
<button onClick={removeQuery}>
123+
Remove current query
124+
</button>
125+
)}
126+
</div>
127+
);
128+
};
129+
```
130+
131+
## Helper Functions
132+
133+
The hook is often used with these helper functions:
134+
135+
### `extractValidSavedQueries`
136+
137+
Filters out invalid saved queries from an array:
138+
139+
```jsx
140+
import { extractValidSavedQueries } from 'ra-core';
141+
142+
const validQueries = extractValidSavedQueries(savedQueries);
143+
```
144+
145+
### `isValidSavedQuery`
146+
147+
Validates whether a saved query has the correct structure:
148+
149+
```jsx
150+
import { isValidSavedQuery } from 'ra-core';
151+
152+
const isValid = isValidSavedQuery(savedQuery);
153+
```
154+
155+
A valid saved query must have:
156+
- A non-empty string `label`
157+
- A `value` object containing:
158+
- `displayedFilters`: array
159+
- `perPage`: number
160+
- `sort.field`: string
161+
- `sort.order`: string
162+
- `filter`: object

0 commit comments

Comments
 (0)