undefined id at edit page in react admin - reactjs

I'm using react admin for a project, I need to add descriptions to users: admins are allowed to add/edit to any user and only user themselves can edit their own description. I am able to show the edit button to the logged in user, but every time it hits the actual edit page, the user id becomes undefined and it routes me to a bad url error page. I'm new to react and react-admin so I don't really understand what's causing it become undefined.
Thanks in advance!
//in userList.js
export const UserList = ({ permissions, ...props }) => (
<List {...props} bulkActionButtons={false} sort={{ field: 'display_name', order: 'ASC'}} >
<Datagrid>
<TextField source="display_name" label="User Name" />
<RoleField source="role" label="User Role" />
<TextField source="description" label="Description"/>
<BooleanField source="active" />
<FormDataConsumer>
{({ formData }) => (formData.id === JSON.parse(user_info).id) &&
<EditButton/>
}
</FormDataConsumer>
{permissions === "administrator" &&<EditButton />}
</Datagrid>
</List>
);
//in useredit.js
export const UserEdit = ({permissions, ...props}) => (
<Edit {...props}>
<SimpleForm toolbar={<SaveOnlyToolbar />}>
<DisabledInput source="display_name" />
<DisabledInput source="distinguished_names" />
<TextInput resource="description" label="Description"/>
<FormDataConsumer>
{({ formData }) => formData.is_only_admin ?
<React.Fragment>
<DisabledInput source="role" />
<DisabledInput source="active" />
</React.Fragment>
:
<React.Fragment>
<SelectInput source="role" label="Role" choices={RoleChoices}/>
<BooleanInput source="active" />
</React.Fragment>
}
</FormDataConsumer>
</SimpleForm>
</Edit>
);
//in app.js
const content = () => {
return (
<Admin
authProvider={authProvider}
dataProvider={dataProvider}
customRoutes={[
<Route exact path="/help" component={Help}/>,
<Route exact path="/" component={Dashboard}/>]}
loginPage={false}
>
{role => [
(role === 'administrator' || role === 'read_only' || role === 'user') ? <Resource name='user' list={UserList} icon={PeopleIcon} edit={role === 'administrator' || role === 'user' ? UserEdit : null}/> : null,
]}
</Admin>
);
}
return <>{content()}</>;
};
export default App;

The <FormDataConsumer>component works only inside forms: <SimpleForm>, <TabbedForm> and others. In the <List>component will not work.

Related

Conditionally render TextFields in react-admin [duplicate]

Some fields I want to only show if they have a value. I would expect to do this like so:
<Show {...props} >
<SimpleShowLayout>
{ props.record.id ? <TextField source="id" />: null }
</SimpleShowLayout>
</Show>
But that doesn't work. I can make it somewhat work by making each field a higher order component, but I wanted to do something cleaner. Here's the HOC method I have:
const exists = WrappedComponent => props => props.record[props.source] ?
<WrappedComponent {...props} />: null;
const ExistsTextField = exists(TextField);
// then in the component:
<Show {...props} >
<SimpleShowLayout>
<ExistsTextField source="id" />
</SimpleShowLayout>
</Show>
This correctly shows the value, but strips the label.
We need to update our documentation about this. In the mean time, you can find informations about how to achieve that in the upgrade guide: https://github.com/marmelab/react-admin/blob/master/UPGRADE.md#aor-dependent-input-was-removed
Here's an example:
import { ShowController, ShowView, SimpleShowLayout, TextField } from 'react-admin';
const UserShow = props => (
<ShowController {...props}>
{controllerProps =>
<ShowView {...props} {...controllerProps}>
<SimpleShowLayout>
<TextField source="username" />
{controllerProps.record && controllerProps.record.hasEmail &&
<TextField source="email" />
}
</SimpleShowLayout>
</ShowView>
}
</ShowController>
);
Maybe this way can be useful
import { FormDataConsumer } from 'react-admin'
<FormDataConsumer>
{
({ formData, ...rest}) => formData.id &&
<>
<ExistsTextField source="id" />
</>
}
</FormDataConsumer>

React-admin: permissions not accessible in react.component

