Skip to content

Commit

Permalink
Add ability to override available routes for a <Resource>
Browse files Browse the repository at this point in the history
  • Loading branch information
slax57 committed Feb 10, 2023
1 parent 09b08ce commit e0f4bc3
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
34 changes: 34 additions & 0 deletions docs/Resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,40 @@ For instance, to change the default representation of "users" records to render
- a function (e.g. `(record) => record.title`) to specify a custom string representation
- a React component (e.g. `<MyCustomRecordRepresentation />`). In such components, use [`useRecordContext`](./useRecordContext.md) to access the record.

## `hasCreate`, `hasEdit`, `hasShow`

Some components, like [`<CreateDialog>`](./CreateDialog.md), [`<EditDialog>`](./EditDialog.md) or [`<ShowDialog>`](./ShowDialog.md) need to declare the CRUD components outside of the `<Resource>` component. In such cases, you can use the `hasCreate`, `hasEdit` and `hasShow` props to tell react-admin which CRUD components are available for a given resource.

This is useful, for instance, to have the `<ReferenceField>` component display a link to the edit or show view of the referenced record.

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

import { PostList } from './posts';
import { CommentEdit } from './commentEdit';

const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts" list={PostList} hasEdit />
<Resource name="comment" edit={CommentEdit} />
</Admin>
);

// in src/commentEdit.js
import { Edit, SimpleForm, ReferenceField } from 'react-admin';

const CommentEdit = () => (
<Edit>
<SimpleForm>
{/* renders a link to the edit view only because `hasEdit` has been set on `<Resource>` */}
<ReferenceField source="post_id" reference="posts" />
</SimpleForm>
</Edit>
);
```

## Resource Context

`<Resource>` also creates a `ResourceContext`, that gives access to the current resource name to all descendants of the main page components (`list`, `create`, `edit`, `show`).
Expand Down
9 changes: 6 additions & 3 deletions packages/ra-core/src/core/Resource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ Resource.registerResource = ({
options,
show,
recordRepresentation,
hasCreate,
hasEdit,
hasShow,
}: ResourceProps) => ({
name,
options,
hasList: !!list,
hasCreate: !!create,
hasEdit: !!edit,
hasShow: !!show,
hasCreate: !!create || !!hasCreate,
hasEdit: !!edit || !!hasEdit,
hasShow: !!show || !!hasShow,
icon,
recordRepresentation,
});
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,30 @@ const TestedComponentWithOnlyLazyCustomRoutes = ({ history }) => {
);
};

const TestedComponentWithForcedRoutes = () => {
const history = createMemoryHistory();

return (
<CoreAdminContext history={history}>
<CoreAdminRoutes
layout={MyLayout}
catchAll={CatchAll}
loading={Loading}
>
<Resource
name="posts"
list={<div />}
hasCreate
hasEdit
hasShow
/>
<Resource name="comments" list={<div />} />
{() => [<Resource name="user" list={<div />} hasEdit />]}
</CoreAdminRoutes>
</CoreAdminContext>
);
};

const expectResource = (resource: string) =>
expect(screen.queryByText(`"name":"${resource}"`, { exact: false }));

Expand Down Expand Up @@ -324,4 +348,21 @@ describe('useConfigureAdminRouterFromChildren', () => {
history.push('/foo');
expect(screen.queryByText('Foo')).not.toBeNull();
});
it('should support forcing hasEdit hasCreate or hasShow', async () => {
render(<TestedComponentWithForcedRoutes />);
await waitFor(() => expect(screen.queryByText('Loading')).toBeNull());

expectResourceView('posts', 'list').not.toBeNull();
expectResourceView('posts', 'create').not.toBeNull();
expectResourceView('posts', 'edit').not.toBeNull();
expectResourceView('posts', 'show').not.toBeNull();
expectResourceView('comments', 'list').not.toBeNull();
expectResourceView('comments', 'create').toBeNull();
expectResourceView('comments', 'edit').toBeNull();
expectResourceView('comments', 'show').toBeNull();
expectResourceView('user', 'list').not.toBeNull();
expectResourceView('user', 'create').toBeNull();
expectResourceView('user', 'edit').not.toBeNull();
expectResourceView('user', 'show').toBeNull();
});
});
3 changes: 3 additions & 0 deletions packages/ra-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ export interface ResourceProps {
create?: ComponentType<any> | ReactElement;
edit?: ComponentType<any> | ReactElement;
show?: ComponentType<any> | ReactElement;
hasCreate?: boolean;
hasEdit?: boolean;
hasShow?: boolean;
icon?: ComponentType<any>;
recordRepresentation?: ReactElement | RecordToStringFunction | string;
options?: ResourceOptions;
Expand Down

0 comments on commit e0f4bc3

Please sign in to comment.