fork refine

This commit is contained in:
Stefan Pejcic
2024-02-05 10:23:04 +01:00
parent 3fffde9a8f
commit 8496a83edb
3634 changed files with 715528 additions and 2 deletions

View File

@@ -0,0 +1,16 @@
export type Action = "create" | "edit" | "list" | "show" | "clone";
export type RouteAction = Exclude<Action, "list"> | undefined;
export type RedirectAction =
| Extract<Action, "list" | "show" | "edit" | "create">
| false;
/**
* @deprecated use RedirectAction type instead
*/
export type RedirectionTypes = RedirectAction;
export type FormAction = Extract<Action, "create" | "edit" | "clone">;
export type ActionWithPage = Extract<Action, "show" | "create" | "edit">;

View File

@@ -0,0 +1 @@
export * from "./logData";

View File

@@ -0,0 +1,15 @@
import { BaseKey } from "..";
export interface ILog<TData = any> {
id: BaseKey;
createdAt: string;
author?: Record<number | string, any>;
name?: string;
data: TData;
previousData: TData;
resource: string;
action: string;
meta?: Record<number | string, any>;
}
export type ILogData<TData = any> = ILog<TData>[];

View File

@@ -0,0 +1,228 @@
import React, { PropsWithChildren } from "react";
export type OAuthProvider = {
name: string;
icon?: React.ReactNode;
label?: string;
};
export interface LoginFormTypes {
email?: string;
password?: string;
remember?: boolean;
providerName?: string;
redirectPath?: string;
}
export interface RegisterFormTypes {
email?: string;
password?: string;
providerName?: string;
}
export interface ForgotPasswordFormTypes {
email?: string;
}
export interface UpdatePasswordFormTypes {
password?: string;
confirmPassword?: string;
}
/**
* This should be the base type for `AuthPage` component implementations in UI integrations.
*/
export type AuthPageProps<
TWrapperProps extends {} = Record<keyof any, unknown>,
TContentProps extends {} = Record<keyof any, unknown>,
TFormProps extends {} = Record<keyof any, unknown>,
> = (
| PropsWithChildren<{
/**
* @description The type of the auth page.
* @default "login"
* @optional
*/
type?: "login";
/**
* @description Providers array for login with third party auth services.
* @type [OAuthProvider](/docs/api-reference/core/components/auth-page/#interface)
* @optional
*/
providers?: OAuthProvider[];
/**
* @description Render a redirect to register page button node. If set to false, register button will not be rendered.
* @default `"/register"`
* @optional
*/
registerLink?: React.ReactNode;
/**
* @description Render a redirect to forgot password page button node. If set to false, forgot password button will not be rendered.
* @default `"/forgot-password"`
* @optional
*/
forgotPasswordLink?: React.ReactNode;
/**
* @description Render a remember me button node. If set to false, remember me button will not be rendered.
* @optional
*/
rememberMe?: React.ReactNode;
/**
* @description Can be used to hide the form components
* @optional
*/
hideForm?: boolean;
}>
| PropsWithChildren<{
/**
* @description The type of the auth page.
* @optional
*/
type: "register";
/**
* @description Providers array for login with third party auth services.
* @optional
*/
providers?: OAuthProvider[];
/**
* @description Render a redirect to login page button node. If set to false, login button will not be rendered.
* @default `"/login"`
* @optional
*/
loginLink?: React.ReactNode;
/**
* @description Can be used to hide the form components
* @optional
*/
hideForm?: boolean;
}>
| PropsWithChildren<{
/**
* @description The type of the auth page.
* @optional
*/
type: "forgotPassword";
/**
* @description render a redirect to login page button node. If set to false, login button will not be rendered.
* @optional
*/
loginLink?: React.ReactNode;
}>
| PropsWithChildren<{
/**
* @description The type of the auth page.
* @optional
*/
type: "updatePassword";
}>
) & {
/**
* @description The props that will be passed to the wrapper component.
* @optional
*/
wrapperProps?: TWrapperProps;
/**
* @description The props that will be passed to the content component.
* @optional
*/
contentProps?: TContentProps;
/**
* @description This method gives you the ability to render a custom content node.
* @optional
*/
renderContent?: (
content: React.ReactNode,
title: React.ReactNode,
) => React.ReactNode;
/**
* @description Can be used to pass additional properties for the `Form`
* @optional
*/
formProps?: TFormProps;
/**
* @description Can be used to pass `Title`
* @optional
* */
title?: React.ReactNode;
};
/**
* This should be the base type for `AuthPage` `Login` component implementations in UI integrations.
*/
export type LoginPageProps<
TWrapperProps extends {} = Record<keyof any, unknown>,
TContentProps extends {} = Record<keyof any, unknown>,
TFormProps extends {} = Record<keyof any, unknown>,
> = PropsWithChildren<{
providers?: OAuthProvider[];
registerLink?: React.ReactNode;
forgotPasswordLink?: React.ReactNode;
rememberMe?: React.ReactNode;
wrapperProps?: TWrapperProps;
renderContent?: (
content: React.ReactNode,
title: React.ReactNode,
) => React.ReactNode;
contentProps?: TContentProps;
formProps?: TFormProps;
title?: React.ReactNode;
hideForm?: boolean;
}>;
/**
* This should be the base type for `AuthPage` `Register` component implementations in UI integrations.
*/
export type RegisterPageProps<
TWrapperProps extends {} = Record<keyof any, unknown>,
TContentProps extends {} = Record<keyof any, unknown>,
TFormProps extends {} = Record<keyof any, unknown>,
> = PropsWithChildren<{
providers?: OAuthProvider[];
loginLink?: React.ReactNode;
wrapperProps?: TWrapperProps;
renderContent?: (
content: React.ReactNode,
title: React.ReactNode,
) => React.ReactNode;
contentProps?: TContentProps;
formProps?: TFormProps;
title?: React.ReactNode;
hideForm?: boolean;
}>;
/**
* This should be the base type for `AuthPage` `Reset Password` component implementations in UI integrations.
*/
export type ForgotPasswordPageProps<
TWrapperProps extends {} = Record<keyof any, unknown>,
TContentProps extends {} = Record<keyof any, unknown>,
TFormProps extends {} = Record<keyof any, unknown>,
> = PropsWithChildren<{
loginLink?: React.ReactNode;
wrapperProps?: TWrapperProps;
renderContent?: (
content: React.ReactNode,
title: React.ReactNode,
) => React.ReactNode;
contentProps?: TContentProps;
formProps?: TFormProps;
title?: React.ReactNode;
}>;
/**
* This should be the base type for `AuthPage` `Update Password` component implementations in UI integrations.
*/
export type UpdatePasswordPageProps<
TWrapperProps extends {} = Record<keyof any, unknown>,
TContentProps extends {} = Record<keyof any, unknown>,
TFormProps extends {} = Record<keyof any, unknown>,
> = PropsWithChildren<{
wrapperProps?: TWrapperProps;
renderContent?: (
content: React.ReactNode,
title: React.ReactNode,
) => React.ReactNode;
contentProps?: TContentProps;
formProps?: TFormProps;
title?: React.ReactNode;
}>;

