mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
packages
This commit is contained in:
1265
packages/core/src/hooks/form/index.spec.tsx
Normal file
1265
packages/core/src/hooks/form/index.spec.tsx
Normal file
File diff suppressed because it is too large
Load Diff
357
packages/core/src/hooks/form/index.ts
Normal file
357
packages/core/src/hooks/form/index.ts
Normal file
@@ -0,0 +1,357 @@
|
||||
import React from "react";
|
||||
import warnOnce from "warn-once";
|
||||
|
||||
import {
|
||||
useMeta,
|
||||
useOne,
|
||||
useCreate,
|
||||
useUpdate,
|
||||
useResourceParams,
|
||||
useInvalidate,
|
||||
useMutationMode,
|
||||
useRefineOptions,
|
||||
useLoadingOvertime,
|
||||
useWarnAboutChange,
|
||||
useRedirectionAfterSubmission,
|
||||
} from "@hooks";
|
||||
|
||||
import {
|
||||
redirectPage,
|
||||
asyncDebounce,
|
||||
deferExecution,
|
||||
pickNotDeprecated,
|
||||
} from "@definitions/helpers";
|
||||
|
||||
import type { UpdateParams } from "../data/useUpdate";
|
||||
import type { UseCreateParams } from "../data/useCreate";
|
||||
import type { UseFormProps, UseFormReturnType } from "./types";
|
||||
import type {
|
||||
BaseKey,
|
||||
BaseRecord,
|
||||
CreateResponse,
|
||||
HttpError,
|
||||
UpdateResponse,
|
||||
} from "../../contexts/data/types";
|
||||
|
||||
export type {
|
||||
ActionParams,
|
||||
UseFormProps,
|
||||
UseFormReturnType,
|
||||
AutoSaveIndicatorElements,
|
||||
AutoSaveProps,
|
||||
AutoSaveReturnType,
|
||||
FormAction,
|
||||
RedirectAction,
|
||||
RedirectionTypes,
|
||||
FormWithSyncWithLocationParams,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* This hook orchestrates Refine's data hooks to create, edit, and clone data. It also provides a set of features to make it easier for users to implement their real world needs and handle edge cases such as redirects, invalidation, auto-save and more.
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/data/hooks/use-form} for more details.
|
||||
*
|
||||
* @typeParam TQueryFnData - Result data returned by the query function. Extends {@link https://refine.dev/docs/core/interface-references/#baserecord `BaseRecord`}
|
||||
* @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/core/interface-references/#httperror `HttpError`}
|
||||
* @typeParam TVariables - Values for params. default `{}`
|
||||
* @typeParam TData - Result data returned by the `select` function. Extends {@link https://refine.dev/docs/core/interface-references/#baserecord `BaseRecord`}. Defaults to `TQueryFnData`
|
||||
* @typeParam TResponse - Result data returned by the mutation function. Extends {@link https://refine.dev/docs/core/interface-references/#baserecord `BaseRecord`}. Defaults to `TData`
|
||||
* @typeParam TResponseError - Custom error object that extends {@link https://refine.dev/docs/core/interface-references/#httperror `HttpError`}. Defaults to `TError`
|
||||
*
|
||||
*/
|
||||
export const useForm = <
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TVariables = {},
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TResponse extends BaseRecord = TData,
|
||||
TResponseError extends HttpError = TError,
|
||||
>(
|
||||
props: UseFormProps<
|
||||
TQueryFnData,
|
||||
TError,
|
||||
TVariables,
|
||||
TData,
|
||||
TResponse,
|
||||
TResponseError
|
||||
> = {},
|
||||
): UseFormReturnType<
|
||||
TQueryFnData,
|
||||
TError,
|
||||
TVariables,
|
||||
TData,
|
||||
TResponse,
|
||||
TResponseError
|
||||
> => {
|
||||
const getMeta = useMeta();
|
||||
const invalidate = useInvalidate();
|
||||
const { redirect: defaultRedirect } = useRefineOptions();
|
||||
const { mutationMode: defaultMutationMode } = useMutationMode();
|
||||
|
||||
const { setWarnWhen } = useWarnAboutChange();
|
||||
const handleSubmitWithRedirect = useRedirectionAfterSubmission();
|
||||
|
||||
const pickedMeta = pickNotDeprecated(props.meta, props.metaData);
|
||||
const mutationMode = props.mutationMode ?? defaultMutationMode;
|
||||
|
||||
const {
|
||||
id,
|
||||
setId,
|
||||
resource,
|
||||
identifier,
|
||||
formAction: action,
|
||||
} = useResourceParams({
|
||||
resource: props.resource,
|
||||
id: props.id,
|
||||
action: props.action,
|
||||
});
|
||||
|
||||
const [autosaved, setAutosaved] = React.useState(false);
|
||||
|
||||
const isEdit = action === "edit";
|
||||
const isClone = action === "clone";
|
||||
const isCreate = action === "create";
|
||||
|
||||
const combinedMeta = getMeta({
|
||||
resource,
|
||||
meta: pickedMeta,
|
||||
});
|
||||
|
||||
const isIdRequired = (isEdit || isClone) && Boolean(props.resource);
|
||||
const isIdDefined = typeof props.id !== "undefined";
|
||||
const isQueryDisabled = props.queryOptions?.enabled === false;
|
||||
|
||||
/**
|
||||
* When a custom resource is provided through props, `id` will not be inferred from the URL to avoid any potential faulty requests.
|
||||
* In this case, `id` is required to be passed through props.
|
||||
* If `id` is not handled, a warning will be thrown in development mode.
|
||||
*/
|
||||
warnOnce(
|
||||
isIdRequired && !isIdDefined && !isQueryDisabled,
|
||||
idWarningMessage(action, identifier, id),
|
||||
);
|
||||
|
||||
/**
|
||||
* Target action to redirect after form submission.
|
||||
*/
|
||||
const redirectAction = redirectPage({
|
||||
redirectFromProps: props.redirect,
|
||||
action,
|
||||
redirectOptions: defaultRedirect,
|
||||
});
|
||||
|
||||
/**
|
||||
* Redirection function to be used in internal redirects and to be provided to the user.
|
||||
*/
|
||||
const redirect: UseFormReturnType["redirect"] = (
|
||||
redirect = isEdit ? "list" : "edit",
|
||||
redirectId = id,
|
||||
routeParams = {},
|
||||
) => {
|
||||
handleSubmitWithRedirect({
|
||||
redirect: redirect,
|
||||
resource,
|
||||
id: redirectId,
|
||||
meta: { ...pickedMeta, ...routeParams },
|
||||
});
|
||||
};
|
||||
|
||||
const queryResult = useOne<TQueryFnData, TError, TData>({
|
||||
resource: identifier,
|
||||
id,
|
||||
queryOptions: {
|
||||
// Only enable the query if it's not a create action and the `id` is defined
|
||||
enabled: !isCreate && id !== undefined,
|
||||
...props.queryOptions,
|
||||
},
|
||||
liveMode: props.liveMode,
|
||||
onLiveEvent: props.onLiveEvent,
|
||||
liveParams: props.liveParams,
|
||||
meta: { ...combinedMeta, ...props.queryMeta },
|
||||
dataProviderName: props.dataProviderName,
|
||||
});
|
||||
|
||||
const createMutation = useCreate<TResponse, TResponseError, TVariables>({
|
||||
mutationOptions: props.createMutationOptions,
|
||||
});
|
||||
|
||||
const updateMutation = useUpdate<TResponse, TResponseError, TVariables>({
|
||||
mutationOptions: props.updateMutationOptions,
|
||||
});
|
||||
|
||||
const mutationResult = isEdit ? updateMutation : createMutation;
|
||||
const isMutationLoading = mutationResult.isLoading;
|
||||
const formLoading = isMutationLoading || queryResult.isFetching;
|
||||
|
||||
const { elapsedTime } = useLoadingOvertime({
|
||||
isLoading: formLoading,
|
||||
interval: props.overtimeOptions?.interval,
|
||||
onInterval: props.overtimeOptions?.onInterval,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
// After `autosaved` is set to `true`, it won't be set to `false` again.
|
||||
// Therefore, the `invalidate` function will be called only once at the end of the hooks lifecycle.
|
||||
return () => {
|
||||
if (
|
||||
props.autoSave?.invalidateOnUnmount &&
|
||||
autosaved &&
|
||||
identifier &&
|
||||
typeof id !== "undefined"
|
||||
) {
|
||||
invalidate({
|
||||
id,
|
||||
invalidates: props.invalidates || ["list", "many", "detail"],
|
||||
dataProviderName: props.dataProviderName,
|
||||
resource: identifier,
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [props.autoSave?.invalidateOnUnmount, autosaved]);
|
||||
|
||||
const onFinish = async (
|
||||
values: TVariables,
|
||||
{ isAutosave = false }: { isAutosave?: boolean } = {},
|
||||
) => {
|
||||
const isPessimistic = mutationMode === "pessimistic";
|
||||
|
||||
// Disable warning trigger when the form is being submitted
|
||||
setWarnWhen(false);
|
||||
|
||||
// Redirect after a successful form submission
|
||||
const onSuccessRedirect = (id?: BaseKey) => redirect(redirectAction, id);
|
||||
|
||||
const submissionPromise = new Promise<
|
||||
CreateResponse<TResponse> | UpdateResponse<TResponse> | void
|
||||
>((resolve, reject) => {
|
||||
// Reject the mutation if the resource is not defined
|
||||
if (!resource) return reject(missingResourceError);
|
||||
// Reject the mutation if the `id` is not defined in edit action
|
||||
// This line is commented out because the `id` might not be set for some cases and edit is done on a resource.
|
||||
// if (isEdit && !id) return reject(missingIdError);
|
||||
// Reject the mutation if the `id` is not defined in clone action
|
||||
if (isClone && !id) return reject(missingIdError);
|
||||
// Reject the mutation if there's no `values` passed
|
||||
if (!values) return reject(missingValuesError);
|
||||
// Auto Save is only allowed in edit action
|
||||
if (isAutosave && !isEdit) return reject(autosaveOnNonEditError);
|
||||
|
||||
if (!isPessimistic && !isAutosave) {
|
||||
// If the mutation mode is not pessimistic, handle the redirect immediately in an async manner
|
||||
// `setWarnWhen` blocks the redirects until set to `false`
|
||||
// If redirect is done before the value is properly set, it will be blocked.
|
||||
// We're deferring the execution of the redirect to ensure that the value is set properly.
|
||||
deferExecution(() => onSuccessRedirect());
|
||||
// Resolve the promise immediately
|
||||
resolve();
|
||||
}
|
||||
|
||||
const variables:
|
||||
| UpdateParams<TResponse, TResponseError, TVariables>
|
||||
| UseCreateParams<TResponse, TResponseError, TVariables> = {
|
||||
values,
|
||||
resource: identifier ?? resource.name,
|
||||
meta: { ...combinedMeta, ...props.mutationMeta },
|
||||
metaData: { ...combinedMeta, ...props.mutationMeta },
|
||||
dataProviderName: props.dataProviderName,
|
||||
invalidates: isAutosave ? [] : props.invalidates,
|
||||
successNotification: isAutosave ? false : props.successNotification,
|
||||
errorNotification: isAutosave ? false : props.errorNotification,
|
||||
// Update specific variables
|
||||
...(isEdit
|
||||
? {
|
||||
id: id ?? "",
|
||||
mutationMode,
|
||||
undoableTimeout: props.undoableTimeout,
|
||||
optimisticUpdateMap: props.optimisticUpdateMap,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
const { mutateAsync } = isEdit ? updateMutation : createMutation;
|
||||
|
||||
mutateAsync(variables as any, {
|
||||
// Call user-defined `onMutationSuccess` and `onMutationError` callbacks if provided
|
||||
// These callbacks will not have an effect on the submission promise
|
||||
onSuccess: props.onMutationSuccess
|
||||
? (data, _, context) => {
|
||||
props.onMutationSuccess?.(data, values, context, isAutosave);
|
||||
}
|
||||
: undefined,
|
||||
onError: props.onMutationError
|
||||
? (error: TResponseError, _, context) => {
|
||||
props.onMutationError?.(error, values, context, isAutosave);
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
// If the mutation mode is pessimistic, resolve the promise after the mutation is succeeded
|
||||
.then((data) => {
|
||||
if (isPessimistic && !isAutosave) {
|
||||
deferExecution(() => onSuccessRedirect(data?.data?.id));
|
||||
}
|
||||
if (isAutosave) {
|
||||
setAutosaved(true);
|
||||
}
|
||||
resolve(data);
|
||||
})
|
||||
// If the mutation mode is pessimistic, reject the promise after the mutation is failed
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
return submissionPromise;
|
||||
};
|
||||
|
||||
const onFinishAutoSave = asyncDebounce(
|
||||
(values: TVariables) => onFinish(values, { isAutosave: true }),
|
||||
props.autoSave?.debounce || 1000,
|
||||
"Cancelled by debounce",
|
||||
);
|
||||
|
||||
const overtime = {
|
||||
elapsedTime,
|
||||
};
|
||||
|
||||
const autoSaveProps = {
|
||||
status: updateMutation.status,
|
||||
data: updateMutation.data,
|
||||
error: updateMutation.error,
|
||||
};
|
||||
|
||||
return {
|
||||
onFinish,
|
||||
onFinishAutoSave,
|
||||
formLoading,
|
||||
mutationResult,
|
||||
mutation: mutationResult,
|
||||
queryResult,
|
||||
query: queryResult,
|
||||
autoSaveProps,
|
||||
id,
|
||||
setId,
|
||||
redirect,
|
||||
overtime,
|
||||
};
|
||||
};
|
||||
|
||||
const missingResourceError = new Error(
|
||||
"[useForm]: `resource` is not defined or not matched but is required",
|
||||
);
|
||||
|
||||
const missingIdError = new Error(
|
||||
"[useForm]: `id` is not defined but is required in edit and clone actions",
|
||||
);
|
||||
|
||||
const missingValuesError = new Error(
|
||||
"[useForm]: `values` is not provided but is required",
|
||||
);
|
||||
|
||||
const autosaveOnNonEditError = new Error(
|
||||
"[useForm]: `autoSave` is only allowed in edit action",
|
||||
);
|
||||
|
||||
const idWarningMessage = (action?: string, identifier?: string, id?: BaseKey) =>
|
||||
`[useForm]: action: "${action}", resource: "${identifier}", id: ${id}
|
||||
|
||||
If you don't use the \`setId\` method to set the \`id\`, you should pass the \`id\` prop to \`useForm\`. Otherwise, \`useForm\` will not be able to infer the \`id\` from the current URL with custom resource provided.
|
||||
|
||||
See https://refine.dev/docs/data/hooks/use-form/#id-`;
|
||||
262
packages/core/src/hooks/form/types.ts
Normal file
262
packages/core/src/hooks/form/types.ts
Normal file
@@ -0,0 +1,262 @@
|
||||
import type { Dispatch, SetStateAction } from "react";
|
||||
import type {
|
||||
QueryObserverResult,
|
||||
UseQueryOptions,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
import type {
|
||||
OptimisticUpdateMapType,
|
||||
UseUpdateProps,
|
||||
UseUpdateReturnType,
|
||||
} from "../data/useUpdate";
|
||||
import type { UseCreateProps, UseCreateReturnType } from "../data/useCreate";
|
||||
import type {
|
||||
UseLoadingOvertimeOptionsProps,
|
||||
UseLoadingOvertimeReturnType,
|
||||
} from "../useLoadingOvertime";
|
||||
import type {
|
||||
BaseKey,
|
||||
BaseRecord,
|
||||
CreateResponse,
|
||||
GetOneResponse,
|
||||
HttpError,
|
||||
IQueryKeys,
|
||||
MetaQuery,
|
||||
MutationMode,
|
||||
UpdateResponse,
|
||||
} from "../../contexts/data/types";
|
||||
import type { LiveModeProps } from "../../contexts/live/types";
|
||||
import type { SuccessErrorNotification } from "../../contexts/notification/types";
|
||||
import type { Action } from "../../contexts/router/types";
|
||||
|
||||
export type FormAction = Extract<Action, "create" | "edit" | "clone">;
|
||||
|
||||
export type RedirectAction =
|
||||
| Extract<Action, "create" | "edit" | "list" | "show">
|
||||
| false;
|
||||
|
||||
/**
|
||||
* @deprecated use RedirectAction type instead
|
||||
*/
|
||||
export type RedirectionTypes = RedirectAction;
|
||||
|
||||
export type AutoSaveProps<TVariables> = {
|
||||
autoSave?: {
|
||||
enabled: boolean;
|
||||
debounce?: number;
|
||||
onFinish?: (values: TVariables) => TVariables;
|
||||
invalidateOnUnmount?: boolean;
|
||||
invalidateOnClose?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type AutoSaveReturnType<
|
||||
TData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TVariables = {},
|
||||
> = {
|
||||
autoSaveProps: Pick<
|
||||
UseUpdateReturnType<TData, TError, TVariables>,
|
||||
"data" | "error" | "status"
|
||||
>;
|
||||
onFinishAutoSave: (
|
||||
values: TVariables,
|
||||
) => Promise<UpdateResponse<TData> | void>;
|
||||
};
|
||||
|
||||
export type AutoSaveIndicatorElements = Partial<
|
||||
Record<"success" | "error" | "loading" | "idle", React.ReactNode>
|
||||
>;
|
||||
|
||||
export type ActionParams = {
|
||||
/**
|
||||
* Type of the form mode
|
||||
* @default Action that it reads from route otherwise "create" is used
|
||||
*/
|
||||
action?: FormAction;
|
||||
};
|
||||
|
||||
type ActionFormProps<
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TVariables = {},
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TResponse extends BaseRecord = TData,
|
||||
TResponseError extends HttpError = TError,
|
||||
> = {
|
||||
/**
|
||||
* Resource name for API data interactions
|
||||
* @default Resource name that it reads from route
|
||||
*/
|
||||
resource?: string;
|
||||
/**
|
||||
* Record id for fetching
|
||||
* @default Id that it reads from the URL
|
||||
*/
|
||||
id?: BaseKey;
|
||||
/**
|
||||
* Page to redirect after a succesfull mutation
|
||||
* @type `"show" | "edit" | "list" | "create" | false`
|
||||
* @default `"list"`
|
||||
*/
|
||||
redirect?: RedirectAction;
|
||||
/**
|
||||
* Metadata query for dataProvider
|
||||
*/
|
||||
meta?: MetaQuery;
|
||||
/**
|
||||
* Metadata query for dataProvider
|
||||
* @deprecated `metaData` is deprecated with refine@4, refine will pass `meta` instead, however, we still support `metaData` for backward compatibility.
|
||||
*/
|
||||
metaData?: MetaQuery;
|
||||
/**
|
||||
* Metadata to pass for the `useOne` query
|
||||
*/
|
||||
queryMeta?: MetaQuery;
|
||||
/**
|
||||
* Metadata to pass for the mutation (`useCreate` for `create` and `clone` actions, `useUpdate` for `edit` action)
|
||||
*/
|
||||
mutationMeta?: MetaQuery;
|
||||
/**
|
||||
* [Determines when mutations are executed](/advanced-tutorials/mutation-mode.md)
|
||||
* @default `"pessimistic"*`
|
||||
*/
|
||||
mutationMode?: MutationMode;
|
||||
/**
|
||||
* Called when a mutation is successful
|
||||
*/
|
||||
onMutationSuccess?: (
|
||||
data: CreateResponse<TResponse> | UpdateResponse<TResponse>,
|
||||
variables: TVariables,
|
||||
context: any,
|
||||
isAutoSave?: boolean,
|
||||
) => void;
|
||||
/**
|
||||
* Called when a mutation encounters an error
|
||||
*/
|
||||
onMutationError?: (
|
||||
error: TResponseError,
|
||||
variables: TVariables,
|
||||
context: any,
|
||||
isAutoSave?: boolean,
|
||||
) => void;
|
||||
/**
|
||||
* Duration to wait before executing mutations when `mutationMode = "undoable"`
|
||||
* @default `5000*`
|
||||
*/
|
||||
undoableTimeout?: number;
|
||||
/**
|
||||
* If there is more than one `dataProvider`, you should use the `dataProviderName` that you will use.
|
||||
*/
|
||||
dataProviderName?: string;
|
||||
/**
|
||||
* You can use it to manage the invalidations that will occur at the end of the mutation.
|
||||
* @type `all`, `resourceAll`, `list`, `many`, `detail`, `false`
|
||||
* @default `["list", "many", "detail"]`
|
||||
*/
|
||||
invalidates?: Array<keyof IQueryKeys>;
|
||||
/**
|
||||
* react-query's [useQuery](https://tanstack.com/query/v4/docs/reference/useQuery) options of useOne hook used while in edit mode.
|
||||
*/
|
||||
queryOptions?: UseQueryOptions<
|
||||
GetOneResponse<TQueryFnData>,
|
||||
TError,
|
||||
GetOneResponse<TData>
|
||||
>;
|
||||
/**
|
||||
* react-query's [useMutation](https://tanstack.com/query/v4/docs/reference/useMutation) options of useCreate hook used while submitting in create and clone modes.
|
||||
*/
|
||||
createMutationOptions?: UseCreateProps<
|
||||
TResponse,
|
||||
TResponseError,
|
||||
TVariables
|
||||
>["mutationOptions"];
|
||||
/**
|
||||
* react-query's [useMutation](https://tanstack.com/query/v4/docs/reference/useMutation) options of useUpdate hook used while submitting in edit mode.
|
||||
*/
|
||||
updateMutationOptions?: UseUpdateProps<
|
||||
TResponse,
|
||||
TResponseError,
|
||||
TVariables
|
||||
>["mutationOptions"];
|
||||
/**
|
||||
* If you customize the [`optimisticUpdateMap`](https://refine.dev/docs/api-reference/core/hooks/data/useUpdateMany/#optimisticupdatemap) option, you can use it to manage the invalidations that will occur at the end of the mutation.
|
||||
* @default {
|
||||
* list: true,
|
||||
* many: true,
|
||||
* detail: true,
|
||||
* }
|
||||
*/
|
||||
optimisticUpdateMap?: OptimisticUpdateMapType<TResponse, TVariables>;
|
||||
} & SuccessErrorNotification<
|
||||
UpdateResponse<TResponse> | CreateResponse<TResponse>,
|
||||
TResponseError,
|
||||
{ id: BaseKey; values: TVariables } | TVariables
|
||||
> &
|
||||
ActionParams &
|
||||
LiveModeProps;
|
||||
|
||||
export type UseFormProps<
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TVariables = {},
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TResponse extends BaseRecord = TData,
|
||||
TResponseError extends HttpError = TError,
|
||||
> = ActionFormProps<
|
||||
TQueryFnData,
|
||||
TError,
|
||||
TVariables,
|
||||
TData,
|
||||
TResponse,
|
||||
TResponseError
|
||||
> &
|
||||
ActionParams &
|
||||
LiveModeProps &
|
||||
UseLoadingOvertimeOptionsProps &
|
||||
AutoSaveProps<TVariables>;
|
||||
|
||||
export type UseFormReturnType<
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TVariables = {},
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TResponse extends BaseRecord = TData,
|
||||
TResponseError extends HttpError = TError,
|
||||
> = {
|
||||
id?: BaseKey;
|
||||
setId: Dispatch<SetStateAction<BaseKey | undefined>>;
|
||||
query?: QueryObserverResult<GetOneResponse<TData>, TError>;
|
||||
/**
|
||||
* @deprecated use `query` instead
|
||||
*/
|
||||
queryResult?: QueryObserverResult<GetOneResponse<TData>, TError>;
|
||||
mutation:
|
||||
| UseUpdateReturnType<TResponse, TResponseError, TVariables>
|
||||
| UseCreateReturnType<TResponse, TResponseError, TVariables>;
|
||||
/**
|
||||
* @deprecated use `mutation` instead
|
||||
*/
|
||||
mutationResult:
|
||||
| UseUpdateReturnType<TResponse, TResponseError, TVariables>
|
||||
| UseCreateReturnType<TResponse, TResponseError, TVariables>;
|
||||
formLoading: boolean;
|
||||
onFinish: (
|
||||
values: TVariables,
|
||||
) => Promise<CreateResponse<TResponse> | UpdateResponse<TResponse> | void>;
|
||||
redirect: (
|
||||
redirect: RedirectAction,
|
||||
idFromFunction?: BaseKey | undefined,
|
||||
routeParams?: Record<string, string | number>,
|
||||
) => void;
|
||||
} & UseLoadingOvertimeReturnType &
|
||||
AutoSaveReturnType<TResponse, TResponseError, TVariables>;
|
||||
|
||||
export type FormWithSyncWithLocationParams = {
|
||||
/**
|
||||
* If true, the form will be synced with the location.
|
||||
* If an object is passed, the key property will be used as the key for the query params.
|
||||
* By default, query params are placed under the key, `${resource.name}-${action}`.
|
||||
*/
|
||||
syncWithLocation?: boolean | { key?: string; syncId?: boolean };
|
||||
};
|
||||
Reference in New Issue
Block a user