Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Count and ReferenceManyCount should allow to override the default sort #8732

Merged
merged 4 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions docs/Count.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,13 @@ const TicketListAside = () => {

## Props

| Prop | Required | Type | Default | Description |
| ---------- | -------- | ------ | ------- | ----------------------------------------------------------------------- |
| `filter` | Optional | Object | - | Filter to apply to the query. |
| `link` | Optional | bool | `false` | If true, the count is wrapped in a `<Link>` to the list view. |
| `resource` | Optional | string | - | Resource to count. Default to the current `ResourceContext` |
| `timeout` | Optional | number | 1000 | Number of milliseconds to wait before displaying the loading indicator. |
| Prop | Required | Type | Default | Description |
| ---------- | -------- | ------------------------------------------ | --------------------------------- | ----------------------------------------------------------------------- |
| `filter` | Optional | Object | - | Filter to apply to the query. |
| `link` | Optional | bool | `false` | If true, the count is wrapped in a `<Link>` to the list view. |
| `resource` | Optional | string | - | Resource to count. Default to the current `ResourceContext` |
| `sort` | Optional | `{ field: string, order: 'ASC' or 'DESC' }` | `{ field: 'id', order: 'DESC' }` | The sort option sent to `getList` |
| `timeout` | Optional | number | 1000 | Number of milliseconds to wait before displaying the loading indicator. |

Additional props are passed to [the underlying MUI `<Typography>` element](https://mui.com/material-ui/api/typography/).

Expand Down Expand Up @@ -116,6 +117,16 @@ If you want to count a different resource, pass it as the `resource` prop.
<Count resource="comments" />
```

## `sort`

If you want to customize the sort options passed to `getList` (for instance because your table does not have an `id` column), you can pass a custom `sort` prop:

{% raw %}
```jsx
<Count resource="posts" sort={{ field: 'custom_id', order: 'ASC' }} />;
```
{% endraw %}

## `timeout`

The `<Count>` component displays a loading indicator after 1 second. This is useful to avoid displaying a loading indicator when the count is retrieved in a few milliseconds. You can change this delay by passing a `timeout` prop.
Expand Down
32 changes: 24 additions & 8 deletions docs/ReferenceManyCount.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@ export const PostList = () => (

## Props

| Prop | Required | Type | Default | Description |
| ----------- | -------- | ------ | ------- | ------------------------------------------------------------------------- |
| `reference` | Required | string | - | Name of the related resource to fetch (e.g. `comments`) |
| `target` | Required | string | - | Name of the field in the related resource that points to the current one. |
| `filter` | Optional | Object | - | Filter to apply to the query. |
| `link` | Optional | bool | `false` | If true, the count is wrapped in a `<Link>` to the filtered list view. |
| `resource` | Optional | string | - | Resource to count. Default to the current `ResourceContext` |
| `timeout` | Optional | number | 1000 | Number of milliseconds to wait before displaying the loading indicator. |
| Prop | Required | Type | Default | Description |
| ----------- | -------- | ------------------------------------------ | --------------------------------- | ------------------------------------------------------------------------- |
| `reference` | Required | string | - | Name of the related resource to fetch (e.g. `comments`) |
| `target` | Required | string | - | Name of the field in the related resource that points to the current one. |
| `filter` | Optional | Object | - | Filter to apply to the query. |
| `link` | Optional | bool | `false` | If true, the count is wrapped in a `<Link>` to the filtered list view. |
| `resource` | Optional | string | - | Resource to count. Default to the current `ResourceContext` |
| `sort` | Optional | `{ field: string, order: 'ASC' or 'DESC' }` | `{ field: 'id', order: 'DESC' }` | The sort option sent to `getManyReference` |
| `timeout` | Optional | number | 1000 | Number of milliseconds to wait before displaying the loading indicator. |

`<ReferenceManyCount>` also accepts the [common field props](./Fields.md#common-field-props).

Expand Down Expand Up @@ -140,6 +141,21 @@ By default, the `<ReferenceManyCount>` component uses the current `ResourceConte
/>
```

## `sort`

If you want to customize the sort options passed to `getManyReference` (for instance because your relation table does not have an `id` column), you can pass a custom `sort` prop:

{% raw %}
```jsx
<ReferenceManyCount
label="Comments"
reference="comments"
target="post_id"
sort={{ field: 'custom_id', order: 'ASC' }}
/>
```
{% endraw %}

## `target`

The `target` prop is required and must be the name of the field in the related resource that points to the current one. For instance, when fetching the number of comments related to the current post, if a comment relates to a post via a `post_id` foreign key, you must set the `target` prop to `post_id`:
Expand Down
30 changes: 29 additions & 1 deletion packages/ra-ui-materialui/src/field/ReferenceManyCount.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import * as React from 'react';
import { render, screen } from '@testing-library/react';

import { Basic, ErrorState, WithFilter } from './ReferenceManyCount.stories';
import {
Basic,
ErrorState,
WithFilter,
Wrapper,
} from './ReferenceManyCount.stories';
import { ReferenceManyCount } from './ReferenceManyCount';

describe('<ReferenceManyCount />', () => {
it('should return the number of related records of a given reference', async () => {
Expand All @@ -17,4 +23,26 @@ describe('<ReferenceManyCount />', () => {
render(<WithFilter />);
await screen.findByText('2');
});
it('should accept a sort prop', async () => {
const dataProvider = {
getManyReference: jest.fn(),
} as any;
render(
<Wrapper dataProvider={dataProvider}>
<ReferenceManyCount
reference="comments"
target="post_id"
sort={{ field: 'custom_id', order: 'ASC' }}
/>
</Wrapper>
);
expect(dataProvider.getManyReference).toHaveBeenCalledWith('comments', {
target: 'post_id',
id: 1,
filter: {},
pagination: { page: 1, perPage: 1 },
sort: { field: 'custom_id', order: 'ASC' },
meta: undefined,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ReferenceManyCount } from './ReferenceManyCount';

export default {
title: 'ra-ui-materialui/fields/ReferenceManyCount',
excludeStories: ['Wrapper'],
};

const post = {
Expand All @@ -25,7 +26,7 @@ const comments = [
{ id: 5, post_id: 2, is_published: false },
];

const Wrapper = ({ dataProvider, children }) => (
export const Wrapper = ({ dataProvider, children }) => (
<MemoryRouter>
<DataProviderContext.Provider value={dataProvider}>
<QueryClientProvider
Expand Down
4 changes: 4 additions & 0 deletions packages/ra-ui-materialui/src/field/ReferenceManyCount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
useRecordContext,
useTimeout,
useCreatePath,
SortPayload,
} from 'ra-core';
import { Typography, TypographyProps, CircularProgress } from '@mui/material';
import ErrorIcon from '@mui/icons-material/Error';
Expand Down Expand Up @@ -31,6 +32,7 @@ export const ReferenceManyCount = (props: ReferenceManyCountProps) => {
reference,
target,
filter,
sort,
link,
resource,
source = 'id',
Expand All @@ -43,6 +45,7 @@ export const ReferenceManyCount = (props: ReferenceManyCountProps) => {

const { isLoading, error, total } = useReferenceManyFieldController({
filter,
sort,
page: 1,
perPage: 1,
record,
Expand Down Expand Up @@ -99,6 +102,7 @@ export interface ReferenceManyCountProps
Omit<TypographyProps, 'textAlign'> {
reference: string;
target: string;
sort?: SortPayload;
filter?: any;
label?: string;
link?: boolean;
Expand Down
24 changes: 22 additions & 2 deletions packages/ra-ui-materialui/src/list/Count.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as React from 'react';
import { render, screen } from '@testing-library/react';
import * as React from 'react';

import { Basic, ErrorState, WithFilter } from './Count.stories';
import { ResourceContextProvider } from 'ra-core';
import { Count } from './Count';
import { Basic, ErrorState, WithFilter, Wrapper } from './Count.stories';

describe('<Count />', () => {
it('should return the number of records of a given resource', async () => {
Expand All @@ -17,4 +19,22 @@ describe('<Count />', () => {
render(<WithFilter />);
await screen.findByText('3');
});
it('should accept a sort prop', async () => {
const dataProvider = {
getList: jest.fn(),
} as any;
render(
<Wrapper dataProvider={dataProvider}>
<ResourceContextProvider value="posts">
<Count sort={{ field: 'custom_id', order: 'ASC' }} />
</ResourceContextProvider>
</Wrapper>
);
expect(dataProvider.getList).toHaveBeenCalledWith('posts', {
filter: {},
pagination: { page: 1, perPage: 1 },
sort: { field: 'custom_id', order: 'ASC' },
meta: undefined,
});
});
});
3 changes: 2 additions & 1 deletion packages/ra-ui-materialui/src/list/Count.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Count } from './Count';

export default {
title: 'ra-ui-materialui/list/Count',
excludeStories: ['Wrapper'],
};

const posts = [
Expand All @@ -17,7 +18,7 @@ const posts = [
{ id: 5, is_published: false },
];

const Wrapper = ({ dataProvider, children }) => (
export const Wrapper = ({ dataProvider, children }) => (
<MemoryRouter>
<DataProviderContext.Provider value={dataProvider}>
<QueryClientProvider
Expand Down
4 changes: 4 additions & 0 deletions packages/ra-ui-materialui/src/list/Count.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
useGetList,
useTimeout,
useCreatePath,
SortPayload,
} from 'ra-core';
import { Typography, TypographyProps, CircularProgress } from '@mui/material';
import ErrorIcon from '@mui/icons-material/Error';
Expand Down Expand Up @@ -32,6 +33,7 @@ import { Link } from '../Link';
export const Count = (props: CountProps) => {
const {
filter,
sort,
link,
resource: resourceFromProps,
timeout = 1000,
Expand All @@ -43,6 +45,7 @@ export const Count = (props: CountProps) => {

const { total, isLoading, error } = useGetList(resource, {
filter,
sort,
pagination: { perPage: 1, page: 1 },
});

Expand Down Expand Up @@ -80,6 +83,7 @@ export const Count = (props: CountProps) => {

export interface CountProps extends TypographyProps {
filter?: any;
sort?: SortPayload;
link?: Boolean;
resource?: string;
timeout?: number;
Expand Down