View File

@@ -0,0 +1,54 @@
import React from "react";
import { BaseRecord, HttpError, UpdateResponse } from ".";
import { UseUpdateReturnType } from "../hooks/data/useUpdate";
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> | void;
};
export type AutoSaveIndicatorElements = Partial<
Record<"success" | "error" | "loading" | "idle", React.ReactNode>
>;
export type AutoSaveIndicatorProps<
TData extends BaseRecord = BaseRecord,
TError extends HttpError = HttpError,
TVariables = {},
> = {
/**
* The data returned by the update request.
*/
data?: UseUpdateReturnType<TData, TError, TVariables>["data"];
/**
* The error returned by the update request.
*/
error?: UseUpdateReturnType<TData, TError, TVariables>["error"];
/**
* The status of the update request.
*/
status: UseUpdateReturnType<TData, TError, TVariables>["status"];
/**
* The elements to display for each status.
*/
elements?: AutoSaveIndicatorElements;
};

View File

@@ -0,0 +1,53 @@
/**
* @author aliemir
*
* `AccessControlBindings` interface, used to define the access control bindings of refine.
*
* Currently, there's no change in the interface, but only in the `params.resource` property.
*
* This also had `{ children?: ITreeMenu[] }` type extension but we can remove it now.
*
* There's an error behind this extension, since we're using `Tanstack Query` to check the `can` function,
* params are stringified and Nodes can't be stringified properly, which throws an error.
*
* These kinds of errors should be handled by the user of the `can` function, not by the `can` function itself.
*
* In this case, its the `CanAccess` component, which wraps the `can` function and is used in the `Sider` components.
* `Sider` should sanitize the `params.resource` property and remove the `children` property (if exists).
*
* This may also apply to `resource.icon` property.
*
*/
import { IResourceItem } from "@contexts/resource";
import { BaseKey } from "src";
export type CanParams = {
/**
* Resource name for API data interactions
*/
resource: string;
/**
* Intenden action on resource
*/
action: string;
/**
* Parameters associated with the resource
* @type { resource?: [IResourceItem](https://refine.dev/docs/api-reference/core/interfaceReferences/#canparams), id?: [BaseKey](https://refine.dev/docs/api-reference/core/interfaceReferences/#basekey), [key: string]: any }
*/
params?: {
resource?: IResourceItem;
id?: BaseKey;
[key: string]: unknown;
};
};
export type CanResponse = {
can: boolean;
reason?: string;
[key: string]: unknown;
};
export type AccessControlBindings = {
can: (params: CanParams) => Promise<CanResponse>;
};

