ronantakizawa/codereview-bench huggingface dataset:
Repository: refinedev/refine
File: packages/antd/src/hooks/form/useForm.spec.tsx (TypeScript)

Code before:
            getOne: async () => {
              await new Promise((resolve) => setTimeout(resolve, 500));
              return {
                data: {
                  id: 1,
                  title:
                    "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
                  content: "Content",
                  category: {
                    id: 1,
                  },
                  tags: ["tag1", "tag2"],
                },
              };
            },
          },
        }),
      },
    );

    await waitFor(
      () => {
        expect(result.current.formLoading).toBe(true);
        expect(result.current.defaultFormValuesLoading).toBe(true);
      },
      { timeout: 200 },
    );

    await waitFor(
      () => {
        expect(result.current.formLoading).toBe(true);
        expect(result.current.defaultFormValuesLoading).toBe(false);
      },
      { timeout: 400 },
    );

    await waitFor(() => {
      expect(result.current.formLoading).toBe(false);
      expect(result.current.defaultFormValuesLoading).toBe(false);
    });
  });
});


Review comment (suggestion):
```
  await act(async () => {
    jest.advanceTimersByTime(200);
  });

  expect(result.current.formLoading).toBe(true);
  expect(result.current.defaultFormValuesLoading).toBe(false);
```

Here, we can use act together with advanceTimersByTime instead of `waitFor`.

For more information, you can refer to the [Jest documentation on timer mocks](https://jestjs.io/docs/timer-mocks#advance-timers-by-time).

Code after:
        wrapper: TestWrapper({
          dataProvider: {
            ...MockJSONServer,
            getOne: async () => {
              await new Promise((resolve) => setTimeout(resolve, 600));
              return {
                data: {
                  id: 1,
                  title:
                    "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
                  content: "Content",
                  category: {
                    id: 1,
                  },
                  tags: ["tag1", "tag2"],
                },
              };
            },
          },
        }),
      },
    );

    expect(result.current.formLoading).toBe(true);
    expect(result.current.defaultFormValuesLoading).toBe(true);
    await act(async () => {
      jest.advanceTimersByTime(400);
    });
    expect(result.current.formLoading).toBe(true);
    expect(result.current.defaultFormValuesLoading).toBe(false);

    await act(async () => {
      jest.advanceTimersByTime(1000);
    });
    expect(result.current.formLoading).toBe(false);
    expect(result.current.defaultFormValuesLoading).toBe(false);
  });
});
Repository: refinedev/refine
File: packages/supabase/src/dataProvider/index.ts (TypeScript)

