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

[TypeScript] Allow providing error type in dataProvider and controllers hooks #10445

Merged
merged 4 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ import { useTranslate } from '../../i18n';
* );
* };
*/
const useDeleteWithConfirmController = <RecordType extends RaRecord = any>(
props: UseDeleteWithConfirmControllerParams<RecordType>
const useDeleteWithConfirmController = <
RecordType extends RaRecord = any,
ErrorType = Error,
>(
props: UseDeleteWithConfirmControllerParams<RecordType, ErrorType>
): UseDeleteWithConfirmControllerReturn => {
const {
record,
Expand All @@ -83,7 +86,7 @@ const useDeleteWithConfirmController = <RecordType extends RaRecord = any>(
const redirect = useRedirect();
const translate = useTranslate();

const [deleteOne, { isPending }] = useDelete<RecordType>(
const [deleteOne, { isPending }] = useDelete<RecordType, ErrorType>(
resource,
undefined,
{
Expand All @@ -106,21 +109,22 @@ const useDeleteWithConfirmController = <RecordType extends RaRecord = any>(
record && unselect([record.id]);
redirect(redirectTo, resource);
},
onError: (error: Error) => {
onError: error => {
setOpen(false);

notify(
typeof error === 'string'
? error
: error.message || 'ra.notification.http_error',
: (error as Error)?.message ||
'ra.notification.http_error',
{
type: 'error',
messageArgs: {
_:
typeof error === 'string'
? error
: error && error.message
? error.message
: (error as Error)?.message
? (error as Error).message
: undefined,
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ import { useTranslate } from '../../i18n';
* );
* };
*/
const useDeleteWithUndoController = <RecordType extends RaRecord = any>(
props: UseDeleteWithUndoControllerParams<RecordType>
const useDeleteWithUndoController = <
RecordType extends RaRecord = any,
ErrorType = Error,
>(
props: UseDeleteWithUndoControllerParams<RecordType, ErrorType>
): UseDeleteWithUndoControllerReturn => {
const {
record,
Expand All @@ -60,7 +63,7 @@ const useDeleteWithUndoController = <RecordType extends RaRecord = any>(
const unselect = useUnselect(resource);
const redirect = useRedirect();
const translate = useTranslate();
const [deleteOne, { isPending }] = useDelete<RecordType>(
const [deleteOne, { isPending }] = useDelete<RecordType, ErrorType>(
resource,
undefined,
{
Expand All @@ -82,19 +85,20 @@ const useDeleteWithUndoController = <RecordType extends RaRecord = any>(
record && unselect([record.id]);
redirect(redirectTo, resource);
},
onError: (error: Error) => {
onError: error => {
notify(
typeof error === 'string'
? error
: error.message || 'ra.notification.http_error',
: (error as Error)?.message ||
'ra.notification.http_error',
{
type: 'error',
messageArgs: {
_:
typeof error === 'string'
? error
: error && error.message
? error.message
: (error as Error)?.message
? (error as Error).message
: undefined,
},
}
Expand Down
15 changes: 11 additions & 4 deletions packages/ra-core/src/controller/create/CreateController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CreateControllerProps,
CreateControllerResult,
} from './useCreateController';
import { RaRecord } from '../../types';

/**
* Render prop version of the useCreateController hook
Expand All @@ -18,12 +19,18 @@ import {
* </CreateController>
* );
*/
export const CreateController = ({
export const CreateController = <
RecordType extends Omit<RaRecord, 'id'> = any,
MutationOptionsError = Error,
>({
children,
...props
}: {
children: (params: CreateControllerResult) => ReactNode;
} & CreateControllerProps) => {
const controllerProps = useCreateController(props);
children: (params: CreateControllerResult<RecordType>) => ReactNode;
} & CreateControllerProps<RecordType, MutationOptionsError>) => {
const controllerProps = useCreateController<
RecordType,
MutationOptionsError
>(props);
return children(controllerProps);
};
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const EditContextProvider = ({
value,
}: {
children: ReactNode;
value: EditControllerResult;
value: EditControllerResult<any, any>;
}) => (
<EditContext.Provider value={value}>
<SaveContextProvider value={usePickSaveContext(value)}>
Expand Down
14 changes: 10 additions & 4 deletions packages/ra-core/src/controller/edit/EditController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
EditControllerProps,
EditControllerResult,
} from './useEditController';
import { RaRecord } from '../../types';

/**
* Render prop version of the useEditController hook
Expand All @@ -18,12 +19,17 @@ import {
* </EditController>
* );
*/
export const EditController = ({
export const EditController = <
RecordType extends RaRecord = any,
ErrorType = Error,
>({
children,
...props
}: {
children: (params: EditControllerResult) => ReactNode;
} & EditControllerProps) => {
const controllerProps = useEditController(props);
children: (
params: EditControllerResult<RecordType, ErrorType>
) => ReactNode;
} & EditControllerProps<RecordType, ErrorType>) => {
const controllerProps = useEditController<RecordType, ErrorType>(props);
return children(controllerProps);
};
5 changes: 3 additions & 2 deletions packages/ra-core/src/controller/edit/useEditContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import { EditControllerResult } from './useEditController';
*/
export const useEditContext = <
RecordType extends RaRecord = any,
>(): EditControllerResult<RecordType> => {
ErrorType = Error,
>(): EditControllerResult<RecordType, ErrorType> => {
const context = useContext(EditContext);
if (!context) {
throw new Error(
'useEditContext must be used inside an EditContextProvider'
);
}
return context;
return context as EditControllerResult<RecordType, ErrorType>;
};
17 changes: 10 additions & 7 deletions packages/ra-core/src/controller/edit/useEditController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const useEditController = <
ErrorType = Error,
>(
props: EditControllerProps<RecordType, ErrorType> = {}
): EditControllerResult<RecordType> => {
): EditControllerResult<RecordType, ErrorType> => {
const {
disableAuthentication = false,
id: propsId,
Expand Down Expand Up @@ -111,7 +111,7 @@ export const useEditController = <
isFetching,
isPending,
refetch,
} = useGetOne<RecordType>(
} = useGetOne<RecordType, ErrorType>(
resource,
{ id, meta: queryMeta },
{
Expand Down Expand Up @@ -279,7 +279,7 @@ export const useEditController = <
save,
saving,
unregisterMutationMiddleware,
} as EditControllerResult<RecordType>;
} as EditControllerResult<RecordType, ErrorType>;
};

const DefaultRedirect = 'list';
Expand All @@ -292,7 +292,7 @@ export interface EditControllerProps<
id?: RecordType['id'];
mutationMode?: MutationMode;
mutationOptions?: UseUpdateOptions<RecordType, ErrorType>;
queryOptions?: UseGetOneOptions<RecordType>;
queryOptions?: UseGetOneOptions<RecordType, ErrorType>;
redirect?: RedirectionSideEffect;
resource?: string;
transform?: TransformData;
Expand Down Expand Up @@ -339,8 +339,11 @@ export interface EditControllerSuccessResult<RecordType extends RaRecord = any>
isPending: false;
}

export type EditControllerResult<RecordType extends RaRecord = any> =
export type EditControllerResult<
RecordType extends RaRecord = any,
ErrorType = Error,
> =
| EditControllerLoadingResult<RecordType>
| EditControllerLoadingErrorResult<RecordType>
| EditControllerRefetchErrorResult<RecordType>
| EditControllerLoadingErrorResult<RecordType, ErrorType>
| EditControllerRefetchErrorResult<RecordType, ErrorType>
| EditControllerSuccessResult<RecordType>;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { UseQueryOptions } from '@tanstack/react-query';
export interface UseReferenceArrayFieldControllerParams<
RecordType extends RaRecord = RaRecord,
ReferenceRecordType extends RaRecord = RaRecord,
ErrorType = Error,
> {
filter?: any;
page?: number;
Expand All @@ -18,7 +19,7 @@ export interface UseReferenceArrayFieldControllerParams<
sort?: SortPayload;
source: string;
queryOptions?: Omit<
UseQueryOptions<ReferenceRecordType[]>,
UseQueryOptions<ReferenceRecordType[], ErrorType>,
'queryFn' | 'queryKey'
>;
}
Expand Down Expand Up @@ -52,12 +53,14 @@ const defaultFilter = {};
export const useReferenceArrayFieldController = <
RecordType extends RaRecord = RaRecord,
ReferenceRecordType extends RaRecord = RaRecord,
ErrorType = Error,
>(
props: UseReferenceArrayFieldControllerParams<
RecordType,
ReferenceRecordType
ReferenceRecordType,
ErrorType
>
): ListControllerResult => {
): ListControllerResult<ReferenceRecordType, ErrorType> => {
const {
filter = defaultFilter,
page = 1,
Expand All @@ -74,23 +77,24 @@ export const useReferenceArrayFieldController = <
const ids = Array.isArray(value) ? value : emptyArray;

const { data, error, isLoading, isFetching, isPending, refetch } =
useGetManyAggregate<ReferenceRecordType>(
useGetManyAggregate<ReferenceRecordType, ErrorType>(
reference,
{ ids, meta },
{
onError: error =>
notify(
typeof error === 'string'
? error
: error.message || 'ra.notification.http_error',
: (error as Error)?.message ||
'ra.notification.http_error',
{
type: 'error',
messageArgs: {
_:
typeof error === 'string'
? error
: error && error.message
? error.message
: (error as Error)?.message
? (error as Error).message
: undefined,
},
}
Expand All @@ -99,7 +103,7 @@ export const useReferenceArrayFieldController = <
}
);

const listProps = useList<ReferenceRecordType>({
const listProps = useList<ReferenceRecordType, ErrorType>({
data,
error,
filter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ import { useFieldValue } from '../../util';

export const useReferenceFieldController = <
ReferenceRecordType extends RaRecord = RaRecord,
ErrorType = Error,
>(
options: UseReferenceFieldControllerOptions<ReferenceRecordType>
): UseReferenceFieldControllerResult<ReferenceRecordType> => {
options: UseReferenceFieldControllerOptions<ReferenceRecordType, ErrorType>
): UseReferenceFieldControllerResult<ReferenceRecordType, ErrorType> => {
const { link, reference, queryOptions } = options;
if (!reference) {
throw new Error(
'useReferenceFieldController: missing reference prop. You must provide a reference, e.g. reference="posts".'
);
}
const id = useFieldValue(options);
const referenceRecordQuery = useReference<ReferenceRecordType>({
const referenceRecordQuery = useReference<ReferenceRecordType, ErrorType>({
reference,
id,
options: {
Expand Down Expand Up @@ -50,10 +51,11 @@ export const useReferenceFieldController = <

export interface UseReferenceFieldControllerOptions<
ReferenceRecordType extends RaRecord = RaRecord,
ErrorType = Error,
> {
source: string;
queryOptions?: Omit<
UseQueryOptions<ReferenceRecordType[], Error>,
UseQueryOptions<ReferenceRecordType[], ErrorType>,
'queryFn' | 'queryKey'
>;
reference: string;
Expand All @@ -62,6 +64,7 @@ export interface UseReferenceFieldControllerOptions<

export interface UseReferenceFieldControllerResult<
ReferenceRecordType extends RaRecord = RaRecord,
> extends UseReferenceResult<ReferenceRecordType> {
ErrorType = Error,
> extends UseReferenceResult<ReferenceRecordType, ErrorType> {
link?: string | false;
}
Loading
Loading