React-admin change EditButton, get request - reactjs

I am fairly new to React and react-admin. So far most of the stuff working smoothly. But I want to make the EditButton little differently that it gives.
The current request is handled like this:
localhost/api/posts/26
EditButton button called in the DataGrid like this
const PostsList = ({ permissions, ...props }) => (
<List
{...props}
filters={<PostsFilter />}
sort={{ field: 'name', order: 'ASC' }}
actions={<ActionsRefresh />}
bulkActions={false}
>
<Datagrid
{...props}
ids={this.state['clasifiers']}
hover={false}>
<TextField source="id" />
<TextField source="name" label="Name" />
<EditButton />
</Datagrid>
</List>
)
export default ClassifiersList
And the respective index.js file =>
import PostList from './PostList'
import PostEdit from './PostEdit'
export default {
list: PostList,
edit: PostEdit
}
But I want to pass more parameters to server from this get request, like:
localhost/api/posts/26/7
OR
localhost/api/posts/26?status=7
Is there a option to make the EditButton request change or do I have to create a custom button and onClick view the EditPost.js component, this I have no idea about how to do.

Related

How to filter a list in react-admin with a parameter that is fetched asynchronously?

I am trying to filter a list in react-admin.
Basically, I have a list of classes, that I want to filter by teacherId. However, the teacherId has to be fetched asynchronously.
The code looks like this:
const activitiesFilters = [
<TextInput key="search" source="q" label="Search an Activity" alwaysOn />,
]
export const ActivityList = (props) => {
const teacher = useCurrentTeacherProfile() // This is the asynchronous call
return (
<List
filters={activitiesFilters}
filter={{ authorId: teacher?.id }} // Here I am using the teacher ID to filter my list
{...props}
exporter={false}
>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="title" />
<TextField source="location" />
<DateField source="dateTime" />
</Datagrid>
</List>
)
}
The above code gives me this error:
Error: ActivityList suspended while rendering, but no fallback UI was specified. Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.
I tried adding a <Suspense /> component above the <List /> but it doesn't work.
And if I add the <Suspense /> component at the root, above the <Admin /> one, it breaks the navigation.
Is there a way I can filter my list with a parameter that is fetched asynchronously?
Thanks!
I wonder if the error does not come from the "?." typescript operator in "teacher?.id" that resolves to undefined in JS before your async call resolves.
So I'd resolve the code as follow:
import { Loading } from 'react-admin';
const activitiesFilters = [
<TextInput key="search" source="q" label="Search an Activity" alwaysOn />,
]
export const ActivityList = (props) => {
const teacher = useCurrentTeacherProfile() // This is the asynchronous call
if (!teacher) return <Loading/>
return (
<List
filters={activitiesFilters}
filter={{ authorId: teacher?.id }} // Here I am using the teacher ID to filter my list
{...props}
exporter={false}
>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="title" />
<TextField source="location" />
<DateField source="dateTime" />
</Datagrid>
</List>
)
}

React Admin - overiding handleSubmit on SimpleForm

