Loading...
Loading...
This skill should be used when building, modifying, or debugging a react-admin application — including creating resources, lists, forms, data fetching, authentication, relationships between entities, custom pages, or any CRUD admin interface built with react-admin.
npx skill4agent add marmelab/react-admin react-admingetListgetOnecreateupdatedeletegetManygetManyReferenceupdateManydeleteManytranslatechangeLocalegetLocalefetchaxios<Edit actions={<MyCustomActions />}>
<SimpleForm>
<TextInput source="title" />
</SimpleForm>
</Edit><Admin layout={MyLayout}><Layout menu={MyMenu}>useRecordContext()useListContext()useShowContext()useEditContext()useCreateContext()useTranslate()useGetIdentity()use*ControlleruseListController()useEditController()useShowController()<Resource>/posts/posts/create/posts/:id/edit/posts/:id/show<CustomRoutes>useCreatePath()<Link>routerProviderconst { data, total, isPending, error } = useGetList('posts', {
pagination: { page: 1, perPage: 25 },
sort: { field: 'created_at', order: 'DESC' },
filter: { status: 'published' },
});
const { data: record, isPending } = useGetOne('posts', { id: 123 });
const { data: records } = useGetMany('posts', { ids: [1, 2, 3] });
const { data, total } = useGetManyReference('comments', {
target: 'post_id', id: 123,
pagination: { page: 1, perPage: 25 },
});[mutate, state]const [create, { isPending }] = useCreate();
const [update] = useUpdate();
const [deleteOne] = useDelete();
// Call with resource and params
create('posts', { data: { title: 'Hello' } });
update('posts', { id: 1, data: { title: 'Updated' }, previousData: record });
deleteOne('posts', { id: 1, previousData: record });const authProvider = {
login: ({ username, password }) => Promise<void>,
logout: () => Promise<void>,
checkAuth: () => Promise<void>, // Verify credentials are valid
checkError: (error) => Promise<void>, // Detect auth errors from API responses
getIdentity: () => Promise<{ id, fullName, avatar }>,
getPermissions: () => Promise<any>,
canAccess: ({ resource, action, record }) => Promise<boolean>, // RBAC
};useGetIdentity()useCanAccess()<Authenticated>useAuthenticated()authProvider.canAccess()useCanAccess()httpClient{/* Show a the company of the current record based on its company_id */}
<ReferenceField source="company_id" reference="companies" />
{/* Show a list of related records (reverse FK) */}
<ReferenceManyField reference="comments" target="post_id">
<DataTable>
<TextField source="body" />
<DateField source="created_at" />
</DataTable>
</ReferenceManyField>
{/* Show multiple referenced records (array of IDs) */}
<ReferenceArrayField source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>{/* Select from another resource (FK) */}
<ReferenceInput source="company_id" reference="companies" />
{/* Multi-select from another resource (array of IDs) */}
<ReferenceArrayInput source="tag_ids" reference="tags" /><SimpleForm><TabbedForm>required()minLength(min)maxLength(max)minValue(min)maxValue(max)number()email()regex(pattern, message)<TextInput source="title" validate={[required(), minLength(3)]} />useWatch()// posts/index.ts
export default {
list: PostList,
create: PostCreate,
edit: PostEdit,
icon: PostIcon,
recordRepresentation: (record) => record.title, // How records appear in references
};const dataProvider = {
...baseDataProvider,
archivePost: async (id) => { /* custom logic */ },
};
// Call via useDataProvider and useQuery:
// const dp = useDataProvider();
// const { data } = useQuery(['archivePost', id], () => dp.archivePost(id));useStore()const [theme, setTheme] = useStore('theme', 'light');const notify = useNotify();
const redirect = useRedirect();
const refresh = useRefresh();
notify('Record saved', { type: 'success' });
redirect('list', 'posts'); // Navigate to /posts
redirect('edit', 'posts', 123); // Navigate to /posts/123
refresh(); // Invalidate all queries<CanAccess>useCanAccess