View File

@@ -0,0 +1,76 @@
/**
* @author aliemir
*
* In the current internal structure, sometimes we pass params and args from one function to another,
* like in case of `check` (formerly `checkAuth`) function, we pass the reject value to `useLogout` hook,
* which handles the redirect after logout.
*
* These actions should be separated,
*
* Apps can exist with an optional auth,
* or do not redirect after logout,
* or do the redirect but not log out,
* or do the redirect to a different page than `/login`.
*
* To cover all those cases, we should return more information from auth functions.
*
* Let's say, they should always resolve, even if user is not authenticated,
* but have the proper information to handle the situation.
*
* like `authenticated: false`, `redirect: '/login'` and `logout: true`
* which will inform refine that user is not authenticated and should be redirected to `/login` and logout.
* In some cases, redirect might need to be transferred to other hooks (like `useLogout` hook),
* but these cases can be handled internally.
*
* If the response from `check` is `{ authenticated: false, logout: false, redirect: "/not-authenticated" }`,
* then the user will be redirected to `/not-authenticated` without logging out.
*
* If the response from `check` is `{ authenticated: false, logout: true, redirect: false }`,
* then the user will be logged out without redirecting.
*
* Same goes for `onError` function, it should always resolve.
*/
import { RefineError } from "../errors";
export type CheckResponse = {
authenticated: boolean;
redirectTo?: string;
logout?: boolean;
error?: RefineError | Error;
};
export type OnErrorResponse = {
redirectTo?: string;
logout?: boolean;
error?: RefineError | Error;
};
export type AuthActionResponse = {
success: boolean;
redirectTo?: string;
error?: RefineError | Error;
[key: string]: unknown;
};
export type PermissionResponse = unknown;
export type IdentityResponse = unknown;
export type AuthBindings = {
login: (params: any) => Promise<AuthActionResponse>;
logout: (params: any) => Promise<AuthActionResponse>;
check: (params?: any) => Promise<CheckResponse>;
onError: (error: any) => Promise<OnErrorResponse>;
register?: (params: any) => Promise<AuthActionResponse>;
forgotPassword?: (params: any) => Promise<AuthActionResponse>;
updatePassword?: (params: any) => Promise<AuthActionResponse>;
getPermissions?: (params?: any) => Promise<PermissionResponse>;
getIdentity?: (params?: any) => Promise<IdentityResponse>;
};
export interface IAuthBindingsContext extends Partial<AuthProvider> {
isProvided: boolean;
}
export type AuthProvider = AuthBindings;

View File

@@ -0,0 +1,18 @@
/**
* @author aliemir
*
* There's no change between `DataBindings` and `DataProvider` interfaces.
*
* But we should probably throw a soft error to the console if there's no `default` key in `MultipleDataBinding`.
*/
import { IDataContext } from "@contexts/data/IDataContext";
export type SingleDataBinding = IDataContext;
export type MultipleDataBinding = {
default: IDataContext;
[key: string]: IDataContext;
};
export type DataBindings = SingleDataBinding | MultipleDataBinding;

View File

@@ -0,0 +1,29 @@
/**
* @author aliemir
*
* i18n bindings are same with the `i18nProvider` interface.
*
* We should probably enforce the three or single parameter use in our hooks.
*
* Currently, we cover the `key, options`, `key, defaultMessage`, `key, options, defaultMessage` usages internally in i18n hooks.
* Which creates an unnecessary confusion in the codebase.
*/
export type TranslateFunction = (
key: string,
options?: unknown,
defaultMessage?: string,
) => string;
export type ChangeLocaleFunction = (
locale: string,
options?: unknown,
) => Promise<unknown> | unknown;
export type GetLocaleFunction = () => string;
export type i18nBindings = {
translate: TranslateFunction;
changeLocale: ChangeLocaleFunction;
getLocale: GetLocaleFunction;
};

View File

@@ -0,0 +1,25 @@
export { AccessControlBindings } from "./access-control";
export {
AuthBindings,
IAuthBindingsContext,
AuthActionResponse,
IdentityResponse,
CheckResponse,
OnErrorResponse,
PermissionResponse,
AuthProvider,
} from "./auth";
export { DataBindings } from "./data";
export { i18nBindings } from "./i18n";
export { LiveBindings } from "./live";
export { NotificationsBindings } from "./notifications";
export { ResourceBindings } from "./resource";
export {
RouterBindings,
ParseResponse,
ParsedParams,
GoConfig,
BackFunction,
GoFunction,
ParseFunction,
} from "./router";

