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

[RFR] Add link function to ReferenceField #3282

Merged
merged 6 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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
17 changes: 13 additions & 4 deletions docs/Fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,10 +495,10 @@ With this configuration, `<ReferenceField>` wraps the user's name in a link to t
</Admin>
```

To change the link from the `<Edit>` page to the `<Show>` page, set the `linkType` prop to "show".
To change the link from the `<Edit>` page to the `<Show>` page, set the `linkTo` prop to "show".
fargito marked this conversation as resolved.
Show resolved Hide resolved

```jsx
<ReferenceField label="User" source="userId" reference="users" linkType="show">
<ReferenceField label="User" source="userId" reference="users" linkTo="show">
<TextField source="name" />
</ReferenceField>
```
Expand All @@ -511,11 +511,20 @@ By default, `<ReferenceField>` is sorted by its `source`. To specify another att
</ReferenceField>
```

You can also prevent `<ReferenceField>` from adding link to children by setting `linkType` to `false`.
You can also prevent `<ReferenceField>` from adding link to children by setting `linkTo` to `false`.

```jsx
// No link
<ReferenceField label="User" source="userId" reference="users" linkType={false}>
<ReferenceField label="User" source="userId" reference="users" linkTo={false}>
<TextField source="name" />
</ReferenceField>
```

You can also use a custom `linkTo` function to get a custom path for the children. This function must accept `record` and `reference` as arguments. On previous versions of React-Admin, this prop was named `LinkType`, however you should migrate it to `linkTo`.
fargito marked this conversation as resolved.
Show resolved Hide resolved

```jsx
// Custom path
<ReferenceField label="User" source="userId" reference="users" linkTo={(record, reference) => `/my/path/to/${reference}/${record.id}`}>
<TextField source="name" />
</ReferenceField>
```
Expand Down
33 changes: 26 additions & 7 deletions packages/ra-core/src/controller/field/useReference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import { crudGetManyAccumulate } from '../../actions';
import { linkToRecord } from '../../util';
import { Record, ReduxState } from '../../types';

type LinkToFunctionType = (record: Record, reference: string) => string;

interface Option {
allowEmpty?: boolean;
basePath: string;
record?: Record;
reference: string;
resource: string;
source: string;
linkType: string | boolean;
linkTo: string | boolean | LinkToFunctionType;
fargito marked this conversation as resolved.
Show resolved Hide resolved
linkType?: string | boolean | LinkToFunctionType;
fargito marked this conversation as resolved.
Show resolved Hide resolved
}

