Skip to content
Closed
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
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ jobs:

e-commerce:
runs-on: ubuntu-latest
if: github.ref_type != 'tag'
needs: [typecheck]
steps:
- name: Checkout
Expand Down Expand Up @@ -218,7 +217,7 @@ jobs:
- name: Build create-react-admin
run: make build-create-react-admin install
- name: Create new project
run: ./node_modules/.bin/create-react-admin myadmin --data-provider ra-data-fakerest --auth-provider local-auth-provider --install npm
run: ./node_modules/.bin/create-react-admin myadmin --data-provider ra-data-fakerest --auth-provider local-auth-provider --resource posts --resource comments --install npm
- name: Run the tests
working-directory: ./myadmin
run: npm run test
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 5.5.4

* Fix `<FilerLiveForm>` does not allow to clear filters ([#10522](https://github.com/marmelab/react-admin/pull/10522)) ([djhi](https://github.com/djhi))
* Fix `create-react-admin` with `ra-data-fakerest` ignore custom resources ([#10502](https://github.com/marmelab/react-admin/pull/10502)) ([djhi](https://github.com/djhi))
* Remove doc from published `react-admin` package ([#10505](https://github.com/marmelab/react-admin/pull/10505)) ([djhi](https://github.com/djhi))
* [Doc] Backport `<DatagridAG>` and `<DatagridAGClient>` access control's doc ([#10521](https://github.com/marmelab/react-admin/pull/10521)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* [Doc] Backport `title={null}`'s doc on dialog components ([#10520](https://github.com/marmelab/react-admin/pull/10520)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* [Doc] Update doc to mention the dependency on `@ag-grid-community/styles` ([#10510](https://github.com/marmelab/react-admin/pull/10510)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* [Doc] Update `warnWhenUnsavedChanges`'s doc on dialog forms ([#10509](https://github.com/marmelab/react-admin/pull/10509)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* [Doc] Update docs to mention `format` prop for timezone adjustment ([#10506](https://github.com/marmelab/react-admin/pull/10506)) ([ogroppo](https://github.com/ogroppo))
* [Doc] Add "Guides and Concepts" section ([#10477](https://github.com/marmelab/react-admin/pull/10477)) ([fzaninotto](https://github.com/fzaninotto))
* [Doc] Deprecate mui v6 system props ([#10463](https://github.com/marmelab/react-admin/pull/10463)) ([smeng9](https://github.com/smeng9))
* [Demo] Fix build ([#10499](https://github.com/marmelab/react-admin/pull/10499)) ([djhi](https://github.com/djhi))
* [Chore] Rename directories for local storage data providers ([#10507](https://github.com/marmelab/react-admin/pull/10507)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* [Chore] Bump serialize-javascript from 6.0.1 to 6.0.2 ([#10508](https://github.com/marmelab/react-admin/pull/10508)) ([dependabot[bot]](https://github.com/apps/dependabot))

## 5.5.3

* Fix `useHandleCallback` compatibility with `React.StrictMode` ([#10486](https://github.com/marmelab/react-admin/pull/10486)) ([erwanMarmelab](https://github.com/erwanMarmelab))
Expand Down
2 changes: 1 addition & 1 deletion cypress/support/LoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export default url => ({
appLoader: '.app-loader',
username: "input[name='username']",
password: "input[name='password']",
submitButton: 'button',
submitButton: "button[type='submit']",
title: '#react-admin-title',
},

Expand Down
39 changes: 35 additions & 4 deletions docs/AppTheme.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ const App = () => (

## Built-In Themes

React-admin comes with 4 built-in themes, each one having a light and a dark variant. You can use them as a starting point for your custom theme, or use them as-is.
React-admin comes with 5 built-in themes, each one having a light and a dark variant. You can use them as a starting point for your custom theme, or use them as-is.

| :---: | :---: |
| &nbsp;&nbsp; [Default](#default) [![Default light theme](./img/defaultLightTheme1.jpg)]((#default)) | &nbsp;&nbsp; [Nano](#nano) [![Nano light theme](./img/nanoLightTheme1.jpg)](#nano) |
| &nbsp;&nbsp; [Radiant](#radiant) [![Radiant light theme](./img/radiantLightTheme1.jpg)](#radiant) | &nbsp;&nbsp; [House](#house) [![House light theme](./img/houseLightTheme1.jpg)](#house) |
| &nbsp;&nbsp; [Default](#default) [![Default light theme](./img/defaultLightTheme1.jpg)]((#default)) | &nbsp;&nbsp; [B&W](#bw) [![B&W light theme](./img/bwLightTheme1.jpg)](#bw) |
| &nbsp;&nbsp; [Nano](#nano) [![Nano light theme](./img/nanoLightTheme1.jpg)](#nano) | &nbsp;&nbsp; [Radiant](#radiant) [![Radiant light theme](./img/radiantLightTheme1.jpg)](#radiant) |
| &nbsp;&nbsp; [House](#house) [![House light theme](./img/houseLightTheme1.jpg)](#house) |

### Default

Expand All @@ -123,6 +123,37 @@ The default theme is a good fit for every application, and works equally well on

You don't need to configure anything to use the default theme - it comes out of the box with react-admin.

### B&W

A high-contrast theme with a black and white palette, ideal for visually impaired users. Its modern-looking style, reminiscent of shadcn, is suitable for desktop apps.

[![B&W light theme](./img/bwLightTheme1.jpg)](./img/bwLightTheme1.jpg)
[![B&W light theme](./img/bwLightTheme2.jpg)](./img/bwLightTheme2.jpg)
[![B&W dark theme](./img/bwDarkTheme1.jpg)](./img/bwDarkTheme1.jpg)
[![B&W dark theme](./img/bwDarkTheme2.jpg)](./img/bwDarkTheme2.jpg)

To use the B&W theme, import the `bwLightTheme` and `bwDarkTheme` objects, and pass them to the `<Admin>` component:

```jsx
import { Admin, bwLightTheme, bwDarkTheme } from 'react-admin';

export const App = () => (
<Admin
dataProvider={dataProvider}
theme={bwLightTheme}
darkTheme={bwDarkTheme}
>
// ...
</Admin>
);
```

You must also import the Geist font in your `index.html` file:

```html
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap" rel="stylesheet">
```

### Nano

A dense theme with minimal chrome, ideal for complex apps. It uses a small font size, reduced spacing, text buttons, standard variant inputs, pale colors. Only fit for desktop apps.
Expand Down
85 changes: 69 additions & 16 deletions docs/Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ const App = () => (
);
```

An `authProvider` is an object that handles authentication and authorization logic, similar to a `dataProvider`. It exposes methods that react-admin calls when needed, and you can also call these methods manually through specialized hooks.

Once an admin has an `authProvider`, react-admin will restrict CRUD pages (the `list`, `edit`, `create`, and `show` components of your `Resources`) to authenticated users and redirect anonymous users to the `/login` page, displaying a login form for a username and password.

## Anatomy Of An `authProvider`
![Login form](./img/login-form.png)

An `authProvider` is an object that handles authentication and authorization logic, similar to a `dataProvider`. It exposes methods that react-admin calls when needed, and you can also call these methods manually through specialized hooks. The `authProvider` methods must return a Promise.
React-admin offers several built-in `authProvider` implementations for popular authentication services like **Google Identity**, **Microsoft Entra ID**, **AWS Cognito**, **Auth0**, **Keycloak**, and others. Refer to the [List of Available Auth Providers](./AuthProviderList.md) to find one that suits your requirements.

A typical `authProvider` has the following methods:
If you need to implement a custom authentication strategy, the [Building Your Own Auth Provider](./AuthProviderWriting.md) offers a step-by-step guide. It boils down to implementing a few methods that react-admin calls when needed:

```js
const authProvider = {
Expand All @@ -54,8 +56,6 @@ const authProvider = {
};
```

You can use an existing Auth Provider from the [List of Available Auth Providers](./AuthProviderList.md) or write your own by following the [Building Your Own Auth Provider](./AuthProviderWriting.md) instructions.

## Sending Credentials To The API

The `authProvider` handles authentication logic, but the `dataProvider` must include the user credentials in requests to the API.
Expand Down Expand Up @@ -229,23 +229,74 @@ const App = () => (

## Customizing The Login Component

Using an `authProvider` is enough to secure your app if authentication relies on a username and password. But for cases like using an email instead of a username, Single-Sign-On (SSO), or two-factor authentication, you can implement your own `LoginPage` component to be displayed under the `/login` route.
Using an `authProvider` is enough to secure your app if authentication relies on a username and password. But for cases like using an email instead of a username, Single-Sign-On (SSO), or two-factor authentication, you can use a custom login page by setting the [`<Admin loginPage>`](./Admin.md#loginpage) prop.

Pass this component to the [`<Admin loginPage>`](./Admin.md#loginpage) prop:
For example, to use an email field instead of a username field, use the `LoginWithEmail` component:

```jsx
// in src/App.js
import { Admin } from 'react-admin';

import MyLoginPage from './MyLoginPage';
```tsx
import { Admin, LoginWithEmail } from 'react-admin';
import authProvider from './authProvider';

const App = () => (
<Admin loginPage={MyLoginPage} authProvider={authProvider}>
...
<Admin loginPage={LoginWithEmail} authProvider={authProvider}>
...
</Admin>
);
```

![Login with email](./img/LoginWithEmail.jpg)

The default login page component is the `Login` component, which delegates the rendering of the login form to its child, usually a `LoginForm` component. This means you can create a custom login page by adding your own content to the `Login` component.

For instance, to add a "forgot password" link to the login page:

```jsx
import { Box, Link } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import { Login, LoginForm } from 'react-admin';

const MyLogin = () => (
<Login>
<LoginForm />
<Box textAlign="center" mb={1}>
<Link component={RouterLink} to="/forgot-password">
Forgot password?
</Link>
</Box>
</Login>
);
```

![Login with content](./img/LoginWithContent.jpg)

You can also customize the login form fields, by setting the `LoginForm` children:

```jsx
import { Link as RouterLink } from 'react-router-dom';
import { Login, LoginForm, TextInput, PasswordInput, required } from 'react-admin';

const MyLogin = () => (
<Login>
<LoginForm>
<TextInput
autoFocus
source="email"
label="Email"
autoComplete="email"
type="email"
validate={required()}
/>
<PasswordInput
source="password"
label="Password"
autoComplete="current-password"
validate={required()}
/>
</LoginForm>
</Login>
);
```

By default, the login page displays a gradient background. To change it, use the default Login component and pass an image URL as the `backgroundImage` prop.

```jsx
Expand All @@ -257,7 +308,9 @@ const MyLoginPage = () => (
);
```

To build a Login page from scratch, use the [`useLogin` hook](./useLogin.md).
![Custom login page](./img/LoginCustomBackground.jpg)

You can also build your login page from scratch, leveraging the [`useLogin` hook](./useLogin.md) to handle the login form submission.

```jsx
// in src/MyLoginPage.js
Expand Down Expand Up @@ -415,7 +468,7 @@ export const dataProvider = addRefreshAuthToDataProvider(baseDataProvider, refre

## Authorization

Access control and permissions allow you to restrict certain pages to specific users. React-admin provides powerful primitives for implementing authorization logic. For detailed guidance, check out the [Authorization](./Permissions.md) documentation.
Access control and permissions allow you to restrict certain pages and features to specific users. React-admin provides powerful primitives for implementing authorization logic. For detailed guidance, check out the [Authorization](./Permissions.md) documentation.

<video controls autoplay muted loop>
<source src="./img/AccessControl.mp4" type="video/mp4"/>
Expand Down
21 changes: 20 additions & 1 deletion docs/CanAccess.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const LogsPage = () => (
);
```

Use the [`<CustomRoutes>`](./CustomRoutes.md) component to add custom routes to your admin.
Use the [`<CustomRoutes>`](./CustomRoutes.md) component to add custom routes to your admin.

```tsx
import { Admin, CustomRoutes, Authenticated, CanAccess, AccessDenied, Layout } from 'react-admin';
Expand Down Expand Up @@ -98,3 +98,22 @@ export const MyMenu = () => (

**Note**: You don't need to use `<Authenticated>` on custom pages if your admin uses [`requireAuth`](./Admin.md#requireauth).

## Access Denied Message

By default, `<CanAccess>` renders nothing when the user doesn't have access to the resource.

On custom pages, it's preferable to show an error message instead. Set the `accessDenied` prop to render a custom component in case of access denial:

```tsx
import { Authenticated, CanAccess, AccessDenied } from 'react-admin';

export const LogsPage = () => (
<Authenticated>
<CanAccess resource="logs" action="read" accessDenied={<AccessDenied />}>
...
</CanAccess>
</Authenticated>
);
```

![Access Denied](./img/accessDenied.png)
29 changes: 29 additions & 0 deletions docs/Create.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ You can customize the `<Create>` component using the following props:
* `className`: passed to the root component
* [`component`](#component): override the root component
* [`disableAuthentication`](#disableauthentication): disable the authentication check
* [`mutationMode`](#mutationmode): switch to optimistic or undoable mutations (pessimistic by default)
* [`mutationOptions`](#mutationoptions): options for the `dataProvider.create()` call
* [`record`](#record): initialize the form with a record
* [`redirect`](#redirect): change the redirect location after successful creation
Expand Down Expand Up @@ -154,6 +155,34 @@ const PostCreate = () => (
);
```

## `mutationMode`

The `<Create>` view exposes a Save button, which perform a "mutation" (i.e. it creates the data). React-admin offers three modes for mutations. The mode determines when the side effects (redirection, notifications, etc.) are executed:

- `pessimistic`: The mutation is passed to the dataProvider first. When the dataProvider returns successfully, the mutation is applied locally, and the side effects are executed.
- `optimistic`: The mutation is applied locally and the side effects are executed immediately. Then the mutation is passed to the dataProvider. If the dataProvider returns successfully, nothing happens (as the mutation was already applied locally). If the dataProvider returns in error, the page is refreshed and an error notification is shown.
- `undoable` (default): The mutation is applied locally and the side effects are executed immediately. Then a notification is shown with an undo button. If the user clicks on undo, the mutation is never sent to the dataProvider, and the page is refreshed. Otherwise, after a 5 seconds delay, the mutation is passed to the dataProvider. If the dataProvider returns successfully, nothing happens (as the mutation was already applied locally). If the dataProvider returns in error, the page is refreshed and an error notification is shown.

By default, pages using `<Create>` use the `pessimistic` mutation mode as the new record identifier is often generated on the backend. However, should you decide to generate this identifier client side, you can change the `mutationMode` to either `optimistic` or `undoable`:

```jsx
const PostCreate = () => (
<Create mutationMode="optimistic">
// ...
</Create>
);
```

And to make the record creation undoable:

```jsx
const PostCreate = () => (
<Create mutationMode="undoable">
// ...
</Create>
);
```

## `mutationOptions`

You can customize the options you pass to react-query's `useMutation` hook, e.g. to pass [a custom `meta`](./Actions.md#meta-parameter) to the `dataProvider.create()` call.
Expand Down
1 change: 1 addition & 0 deletions docs/CreateBase.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ You can customize the `<CreateBase>` component using the following props, docume

* `children`: the components that renders the form
* [`disableAuthentication`](./Create.md#disableauthentication): disable the authentication check
* [`mutationMode`](./Create.md#mutationmode): Switch to optimistic or undoable mutations (pessimistic by default)
* [`mutationOptions`](./Create.md#mutationoptions): options for the `dataProvider.create()` call
* [`record`](./Create.md#record): initialize the form with a record
* [`redirect`](./Create.md#redirect): change the redirect location after successful creation
Expand Down
Loading
Loading