View File

@@ -0,0 +1,56 @@
/**
* @author aliemir
*
* There's a small change in the `LiveBindings` interface, we've defined the `params` property of `subscribe` function
* as a combination of `LiveCommonParams` and `LiveListParams & LiveOneParams & LiveManyParams`.
* which creates a bit of a confusion because in `list` type we don't need `id` or `ids` and in `one` type we don't need `ids`.
* There should be an update like below to make it more clear in usage.
*
* A small but kinda important change for the consistency of the codebase.
*/
import {
BaseKey,
CrudFilters,
CrudSorting,
LiveEvent,
MetaQuery,
Pagination,
} from "src";
export type LiveListParams = {
resource?: string;
pagination?: Pagination;
hasPagination?: boolean;
sort?: CrudSorting;
filters?: CrudFilters;
meta?: MetaQuery;
metaData?: MetaQuery;
};
export type LiveOneParams = {
resource?: string;
id?: BaseKey;
};
export type LiveManyParams = {
resource?: string;
ids?: BaseKey[];
};
export type LiveCommonParams = {
subscriptionType: "useList" | "useOne" | "useMany";
[key: string]: unknown;
};
export type LiveBindings = {
publish?: (event: LiveEvent) => void;
subscribe: (options: {
channel: string;
types: Array<LiveEvent["type"]>;
callback: (event: LiveEvent) => void;
params?: LiveCommonParams &
(LiveListParams | LiveOneParams | LiveManyParams);
}) => unknown;
unsubscribe: (subscription: unknown) => void;
};

View File

@@ -0,0 +1,25 @@
/**
* @author aliemir
*
* While switching to NotificationBindings, we can try to experiment and explore the idea of
* user controlled undoable notifications.
*
* Currently, we're handling the undoable notifications internally by updating the existing notification.
* This is leading to some uncontrollable behaviors in the notification bindings.
*
* While leaving the control might not be possible, we can still try it at least. :)
*/
export interface OpenNotificationParams {
key?: string;
message: string;
type: "success" | "error" | "progress";
description?: string;
cancelMutation?: () => void;
undoableTimeout?: number;
}
export type NotificationsBindings = {
open: (params: OpenNotificationParams) => void;
close: (key: string) => void;
};

View File