export interface UseReferenceProps {
Expand All @@ -28,7 +31,7 @@ export interface UseReferenceProps {
* @type {Object}
* @property {boolean} isLoading: boolean indicating if the reference has loaded
* @property {Object} referenceRecord: the referenced record.
* @property {string | false} resourceLinkPath link to the page of the related record (depends on linkType) (false is no link)
* @property {string | false} resourceLinkPath link to the page of the related record (depends on linkTo) (false is no link)
*/

/**
Expand All @@ -50,7 +53,8 @@ export interface UseReferenceProps {
* @param {Object} option
* @param {boolean} option.allowEmpty do we allow for no referenced record (default to false)
* @param {string} option.basePath basepath to current resource
* @param {string | false} option.linkType The type of the link toward the referenced record. edit, show of false for no link (default to edit)
* @param {string | false | LinkToFunctionType} option.linkTo="edit" The link toward the referenced record. 'edit', 'show' or false for no link (default to edit). Alternatively a function that returns a string
* @param {string | false | LinkToFunctionType} [option.linkType] DEPRECATED : old name for linkTo
* @param {Object} option.record The The current resource record
* @param {string} option.reference The linked resource name
* @param {string} option.resource The current resource name
Expand All @@ -61,7 +65,8 @@ export interface UseReferenceProps {
export const useReference = ({
allowEmpty = false,
basePath,
linkType = 'edit',
linkTo = 'edit',
linkType,
record = { id: '' },
reference,
resource,
Expand All @@ -78,9 +83,23 @@ export const useReference = ({
}
}, [sourceId, reference]);
const rootPath = basePath.replace(resource, reference);
const resourceLinkPath = !linkType
? false
: linkToRecord(rootPath, sourceId, linkType as string);
// backcompatibility : keep linkType but with warning
fargito marked this conversation as resolved.
Show resolved Hide resolved
const getResourceLinkPath = (linkTo, linkType) => {
if (linkType !== undefined) {
fargito marked this conversation as resolved.
Show resolved Hide resolved
console.warn("DEPRECATED : argument 'linkType' should be replaced by 'linkTo' in <ReferenceField />")
fargito marked this conversation as resolved.
Show resolved Hide resolved
if (!linkType) return false;
return typeof linkType === 'function'
? linkType(record, reference)
: linkToRecord(rootPath, sourceId, linkType as string);
}
else if (linkTo) {
return typeof linkTo === 'function'
? linkTo(record, reference)
: linkToRecord(rootPath, sourceId, linkTo as string);
}
else return false;
}
const resourceLinkPath = getResourceLinkPath(linkTo, linkType)

return {
isLoading: !referenceRecord && !allowEmpty,
Expand Down
30 changes: 23 additions & 7 deletions packages/ra-ui-materialui/src/field/ReferenceField.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,40 @@ ReferenceFieldView.propTypes = {
* <TextField source="name" />
* </ReferenceField>
*
* @default
* By default, includes a link to the <Edit> page of the related record
* (`/users/:userId` in the previous example).
*
* Set the linkType prop to "show" to link to the <Show> page instead.
* Set the `linkTo` prop to "show" to link to the <Show> page instead.
*
* @example
* <ReferenceField label="User" source="userId" reference="users" linkType="show">
* <ReferenceField label="User" source="userId" reference="users" linkTo="show">
* <TextField source="name" />
* </ReferenceField>
*
* @default
* You can also prevent `<ReferenceField>` from adding link to children by setting
* `linkType` to false.
* `linkTo` to false.
*
* @example
* <ReferenceField label="User" source="userId" reference="users" linkType={false}>
* <ReferenceField label="User" source="userId" reference="users" linkTo={false}>
* <TextField source="name" />
* </ReferenceField>
*
* @default
* Alternatively, you can also pass a custom function to `LinkTo`. It must take reference and record
* as arguments and return a string
*
* @example
* <ReferenceField label="User" source="userId" reference="users" linkTo={(reference, record) => "/path/to/${reference}/${record}"}>
* <TextField source="name" />
* </ReferenceField>
*
* @default
* In previous versions of React-Admin, the prop `linkType` was used. It is now deprecated and replaced with `linkTo`. However
* backward-compatibility is still kept
*/

const ReferenceField = ({ children, ...props }) => {
if (React.Children.count(children) !== 1) {
throw new Error('<ReferenceField> only accepts a single child');
Expand Down Expand Up @@ -149,14 +165,14 @@ ReferenceField.propTypes = {
sortBy: PropTypes.string,
source: PropTypes.string.isRequired,
translateChoice: PropTypes.func,
linkType: PropTypes.oneOfType([PropTypes.string, PropTypes.bool])
.isRequired,
linkType: PropTypes.oneOfType([PropTypes.string, PropTypes.bool, PropTypes.func]),
linkTo: PropTypes.oneOfType([PropTypes.string, PropTypes.bool, PropTypes.func]).isRequired,
fargito marked this conversation as resolved.
Show resolved Hide resolved
};

ReferenceField.defaultProps = {
allowEmpty: false,
classes: {},
linkType: 'edit',
linkTo: 'edit',
record: {},
};

Expand Down
1 change: 1 addition & 0 deletions packages/ra-ui-materialui/src/field/sanitizeRestProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default (props: object): object =>
'headerClassName',
'label',
'linkType',
'linkTo',
'locale',
'record',
'resource',
Expand Down