Skip to content

Commit

Permalink
Merge branch 'master' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
djhi committed Dec 19, 2024
2 parents 516d3ea + a1b7be0 commit ad6bf18
Show file tree
Hide file tree
Showing 45 changed files with 2,955 additions and 1,324 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 5.4.3

* Fix `<FormDataConsumer>` causes its children to flicker ([#10417](https://github.com/marmelab/react-admin/pull/10417)) ([djhi](https://github.com/djhi))
* [Doc] Remove `<ShowBase emptyWhileLoading>` from the docs ([#10416](https://github.com/marmelab/react-admin/pull/10416)) ([slax57](https://github.com/slax57))
* [Doc] Introduce `<DatagridAG>` custom cell editors ([#10410](https://github.com/marmelab/react-admin/pull/10410)) ([djhi](https://github.com/djhi))
* [Doc] Update Access Control instructions following ra-rbac update ([#10409](https://github.com/marmelab/react-admin/pull/10409)) ([djhi](https://github.com/djhi))
* [Doc] Fix `<TreeWithDetails filter>` doc chapter ([#10406](https://github.com/marmelab/react-admin/pull/10406)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* Bump nanoid from 3.3.7 to 3.3.8 ([#10414](https://github.com/marmelab/react-admin/pull/10414)) ([dependabot[bot]](https://github.com/apps/dependabot))

## 5.4.2

* Fix: Improve AutocompleteInput creation support ([#10391](https://github.com/marmelab/react-admin/pull/10391)) ([djhi](https://github.com/djhi))
Expand Down
371 changes: 329 additions & 42 deletions docs/AccordionForm.md

Large diffs are not rendered by default.

1,069 changes: 245 additions & 824 deletions docs/AuthRBAC.md

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions docs/Buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,80 @@ To override the style of all instances of `<Button>` using the [application-wide

## `<CloneButton>`

The `<CloneButton>` can be added anywhere there is a `RecordContext` to redirect users to the record's resource create page. The create page form will be prefilled with the record values (except the `id`).

### Usage

`<CloneButton>` reads the current resource from `ResourceContext`, so in general it doesn't need any props:

```jsx
import { CloneButton, TopToolbar, List } from 'react-admin';

const PostList = () => (
<List>
<TextField source="title" />
<CloneButton />
</List>
);
```

`<CloneButton>` is based on react-admin's base `<Button>`, so it's responsive, accessible, and the label is translatable.

### Props

| Prop | Required | Type | Default | Description |
| ------------- | -------- | --------------- | ------------------ | -------------------------------------------- |
| `resource` | Optional | `string` | - | Target resource, e.g. 'posts' |
| `label` | Optional | `string` | 'ra.action.create' | label or translation message to use |
| `icon` | Optional | `ReactElement` | - | iconElement, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |

It also supports [all the other `<Button>` props](#button).

### Access Control

If you want to control whether this button should be displayed based on users permissions, use the `<CloneButton>` exported by the `@react-admin/ra-rbac` Enterprise package.

```diff
-import { CloneButton } from 'react-admin';
+import { CloneButton } from '@react-admin/ra-rbac';
```

This component adds the following [RBAC](./AuthRBAC.md) controls:

- It will only render if the user has the `'clone'` permission on the current resource.

```js
{ action: "clone", resource: [current resource] }
```

Here is an example of how to use the `<CloneButton>` with RBAC:

```tsx
import { Edit, TopToolbar } from 'react-admin';
import { CloneButton } from '@react-admin/ra-rbac';

const PostEditActions = () => (
<TopToolbar>
<CloneButton />
</TopToolbar>
);

export const PostEdit = () => (
<Edit actions={<PostEditActions />}>
{/* ... */}
</Edit>
);
```

This component accepts additional props:

| Prop | Required | Type | Default | Description |
| -------------------- | -------- | ----------------- | ---------- | ---------------------------------------------------------------------- |
| `accessDenied` | Optional | ReactNode | null | The content to display when users don't have the `'clone'` permission |
| `action` | Optional | String | `"clone"` | The action to call `authProvider.canAccess` with |
| `authorizationError` | Optional | ReactNode | null | The content to display when an error occurs while checking permission |

## `<CreateButton>`

Opens the Create view of the current resource:
Expand Down Expand Up @@ -942,6 +1016,58 @@ export const PostList = () => (

**Tip**: If you are looking for an `<ImportButton>`, check out this third-party package: [benwinding/react-admin-import-csv](https://github.com/benwinding/react-admin-import-csv).

### Access Control

If you want to control whether this button should be displayed based on users permissions, use the `<ExportButton>` exported by the `@react-admin/ra-rbac` Enterprise package.

```diff
-import { ExportButton } from 'react-admin';
+import { ExportButton } from '@react-admin/ra-rbac';
```

This component adds the following [RBAC](./AuthRBAC.md) controls:

- It will only render if the user has the `'export'` permission on the current resource.

```js
{ action: "export", resource: [current resource] }
```

- It will only export the fields the user has the `'read'` permission on.

```js
{ action: "read", resource: `${resource}.${source}` }
```

Here is an example usage:

```jsx
import { CreateButton, TopToolbar } from 'react-admin';
import { ExportButton } from '@react-admin/ra-rbac';

const PostListActions = () => (
<TopToolbar>
<PostFilter context="button" />
<CreateButton />
<ExportButton />
</TopToolbar>
);

export const PostList = () => (
<List actions={<PostListActions />}>
...
</List>
);
```

This component accepts additional props:

| Prop | Required | Type | Default | Description |
| -------------------- | -------- | ----------------- | ---------- | ---------------------------------------------------------------------- |
| `accessDenied` | Optional | ReactNode | null | The content to display when users don't have the `'export'` permission |
| `action` | Optional | String | `"export"` | The action to call `authProvider.canAccess` with |
| `authorizationError` | Optional | ReactNode | null | The content to display when an error occurs while checking permission |

## `<FilterButton>`

This button is an internal component used by react-admin in [the Filter button/form combo](./FilteringTutorial.md#the-filter-buttonform-combo).
Expand Down
12 changes: 11 additions & 1 deletion docs/Create.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,10 +701,20 @@ export const BookCreate = () => {
};
```

## Security
## Anonymous Access

The `<Create>` component requires authentication and will redirect anonymous users to the login page. If you want to allow anonymous access, use the [`disableAuthentication`](#disableauthentication) prop.

```jsx
const PostCreate = () => (
<Create disableAuthentication>
...
</Create>
);
```

## Access Control

If your `authProvider` implements [Access Control](./Permissions.md#access-control), `<Create>` will only render if the user has the "create" access to the related resource.

For instance, for the `<PostCreate>`page below:
Expand Down
169 changes: 127 additions & 42 deletions docs/Datagrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -1074,48 +1074,6 @@ Additionally, `<DatagridAG>` is compatible with the [Enterprise version of ag-gr

Check [the `<DatagridAG>` documentation](./DatagridAG.md) for more details.

## Fields And Permissions

You might want to display some fields only to users with specific permissions. Use the `usePermissions` hook to get the user permissions and hide Fields accordingly:

{% raw %}
```tsx
import { List, Datagrid, TextField, TextInput, ShowButton, usePermissions } from 'react-admin';

const getUserFilters = (permissions) => ([
<TextInput label="user.list.search" source="q" alwaysOn />,
<TextInput source="name" />,
permissions === 'admin' ? <TextInput source="role" /> : null,
].filter(filter => filter !== null)
);

export const UserList = ({ permissions, ...props }) => {
const { permissions } = usePermissions();
return (
<List
{...props}
filters={getUserFilters(permissions)}
sort={{ field: 'name', order: 'ASC' }}
>
<Datagrid>
<TextField source="id" />
<TextField source="name" />
{permissions === 'admin' && <TextField source="role" />}
{permissions === 'admin' && <EditButton />}
<ShowButton />
</Datagrid>
</List>
)
};
```
{% endraw %}

Note how the `permissions` prop is passed down to the custom `filters` component to allow Filter customization, too.

It's up to your `authProvider` to return whatever you need to check roles and permissions inside your component. Check [the authProvider documentation](./Authentication.md) for more information.

**Tip**: The [ra-rbac module](./AuthRBAC.md#datagrid) provides a wrapper for the `<Datagrid>` with built-in permission check for columns.

## Standalone Usage

You can use the `<Datagrid>` component to display data that you've fetched yourself. You'll need to pass all the props required for its features:
Expand Down Expand Up @@ -1386,3 +1344,130 @@ export const PostList = () => (
</List>
);
```

## Access Control

If you need to hide some columns based on a set of permissions, use the `<Datagrid>` component from the `@react-admin/ra-rbac` package.

```diff
-import { Datagrid } from 'react-admin';
+import { Datagrid } from '@react-admin/ra-rbac';
```

This component adds the following [RBAC](./AuthRBAC.md) controls:

- Users must have the `'read'` permission on a resource column to see it in the export:

```jsx
{ action: "read", resource: `${resource}.${source}` }.
// or
{ action: "read", resource: `${resource}.*` }.
```

- Users must have the `'delete'` permission on the resource to see the `<BulkExportButton>`.

- The default `rowClick` depends on the user permissions:
- `"edit"` if the user can access the current resource with the `edit` action
- `"show"` if the user can access the current resource with the `show` action
- empty otherwise

Here is an example of `<Datagrid>` with RBAC:

```tsx
import { canAccessWithPermissions, List, Datagrid } from '@react-admin/ra-rbac';
import {
ImageField,
TextField,
ReferenceField,
NumberField,
} from 'react-admin';

const authProvider = {
// ...
canAccess: async ({ action, record, resource }) =>
canAccessWithPermissions({
permissions: [
{ action: 'list', resource: 'products' },
{ action: 'read', resource: 'products.thumbnail' },
{ action: 'read', resource: 'products.reference' },
{ action: 'read', resource: 'products.category_id' },
{ action: 'read', resource: 'products.width' },
{ action: 'read', resource: 'products.height' },
{ action: 'read', resource: 'products.price' },
{ action: 'read', resource: 'products.description' },
// { action: 'read', resource: 'products.stock' },
// { action: 'read', resource: 'products.sales' },
// { action: 'delete', resource: 'products' },
{ action: 'show', resource: 'products' },
],
action,
record,
resource
}),
};

const ProductList = () => (
<List>
{/* The datagrid has no bulk actions as the user doesn't have the 'delete' permission */}
<Datagrid>
<ImageField source="thumbnail" />
<TextField source="reference" />
<ReferenceField source="category_id" reference="categories">
<TextField source="name" />
</ReferenceField>
<NumberField source="width" />
<NumberField source="height" />
<NumberField source="price" />
<TextField source="description" />
{/** These two columns are not visible to the user **/}
<NumberField source="stock" />
<NumberField source="sales" />
</Datagrid>
</List>
);
```

**Tip**: Adding the 'read' permission on the resource itself doesn't grant the 'read' permission on the columns. If you want a user to see all possible columns, add the 'read' permission on columns using a wildcard:

```jsx
{ action: "read", resource: "products.*" }.
```

Fow simple cases, you can also use [the `useCanAccess` hook](./useCanAccess.md) to check whether users have access to a field:

{% raw %}
```tsx
import { List, Datagrid, TextField, TextInput, ShowButton, useCanAccess } from 'react-admin';

const getUserFilters = (canAccessRole) => ([
<TextInput label="user.list.search" source="q" alwaysOn />,
<TextInput source="name" />,
canAccessRole ? <TextInput source="role" /> : null,
].filter(filter => filter !== null)
);

export const UserList = ({ permissions, ...props }) => {
const { canAccess, error, isPending } = useCanAccess({
resource: 'users.role',
action: 'read'
});
return (
<List
{...props}
filters={getUserFilters(canAccess)}
sort={{ field: 'name', order: 'ASC' }}
>
<Datagrid>
<TextField source="id" />
<TextField source="name" />
{canAccess ? <TextField source="role" /> : null}
<EditButton />
<ShowButton />
</Datagrid>
</List>
)
};
```
{% endraw %}

Note how the `canAccess` value is passed down to the custom `filters` component to allow Filter customization, too.
Loading

0 comments on commit ad6bf18

Please sign in to comment.