Skip to content

Commit d6a3661

Browse files
eunjae-leehbjORbj
andauthored
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>
1 parent be40443 commit d6a3661

File tree

11 files changed

+89
-81
lines changed

11 files changed

+89
-81
lines changed

apps/web/modules/bookings/views/bookings-listing-view.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ function BookingsContent({ status }: BookingsProps) {
364364
table={table}
365365
testId={`${status}-bookings`}
366366
bodyTestId="bookings"
367-
hideHeader={true}
367+
headerClassName="hidden"
368368
isPending={query.isPending}
369369
totalRowCount={query.data?.totalCount}
370370
variant="compact"

packages/features/data-table/components/DataTable.tsx

+56-48
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,29 @@ import classNames from "@calcom/ui/classNames";
3030
import { useColumnSizingVars } from "../hooks";
3131
import { usePersistentColumnResizing } from "../lib/resizing";
3232

33-
export type DataTableProps<TData> = {
33+
export type DataTablePropsFromWrapper<TData> = {
3434
table: ReactTableType<TData>;
3535
tableContainerRef: React.RefObject<HTMLDivElement>;
3636
isPending?: boolean;
37-
onRowMouseclick?: (row: Row<TData>) => void;
38-
onScroll?: (e: Pick<React.UIEvent<HTMLDivElement, UIEvent>, "target">) => void;
39-
tableOverlay?: React.ReactNode;
4037
variant?: "default" | "compact";
4138
testId?: string;
4239
bodyTestId?: string;
43-
hideHeader?: boolean;
4440
children?: React.ReactNode;
45-
identifier?: string;
46-
enableColumnResizing?: boolean;
4741
className?: string;
4842
containerClassName?: string;
43+
headerClassName?: string;
44+
rowClassName?: string;
4945
paginationMode?: "infinite" | "standard";
5046
};
5147

48+
export type DataTableProps<TData> = DataTablePropsFromWrapper<TData> & {
49+
onRowMouseclick?: (row: Row<TData>) => void;
50+
onScroll?: (e: Pick<React.UIEvent<HTMLDivElement, UIEvent>, "target">) => void;
51+
tableOverlay?: React.ReactNode;
52+
identifier?: string;
53+
enableColumnResizing?: boolean;
54+
};
55+
5256
export function DataTable<TData>({
5357
table,
5458
tableContainerRef,
@@ -57,13 +61,14 @@ export function DataTable<TData>({
5761
onRowMouseclick,
5862
onScroll,
5963
children,
60-
hideHeader,
6164
identifier: _identifier,
6265
enableColumnResizing,
6366
testId,
6467
bodyTestId,
6568
className,
6669
containerClassName,
70+
headerClassName,
71+
rowClassName,
6772
paginationMode = "infinite",
6873
...rest
6974
}: DataTableProps<TData> & React.ComponentPropsWithoutRef<"div">) {
@@ -145,44 +150,42 @@ export function DataTable<TData>({
145150
...columnSizingVars,
146151
...(Boolean(enableColumnResizing) && { width: table.getTotalSize() }),
147152
}}>
148-
{!hideHeader && (
149-
<TableHeader className="sticky top-0 z-10">
150-
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
151-
<TableRow key={headerGroup.id} className="hover:bg-subtle flex w-full">
152-
{headerGroup.headers.map((header: Header<TData, unknown>) => {
153-
const { column } = header;
154-
return (
155-
<TableHead
156-
key={header.id}
157-
style={{
158-
...(column.getIsPinned() === "left" && { left: `${column.getStart("left")}px` }),
159-
...(column.getIsPinned() === "right" && { right: `${column.getStart("right")}px` }),
160-
width: `var(--header-${kebabCase(header?.id)}-size)`,
161-
}}
162-
className={classNames(
163-
"relative flex shrink-0 items-center",
164-
"bg-subtle",
165-
column.getIsPinned() && "top-0 z-20 sm:sticky"
166-
)}>
167-
<TableHeadLabel header={header} />
168-
{Boolean(enableColumnResizing) && header.column.getCanResize() && (
169-
<div
170-
onMouseDown={header.getResizeHandler()}
171-
onTouchStart={header.getResizeHandler()}
172-
className={classNames(
173-
"group absolute right-0 top-0 h-full w-[5px] cursor-col-resize touch-none select-none opacity-[0.1] hover:opacity-50",
174-
header.column.getIsResizing() && "!opacity-75"
175-
)}>
176-
<div className="bg-inverted mx-auto h-full w-[1px]" />
177-
</div>
178-
)}
179-
</TableHead>
180-
);
181-
})}
182-
</TableRow>
183-
))}
184-
</TableHeader>
185-
)}
153+
<TableHeader className={classNames("sticky top-0 z-10", headerClassName)}>
154+
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
155+
<TableRow key={headerGroup.id} className="hover:bg-subtle flex w-full">
156+
{headerGroup.headers.map((header: Header<TData, unknown>) => {
157+
const { column } = header;
158+
return (
159+
<TableHead
160+
key={header.id}
161+
style={{
162+
...(column.getIsPinned() === "left" && { left: `${column.getStart("left")}px` }),
163+
...(column.getIsPinned() === "right" && { right: `${column.getStart("right")}px` }),
164+
width: `var(--header-${kebabCase(header?.id)}-size)`,
165+
}}
166+
className={classNames(
167+
"relative flex shrink-0 items-center",
168+
"bg-subtle",
169+
column.getIsPinned() && "top-0 z-20 sm:sticky"
170+
)}>
171+
<TableHeadLabel header={header} />
172+
{Boolean(enableColumnResizing) && header.column.getCanResize() && (
173+
<div
174+
onMouseDown={header.getResizeHandler()}
175+
onTouchStart={header.getResizeHandler()}
176+
className={classNames(
177+
"group absolute right-0 top-0 h-full w-[5px] cursor-col-resize touch-none select-none opacity-[0.1] hover:opacity-50",
178+
header.column.getIsResizing() && "!opacity-75"
179+
)}>
180+
<div className="bg-inverted mx-auto h-full w-[1px]" />
181+
</div>
182+
)}
183+
</TableHead>
184+
);
185+
})}
186+
</TableRow>
187+
))}
188+
</TableHeader>
186189
{/* When resizing any column we will render this special memoized version of our table body */}
187190
{table.getState().columnSizingInfo.isResizingColumn ? (
188191
<MemoizedTableBody
@@ -194,6 +197,7 @@ export function DataTable<TData>({
194197
isPending={isPending}
195198
onRowMouseclick={onRowMouseclick}
196199
paginationMode={paginationMode}
200+
rowClassName={rowClassName}
197201
/>
198202
) : (
199203
<DataTableBody
@@ -205,6 +209,7 @@ export function DataTable<TData>({
205209
isPending={isPending}
206210
onRowMouseclick={onRowMouseclick}
207211
paginationMode={paginationMode}
212+
rowClassName={rowClassName}
208213
/>
209214
)}
210215
</TableNew>
@@ -224,7 +229,8 @@ const MemoizedTableBody = memo(
224229
prev.variant === next.variant &&
225230
prev.isPending === next.isPending &&
226231
prev.onRowMouseclick === next.onRowMouseclick &&
227-
prev.paginationMode === next.paginationMode
232+
prev.paginationMode === next.paginationMode &&
233+
prev.rowClassName === next.rowClassName
228234
) as typeof DataTableBody;
229235

230236
type DataTableBodyProps<TData> = {
@@ -236,6 +242,7 @@ type DataTableBodyProps<TData> = {
236242
isPending?: boolean;
237243
onRowMouseclick?: (row: Row<TData>) => void;
238244
paginationMode?: "infinite" | "standard";
245+
rowClassName?: string;
239246
};
240247

241248
type RowToRender<TData> = {
@@ -252,6 +259,7 @@ function DataTableBody<TData>({
252259
isPending,
253260
onRowMouseclick,
254261
paginationMode,
262+
rowClassName,
255263
}: DataTableBodyProps<TData> & { paginationMode?: "infinite" | "standard" }) {
256264
const { t } = useLocale();
257265
const virtualItems = rowVirtualizer.getVirtualItems();
@@ -297,7 +305,7 @@ function DataTableBody<TData>({
297305
width: "100%",
298306
}),
299307
}}
300-
className={classNames(onRowMouseclick && "hover:cursor-pointer", "group")}>
308+
className={classNames(onRowMouseclick && "hover:cursor-pointer", "group", rowClassName)}>
301309
{row.getVisibleCells().map((cell) => {
302310
const column = cell.column;
303311
return (

packages/features/data-table/components/DataTableWrapper.tsx

+15-20
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,26 @@
11
"use client";
22

3-
import type { Table as ReactTableType, VisibilityState } from "@tanstack/react-table";
3+
import type { VisibilityState } from "@tanstack/react-table";
44
// eslint-disable-next-line no-restricted-imports
55
import { noop } from "lodash";
66
import { useEffect, useRef } from "react";
77

8-
import {
9-
DataTable,
10-
DataTablePagination,
11-
useFetchMoreOnBottomReached,
12-
useDataTable,
13-
useColumnFilters,
14-
} from "@calcom/features/data-table";
8+
import { useColumnFilters } from "../hooks/useColumnFilters";
9+
import { useDataTable } from "../hooks/useDataTable";
10+
import { useFetchMoreOnBottomReached } from "../hooks/useFetchMoreOnBottomReached";
11+
import type { DataTablePropsFromWrapper } from "./DataTable";
12+
import { DataTable } from "./DataTable";
13+
import { DataTablePagination } from "./DataTablePagination";
1514

16-
type BaseDataTableWrapperProps<TData> = {
17-
testId?: string;
18-
bodyTestId?: string;
19-
table: ReactTableType<TData>;
20-
isPending: boolean;
21-
hideHeader?: boolean;
22-
variant?: "default" | "compact";
15+
type BaseDataTableWrapperProps<TData> = Omit<
16+
DataTablePropsFromWrapper<TData>,
17+
"paginationMode" | "tableContainerRef"
18+
> & {
2319
totalRowCount?: number;
2420
ToolbarLeft?: React.ReactNode;
2521
ToolbarRight?: React.ReactNode;
2622
EmptyView?: React.ReactNode;
2723
LoaderView?: React.ReactNode;
28-
className?: string;
29-
containerClassName?: string;
30-
children?: React.ReactNode;
3124
tableContainerRef?: React.RefObject<HTMLDivElement>;
3225
};
3326

@@ -57,13 +50,14 @@ export function DataTableWrapper<TData>({
5750
isFetching,
5851
totalRowCount,
5952
variant,
60-
hideHeader,
6153
ToolbarLeft,
6254
ToolbarRight,
6355
EmptyView,
6456
LoaderView,
6557
className,
6658
containerClassName,
59+
headerClassName,
60+
rowClassName,
6761
children,
6862
tableContainerRef: externalRef,
6963
paginationMode,
@@ -130,10 +124,11 @@ export function DataTableWrapper<TData>({
130124
tableContainerRef={tableContainerRef}
131125
isPending={isPending}
132126
enableColumnResizing={true}
133-
hideHeader={hideHeader}
134127
variant={variant}
135128
className={className}
136129
containerClassName={containerClassName}
130+
headerClassName={headerClassName}
131+
rowClassName={rowClassName}
137132
paginationMode={paginationMode}
138133
onScroll={
139134
paginationMode === "infinite"

packages/features/data-table/components/filters/ClearFiltersButton.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useDataTable } from "@calcom/features/data-table";
21
import { useLocale } from "@calcom/lib/hooks/useLocale";
32
import { Button, Tooltip } from "@calcom/ui";
43

4+
import { useDataTable } from "../../hooks/useDataTable";
5+
56
export const ClearFiltersButton = ({ exclude }: { exclude?: string[] }) => {
67
const { t } = useLocale();
78
const { activeFilters, clearAll } = useDataTable();

packages/features/ee/billing/api/webhook/_invoice.paid.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import logger from "@calcom/lib/logger";
2+
13
import { HttpCode } from "./__handler";
24
import type { LazyModule, SWHMap } from "./__handler";
3-
import logger from "@calcom/lib/logger";
45

56
type Data = SWHMap["invoice.paid"]["data"];
67

Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { IS_PRODUCTION } from "@calcom/lib/constants";
2-
import { prisma } from "@calcom/prisma";
32

43
import { InternalOrganizationBilling } from "./internal-organization-billing";
54
import { OrganizationBillingRepository } from "./organization-billing.repository";
65
import { StubOrganizationBilling } from "./stub-organization-billing";
76

87
export { OrganizationBillingRepository };
98

10-
export const OrganizationBilling = IS_PRODUCTION ? InternalOrganizationBilling : StubOrganizationBilling;
9+
export const OrganizationBilling = IS_PRODUCTION ? InternalOrganizationBilling : StubOrganizationBilling;

packages/features/ee/billing/teams/internal-team-billing.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import type { Prisma } from "@prisma/client";
22
import type { z } from "zod";
3-
import { safeStringify } from "@calcom/lib/safeStringify";
3+
44
import { getRequestedSlugError } from "@calcom/app-store/stripepayment/lib/team-billing";
55
import { purchaseTeamOrOrgSubscription } from "@calcom/features/ee/teams/lib/payments";
66
import { MINIMUM_NUMBER_OF_ORG_SEATS, WEBAPP_URL } from "@calcom/lib/constants";
77
import { getMetadataHelpers } from "@calcom/lib/getMetadataHelpers";
88
import logger from "@calcom/lib/logger";
99
import { Redirect } from "@calcom/lib/redirect";
10+
import { safeStringify } from "@calcom/lib/safeStringify";
11+
import { OrganizationOnboardingRepository } from "@calcom/lib/server/repository/organizationOnboarding";
1012
import prisma from "@calcom/prisma";
1113
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
1214

1315
import billing from "..";
1416
import { TeamBillingPublishResponseStatus, type TeamBilling, type TeamBillingInput } from "./team-billing";
15-
import { OrganizationOnboardingRepository } from "@calcom/lib/server/repository/organizationOnboarding";
1617

1718
const log = logger.getSubLogger({ prefix: ["TeamBilling"] });
1819

@@ -124,13 +125,15 @@ export class InternalTeamBilling implements TeamBilling {
124125
const { id: teamId, metadata, isOrganization } = this.team;
125126

126127
const { url } = await this.checkIfTeamPaymentRequired();
127-
const organizationOnboarding = await OrganizationOnboardingRepository.findByOrganizationId(this.team.id);
128+
const organizationOnboarding = await OrganizationOnboardingRepository.findByOrganizationId(
129+
this.team.id
130+
);
128131
log.debug("updateQuantity", safeStringify({ url, team: this.team }));
129132

130133
/**
131134
* If there's no pending checkout URL it means that this team has not been paid.
132135
* We cannot update the subscription yet, this will be handled on publish/checkout.
133-
*
136+
*
134137
* An organization can only be created if it is paid for and updateQuantity is called only when we have an organization.
135138
* 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)
136139
* So, we can safely assume go forward for organizations.

packages/features/insights/components/RoutingFormResponsesTable.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ export function RoutingFormResponsesTable() {
109109
return (
110110
<>
111111
<div className="flex-1">
112-
<DataTableWrapper
112+
<DataTableWrapper<RoutingFormTableRow>
113113
table={table}
114114
isPending={isPending}
115+
rowClassName="min-h-14"
115116
paginationMode="standard"
116117
totalRowCount={data?.total}
117118
LoaderView={<DataTableSkeleton columns={4} columnWidths={[200, 200, 250, 250]} />}

packages/features/settings/outOfOffice/OutOfOfficeEntriesList.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ function OutOfOfficeEntriesListContent() {
329329
<>
330330
<DataTableWrapper
331331
testId="ooo-list-data-table"
332-
hideHeader={selectedTab === OutOfOfficeTab.MINE}
332+
rowClassName={selectedTab === OutOfOfficeTab.MINE ? "hidden" : ""}
333333
table={table}
334334
isPending={isPending}
335335
hasNextPage={hasNextPage}

packages/features/users/components/UserTable/PlatformManagedUsersTable.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ function UserListTableContent({ oAuthClientId }: PlatformManagedUsersTableProps)
277277

278278
return (
279279
<>
280-
<DataTableWrapper
280+
<DataTableWrapper<PlatformManagedUserTableUser>
281281
testId="managed-user-list-data-table"
282282
table={table}
283283
isPending={isPending}

packages/features/users/components/UserTable/UserListTable.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ function UserListTableContent() {
512512

513513
return (
514514
<>
515-
<DataTableWrapper
515+
<DataTableWrapper<UserTableUser>
516516
testId="user-list-data-table"
517517
table={table}
518518
isPending={isPending}

0 commit comments

Comments
 (0)