mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
packages
This commit is contained in:
3
packages/antd/src/hooks/fields/index.ts
Normal file
3
packages/antd/src/hooks/fields/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./useSelect";
|
||||
export * from "./useCheckboxGroup";
|
||||
export * from "./useRadioGroup";
|
||||
134
packages/antd/src/hooks/fields/useCheckboxGroup/index.spec.ts
Normal file
134
packages/antd/src/hooks/fields/useCheckboxGroup/index.spec.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
|
||||
import { TestWrapper } from "@test";
|
||||
|
||||
import { useCheckboxGroup } from "./";
|
||||
|
||||
describe("render hook default options", () => {
|
||||
it("should success data with resource", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCheckboxGroup({
|
||||
resource: "posts",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.checkboxGroupProps.options).toHaveLength(2),
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.checkboxGroupProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should success data with resource with optionLabel and optionValue", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCheckboxGroup<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
optionLabel: "slug",
|
||||
optionValue: "id",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.checkboxGroupProps.options).toHaveLength(2),
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.checkboxGroupProps.options).toEqual([
|
||||
{ label: "ut-ad-et", value: "1" },
|
||||
{ label: "consequatur-molestiae-rerum", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should generate options with custom optionLabel and optionValue functions", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCheckboxGroup({
|
||||
resource: "posts",
|
||||
optionLabel: (item) => `${item.title} - ${item.userId}`,
|
||||
optionValue: (item) => `${item.id}`,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
const { checkboxGroupProps } = result.current;
|
||||
|
||||
expect(checkboxGroupProps.options).toHaveLength(2);
|
||||
expect(checkboxGroupProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet. - 5",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est. - 36", value: "2" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should invoke queryOptions methods successfully", async () => {
|
||||
const mockFunc = jest.fn();
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCheckboxGroup<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
optionLabel: "slug",
|
||||
optionValue: "id",
|
||||
queryOptions: {
|
||||
onSuccess: (data) => {
|
||||
mockFunc();
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.checkboxGroupProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.checkboxGroupProps.options).toEqual([
|
||||
{ label: "ut-ad-et", value: "1" },
|
||||
{ label: "consequatur-molestiae-rerum", value: "2" },
|
||||
]),
|
||||
);
|
||||
|
||||
expect(mockFunc).toBeCalled();
|
||||
});
|
||||
});
|
||||
108
packages/antd/src/hooks/fields/useCheckboxGroup/index.ts
Normal file
108
packages/antd/src/hooks/fields/useCheckboxGroup/index.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import type { QueryObserverResult } from "@tanstack/react-query";
|
||||
import type { Checkbox } from "antd";
|
||||
|
||||
import {
|
||||
type BaseRecord,
|
||||
type GetListResponse,
|
||||
type HttpError,
|
||||
type UseSelectProps,
|
||||
useSelect,
|
||||
type BaseKey,
|
||||
pickNotDeprecated,
|
||||
type BaseOption,
|
||||
} from "@refinedev/core";
|
||||
|
||||
export type UseCheckboxGroupReturnType<
|
||||
TData extends BaseRecord = BaseRecord,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
> = {
|
||||
checkboxGroupProps: Omit<
|
||||
React.ComponentProps<typeof Checkbox.Group>,
|
||||
"options"
|
||||
> & {
|
||||
options: TOption[];
|
||||
};
|
||||
query: QueryObserverResult<GetListResponse<TData>>;
|
||||
/**
|
||||
* @deprecated Use `query` instead
|
||||
*/
|
||||
queryResult: QueryObserverResult<GetListResponse<TData>>;
|
||||
};
|
||||
|
||||
type UseCheckboxGroupProps<TQueryFnData, TError, TData> = Omit<
|
||||
UseSelectProps<TQueryFnData, TError, TData>,
|
||||
"defaultValue"
|
||||
> & {
|
||||
/**
|
||||
* Sets the default value
|
||||
*/
|
||||
defaultValue?: BaseKey[];
|
||||
};
|
||||
|
||||
/**
|
||||
* `useCheckboxGroup` hook allows you to manage an Ant Design {@link https://ant.design/components/checkbox/#components-checkbox-demo-group Checkbox.Group} component when records in a resource needs to be used as checkbox options.
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/api-reference/antd/hooks/field/useCheckboxGroup/} for more details
|
||||
*
|
||||
* @typeParam TQueryFnData - Result data returned by the query function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}
|
||||
* @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#httperror `HttpError`}
|
||||
* @typeParam TData - Result data returned by the `select` function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}. Defaults to `TQueryFnData`
|
||||
*
|
||||
*/
|
||||
|
||||
export const useCheckboxGroup = <
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
>({
|
||||
resource,
|
||||
sort,
|
||||
sorters,
|
||||
filters,
|
||||
optionLabel,
|
||||
optionValue,
|
||||
queryOptions,
|
||||
fetchSize,
|
||||
pagination,
|
||||
liveMode,
|
||||
defaultValue,
|
||||
selectedOptionsOrder,
|
||||
onLiveEvent,
|
||||
liveParams,
|
||||
meta,
|
||||
metaData,
|
||||
dataProviderName,
|
||||
}: UseCheckboxGroupProps<
|
||||
TQueryFnData,
|
||||
TError,
|
||||
TData
|
||||
>): UseCheckboxGroupReturnType<TData, TOption> => {
|
||||
const { query, options } = useSelect<TQueryFnData, TError, TData, TOption>({
|
||||
resource,
|
||||
sort,
|
||||
sorters,
|
||||
filters,
|
||||
optionLabel,
|
||||
optionValue,
|
||||
queryOptions,
|
||||
fetchSize,
|
||||
pagination,
|
||||
liveMode,
|
||||
defaultValue,
|
||||
selectedOptionsOrder,
|
||||
onLiveEvent,
|
||||
liveParams,
|
||||
meta: pickNotDeprecated(meta, metaData),
|
||||
metaData: pickNotDeprecated(meta, metaData),
|
||||
dataProviderName,
|
||||
});
|
||||
return {
|
||||
checkboxGroupProps: {
|
||||
options,
|
||||
defaultValue,
|
||||
},
|
||||
query,
|
||||
queryResult: query,
|
||||
};
|
||||
};
|
||||
151
packages/antd/src/hooks/fields/useRadioGroup/index.spec.ts
Normal file
151
packages/antd/src/hooks/fields/useRadioGroup/index.spec.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
|
||||
import { TestWrapper } from "@test";
|
||||
|
||||
import { useRadioGroup } from "./";
|
||||
|
||||
describe("render hook default options", () => {
|
||||
it("should success data without default values", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useRadioGroup({
|
||||
resource: "posts",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.radioGroupProps.options).toHaveLength(2),
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.radioGroupProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should success data with resource with optionLabel and optionValue", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useRadioGroup<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
optionLabel: "slug",
|
||||
optionValue: "id",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.radioGroupProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.radioGroupProps.options).toEqual([
|
||||
{ label: "ut-ad-et", value: "1" },
|
||||
{ label: "consequatur-molestiae-rerum", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should generate options with custom optionLabel and optionValue functions", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useRadioGroup({
|
||||
resource: "posts",
|
||||
optionLabel: (item) => `${item.title} - ${item.userId}`,
|
||||
optionValue: (item) => `${item.id}`,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
const { radioGroupProps } = result.current;
|
||||
|
||||
expect(radioGroupProps.options).toHaveLength(2);
|
||||
expect(radioGroupProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet. - 5",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est. - 36", value: "2" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should invoke queryOptions methods successfully", async () => {
|
||||
const mockFunc = jest.fn();
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useRadioGroup<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
optionLabel: "slug",
|
||||
optionValue: "id",
|
||||
queryOptions: {
|
||||
onSuccess: (data) => {
|
||||
mockFunc();
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.radioGroupProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.radioGroupProps.options).toEqual([
|
||||
{ label: "ut-ad-et", value: "1" },
|
||||
{ label: "consequatur-molestiae-rerum", value: "2" },
|
||||
]),
|
||||
);
|
||||
|
||||
expect(mockFunc).toBeCalled();
|
||||
});
|
||||
|
||||
it("should work with queryResult and query", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useRadioGroup({
|
||||
resource: "posts",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(result.current.query).toEqual(result.current.queryResult);
|
||||
});
|
||||
});
|
||||
105
packages/antd/src/hooks/fields/useRadioGroup/index.ts
Normal file
105
packages/antd/src/hooks/fields/useRadioGroup/index.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import type { QueryObserverResult } from "@tanstack/react-query";
|
||||
import type { Radio } from "antd";
|
||||
|
||||
import {
|
||||
type BaseKey,
|
||||
type BaseOption,
|
||||
type BaseRecord,
|
||||
type GetListResponse,
|
||||
type HttpError,
|
||||
pickNotDeprecated,
|
||||
useSelect,
|
||||
type UseSelectProps,
|
||||
} from "@refinedev/core";
|
||||
|
||||
export type UseRadioGroupReturnType<
|
||||
TData extends BaseRecord = BaseRecord,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
> = {
|
||||
radioGroupProps: Omit<React.ComponentProps<typeof Radio.Group>, "options"> & {
|
||||
options: TOption[];
|
||||
};
|
||||
query: QueryObserverResult<GetListResponse<TData>>;
|
||||
/**
|
||||
* @deprecated Use `query` instead
|
||||
*/
|
||||
queryResult: QueryObserverResult<GetListResponse<TData>>;
|
||||
};
|
||||
|
||||
type UseRadioGroupProps<TQueryFnData, TError, TData> = Omit<
|
||||
UseSelectProps<TQueryFnData, TError, TData>,
|
||||
"defaultValue"
|
||||
> & {
|
||||
/**
|
||||
* Sets the default value
|
||||
*/
|
||||
defaultValue?: BaseKey;
|
||||
};
|
||||
|
||||
/**
|
||||
* `useRadioGroup` hook allows you to manage an Ant Design {@link https://ant.design/components/radio/#components-radio-demo-radiogroup-with-name Radio.Group} component when records in a resource needs to be used as radio options.
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/api-reference/antd/hooks/field/useRadioGroup/} for more details.
|
||||
*
|
||||
* @typeParam TQueryFnData - Result data returned by the query function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}
|
||||
* @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#httperror `HttpError`}
|
||||
* @typeParam TData - Result data returned by the `select` function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}. Defaults to `TQueryFnData`
|
||||
*
|
||||
*/
|
||||
|
||||
export const useRadioGroup = <
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
>({
|
||||
resource,
|
||||
sort,
|
||||
sorters,
|
||||
filters,
|
||||
optionLabel,
|
||||
optionValue,
|
||||
queryOptions,
|
||||
fetchSize,
|
||||
pagination,
|
||||
liveMode,
|
||||
defaultValue,
|
||||
selectedOptionsOrder,
|
||||
onLiveEvent,
|
||||
liveParams,
|
||||
meta,
|
||||
metaData,
|
||||
dataProviderName,
|
||||
}: UseRadioGroupProps<TQueryFnData, TError, TData>): UseRadioGroupReturnType<
|
||||
TData,
|
||||
TOption
|
||||
> => {
|
||||
const { query, options } = useSelect<TQueryFnData, TError, TData, TOption>({
|
||||
resource,
|
||||
sort,
|
||||
sorters,
|
||||
filters,
|
||||
optionLabel,
|
||||
optionValue,
|
||||
queryOptions,
|
||||
fetchSize,
|
||||
pagination,
|
||||
liveMode,
|
||||
defaultValue,
|
||||
selectedOptionsOrder,
|
||||
onLiveEvent,
|
||||
liveParams,
|
||||
meta: pickNotDeprecated(meta, metaData),
|
||||
metaData: pickNotDeprecated(meta, metaData),
|
||||
dataProviderName,
|
||||
});
|
||||
|
||||
return {
|
||||
radioGroupProps: {
|
||||
options,
|
||||
defaultValue,
|
||||
},
|
||||
query,
|
||||
queryResult: query,
|
||||
};
|
||||
};
|
||||
372
packages/antd/src/hooks/fields/useSelect/index.spec.ts
Normal file
372
packages/antd/src/hooks/fields/useSelect/index.spec.ts
Normal file
@@ -0,0 +1,372 @@
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
|
||||
import { MockJSONServer, TestWrapper } from "@test";
|
||||
|
||||
import { useSelect } from "./";
|
||||
|
||||
describe("useSelect Hook", () => {
|
||||
it("default", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("defaultValue", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: ["1", "2", "3", "4"],
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("defaultValue is not an array", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: "1",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should success data with resource with optionLabel and optionValue", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
optionLabel: "slug",
|
||||
optionValue: "id",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{ label: "ut-ad-et", value: "1" },
|
||||
{ label: "consequatur-molestiae-rerum", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should generate options with custom optionLabel and optionValue functions", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
optionLabel: (item) => `${item.title} - ${item.userId}`,
|
||||
optionValue: (item) => `${item.id}`,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
resources: [{ name: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
const { selectProps } = result.current;
|
||||
|
||||
expect(selectProps.options).toHaveLength(2);
|
||||
expect(selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet. - 5",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est. - 36", value: "2" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should success data with resource with filters", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
filters: [
|
||||
{
|
||||
field: "slug",
|
||||
operator: "ncontains",
|
||||
value: "test",
|
||||
},
|
||||
],
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("onSearch debounce with default value (300ms)", async () => {
|
||||
const getListMock = jest.fn(() => Promise.resolve({ data: [], total: 0 }));
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
debounce: 300,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: {
|
||||
...MockJSONServer,
|
||||
getList: getListMock,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(1));
|
||||
|
||||
const { selectProps } = result.current;
|
||||
|
||||
selectProps?.onSearch?.("1");
|
||||
selectProps?.onSearch?.("12");
|
||||
selectProps?.onSearch?.("123");
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(2));
|
||||
});
|
||||
|
||||
it("onSearch disabled debounce (0ms)", async () => {
|
||||
const getListMock = jest.fn(() => {
|
||||
return Promise.resolve({ data: [], total: 0 });
|
||||
});
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
debounce: 0,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: {
|
||||
...MockJSONServer,
|
||||
getList: getListMock,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(1));
|
||||
|
||||
const { selectProps } = result.current;
|
||||
|
||||
selectProps?.onSearch?.("1");
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(2));
|
||||
|
||||
selectProps?.onSearch?.("2");
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(3));
|
||||
|
||||
selectProps?.onSearch?.("3");
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(4));
|
||||
});
|
||||
|
||||
it("should invoke queryOptions methods successfully", async () => {
|
||||
const mockFunc = jest.fn();
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
queryOptions: {
|
||||
onSuccess: (data) => {
|
||||
mockFunc();
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
|
||||
expect(mockFunc).toBeCalled();
|
||||
});
|
||||
|
||||
it("should invoke queryOptions methods for default value successfully", async () => {
|
||||
const mockFunc = jest.fn();
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: ["1", "2", "3", "4"],
|
||||
defaultValueQueryOptions: {
|
||||
onSuccess: (data) => {
|
||||
mockFunc();
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label:
|
||||
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
expect(mockFunc).toBeCalled();
|
||||
});
|
||||
|
||||
it("should work with queryResult and query", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: ["1", "2", "3", "4"],
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
resources: [{ name: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(result.current.query).toEqual(result.current.queryResult);
|
||||
});
|
||||
});
|
||||
70
packages/antd/src/hooks/fields/useSelect/index.ts
Normal file
70
packages/antd/src/hooks/fields/useSelect/index.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import type { SelectProps } from "antd/lib/select";
|
||||
import type { QueryObserverResult } from "@tanstack/react-query";
|
||||
|
||||
import {
|
||||
useSelect as useSelectCore,
|
||||
type BaseRecord,
|
||||
type GetManyResponse,
|
||||
type GetListResponse,
|
||||
type HttpError,
|
||||
type UseSelectProps,
|
||||
type BaseOption,
|
||||
} from "@refinedev/core";
|
||||
|
||||
export type UseSelectReturnType<
|
||||
TData extends BaseRecord = BaseRecord,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
> = {
|
||||
selectProps: SelectProps<TOption>;
|
||||
query: QueryObserverResult<GetListResponse<TData>>;
|
||||
defaultValueQuery: QueryObserverResult<GetManyResponse<TData>>;
|
||||
/**
|
||||
* @deprecated Use `query` instead
|
||||
*/
|
||||
queryResult: QueryObserverResult<GetListResponse<TData>>;
|
||||
/**
|
||||
* @deprecated Use `defaultValueQuery` instead
|
||||
*/
|
||||
defaultValueQueryResult: QueryObserverResult<GetManyResponse<TData>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* `useSelect` hook allows you to manage an Ant Design {@link https://ant.design/components/select/ Select} component when records in a resource needs to be used as select options.
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/api-reference/antd/hooks/field/useSelect/} for more details.
|
||||
*
|
||||
* @typeParam TQueryFnData - Result data returned by the query function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}
|
||||
* @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#httperror `HttpError`}
|
||||
* @typeParam TData - Result data returned by the `select` function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}. Defaults to `TQueryFnData`
|
||||
*
|
||||
*/
|
||||
|
||||
export const useSelect = <
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
>(
|
||||
props: UseSelectProps<TQueryFnData, TError, TData>,
|
||||
): UseSelectReturnType<TData, TOption> => {
|
||||
const { query, defaultValueQuery, onSearch, options } = useSelectCore<
|
||||
TQueryFnData,
|
||||
TError,
|
||||
TData,
|
||||
TOption
|
||||
>(props);
|
||||
|
||||
return {
|
||||
selectProps: {
|
||||
options,
|
||||
onSearch,
|
||||
loading: defaultValueQuery.isFetching,
|
||||
showSearch: true,
|
||||
filterOption: false,
|
||||
},
|
||||
query,
|
||||
defaultValueQuery,
|
||||
queryResult: query,
|
||||
defaultValueQueryResult: defaultValueQuery,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user