@@ -0,0 +1,178 @@
import { ReactNode, ComponentType } from "react";
import { UseQueryResult } from "@tanstack/react-query";
import { ILogData } from "src/interfaces";
/**
* Resource route components
*/
export type ResourceRouteComponent = ComponentType<
IResourceComponentsProps<any, any>
>;
export type ResourceRoutePath = string;
export type ResourceRouteDefinition = {
path: ResourceRoutePath;
component: ResourceRouteComponent;
};
export type ResourceRouteComposition =
| ResourceRouteDefinition
| ResourceRoutePath
| ResourceRouteComponent;
export interface IResourceComponents {
list?: ResourceRouteComposition;
create?: ResourceRouteComposition;
clone?: ResourceRouteComposition;
edit?: ResourceRouteComposition;
show?: ResourceRouteComposition;
}
export type AnyString = string & { __ignore?: never };
export type ResourceAuditLogPermissions =
| "create"
| "update"
| "delete"
| AnyString;
/** Resource `meta` */
export interface KnownResourceMeta {
/**
* This is used when setting the document title, in breadcrumbs and `<Sider />` components.
* Therefore it will only work if the related components have implemented the `label` property.
*/
label?: string;
/**
* Whether to hide the resource from the sidebar or not.
* This property is checked by the `<Sider />` components.
* Therefore it will only work if the `<Sider />` component has implemented the `hide` property.
*/
hide?: boolean;
/**
* Dedicated data provider name for the resource.
* If not set, the default data provider will be used.
* You can use this property to pick a data provider for a resource when you have multiple data providers.
*/
dataProviderName?: string;
/**
* To nest a resource under another resource, set the parent property to the name of the parent resource.
* This will work even if the parent resource is not explicitly defined.
*/
parent?: string;
/**
* To determine if the resource has ability to delete or not.
*/
canDelete?: boolean;
/**
* To permit the audit log for actions on the resource.
* @default All actions are permitted to be logged.
*/
audit?: ResourceAuditLogPermissions[];
/**
* To pass `icon` to the resource.
*/
icon?: ReactNode;
}
export interface DeprecatedOptions {
/**
* @deprecated Please use `audit` property instead.
*/
auditLog?: {
permissions?: ResourceAuditLogPermissions[];
};
/**
* @deprecated Define the route in the resource components instead
*/
route?: string;
}
export interface ResourceMeta extends KnownResourceMeta {
[key: string]: any;
}
export interface ResourceProps extends IResourceComponents {
name: string;
/**
* This property can be used to identify a resource. In some cases, `name` of the resource might be repeated in different resources.
* To avoid conflicts, you pass the `identifier` property to be used as the key of the resource.
* @default `name` of the resource
*/
identifier?: string;
/**
* @deprecated This property is not used anymore.
*/
key?: string;
/**
* @deprecated Please use the `meta` property instead.
*/
options?: ResourceMeta & DeprecatedOptions;
/**
* To configure the resource, you can set `meta` properties. You can use `meta` to store any data related to the resource.
* There are some known `meta` properties that are used by the core and extension packages.
*/
meta?: ResourceMeta & DeprecatedOptions;
/**
* @deprecated Please use the `meta.canDelete` property instead.
*/
canDelete?: boolean;
/**
* @deprecated Please use the `meta.icon` property instead
*/
icon?: ReactNode;
/**
* @deprecated Please use the `meta.parent` property instead
*/
parentName?: string;
}
export interface RouteableProperties {
/**
* @deprecated Please use action props instead.
*/
canCreate?: boolean;
/**
* @deprecated Please use action props instead.
*/
canEdit?: boolean;
/**
* @deprecated Please use action props instead.
*/
canShow?: boolean;
/**
* @deprecated Please use the `meta.canDelete` property instead.
*/
canDelete?: boolean;
}
export interface IResourceComponentsProps<
TCrudData = any,
TLogQueryResult = ILogData,
> extends RouteableProperties {
name?: string;
initialData?: TCrudData;
options?: ResourceMeta & DeprecatedOptions;
logQueryResult?: UseQueryResult<TLogQueryResult>;
}
export interface IResourceItem
extends IResourceComponents,
RouteableProperties,
ResourceProps {
/**
* @deprecated Please use the `meta.label` property instead.
*/
label?: string;
/**
* @deprecated Please use action components and `getDefaultActionPath` helper instead.
*/
route?: string;
}
export interface IResourceContext {
resources: IResourceItem[];
}
export type ResourceBindings = ResourceProps[];

View File

@@ -0,0 +1,78 @@
/**
* @author aliemir
*
* Router bindings interface, used to define the router bindings of refine.
*
* We're marking of the functions as optional, some features may not work properly but this is intentional.
* Users can choose to use the router bindings or not, or use their own router bindings.
* Leaving the control to the user is the best way to go.
*
* We're defining the functions as function generators, this is to allow the user to use hooks inside the functions.
*
* `go` function is used to navigate to a specific route. We're expecting a `GoConfig` object as the only parameter.
* Passing `query` as an object, will also let users to stringify the object as they like or ignore it completely or even use a custom logic to handle query strings.
*
* `back` function is used to navigate back to the previous route. It doesn't take any parameters.
* This one is a basic function for the back buttons, absence of this function can also hide the back button,
* but this depends on the UI package implementations.
*
* `parse` function is used to parse the current route, query parameters and other information.
* We're expecting this function to lead refine to the correct resource, action and id (again, not required but recommended).
* Also there's `params` property, which is used in data hooks and other places.
* This property has an interface to match but not restricted to it.
*
* Instead of a single `useNavigation` hook,
* we can separate those functions into three different hooks,
* `useGo`, `useBack` and `useParsed`
*/
import { CrudFilters, CrudSorting } from "@contexts/data/IDataContext";
import { IResourceItem } from "./resource";
import { Action, BaseKey } from "..";
export type GoConfig = {
to?: string;
query?: Record<string, unknown>;
hash?: string;
options?: {
keepQuery?: boolean;
keepHash?: boolean;
};
type?: "push" | "replace" | "path";
};
export type ParsedParams<
TParams extends Record<string, any> = Record<string, any>,
> = {
filters?: CrudFilters;
sorters?: CrudSorting;
current?: number;
pageSize?: number;
} & TParams;
export type ParseResponse<
TParams extends Record<string, any> = Record<string, any>,
> = {
params?: ParsedParams<TParams>;
resource?: IResourceItem;
id?: BaseKey;
action?: Action;
pathname?: string;
};
export type GoFunction = (config: GoConfig) => void | string;
export type BackFunction = () => void;
export type ParseFunction<
TParams extends Record<string, any> = Record<string, any>,
> = () => ParseResponse<TParams>;
export type RouterBindings = {
go?: () => GoFunction;
back?: () => BackFunction;
parse?: () => ParseFunction;
Link?: React.ComponentType<
React.PropsWithChildren<{ to: string; [prop: string]: any }>
>;
};