Code before:
      }

      sorters?.map((item) => {
        const [foreignTable, field] = item.field.split(/\.(?=[^.]+$)/);

        if (foreignTable && field) {
          query
            .select(meta?.select ?? `*, ${foreignTable}(${field})`)
            .order(field, {
              ascending: item.order === "asc",
              foreignTable: foreignTable,
            });
        } else {
          query.order(item.field, {
            ascending: item.order === "asc",
          });
        }
      });

      filters?.map((item) => {
        if (item.operator === "between") {
          generateFilter(
            {
              field: item.field,
              operator: "gte",
              value: item.value[0],
            },
            query,
          );
          generateFilter(
            {
              field: item.field,
              operator: "lte",
              value: item.value[1],
            },
            query,
          );
        } else {
          generateFilter(item, query);
        }
      });

      const { data, count, error } = await query;

      if (error) {
        return handleError(error);
      }

      return {
        data: data || [],
        total: count || 0,

Review comment (suggestion):
Also can we add a small condition to check `item.value` is an array with length of 2 and if not throw an error 🤔 

Code after:
      }

      sorters?.map((item) => {
        const [foreignTable, field] = item.field.split(/\.(?=[^.]+$)/);

        if (foreignTable && field) {
          query
            .select(meta?.select ?? `*, ${foreignTable}(${field})`)
            .order(field, {
              ascending: item.order === "asc",
              foreignTable: foreignTable,
            });
        } else {
          query.order(item.field, {
            ascending: item.order === "asc",
          });
        }
      });

      filters?.map((item) => {
        generateFilter(item, query);
      });

      const { data, count, error } = await query;

      if (error) {
        return handleError(error);
      }

      return {
        data: data || [],
        total: count || 0,
      } as any;
    },

    getMany: async ({ resource, ids, meta }) => {
      const client = meta?.schema
        ? supabaseClient.schema(meta.schema)
        : supabaseClient;

      const query = client.from(resource).select(meta?.select ?? "*");

      if (meta?.idColumnName) {
        query.in(meta.idColumnName, ids);
      } else {
        query.in("id", ids);
      }

      const { data, error } = await query;

      if (error) {
Repository: refinedev/refine
File: packages/appwrite/src/utils/getAppwriteFilters.ts (TypeScript)

Code before:
import type { CrudFilters } from "@refinedev/core";
import { generateFilter } from "./generateFilter";
import { replaceIdWithAppwriteId } from "./replaceIdWithAppwriteId";

type GetAppwriteFiltersType = (filters?: CrudFilters) => string[];

export const getAppwriteFilters: GetAppwriteFiltersType = (filters) => {
  const appwriteFilters: string[] = [];

  for (const filter of filters ?? []) {
    appwriteFilters.push(generateFilter(replaceIdWithAppwriteId(filter)));
  }

  return appwriteFilters;
};


Review comment (bug):
It's great to see this part is finally refactored to a better shape 😅 Do you think we can move `replaceIdWithAppwriteId` call to `generateFilter` method? I'm not sure if Appwrite supports nested conditional filters (`or`, `and`) but if they do we'll need to check for them too, am I wrong? 🤔 

We can check their docs and implementation or test it manually and see if they support it. We can also add a test case to see if we cover that.

What do you think @soranoo? 🙏 

Code after:
import type { CrudFilters } from "@refinedev/core";
import { generateFilter } from "./generateFilter";

type GetAppwriteFiltersType = (filters?: CrudFilters) => string[];

export const getAppwriteFilters: GetAppwriteFiltersType = (filters) => {
  const appwriteFilters: string[] = [];

  for (const filter of filters ?? []) {
    appwriteFilters.push(generateFilter(filter));
  }

  return appwriteFilters;
};
Repository: refinedev/refine
File: packages/ui-types/src/types/layout.tsx (TypeScript)

Code before:
  /**
   * Text to be displayed in the title.
   *
   * @default "Refine Project"
   */
  text?: React.ReactNode;
  wrapperStyles?: React.CSSProperties;
};

export type RefineThemedLayoutV2Props = {
  /**
   * Whether the sider is collapsed or not by default.
   */
  initialSiderCollapsed?: boolean;

  /**
   * Additional properties for the container box.
   * This type includes all properties of BoxProps, including 'sx'.
   */
  containerBoxProps?: BoxProps;

  /**
   * Additional properties for the children box.
   * This type includes all properties of BoxProps, including 'sx'.
   */
  childrenBoxProps?: BoxProps;
} & RefineLayoutLayoutProps;

export type RefineThemedLayoutV2SiderProps = RefineLayoutSiderProps & {
  activeItemDisabled?: boolean;
};

export type RefineThemedLayoutV2HeaderProps = RefineLayoutHeaderProps & {
  /**
   * Whether the header is sticky or not.
   * @deprecated `isSticky` is deprecated. Please use `sticky` instead.
   */
  isSticky?: boolean;
  sticky?: boolean;
};


Review comment (suggestion):
These types should be on [@refinedev/mui](https://github.com/refinedev/refine/blob/446f467ae2b7f9b65873e3cd78c8b5f99df1f903/packages/mui/src/components/themedLayoutV2/index.tsx#L10) package because `@refinedev/ui-types` packages used by other UI packages and these packages don't use these props.

Code after:
   * Text to be displayed in the title.
   *
   * @default "Refine Project"
   */
  text?: React.ReactNode;
  wrapperStyles?: React.CSSProperties;
};

export type RefineThemedLayoutV2Props = {
  /**
   * Whether the sider is collapsed or not by default.
   */
  initialSiderCollapsed?: boolean;
} & RefineLayoutLayoutProps;
export type RefineThemedLayoutV2SiderProps = RefineLayoutSiderProps & {
  activeItemDisabled?: boolean;
};
export type RefineThemedLayoutV2HeaderProps = RefineLayoutHeaderProps & {
  /**
   * Whether the header is sticky or not.
   * @deprecated `isSticky` is deprecated. Please use `sticky` instead.
   */
  isSticky?: boolean;
  sticky?: boolean;
};
Repository: refinedev/refine
File: packages/antd/src/components/breadcrumb/index.tsx (TypeScript)

Code before:
import { HomeOutlined } from "@ant-design/icons";

export type BreadcrumbProps = RefineBreadcrumbProps<AntdBreadcrumbProps>;

export const Breadcrumb: React.FC<BreadcrumbProps> = ({
  breadcrumbProps,
  showHome = true,
  hideIcons = false,
  meta,
  minItems = 1,
}) => {
  const routerType = useRouterType();
  const { breadcrumbs } = useBreadcrumb({
    meta,
  });
  const Link = useLink();
  const { Link: LegacyLink } = useRouterContext();
  const { hasDashboard } = useRefineContext();

  const { resources } = useResource();

  const rootRouteResource = matchResourceFromRoute("/", resources);

  const ActiveLink = routerType === "legacy" ? LegacyLink : Link;

  if (breadcrumbs.length >= minItems) return null;

  const breadCrumbItems = breadcrumbs.map(({ label, icon, href }) => ({
    key: `breadcrumb-item-${label}`,
    title: (
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          gap: 4,
        }}
      >
        {!hideIcons && icon}
        {href ? (
          <ActiveLink to={href}>{label}</ActiveLink>
        ) : (
          <span>{label}</span>
        )}
      </div>
    ),
  }));

  const getBreadcrumbItems = () => {
    if (showHome && (hasDashboard || rootRouteResource.found)) {
      return [

Review comment (suggestion):
I believe it should be like this:

```suggestion
  if (breadcrumbs.length < minItems) return null;
```



Code after:
import { HomeOutlined } from "@ant-design/icons";

export type BreadcrumbProps = RefineBreadcrumbProps<AntdBreadcrumbProps>;

export const Breadcrumb: React.FC<BreadcrumbProps> = ({
  breadcrumbProps,
  showHome = true,
  hideIcons = false,
  meta,
  minItems = 2,
}) => {
  const routerType = useRouterType();
  const { breadcrumbs } = useBreadcrumb({
    meta,
  });
  const Link = useLink();
  const { Link: LegacyLink } = useRouterContext();
  const { hasDashboard } = useRefineContext();

  const { resources } = useResource();

  const rootRouteResource = matchResourceFromRoute("/", resources);

  const ActiveLink = routerType === "legacy" ? LegacyLink : Link;

  if (breadcrumbs.length < minItems) return null;

  const breadCrumbItems = breadcrumbs.map(({ label, icon, href }) => ({
    key: `breadcrumb-item-${label}`,
    title: (
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          gap: 4,
        }}
      >
        {!hideIcons && icon}
        {href ? (
          <ActiveLink to={href}>{label}</ActiveLink>
        ) : (
          <span>{label}</span>
        )}
      </div>
    ),
  }));

  const getBreadcrumbItems = () => {
    if (showHome && (hasDashboard || rootRouteResource.found)) {
      return [
Repository: refinedev/refine
File: packages/hasura/src/utils/generateUseListSubscription.ts (TypeScript)

Code before:
import type { CrudSorting, MetaQuery, Pagination } from "@refinedev/core";
import * as gql from "gql-query-builder";
import camelcase from "camelcase";
import { type HasuraCrudFilters, generateFilters } from "./generateFilters";
import { generateSorting } from "./generateSorting";
import { getOperationFields } from "./graphql";
import { NamingConvention } from "../dataProvider";

type GenerateUseListSubscriptionParams = {
  resource: string;
  meta: MetaQuery;
  pagination?: Pagination;
  sorters?: CrudSorting;
  filters?: HasuraCrudFilters;
  namingConvention?: NamingConvention;
};

type GenerateUseListSubscriptionReturnValues = {
  variables: any;
  query: string;
  operation: string;
};

export const generateUseListSubscription = ({
  resource,
  meta,
  pagination,
  sorters,
  filters,
  namingConvention,
}: GenerateUseListSubscriptionParams): GenerateUseListSubscriptionReturnValues => {
  const {

Review comment (suggestion):
```suggestion
import type { NamingConvention } from "../dataProvider";
```

Code after:
import type { CrudSorting, MetaQuery, Pagination } from "@refinedev/core";
import * as gql from "gql-query-builder";
import camelcase from "camelcase";
import { type HasuraCrudFilters, generateFilters } from "./generateFilters";
import { generateSorting } from "./generateSorting";
import { getOperationFields } from "./graphql";
import type { NamingConvention } from "../types";

type GenerateUseListSubscriptionParams = {
  resource: string;
  meta: MetaQuery;
  pagination?: Pagination;
  sorters?: CrudSorting;
  filters?: HasuraCrudFilters;
  namingConvention?: NamingConvention;
};

type GenerateUseListSubscriptionReturnValues = {
  variables: any;
  query: string;
  operation: string;
};

export const generateUseListSubscription = ({
  resource,
  meta,
  pagination,
  sorters,
  filters,
  namingConvention,
}: GenerateUseListSubscriptionParams): GenerateUseListSubscriptionReturnValues => {
  const {
Repository: refinedev/refine
File: documentation/src/refine-theme/landing-ai-hero-section.tsx (TypeScript)

Code before:
          <a
            href="https://s.refine.dev/ai-banner"
            target="_blank"
            rel="noreferrer"
            className={clsx(
              "appearance-none",
              "bg-refine-indigo",
              "text-white",
              "hover:text-white",
              "no-underline",
              "px-5",
              "py-3",
              "rounded-[48px]",
              "z-[4]",
            )}
          >
            Start for free!
          </a>
          <a
            href="/ai"
            target="_blank"
            rel="noopener noreferrer"
            className={clsx("text-refine-indigo", "underline", "z-[4]")}
          >
            Learn more
          </a>
        </div>
      </div>

      <div className={clsx("absolute", "inset-0", "bg-noise", "z-[2]")} />

      <video
        className={clsx(
          "z-[1]",
          "absolute",
          "inset-0",
          "w-full",
          "h-full",
          "object-cover",
        )}
        autoPlay={true}
        muted={true}
        loop={true}
        playsInline={true}
        controls={false}
        preload="auto"
      >
        <source
          type="video/quicktime"
          src="https://refine.ams3.cdn.digitaloceanspaces.com/website/static/ai-landing-page/ai-banner-bg-video.mov"
        />

Review comment (suggestion):
```suggestion
          <Link
            to="/ai"
            target="_blank"
            rel="noopener noreferrer"
            className={clsx("text-refine-indigo", "underline", "z-[4]")}
          >
            Learn more
          </Link>
```

```
import Link from "@docusaurus/Link";
```

Code after:
        >
          <a
            href="https://s.refine.dev/ai-banner"
            target="_blank"
            rel="noreferrer"
            className={clsx(
              "appearance-none",
              "bg-refine-indigo",
              "text-white",
              "hover:text-white",
              "no-underline",
              "px-5",
              "py-3",
              "rounded-[48px]",
              "z-[4]",
            )}
          >
            Start for free!
          </a>
          <Link
            to="/ai"
            className={clsx("text-refine-indigo", "underline", "z-[4]")}
          >
            Learn more
          </Link>
        </div>
      </div>

      <div className={clsx("absolute", "inset-0", "bg-noise", "z-[2]")} />

      <video
        className={clsx(
          "z-[1]",
          "absolute",
          "inset-0",
          "w-full",
          "h-full",
          "object-cover",
        )}
        autoPlay={true}
        muted={true}
        loop={true}
        playsInline={true}
        controls={false}
        preload="auto"
      >
        <source
          type="video/mp4"
          src="https://refine.ams3.cdn.digitaloceanspaces.com/website/static/ai-landing-page/ai-banner-bg-video.mp4"
        />
      </video>
Repository: refinedev/refine
File: packages/core/src/hooks/button/button-can-access/index.tsx (TypeScript)

Code before:

type ButtonCanAccessValues = {
  title: string;
  hidden: boolean;
  disabled: boolean;
  canAccess: CanReturnType | undefined;
};

export const useButtonCanAccess = (
  props: ButtonCanAccessProps,
): ButtonCanAccessValues => {
  const translate = useTranslate();
  const accessControlContext = React.useContext(AccessControlContext);

  const accessControlEnabled =
    props.accessControl?.enabled ??
    accessControlContext.options.buttons.enableAccessControl;

  const hideIfUnauthorized =
    props.accessControl?.hideIfUnauthorized ??
    accessControlContext.options.buttons.hideIfUnauthorized;

  const { data: canAccess } = useCan({
    resource: props.resource?.name,
    action: props.action === "clone" ? "create" : props.action,
    params: { ...props.meta, id: props.id, resource: props.resource },
    queryOptions: {
      enabled: accessControlEnabled,
    },
  });

  const title = React.useMemo(() => {
    if (canAccess?.can) return "";
    if (canAccess?.reason) return canAccess.reason;

    return translate(
      "buttons.notAccessTitle",
      "You don't have permission to access",
    );
  }, [canAccess?.can, canAccess?.reason, translate]);

  const hidden = accessControlEnabled && hideIfUnauthorized && !canAccess?.can;

  const disabled = canAccess?.can === false;

  return {
    title,
    hidden,
    disabled,
    canAccess,
  };

Review comment (suggestion):
can we pass this like this:
```suggestion
    params: { meta: { ...props.meta }, id: props.id, resource: props.resource },
```

I believe we can manage better with this way

Code after:

type ButtonCanAccessValues = {
  title: string;
  hidden: boolean;
  disabled: boolean;
  canAccess: CanReturnType | undefined;
};

export const useButtonCanAccess = (
  props: ButtonCanAccessProps,
): ButtonCanAccessValues => {
  const translate = useTranslate();
  const accessControlContext = React.useContext(AccessControlContext);

  const accessControlEnabled =
    props.accessControl?.enabled ??
    accessControlContext.options.buttons.enableAccessControl;

  const hideIfUnauthorized =
    props.accessControl?.hideIfUnauthorized ??
    accessControlContext.options.buttons.hideIfUnauthorized;

  const { data: canAccess } = useCan({
    resource: props.resource?.name,
    action: props.action === "clone" ? "create" : props.action,
    params: { meta: props.meta, id: props.id, resource: props.resource },
    queryOptions: {
      enabled: accessControlEnabled,
    },
  });

  const title = React.useMemo(() => {
    if (canAccess?.can) return "";
    if (canAccess?.reason) return canAccess.reason;

    return translate(
      "buttons.notAccessTitle",
      "You don't have permission to access",
    );
  }, [canAccess?.can, canAccess?.reason, translate]);

  const hidden = accessControlEnabled && hideIfUnauthorized && !canAccess?.can;

  const disabled = canAccess?.can === false;

  return {
    title,
    hidden,
    disabled,
    canAccess,
  };
Repository: refinedev/refine
File: packages/core/src/hooks/data/useList.ts (TypeScript)

Code before:
          ? errorNotification(
              queryResponse.error,
              notificationValues,
              identifier,
            )
          : errorNotification;

      handleNotification(notificationConfig, {
        key: `${identifier}-useList-notification`,
        message: translate(
          "notifications.error",
          { statusCode: queryResponse.error.statusCode },
          `Error (status code: ${queryResponse.error.statusCode})`,
        ),
        description: queryResponse.error.message,
        type: "error",
      });
    }
  }, [queryResponse.isError, queryResponse.error?.message]);

  const { elapsedTime } = useLoadingOvertime({
    ...overtimeOptions,
    isLoading: queryResponse.isFetching,
  });

  const EMPTY_ARRAY: readonly [] = Object.freeze([]);

  return {
    query: queryResponse,
    result: {
      data: queryResponse?.data?.data || EMPTY_ARRAY,
      total: queryResponse?.data?.total,
    },
    overtime: { elapsedTime },
  };
};


Review comment (suggestion):
I guess we need to initialize this outside the React component, otherwise it will be re-initialized on every render. or we must use `useMemo`

Code after:
      const notificationConfig =
        typeof errorNotification === "function"
          ? errorNotification(
              queryResponse.error,
              notificationValues,
              identifier,
            )
          : errorNotification;

      handleNotification(notificationConfig, {
        key: `${identifier}-useList-notification`,
        message: translate(
          "notifications.error",
          { statusCode: queryResponse.error.statusCode },
          `Error (status code: ${queryResponse.error.statusCode})`,
        ),
        description: queryResponse.error.message,
        type: "error",
      });
    }
  }, [queryResponse.isError, queryResponse.error?.message]);

  const { elapsedTime } = useLoadingOvertime({
    ...overtimeOptions,
    isLoading: queryResponse.isFetching,
  });

  return {
    query: queryResponse,
    result: {
      data: queryResponse?.data?.data || EMPTY_ARRAY,
      total: queryResponse?.data?.total,
    },
    overtime: { elapsedTime },
  };
};