fix: support more className-related props at DataTable (#19953)
* fix: support more className-related props at DataTable * update style * fix type error * use relative import --------- Co-authored-by: Benny Joo <sldisek783@gmail.com>
This commit is contained in:
@@ -364,7 +364,7 @@ function BookingsContent({ status }: BookingsProps) {
|
||||
table={table}
|
||||
testId={`${status}-bookings`}
|
||||
bodyTestId="bookings"
|
||||
hideHeader={true}
|
||||
headerClassName="hidden"
|
||||
isPending={query.isPending}
|
||||
totalRowCount={query.data?.totalCount}
|
||||
variant="compact"
|
||||
|
||||
@@ -30,25 +30,29 @@ import classNames from "@calcom/ui/classNames";
|
||||
import { useColumnSizingVars } from "../hooks";
|
||||
import { usePersistentColumnResizing } from "../lib/resizing";
|
||||
|
||||
export type DataTableProps<TData> = {
|
||||
export type DataTablePropsFromWrapper<TData> = {
|
||||
table: ReactTableType<TData>;
|
||||
tableContainerRef: React.RefObject<HTMLDivElement>;
|
||||
isPending?: boolean;
|
||||
onRowMouseclick?: (row: Row<TData>) => void;
|
||||
onScroll?: (e: Pick<React.UIEvent<HTMLDivElement, UIEvent>, "target">) => void;
|
||||
tableOverlay?: React.ReactNode;
|
||||
variant?: "default" | "compact";
|
||||
testId?: string;
|
||||
bodyTestId?: string;
|
||||
hideHeader?: boolean;
|
||||
children?: React.ReactNode;
|
||||
identifier?: string;
|
||||
enableColumnResizing?: boolean;
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
headerClassName?: string;
|
||||
rowClassName?: string;
|
||||
paginationMode?: "infinite" | "standard";
|
||||
};
|
||||
|
||||
export type DataTableProps<TData> = DataTablePropsFromWrapper<TData> & {
|
||||
onRowMouseclick?: (row: Row<TData>) => void;
|
||||
onScroll?: (e: Pick<React.UIEvent<HTMLDivElement, UIEvent>, "target">) => void;
|
||||
tableOverlay?: React.ReactNode;
|
||||
identifier?: string;
|
||||
enableColumnResizing?: boolean;
|
||||
};
|
||||
|
||||
export function DataTable<TData>({
|
||||
table,
|
||||
tableContainerRef,
|
||||
@@ -57,13 +61,14 @@ export function DataTable<TData>({
|
||||
onRowMouseclick,
|
||||
onScroll,
|
||||
children,
|
||||
hideHeader,
|
||||
identifier: _identifier,
|
||||
enableColumnResizing,
|
||||
testId,
|
||||
bodyTestId,
|
||||
className,
|
||||
containerClassName,
|
||||
headerClassName,
|
||||
rowClassName,
|
||||
paginationMode = "infinite",
|
||||
...rest
|
||||
}: DataTableProps<TData> & React.ComponentPropsWithoutRef<"div">) {
|
||||
@@ -145,44 +150,42 @@ export function DataTable<TData>({
|
||||
...columnSizingVars,
|
||||
...(Boolean(enableColumnResizing) && { width: table.getTotalSize() }),
|
||||
}}>
|
||||
{!hideHeader && (
|
||||
<TableHeader className="sticky top-0 z-10">
|
||||
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
|
||||
<TableRow key={headerGroup.id} className="hover:bg-subtle flex w-full">
|
||||
{headerGroup.headers.map((header: Header<TData, unknown>) => {
|
||||
const { column } = header;
|
||||
return (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
style={{
|
||||
...(column.getIsPinned() === "left" && { left: `${column.getStart("left")}px` }),
|
||||
...(column.getIsPinned() === "right" && { right: `${column.getStart("right")}px` }),
|
||||
width: `var(--header-${kebabCase(header?.id)}-size)`,
|
||||
}}
|
||||
className={classNames(
|
||||
"relative flex shrink-0 items-center",
|
||||
"bg-subtle",
|
||||
column.getIsPinned() && "top-0 z-20 sm:sticky"
|
||||
)}>
|
||||
<TableHeadLabel header={header} />
|
||||
{Boolean(enableColumnResizing) && header.column.getCanResize() && (
|
||||
<div
|
||||
onMouseDown={header.getResizeHandler()}
|
||||
onTouchStart={header.getResizeHandler()}
|
||||
className={classNames(
|
||||
"group absolute right-0 top-0 h-full w-[5px] cursor-col-resize touch-none select-none opacity-[0.1] hover:opacity-50",
|
||||
header.column.getIsResizing() && "!opacity-75"
|
||||
)}>
|
||||
<div className="bg-inverted mx-auto h-full w-[1px]" />
|
||||
</div>
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
)}
|
||||
<TableHeader className={classNames("sticky top-0 z-10", headerClassName)}>
|
||||
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
|
||||
<TableRow key={headerGroup.id} className="hover:bg-subtle flex w-full">
|
||||
{headerGroup.headers.map((header: Header<TData, unknown>) => {
|
||||
const { column } = header;
|
||||
return (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
style={{
|
||||
...(column.getIsPinned() === "left" && { left: `${column.getStart("left")}px` }),
|
||||
...(column.getIsPinned() === "right" && { right: `${column.getStart("right")}px` }),
|
||||
width: `var(--header-${kebabCase(header?.id)}-size)`,
|
||||
}}
|
||||
className={classNames(
|
||||
"relative flex shrink-0 items-center",
|
||||
"bg-subtle",
|
||||
column.getIsPinned() && "top-0 z-20 sm:sticky"
|
||||
)}>
|
||||
<TableHeadLabel header={header} />
|
||||
{Boolean(enableColumnResizing) && header.column.getCanResize() && (
|
||||
<div
|
||||
onMouseDown={header.getResizeHandler()}
|
||||
onTouchStart={header.getResizeHandler()}
|
||||
className={classNames(
|
||||
"group absolute right-0 top-0 h-full w-[5px] cursor-col-resize touch-none select-none opacity-[0.1] hover:opacity-50",
|
||||
header.column.getIsResizing() && "!opacity-75"
|
||||
)}>
|
||||
<div className="bg-inverted mx-auto h-full w-[1px]" />
|
||||
</div>
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
{/* When resizing any column we will render this special memoized version of our table body */}
|
||||
{table.getState().columnSizingInfo.isResizingColumn ? (
|
||||
<MemoizedTableBody
|
||||
@@ -194,6 +197,7 @@ export function DataTable<TData>({
|
||||
isPending={isPending}
|
||||
onRowMouseclick={onRowMouseclick}
|
||||
paginationMode={paginationMode}
|
||||
rowClassName={rowClassName}
|
||||
/>
|
||||
) : (
|
||||
<DataTableBody
|
||||
@@ -205,6 +209,7 @@ export function DataTable<TData>({
|
||||
isPending={isPending}
|
||||
onRowMouseclick={onRowMouseclick}
|
||||
paginationMode={paginationMode}
|
||||
rowClassName={rowClassName}
|
||||
/>
|
||||
)}
|
||||
</TableNew>
|
||||
@@ -224,7 +229,8 @@ const MemoizedTableBody = memo(
|
||||
prev.variant === next.variant &&
|
||||
prev.isPending === next.isPending &&
|
||||
prev.onRowMouseclick === next.onRowMouseclick &&
|
||||
prev.paginationMode === next.paginationMode
|
||||
prev.paginationMode === next.paginationMode &&
|
||||
prev.rowClassName === next.rowClassName
|
||||
) as typeof DataTableBody;
|
||||
|
||||
type DataTableBodyProps<TData> = {
|
||||
@@ -236,6 +242,7 @@ type DataTableBodyProps<TData> = {
|
||||
isPending?: boolean;
|
||||
onRowMouseclick?: (row: Row<TData>) => void;
|
||||
paginationMode?: "infinite" | "standard";
|
||||
rowClassName?: string;
|
||||
};
|
||||
|
||||
type RowToRender<TData> = {
|
||||
@@ -252,6 +259,7 @@ function DataTableBody<TData>({
|
||||
isPending,
|
||||
onRowMouseclick,
|
||||
paginationMode,
|
||||
rowClassName,
|
||||
}: DataTableBodyProps<TData> & { paginationMode?: "infinite" | "standard" }) {
|
||||
const { t } = useLocale();
|
||||
const virtualItems = rowVirtualizer.getVirtualItems();
|
||||
@@ -297,7 +305,7 @@ function DataTableBody<TData>({
|
||||
width: "100%",
|
||||
}),
|
||||
}}
|
||||
className={classNames(onRowMouseclick && "hover:cursor-pointer", "group")}>
|
||||
className={classNames(onRowMouseclick && "hover:cursor-pointer", "group", rowClassName)}>
|
||||
{row.getVisibleCells().map((cell) => {
|
||||
const column = cell.column;
|
||||
return (
|
||||
|
||||
@@ -1,33 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import type { Table as ReactTableType, VisibilityState } from "@tanstack/react-table";
|
||||
import type { VisibilityState } from "@tanstack/react-table";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { noop } from "lodash";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
import {
|
||||
DataTable,
|
||||
DataTablePagination,
|
||||
useFetchMoreOnBottomReached,
|
||||
useDataTable,
|
||||
useColumnFilters,
|
||||
} from "@calcom/features/data-table";
|
||||
import { useColumnFilters } from "../hooks/useColumnFilters";
|
||||
import { useDataTable } from "../hooks/useDataTable";
|
||||
import { useFetchMoreOnBottomReached } from "../hooks/useFetchMoreOnBottomReached";
|
||||
import type { DataTablePropsFromWrapper } from "./DataTable";
|
||||
import { DataTable } from "./DataTable";
|
||||
import { DataTablePagination } from "./DataTablePagination";
|
||||
|
||||
type BaseDataTableWrapperProps<TData> = {
|
||||
testId?: string;
|
||||
bodyTestId?: string;
|
||||
table: ReactTableType<TData>;
|
||||
isPending: boolean;
|
||||
hideHeader?: boolean;
|
||||
variant?: "default" | "compact";
|
||||
type BaseDataTableWrapperProps<TData> = Omit<
|
||||
DataTablePropsFromWrapper<TData>,
|
||||
"paginationMode" | "tableContainerRef"
|
||||
> & {
|
||||
totalRowCount?: number;
|
||||
ToolbarLeft?: React.ReactNode;
|
||||
ToolbarRight?: React.ReactNode;
|
||||
EmptyView?: React.ReactNode;
|
||||
LoaderView?: React.ReactNode;
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
children?: React.ReactNode;
|
||||
tableContainerRef?: React.RefObject<HTMLDivElement>;
|
||||
};
|
||||
|
||||
@@ -57,13 +50,14 @@ export function DataTableWrapper<TData>({
|
||||
isFetching,
|
||||
totalRowCount,
|
||||
variant,
|
||||
hideHeader,
|
||||
ToolbarLeft,
|
||||
ToolbarRight,
|
||||
EmptyView,
|
||||
LoaderView,
|
||||
className,
|
||||
containerClassName,
|
||||
headerClassName,
|
||||
rowClassName,
|
||||
children,
|
||||
tableContainerRef: externalRef,
|
||||
paginationMode,
|
||||
@@ -130,10 +124,11 @@ export function DataTableWrapper<TData>({
|
||||
tableContainerRef={tableContainerRef}
|
||||
isPending={isPending}
|
||||
enableColumnResizing={true}
|
||||
hideHeader={hideHeader}
|
||||
variant={variant}
|
||||
className={className}
|
||||
containerClassName={containerClassName}
|
||||
headerClassName={headerClassName}
|
||||
rowClassName={rowClassName}
|
||||
paginationMode={paginationMode}
|
||||
onScroll={
|
||||
paginationMode === "infinite"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useDataTable } from "@calcom/features/data-table";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, Tooltip } from "@calcom/ui";
|
||||
|
||||
import { useDataTable } from "../../hooks/useDataTable";
|
||||
|
||||
export const ClearFiltersButton = ({ exclude }: { exclude?: string[] }) => {
|
||||
const { t } = useLocale();
|
||||
const { activeFilters, clearAll } = useDataTable();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logger from "@calcom/lib/logger";
|
||||
|
||||
import { HttpCode } from "./__handler";
|
||||
import type { LazyModule, SWHMap } from "./__handler";
|
||||
import logger from "@calcom/lib/logger";
|
||||
|
||||
type Data = SWHMap["invoice.paid"]["data"];
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import { InternalOrganizationBilling } from "./internal-organization-billing";
|
||||
import { OrganizationBillingRepository } from "./organization-billing.repository";
|
||||
@@ -7,4 +6,4 @@ import { StubOrganizationBilling } from "./stub-organization-billing";
|
||||
|
||||
export { OrganizationBillingRepository };
|
||||
|
||||
export const OrganizationBilling = IS_PRODUCTION ? InternalOrganizationBilling : StubOrganizationBilling;
|
||||
export const OrganizationBilling = IS_PRODUCTION ? InternalOrganizationBilling : StubOrganizationBilling;
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import type { z } from "zod";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
|
||||
import { getRequestedSlugError } from "@calcom/app-store/stripepayment/lib/team-billing";
|
||||
import { purchaseTeamOrOrgSubscription } from "@calcom/features/ee/teams/lib/payments";
|
||||
import { MINIMUM_NUMBER_OF_ORG_SEATS, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getMetadataHelpers } from "@calcom/lib/getMetadataHelpers";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { Redirect } from "@calcom/lib/redirect";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { OrganizationOnboardingRepository } from "@calcom/lib/server/repository/organizationOnboarding";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import billing from "..";
|
||||
import { TeamBillingPublishResponseStatus, type TeamBilling, type TeamBillingInput } from "./team-billing";
|
||||
import { OrganizationOnboardingRepository } from "@calcom/lib/server/repository/organizationOnboarding";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["TeamBilling"] });
|
||||
|
||||
@@ -124,13 +125,15 @@ export class InternalTeamBilling implements TeamBilling {
|
||||
const { id: teamId, metadata, isOrganization } = this.team;
|
||||
|
||||
const { url } = await this.checkIfTeamPaymentRequired();
|
||||
const organizationOnboarding = await OrganizationOnboardingRepository.findByOrganizationId(this.team.id);
|
||||
const organizationOnboarding = await OrganizationOnboardingRepository.findByOrganizationId(
|
||||
this.team.id
|
||||
);
|
||||
log.debug("updateQuantity", safeStringify({ url, team: this.team }));
|
||||
|
||||
/**
|
||||
* If there's no pending checkout URL it means that this team has not been paid.
|
||||
* We cannot update the subscription yet, this will be handled on publish/checkout.
|
||||
*
|
||||
*
|
||||
* An organization can only be created if it is paid for and updateQuantity is called only when we have an organization.
|
||||
* For some old organizations, it is possible that they aren't paid for yet, but then they wouldn't have been published as well(i.e. slug would be null and are unusable)
|
||||
* So, we can safely assume go forward for organizations.
|
||||
|
||||
@@ -109,9 +109,10 @@ export function RoutingFormResponsesTable() {
|
||||
return (
|
||||
<>
|
||||
<div className="flex-1">
|
||||
<DataTableWrapper
|
||||
<DataTableWrapper<RoutingFormTableRow>
|
||||
table={table}
|
||||
isPending={isPending}
|
||||
rowClassName="min-h-14"
|
||||
paginationMode="standard"
|
||||
totalRowCount={data?.total}
|
||||
LoaderView={<DataTableSkeleton columns={4} columnWidths={[200, 200, 250, 250]} />}
|
||||
|
||||
@@ -329,7 +329,7 @@ function OutOfOfficeEntriesListContent() {
|
||||
<>
|
||||
<DataTableWrapper
|
||||
testId="ooo-list-data-table"
|
||||
hideHeader={selectedTab === OutOfOfficeTab.MINE}
|
||||
rowClassName={selectedTab === OutOfOfficeTab.MINE ? "hidden" : ""}
|
||||
table={table}
|
||||
isPending={isPending}
|
||||
hasNextPage={hasNextPage}
|
||||
|
||||
@@ -277,7 +277,7 @@ function UserListTableContent({ oAuthClientId }: PlatformManagedUsersTableProps)
|
||||
|
||||
return (
|
||||
<>
|
||||
<DataTableWrapper
|
||||
<DataTableWrapper<PlatformManagedUserTableUser>
|
||||
testId="managed-user-list-data-table"
|
||||
table={table}
|
||||
isPending={isPending}
|
||||
|
||||
@@ -512,7 +512,7 @@ function UserListTableContent() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<DataTableWrapper
|
||||
<DataTableWrapper<UserTableUser>
|
||||
testId="user-list-data-table"
|
||||
table={table}
|
||||
isPending={isPending}
|
||||
|
||||
Reference in New Issue
Block a user