View File

@@ -0,0 +1,28 @@
import React, { ReactNode } from "react";
export type TitleProps = {
collapsed: boolean;
};
export type LayoutProps = {
Sider?: React.FC<{
Title?: React.FC<TitleProps>;
render?: (props: {
items: JSX.Element[];
logout: React.ReactNode;
dashboard: React.ReactNode;
collapsed: boolean;
}) => React.ReactNode;
meta?: Record<string, unknown>;
}>;
Header?: React.FC;
Title?: React.FC<TitleProps>;
Footer?: React.FC;
OffLayoutArea?: React.FC;
dashboard?: boolean;
children?: ReactNode;
};
export type DashboardPageProps<TCrudData = any> = {
initialData?: TCrudData;
} & Record<any, any>;

View File

@@ -0,0 +1,13 @@
export interface ValidationErrors {
[field: string]:
| string
| string[]
| boolean
| { key: string; message: string };
}
export interface HttpError extends Record<string, any> {
message: string;
statusCode: number;
errors?: ValidationErrors;
}

View File

@@ -0,0 +1,3 @@
import { HttpError } from "./HttpError";
export type RefineError = HttpError;

View File

@@ -0,0 +1,2 @@
export * from "./HttpError";
export * from "./RefineError";

View File

@@ -0,0 +1,8 @@
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 };
};

View File

@@ -0,0 +1,98 @@
import { IResourceItem } from "./bindings/resource";
// contexts
export * from "../contexts/data/IDataContext";
export * from "../contexts/live/ILiveContext";
export * from "../contexts/auth/IAuthContext";
export * from "../contexts/refine/IRefineContext";
export * from "../contexts/translation/ITranslationContext";
export * from "../contexts/undoableQueue/IUndoableQueueContext";
export * from "../contexts/resource/IResourceContext";
export * from "../contexts/unsavedWarn/IUnsavedWarnContext";
export * from "../contexts/legacy-router/IRouterContext";
export * from "../contexts/accessControl/IAccessControlContext";
export * from "../contexts/notification/INotificationContext";
export * from "../contexts/auditLog/IAuditLogContext";
export * from "../components/pages/login";
// actions
export * from "./actions";
// notification
export * from "./notification";
// mutationMode
export * from "./mutationMode";
// mutationMode
export * from "./errors";
// custom components
export * from "./customComponents";
// resourceRouterParams
export * from "./resourceRouterParams";
// resourceErrorRouterParams
export * from "./resourceErrorRouterParams";
// mapData
export * from "./mapDataFn";
// successErrorNotification
export * from "./successErrorNotification";
//metaData
export * from "./metaData";
//queryKeys
export * from "./queryKey";
//metaData
export * from "./live";
//auditLog
export * from "./auditLog";
export type BaseKey = string | number;
export type BaseRecord = {
id?: BaseKey;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
};
export type BaseOption = {
label: any;
value: any;
};
/**
* @deprecated Use `BaseOption` instead.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Option extends BaseOption {}
/* Backward compatible version of 'TreeMenuItem' */
export type ITreeMenu = IResourceItem & {
key?: string;
children: ITreeMenu[];
};
export type IMenuItem = IResourceItem & {
key: string;
route: string;
};
export * from "./form-url-params";
export * from "./auth";
export * from "./bindings";
export * from "./prettify";
export * from "./autoSave";
export * from "./textTransformers";
export * from "./optimistic-update-map";

View File

@@ -0,0 +1,14 @@
import { BaseKey, MetaQuery } from "..";
export type LiveEvent = {
channel: string;
type: "deleted" | "updated" | "created" | "*" | string;
payload: {
ids?: BaseKey[];
[x: string]: any;
};
date: Date;
meta?: MetaQuery & {
dataProviderName?: string;
};
};

View File

@@ -0,0 +1,28 @@
import { LiveEvent } from ".";
import { BaseKey } from "..";
export type LiveModeProps = {
/**
* Whether to update data automatically ("auto") or not ("manual") if a related live event is received. The "off" value is used to avoid creating a subscription.
* @type [`"auto" | "manual" | "off"`](/docs/api-reference/core/providers/live-provider/#livemode)
* @default `"off"`
*/
liveMode?: "auto" | "manual" | "off";
/**
* Callback to handle all related live events of this hook.
* @type [`(event: LiveEvent) => void`](/docs/api-reference/core/interfaceReferences/#livemodeprops)
* @default `undefined`
*/
onLiveEvent?: (event: LiveEvent) => void;
/**
* Params to pass to liveProvider's subscribe method if liveMode is enabled.
* @type [`{ ids?: BaseKey[]; [key: string]: any; }`](/docs/api-reference/core/interfaceReferences/#livemodeprops)
* @default `undefined`
*/
liveParams?: {
ids?: BaseKey[];
[key: string]: any;
};
};
export type ILiveModeContextProvider = LiveModeProps;

