Hello and thanks for this project :-).
In my list components, I would prefer to be able to click on the id or name of my record instead of the edit/show button to access the detailed page of the record.
For example here I always click on the class name instead of the (far on the right) edit button to see details about the class.

So I have been looking for a kind of LinkField where the text is specified with the source prop and the link is a function with the record as parameter (but it could also be a linkType props as in ReferenceField.
<LinkField source="name" linkType="edit" />
or
<LinkField source="name" link={record => `/someResource/${record.id}`} />
Does it make sense to you?
Makes sense to me. In the last month, I've made a custom component called LinkAnyFieldButton that I can wrap around any field and make it link like a ShowButton or EditButton and more.
Here it is and how you may use it. I don't have time for documentation, so you'll have to follow the render logic to see what the props do.
<LinkAnyFieldButton to="show">
<ChipField source="title" />
</LinkAnyFieldButton>
// react etc
import React, { Component, Children, cloneElement, Fragment } from 'react';
import PropTypes from 'prop-types';
import shouldUpdate from 'recompose/shouldUpdate';
import { withRouter } from 'react-router-dom';
import compose from 'recompose/compose';
// mui etc
import { withStyles } from '@material-ui/core/styles';
// ra etc
import { Link, linkToRecord } from 'react-admin';
const styles = {
link: {
cursor: 'pointer',
'& *': {
cursor: 'pointer',
},
},
};
const sanitizeRestClasses = ({ link, ...rest }) => rest;
const sanitizeRestProps = ({
classes,
to,
relative,
disabled,
history,
location,
match,
staticContext,
...rest
}) => rest;
class LinkAnyFieldButton extends Component {
static propTypes = {
// passed by parent
basePath: PropTypes.string,
children: PropTypes.any,
record: PropTypes.object,
classes: PropTypes.object,
// own props
to: PropTypes.string,
relative: PropTypes.bool,
disabled: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
// withRouter props
match: PropTypes.object,
};
static defaultProps = {
to: 'show',
};
render() {
const {
basePath = '',
children,
record = {},
classes,
to,
relative,
disabled,
match,
} = this.props;
const recordLink = to.startsWith('/')
? to.replace(/\/:([\w-]+)/g, (m, param) => {
return `/${record[param]}`;
})
: linkToRecord(basePath, record.id, to);
const completeTo = relative ? `${match.url}${recordLink}` : recordLink;
const rest = sanitizeRestProps(this.props);
const restClasses = sanitizeRestClasses(classes);
const isDisabled =
typeof disabled === 'function' ? disabled(record) : disabled;
const countChildren = Children.count(children);
const childElements =
countChildren === 1
? cloneElement(children, {
record,
basePath,
classes: restClasses,
})
: Children.map(children, field =>
cloneElement(field, {
record,
basePath,
classes: restClasses,
...rest,
})
);
return isDisabled ? (
<Fragment>{childElements}</Fragment>
) : (
<Link to={`${completeTo}`} className={classes.link}>
{childElements}
</Link>
);
}
}
const enhance = compose(
withRouter, // adds props: history, location, match, staticContext
withStyles(styles),
shouldUpdate(
(props, nextProps) =>
props.translate !== nextProps.translate ||
(props.record &&
nextProps.record &&
props.record.id !== nextProps.record.id) ||
props.basePath !== nextProps.basePath ||
(props.record == null && nextProps.record != null)
)
);
export default enhance(LinkAnyFieldButton);
Thanks for the suggestion! As this can be achieved in userland (thank you for the example @christiaanwesterbeek :heart:), we won't make it a priority. If you feel this can be useful for others, please create an addon for it and add it to our Ecosystem documentation page.
Most helpful comment
Here it is and how you may use it. I don't have time for documentation, so you'll have to follow the render logic to see what the props do.