What I want to achieve is this but using react admin SimpleForm instead of Form:
import React, { useState } from "react";
export function NameForm(props) {
const [name, setName] = useState("");
const handleSubmit = (evt) => {
evt.preventDefault();
alert(`Submitting Name ${name}`)
}
return (
<form onSubmit={handleSubmit}>
<label>
Frirst Name:
<input
type="text"
value={name}
onChange={e => setName(e.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
When I try the same pattern, i.e.:
<SimpleForm onSubmit={handleSubmit}>
it never reaches the handleSubmit function. I also tried:
<SimpleForm handleSubmit={handleSubmit}>
But again no joy.
The react admin docs here say:
Finally, it receives a handleSubmit function as prop, to be called with the updated record as an argument when the user submits the form.
Unfortunately being new to react this doesn't give me any clue as to what I should do to get this to work.
When you're using any third party library you need to follow their rules. Here you're using React admin library which support normal admin features like add/edit/listing etc. With minimal effort you can create admin panel.
So when you're focusing on creating form using React Admin , you can create add/edit form.
In your App.js you need to first define routing using Resource which contains create and edit attribute. In create/edit you can import your add/edit component and pass it. The example is given below. You can see dataProvider link is also provided. When you'll create edit form it will take data from there
// in src/App.js
import * as React from "react";
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostCreate, PostEdit } from './posts';
const App = () => (
<Admin dataProvider={jsonServerProvider('https://jsonplaceholder.typicode.com')}>
<Resource name="posts" create={PostCreate} edit={PostEdit} />
</Admin>
);
export default App;
After creating proper routing you can go to your component and can create add/edit form just like below
// in src/posts.js
import * as React from "react";
import { Create, Edit, SimpleForm, TextInput, DateInput, ReferenceManyField, Datagrid, TextField, DateField, EditButton } from 'react-admin';
import RichTextInput from 'ra-input-rich-text';
export const PostCreate = (props) => (
<Create {...props}>
<SimpleForm>
<TextInput source="title" />
<TextInput source="teaser" options={{ multiLine: true }} />
<RichTextInput source="body" />
<DateInput label="Publication date" source="published_at" defaultValue={new Date()} />
</SimpleForm>
</Create>
);
export const PostEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextInput disabled label="Id" source="id" />
<TextInput source="title" validate={required()} />
<TextInput multiline source="teaser" validate={required()} />
<RichTextInput source="body" validate={required()} />
<DateInput label="Publication date" source="published_at" />
<ReferenceManyField label="Comments" reference="comments" target="post_id">
<Datagrid>
<TextField source="body" />
<DateField source="created_at" />
<EditButton />
</Datagrid>
</ReferenceManyField>
</SimpleForm>
</Edit>
);
React-admin injects a few props to the create and edit views: the resource name, the basePath (the root URL), the permissions, and, in the case of the edit view, the record id. That’s why you need to pass the props to the <Create> and <Edit> components.
The <Create> and <Edit> components call the dataProvider, prepare the form submit handler, and render the page title and actions.
<SimpleForm> Which you mentioned in your question is responsible for creating the form only, it's not responsible for handleSubmit operation , <Create> and <Edit> components handle that.
To know more in details follow the React Admin <Create> and <Edit> doc carefully.
So I found the solution I was looking for thanks to the answer from Saswata Pal. To achieve the effect I was looking for I changed the component so it was like this:
<Create transform={transform}>
This allowed me to grab the form result before submission and modify.
Relevant docs here:
https://marmelab.com/blog/2020/06/09/react-admin-3-6.html

How can I force sorting arrows to always display in a react-admin Datagrid?

It doesn't feel like best practice, but my users want to always see the arrows next to every column that's sortable in a list view. I'm building a web app in react, using the react-admin Datagrid object:
export const PermitList: FunctionComponent<FullProps> = (props) => {
const { hasShow, ...rest } = props;
return (
<Datagrid {...rest}>
<TextInput source="permitID" />
<TextInput source="dept" />
<TextInput source="workOrder" />
<TextInput source="status" getColor={getColorFromStatus} />
<ListButtons hasShow={hasShow!} label="Edit Permit" canDelete={false} />
</Datagrid>
);
};
Fields permitID, dept, workOrder, and status are all sortable. The sort arrow appears by default when the grid header is clicked and the field sorts, but my users want to see all sort arrows all the time. I haven't been able to find any documentation on this. Is there a way to display it using Datagrid, or do I need to use a different grid object?
You can manually add your own arrow elements using headerClassName for each sortable field:
const useListStyles = makeStyles(theme => ({
myHeader: {
"&&:before": {
content: '" ⇅ "',
color: 'red',
},
},
}))
const CardList = (props) => {
const classes = useListStyles()
return (
<List {...props} >
<Datagrid>
<TextField source="id" />
<TextField source="name" headerClassName={classes.myHeader} />
</Datagrid>
</List>
)
}

Is it possible to disable default sorting in React Admin?

I have simple question
Is it possible to disable default sorting by column id? Or at least change it globally?
Thanks for answer
EDIT:
To be more specific, I have REST API (OData) which returns "Id" instead of "id" so I have to set sort everytime I use related component to prevent undefined errors.
I would welcome option to disable default sort in related components.
If you are looking for a solution to disable sort option for that column, you can use sortable={false}.
Example usage:
import React from 'react';
import { List, Datagrid, TextField } from 'react-admin';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" sortable={false} />
<TextField source="title" />
<TextField source="body" />
</Datagrid>
</List>
);
Or you can specify a default sort for the List.
export const PostList = (props) => (
<List {...props} sort={{ field: 'published_at', order: 'DESC' }}>
...
</List>
);

Add custom column to Datagrid in admin-on-rest

I've created an admin panel in React.js using admin-on-rest. I have a page showing a user list pulling data from an api. I need to add a custom column at the end of each row of that table that will display a progress bar for each user.
I'm using a module called rc-progress to generate the progress bar. Here's an example display on a separate page currently from the user list:
import React from 'react';
import { Line } from 'rc-progress';
var Progress = React.createClass({
render: function render() {
return (
<Line percent="40" strokeWidth="1" strokeColor="#38bcd5" />
);
}
});
export default Progress;
I'm not sure how to append a custom column to a Datagrid in admin-on-rest to add in that progress bar.
Here's the code I have for the User list which is displaying the data from the API correctly. I've added a comment where I'd want to add the progress bar:
import React from 'react';
import { List, Datagrid, TextField} from 'admin-on-rest';
import { Line } from 'rc-progress';
export const UserList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="firstName" />
<TextField source="lastName" />
<TextField source="email" />
<TextField source="phone" />
<TextField source="type" />
//I'd like to add the progress bar below:
//<Line percent="40" strokeWidth="1" strokeColor="#38bcd5" />
</Datagrid>
</List>
);
export default UserList;
Any help is much appreciated!
Update (Solution)
So on the recommendation of Gildas I've tried to use the FunctionField. Here is the working version of the code. (The progress bar has hard-coded values right now)
import React from 'react';
import { List, Datagrid, TextField} from 'admin-on-rest';
import { Line } from 'rc-progress';
import { FunctionField } from 'admin-on-rest'
export const UserList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="firstName" />
<TextField source="lastName" />
<TextField source="email" />
<TextField source="phone" />
<TextField source="type" />
//Here is the working version below:
<FunctionField label="Progress" render= {function render() { return ( <Line percent="40" strokeWidth="1" strokeColor="#38bcd5" />);}} />
</Datagrid>
</List>
);
export default UserList;
Here's a current screenshot:
The FunctionField should do the trick: https://marmelab.com/admin-on-rest/Fields.html#functionfield
If not, have you tried following the custom field documentation ?

Resources