View File

@@ -0,0 +1,2 @@
export * from "./LiveEvent";
export * from "./LiveModeProps";

View File

@@ -0,0 +1,3 @@
export interface MapDataFn<TItem, TVariables> {
(item: TItem, index?: number, items?: TItem[]): TVariables;
}

View File

@@ -0,0 +1,3 @@
import { NestedField } from "./nestedField";
export type Fields = Array<string | object | NestedField>;

View File

@@ -0,0 +1,53 @@
import type { DocumentNode } from "graphql";
export type GraphQLQueryOptions = {
/**
* @description GraphQL query to be used by data providers.
* @optional
* @example
* ```tsx
* import gql from 'graphql-tag'
* import { useOne } from '@refinedev/core'
*
* const PRODUCT_QUERY = gql`
* query GetProduct($id: ID!) {
* product(id: $id) {
* id
* name
* }
* }
* `
*
* useOne({
* id: 1,
* meta: { gqlQuery: PRODUCT_QUERY }
* })
* ```
*/
gqlQuery?: DocumentNode;
/**
* @description GraphQL mutation to be used by data providers.
* @optional
* @example
* ```tsx
* import gql from 'graphql-tag'
* import { useCreate } from '@refinedev/core'
*
* const PRODUCT_CREATE_MUTATION = gql`
* mutation CreateProduct($input: CreateOneProductInput!) {
* createProduct(input: $input) {
* id
* name
* }
* }
* `
* const { mutate } = useCreate()
*
* mutate({
* values: { name: "My Product" },
* meta: { gqlQuery: PRODUCT_QUERY }
* })
* ```
*/
gqlMutation?: DocumentNode;
};

View File

@@ -0,0 +1,2 @@
export * from "./metaDataQuery";
export * from "./metaQuery";

View File

@@ -0,0 +1,10 @@
import { QueryFunctionContext } from "@tanstack/react-query";
import { QueryBuilderOptions } from "./queryBuilderOptions";
/**
* @deprecated `MetaDataQuery` is deprecated with refine@4, use `MetaQuery` instead, however, we still support `MetaDataQuery` for backward compatibility.
*/
export type MetaDataQuery = {
[k: string]: any;
queryContext?: Omit<QueryFunctionContext, "meta">;
} & QueryBuilderOptions;

View File

@@ -0,0 +1,9 @@
import { QueryFunctionContext } from "@tanstack/react-query";
import { QueryBuilderOptions } from "./queryBuilderOptions";
import { GraphQLQueryOptions } from "./graphqlQueryOptions";
export type MetaQuery = {
[k: string]: any;
queryContext?: Omit<QueryFunctionContext, "meta">;
} & QueryBuilderOptions &
GraphQLQueryOptions;

View File

@@ -0,0 +1,8 @@
import { Fields } from "./fields";
import { QueryBuilderOptions } from "./queryBuilderOptions";
export type NestedField = {
operation: string;
variables: QueryBuilderOptions[];
fields: Fields;
};

View File

@@ -0,0 +1,8 @@
import { VariableOptions } from "./variableOptions";
import { Fields } from "./fields";
export interface QueryBuilderOptions {
operation?: string;
fields?: Fields;
variables?: VariableOptions;
}

View File

@@ -0,0 +1,9 @@
export type VariableOptions =
| {
type?: string;
name?: string;
value: any;
list?: boolean;
required?: boolean;
}
| { [k: string]: any };

View File

@@ -0,0 +1,32 @@
import {
BaseRecord,
GetListResponse,
GetOneResponse,
IQueryKeys,
} from "../interfaces";
import { QueryKey } from "@tanstack/react-query";
export type MutationMode = "pessimistic" | "optimistic" | "undoable";
export type QueryResponse<T = BaseRecord> =
| GetListResponse<T>
| GetOneResponse<T>;
export type PreviousQuery<TData> = [QueryKey, TData | unknown];
export type PrevContext<TData> = {
previousQueries: PreviousQuery<TData>[];
/**
* @deprecated `QueryKeys` is deprecated in favor of `keys`. Please use `keys` instead to construct query keys for queries and mutations.
*/
queryKey: IQueryKeys;
};
export type Context = {
previousQueries: ContextQuery[];
};
export type ContextQuery<T = BaseRecord> = {
query: QueryResponse<T>;
queryKey: QueryKey;
};

