Skip to content

Commit c047222

Browse files
authored
Merge pull request #8631 from marmelab/doc-stacked-filters
[Doc] Add StackedFilters chapter
2 parents 31b242d + d1aa81b commit c047222

File tree

19 files changed

+576
-197
lines changed

19 files changed

+576
-197
lines changed

docs/Features.md

Lines changed: 74 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -291,94 +291,105 @@ Check the following components to learn more about guessers:
291291

292292
In most admin and B2B apps, the most common task is to look for a record. React-admin includes many features to help you **build a user experience that streamlines the search workflow**.
293293

294-
The most basic search feature is [the Filter Button/Form combo](./FilteringTutorial.md#the-filter-buttonform-combo): an inline form displayed on top of the list. Users also see a dropdown button allowing them to add more inputs to that form.
295-
296-
![List Filters](./img/list_filter.gif)
297-
298-
This functionality relies on the `<List filters>` prop:
294+
<table><tbody>
295+
<tr style="border:none">
296+
<td style="width:50%;border:none;text-align:center">
297+
<a title="Filter Button/Form Combo" href="./img/list_filter.gif"><img src="./img/list_filter.gif" /></a>
298+
<a href="./FilteringTutorial.html#the-filter-buttonform-combo" style="display: block;transform: translateY(-10px);">Filter Button/Form Combo</a>
299+
</td>
300+
<td style="width:50%;border:none;text-align:center">
301+
<a title="<FilterList> Sidebar" href="./img/filter-sidebar.gif"><img src="./img/filter-sidebar.gif" /></a>
302+
<a href="./FilteringTutorial.html#the-filterlist-sidebar" style="display: block;transform: translateY(-10px);"><code>&lt;FilterList&gt;</code> Sidebar</a>
303+
</td>
304+
</tr>
305+
<tr style="border:none;background-color:#fff;">
306+
<td style="width:50%;border:none;text-align:center">
307+
<a title="Stacked Filters" href="https://marmelab.com/ra-enterprise/modules/assets/ra-form-layout/latest/stackedfilters-overview.webm">
308+
<video controls autoplay muted loop width="90%" style="margin:1rem;box-shadow:0px 4px 4px 0px rgb(0 0 0 / 24%);">
309+
<source src="https://marmelab.com/ra-enterprise/modules/assets/ra-form-layout/latest/stackedfilters-overview.webm" type="video/mp4">
310+
Your browser does not support the video tag.
311+
</video>
312+
</a>
313+
<a href="./FilteringTutorial.html#the-stackedfilters-component" style="display: block;transform: translateY(-10px);"><code>&lt;StackedFilters&gt;</code> Dialog</a>
314+
</td>
315+
<td style="width:50%;border:none;text-align:center;vertical-align:top;">
316+
<a title="<Search> input" href="https://marmelab.com/ra-enterprise/modules/assets/ra-search-overview.gif"><img src="https://marmelab.com/ra-enterprise/modules/assets/ra-search-overview.gif" /></a>
317+
<a href="./FilteringTutorial.html#global-search" style="display: block;transform: translateY(-10px);">Global <code>&lt;Search&gt;</code></a>
318+
</td>
319+
</tr>
320+
</tbody></table>
321+
322+
These features rely on powerful components with an intuitive API. For instance, you can set the Filter Button/Form Combo with the `<List filters>` prop, using the same input components as in edition forms:
299323

300324
```jsx
301-
import { TextInput } from 'react-admin';
325+
import { List, TextInput } from 'react-admin';
302326

303327
const postFilters = [
304328
<TextInput label="Search" source="q" alwaysOn />,
305329
<TextInput label="Title" source="title" defaultValue="Hello, World!" />,
306330
];
307331

308-
export const PostList = (props) => (
309-
<List {...props} filters={postFilters}>
310-
...
332+
export const PostList = () => (
333+
<List filters={postFilters}>
334+
{/* ... */}
311335
</List>
312336
);
313337
```
314338

315-
An alternative UI to the Filter Button/Form Combo is [the FilterList Sidebar](./FilteringTutorial.md#the-filterlist-sidebar). Similar to what users usually see on e-commerce websites, it's **a panel with many simple filters that can be enabled and combined** using the mouse. The user experience is better than the Button/Form Combo, because the filter values are explicit, and it doesn't require typing anything in a form. But it's a bit less powerful, as only filters with a finite set of values (or intervals) can be used in the `<FilterList>`.
339+
Check the following chapters to learn more about each search and filtering component:
316340

317-
![Filter Sidebar](./img/filter-sidebar.gif)
341+
- [The Filter Button/Form Combo](./FilteringTutorial.md#the-filter-buttonform-combo)
342+
- [`<FilterList>`](./FilterList.md)
343+
- [`<StackedFilters>`](./StackedFilters.md)
344+
- [`<Search>`](./Search.md)
318345

319-
Here is an example FilterList sidebar:
346+
Users often apply the same filters over and over again. Saved Queries **let users save a combination of filters** and sort parameters into a new, personal filter, that persists between sessions.
347+
348+
[![Saved Queries in FilterList](./img/SavedQueriesList.gif)](./img/SavedQueriesList.gif)
349+
350+
Here is an example `<FilterList>` sidebar with saved queries:
320351

321-
{% raw %}
322352
```jsx
323-
import { SavedQueriesList, FilterLiveSearch, FilterList, FilterListItem } from 'react-admin';
353+
import { FilterList, FilterListItem, List, Datagrid } from 'react-admin';
324354
import { Card, CardContent } from '@mui/material';
325-
import MailIcon from '@mui/icons-material/MailOutline';
326-
import CategoryIcon from '@mui/icons-material/LocalOffer';
327355

328-
export const PostFilterSidebar = () => (
329-
<Card sx={{ order: -1, mr: 2, mt: 9, width: 200 }}>
356+
import { SavedQueriesList } from 'react-admin';
357+
358+
const SongFilterSidebar = () => (
359+
<Card>
330360
<CardContent>
331361
<SavedQueriesList />
332-
<FilterLiveSearch >
333-
<FilterList label="Subscribed to newsletter" icon={<MailIcon />}>
334-
<FilterListItem label="Yes" value={{ has_newsletter: true }} />
335-
<FilterListItem label="No" value={{ has_newsletter: false }} />
362+
<FilterList label="Record Company" icon={<BusinessIcon />}>
363+
...
336364
</FilterList>
337-
<FilterList label="Category" icon={<CategoryIcon />}>
338-
<FilterListItem label="Tests" value={{ category: 'tests' }} />
339-
<FilterListItem label="News" value={{ category: 'news' }} />
340-
<FilterListItem label="Deals" value={{ category: 'deals' }} />
341-
<FilterListItem label="Tutorials" value={{ category: 'tutorials' }} />
365+
<FilterList label="Released" icon={<DateRangeeIcon />}>
366+
...
342367
</FilterList>
343368
</CardContent>
344369
</Card>
345370
);
346-
```
347-
{% endraw %}
348371

349-
React-admin also offers a **site-wide, full-text search input**, designed to be displayed on every page.
372+
const SongList = () => (
373+
<List aside={<SongFilterSidebar />}>
374+
<Datagrid>
375+
...
376+
</Datagrid>
377+
</List>
378+
);
379+
```
350380

351-
![ra-search basic](https://marmelab.com/ra-enterprise/modules/assets/ra-search-overview.gif)
381+
Check [the Saved Queries Tutorial](./FilteringTutorial.md##saved-queries-let-users-save-filter-and-sort) to learn more.
352382

353-
Use [the `<Search>` component](./Search.md) to add a global search input to your app:
383+
Finally, react-admin offers low-level components and hooks to **build your own search UI**:
354384

355-
{% raw %}
356-
```jsx
357-
// in src/MyAppBar.jsx
358-
import { AppBar } from "react-admin";
359-
import { Typography } from "@mui/material";
360-
import { Search } from "@react-admin/ra-search";
361-
362-
export const MyAppbar = (props) => (
363-
<AppBar {...props}>
364-
<Typography
365-
variant="h6"
366-
color="inherit"
367-
sx={{
368-
flex: 1,
369-
textOverflow: "ellipsis",
370-
whiteSpace: "nowrap",
371-
overflow: "hidden",
372-
}}
373-
id="react-admin-title"
374-
/>
375-
<Search />
376-
</AppBar>
377-
);
378-
```
379-
{% endraw %}
385+
- [`<FilterButton>`](./FilterButton.md)
386+
- [`<SearchInput>`](./FilteringTutorial.md#searchinput)
387+
- [`<FilterLiveSearch>`](./FilterLiveSearch.md)
388+
- [`<SavedQueriesList>`](./SavedQueriesList.md)
389+
- [`useListContext()`](./useListContext.md)
390+
- [`useList()`](./useList.md)
380391

381-
Finally, react-admin offers low-level hooks and components to build your own search UI. Check the [Building A Custom Filter Tutorial](./FilteringTutorial.md#building-a-custom-filter) to learn more.
392+
Check the [Building A Custom Filter Tutorial](./FilteringTutorial.md#building-a-custom-filter) to learn more.
382393

383394
## Forms & Validation
384395

@@ -876,17 +887,16 @@ For instance, replace `<List>` with `<ListLive>` to have a list refreshing autom
876887
```diff
877888
import {
878889
- List,
879-
ListProps,
880890
Datagrid,
881891
TextField,
882892
NumberField,
883893
Datefield,
884894
} from 'react-admin';
885895
+import { ListLive } from '@react-admin/ra-realtime';
886896

887-
const PostList = (props: ListProps) => (
888-
- <List {...props}>
889-
+ <ListLive {...props}>
897+
const PostList = () => (
898+
- <List>
899+
+ <ListLive>
890900
<Datagrid>
891901
<TextField source="title" />
892902
<NumberField source="views" />
@@ -1023,8 +1033,8 @@ const SongFilterSidebar = () => (
10231033
</Card>
10241034
);
10251035

1026-
const SongList = props => (
1027-
<List {...props} aside={<SongFilterSidebar />}>
1036+
const SongList = () => (
1037+
<List aside={<SongFilterSidebar />}>
10281038
<Datagrid>
10291039
...
10301040
</Datagrid>

0 commit comments

Comments
 (0)