I am using react-admin and have incorporated the advanced tutorial "Creating and Editing a Record From the List Page". This tutorial uses react.component instead of constants. I now need to display fields based of my values in the permissions object passed by authorization. I can do this fine in constants and in the admin component but permissions is always null if I try to access it in the react.component.
class InviteCodeList extends React.Component {
render() {
const { permissions,push, classes, ...props } = this.props;
console.log('permissions');
console.log(permissions);
return (
<Fragment>
<List
{...props}
filters={<CustomFilter />}
actions={<CustomActions />}
sort={{ field: 'title', order: 'ASC' }}
>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<WithPermissions
render={({ permissions }) => (
permissions.find(f => f.resource === 'admin') !== undefined
? <TextField source="invite_code" />
: null
)}
/>
<ReferenceField source="price_list_id" reference="pricelists">
<TextField source="price_list_name" />
</ReferenceField>
<TextField source="effective_dt" />
<DateField source="expiration_dt" />
<EditButton />
</Datagrid>
</List>
Here is the new code segment. I did not check for null which is returned before the API call returns the actual data.
<Fragment>
<List
{...props}
filters={<CustomFilter />}
actions={<CustomActions />}
sort={{ field: 'title', order: 'ASC' }}
>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
permissions !== null ? permissions.find(f => f.resource === 'admin') !== undefined
? <TextField source="invite_code" />
: null : null
<DateField source="expiration_dt" />
<EditButton />
</Datagrid>
</List>

Displaying Menu List depending on the user permissions

I am getting the same menu list for all users when I log in. But, I need to display different menu item for different users based on their roles using react-admin.
const cardActionStyle = {
zIndex: 2,
display: 'inline-block',
float: 'right',
};
const PostShowActions = ({ permissions, basePath, data, resource }) => (
<CardActions style={cardActionStyle}>
<EditButton basePath={basePath} record={data} />
{permissions === 'admin' &&
<DeleteButton basePath={basePath} record={data} resource={resource} />
}
</CardActions>
);
export const PostShow = ({ permissions, ...props }) => (
<Show actions={<PostShowActions permissions={permissions} />} {...props}>
<SimpleShowLayout>
<TextField source="title" />
<RichTextField source="body" />
{permissions === 'admin' &&
<NumberField source="nb_views" />
}
</SimpleShowLayout>
</Show>
);
Change the component function to be able to console log the permission prop, like
const Component = ({permissions, ...props}) => {
console.log("permissions", permissions)
return <YourComponentRendering/>
}
If permissions object is undefined, you can import <WithPermissions> from React-Admin in order to have permissions prop on you component. Check Authorization for more information.

Access the values of components in react-admin

I want to access values of components. Because I'll use it to access to another data. For example;
<ArrayInput source='services'>
<SimpleFormIterator>
<ReferenceInput label="Service Type"
source="serviceType"
reference="servicetypes"
validate={required()}>
<SelectInput optionText={GAMMA_CONSTANTS.SOURCE_ID} />
</ReferenceInput>
{(this.state.serviceTypes && this.state.serviceTypes.length > 0) ?
this.state.serviceTypes.filter(serviceType => {
return serviceType.id === (**source="serviceType"**)
})[0]["datapointtype"].map((feature, index) => {
return <TextInput source={index} label="deneme" />
})
: null}
</SimpleFormIterator>
</ArrayInput>
I want to access it in the filter method. Is there a way to do that?
You can use something like this:
import { FormDataConsumer } from 'react-admin';
const PostEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<BooleanInput source="hasEmail" />
<FormDataConsumer>
{({ formData, ...rest }) => formData.hasEmail &&
<TextInput source="email" {...rest} />
}
</FormDataConsumer>
</SimpleForm>
</Edit>
);
Reference: https://marmelab.com/react-admin/Inputs.html#hiding-inputs-based-on-other-inputs
You're not limited to hide/show things. In your case, you should be able to avoid using state and directly access formData.serviceTypes

Cutomize Delete button react-admin

Is there any way to customise DeleteButton button in react-admin to add a confirmation message like 'Do you want to delete item?'. Currently on clicking on DeleteButton it directly deletes the item without asking for a confirmation. I tried adding title attribute to delete button but it does not get fired.
Here is my code
//This worked with admin-on-rest, but not working with react-admin
const CategoryDeleteTitle = translate(({ record, translate }) => <span>
{translate('Delete')}
{record && `${record.code} ${record.name}`}
</span>);
const EditActions = ({ basePath, data, resource }) => (
<CardActions>
<ShowButton basePath={basePath} record={data} />
<ListButton basePath={basePath} />
<DeleteButton title={<CategoryTitle />} basePath={basePath} record={data} resource={resource} />
</CardActions>
);
export const CategoryEdit = (props) => (
<Edit actions={<EditActions />} title={<CategoryTitle />} {...props}>
<SimpleForm>
<DisabledInput source="id" />
<TextInput source="name" />
</SimpleForm>
</Edit>
);
We now handle deletions in an optimistic way, providing an undo mechanism instead of a confirmation dialog.
If this doesn't suit you, you can follow the UPGRADE GUIDE which leads to this page of the documentation: https://marmelab.com/react-admin/CreateEdit.html#actions
Note that you'll have to create and handle your confirmation dialog using something like react-modals and dispatch the DELETE action yourself.
You can use this gist with custom actions like:
const UserEditActions = ({ basePath, data, resource }) => (
<CardActions>
<ListButton basePath={basePath} />
<DeleteButtonWithConfirmation basePath={basePath} record={data} resource={resource} undoable={false} />
<RefreshButton />
</CardActions>
);
export const UserEdit = ({ ...props }) => (
<Edit {...props} actions={<UserEditActions />} >
<CreateEditForm title={<EntityTitle label="User" />} />
</Edit>
);
In react-admin v3, there is now a DeleteWithConfirmButton :-)
According to the documentation "https://marmelab.com/react-admin/CreateEdit.html" create:
const CustomToolbar = props => (
<Toolbar {...props} classes={useStyles()}>
<SaveButton />
<DeleteButton undoable={false} />
</Toolbar>
);
import from react-admin button you need like this:
import {
Toolbar,
SaveButton,
DeleteWithConfirmButton
} from 'react-admin';
see all available names here https://github.com/marmelab/react-admin/tree/master/packages/ra-ui-materialui/src/button, and change DeleteButton on ImportedButton like this:
export const CustomToolbar = props => (
<Toolbar {...props} classes={useStyles()}>
<SaveButton/>
<DeleteWithConfirmButton/>
</Toolbar>
);
And change in the code, where you need <SimpleForm toolbar={<CustomToolbar />}>.

Resources