View File

@@ -0,0 +1,10 @@
import { BaseKey } from ".";
export interface IUndoableQueue {
id: BaseKey;
resource: string;
cancelMutation: () => void;
doMutation: () => void;
seconds: number;
isRunning: boolean;
isSilent: boolean;
}

View File

@@ -0,0 +1,49 @@
import { BaseKey, GetListResponse, GetManyResponse, GetOneResponse } from ".";
export type OptimisticUpdateMapType<TData, TVariables> = {
list?:
| ((
previous: GetListResponse<TData> | null | undefined,
values: TVariables,
id: BaseKey,
) => GetListResponse<TData> | null)
| boolean;
many?:
| ((
previous: GetManyResponse<TData> | null | undefined,
values: TVariables,
id: BaseKey,
) => GetManyResponse<TData> | null)
| boolean;
detail?:
| ((
previous: GetOneResponse<TData> | null | undefined,
values: TVariables,
id: BaseKey,
) => GetOneResponse<TData> | null)
| boolean;
};
export type OptimisticUpdateManyMapType<TData, TVariables> = {
list?:
| ((
previous: GetListResponse<TData> | null | undefined,
values: TVariables,
ids: BaseKey[],
) => GetListResponse<TData> | null)
| boolean;
many?:
| ((
previous: GetManyResponse<TData> | null | undefined,
values: TVariables,
ids: BaseKey[],
) => GetManyResponse<TData> | null)
| boolean;
detail?:
| ((
previous: GetOneResponse<TData> | null | undefined,
values: TVariables,
id: BaseKey,
) => GetOneResponse<TData> | null)
| boolean;
};

View File

@@ -0,0 +1,3 @@
export type Prettify<T> = {
[K in keyof T]: T[K];
} & {};

View File

@@ -0,0 +1,23 @@
import { QueryKey } from "@tanstack/react-query";
import { UseListConfig } from "@hooks/data/useList";
import { BaseKey, CrudFilters, CrudSorting, Pagination } from "src/interfaces";
export interface IQueryKeys {
all: QueryKey;
resourceAll: QueryKey;
list: (
config?:
| UseListConfig
| {
pagination?: Required<Pagination>;
hasPagination?: boolean;
sorters?: CrudSorting;
filters?: CrudFilters;
}
| undefined,
) => QueryKey;
many: (ids?: BaseKey[]) => QueryKey;
detail: (id?: BaseKey) => QueryKey;
logList: (meta?: Record<number | string, any>) => QueryKey;
}

View File

@@ -0,0 +1,6 @@
import { ActionWithPage } from "./actions";
export type ResourceErrorRouterParams = {
resource: string;
action: ActionWithPage | undefined;
};

View File

@@ -0,0 +1,7 @@
import { RouteAction } from "./actions";
export type ResourceRouterParams = {
resource: string;
id?: string;
action: RouteAction;
};

View File

@@ -0,0 +1,33 @@
import { OpenNotificationParams } from ".";
export type SuccessErrorNotification<
TData = unknown,
TError = unknown,
TVariables = unknown,
> = {
/**
* Success notification configuration to be displayed when the mutation is successful.
* @default '"There was an error creating resource (status code: `statusCode`)" or "Error when updating resource (status code: statusCode)"'
*/
successNotification?:
| OpenNotificationParams
| false
| ((
data?: TData,
values?: TVariables,
resource?: string,
) => OpenNotificationParams | false);
/**
* Error notification configuration to be displayed when the mutation fails.
* @default '"There was an error creating resource (status code: `statusCode`)" or "Error when updating resource (status code: statusCode)"'
*/
errorNotification?:
| OpenNotificationParams
| false
| ((
error?: TError,
values?: TVariables,
resource?: string,
) => OpenNotificationParams | false);
};

View File

@@ -0,0 +1,15 @@
export type ITelemetryData = {
providers: {
auth?: boolean;
data?: boolean;
router?: boolean;
notification?: boolean;
live?: boolean;
auditLog?: boolean;
i18n?: boolean;
accessControl?: boolean;
};
version: string;
resourceCount: number;
projectId?: string;
};

View File

@@ -0,0 +1,20 @@
export type TextTransformers = {
/**
* Convert a camelized/dasherized/underscored string into a humanized one
* @example
* humanize("some_name") => "Some name"
*/
humanize?: (text: string) => string;
/**
* Pluralize a word
* @example
* plural('regex') => "regexes"
*/
plural?: (word: string) => string;
/**
* Singularize a word
* @example
* singular('singles') => "single"
*/
singular?: (word: string) => string;
};