Skip to content

Commit

Permalink
fix: provide fixed widths for DataTable columns (#17853)
Browse files Browse the repository at this point in the history
Co-authored-by: Omar López <zomars@me.com>
  • Loading branch information
eunjae-lee and zomars authored Nov 26, 2024
1 parent f81716f commit e22fec9
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 43 deletions.
61 changes: 33 additions & 28 deletions packages/features/data-table/components/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import type { Row } from "@tanstack/react-table";
import { flexRender } from "@tanstack/react-table";
import type { Table as ReactTableType } from "@tanstack/react-table";
import { useVirtualizer } from "@tanstack/react-virtual";
import { useMemo } from "react";
import { useVirtual } from "react-virtual";

import classNames from "@calcom/lib/classNames";
import { Icon, TableNew, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@calcom/ui";
Expand Down Expand Up @@ -32,15 +32,20 @@ export function DataTable<TData, TValue>({
}: DataTableProps<TData, TValue> & React.ComponentPropsWithoutRef<"div">) {
const { rows } = table.getRowModel();

const rowVirtualizer = useVirtual({
parentRef: tableContainerRef,
size: rows.length,
// https://stackblitz.com/github/tanstack/table/tree/main/examples/react/virtualized-infinite-scrolling
const rowVirtualizer = useVirtualizer({
count: rows.length,
estimateSize: () => 100,
getScrollElement: () => tableContainerRef.current,
// measure dynamic row height, except in firefox because it measures table border height incorrectly
measureElement:
typeof window !== "undefined" && navigator.userAgent.indexOf("Firefox") === -1
? (element) => element?.getBoundingClientRect().height
: undefined,
overscan: 10,
});
const { virtualItems: virtualRows, totalSize } = rowVirtualizer;
const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
const paddingBottom =
virtualRows.length > 0 ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) : 0;

const virtualRows = rowVirtualizer.getVirtualItems();

const columnSizeVars = useMemo(() => {
const headers = table.getFlatHeaders();
Expand All @@ -52,14 +57,11 @@ export function DataTable<TData, TValue>({
colSizes[`--col-${header.column.id}-size`] = header.column.getSize();
}
return colSizes;
}, [table.getState().columnSizingInfo, table.getState().columnSizing]);
}, [table.getFlatHeaders(), table.getState().columnSizingInfo, table.getState().columnSizing]);

return (
<div
className={classNames(
"grid h-[85dvh]", // Set a fixed height for the container
rest.className
)}
className={classNames("grid", rest.className)}
style={{
gridTemplateRows: "auto 1fr auto",
gridTemplateAreas: "'header' 'body' 'footer'",
Expand All @@ -70,12 +72,15 @@ export function DataTable<TData, TValue>({
<div
ref={tableContainerRef}
onScroll={onScroll}
className="scrollbar-thin border-subtle relative h-full overflow-auto rounded-md border"
className={classNames(
"relative h-[80dvh] overflow-auto", // Set a fixed height for the container
"scrollbar-thin border-subtle relative rounded-md border"
)}
style={{ gridArea: "body" }}>
<TableNew className="border-0">
<TableNew className="grid border-0">
<TableHeader className="bg-subtle sticky top-0 z-10">
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
<TableRow key={headerGroup.id} className="flex w-full">
{headerGroup.headers.map((header) => {
const meta = header.column.columnDef.meta;
return (
Expand All @@ -87,8 +92,9 @@ export function DataTable<TData, TValue>({
width: `calc(var(--header-${header?.id}-size) * 1px)`,
}}
className={classNames(
"flex shrink-0 items-center",
header.column.getCanSort() ? "cursor-pointer select-none" : "",
meta?.sticky && "bg-subtle sticky top-0 z-20"
meta?.sticky && "sticky top-0 z-20"
)}>
<div className="flex items-center" onClick={header.column.getToggleSortingHandler()}>
{header.isPlaceholder
Expand All @@ -112,20 +118,23 @@ export function DataTable<TData, TValue>({
</TableRow>
))}
</TableHeader>
<TableBody>
{paddingTop > 0 && (
<tr>
<td style={{ height: `${paddingTop}px` }} />
</tr>
)}
<TableBody className="relative grid" style={{ height: `${rowVirtualizer.getTotalSize()}px` }}>
{virtualRows && !isPending ? (
virtualRows.map((virtualRow) => {
const row = rows[virtualRow.index] as Row<TData>;
return (
<TableRow
ref={(node) => rowVirtualizer.measureElement(node)} //measure dynamic row height
key={row.id}
data-index={virtualRow.index} //needed for dynamic row height measurement
data-state={row.getIsSelected() && "selected"}
onClick={() => onRowMouseclick && onRowMouseclick(row)}
style={{
display: "flex",
position: "absolute",
transform: `translateY(${virtualRow.start}px)`, //this should always be a `style` as it changes on scroll
width: "100%",
}}
className={classNames(
onRowMouseclick && "hover:cursor-pointer",
variant === "compact" && "!border-0",
Expand All @@ -143,6 +152,7 @@ export function DataTable<TData, TValue>({
width: `calc(var(--col-${cell.column.id}-size) * 1px)`,
}}
className={classNames(
"flex shrink-0 items-center overflow-auto",
variant === "compact" && "p-1.5",
meta?.sticky && "group-hover:bg-muted bg-default sticky"
)}>
Expand All @@ -160,11 +170,6 @@ export function DataTable<TData, TValue>({
</TableCell>
</TableRow>
)}
{paddingBottom > 0 && (
<tr>
<td style={{ height: `${paddingBottom}px` }} />
</tr>
)}
</TableBody>
</TableNew>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/features/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
"@calcom/ui": "*",
"@lexical/react": "^0.9.0",
"@tanstack/react-table": "^8.9.3",
"@tanstack/react-virtual": "^3.10.9",
"@vercel/functions": "^1.4.0",
"framer-motion": "^10.12.8",
"lexical": "^0.9.0",
"react-select": "^5.7.0",
"react-sticky-box": "^2.0.4",
"react-virtual": "^2.10.4",
"stripe-event-types": "^3.1.0",
"web-push": "^3.6.7",
"zustand": "^4.3.2"
Expand Down
2 changes: 1 addition & 1 deletion packages/features/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"resolveJsonModule": true,
"esModuleInterop": true
},
"include": [".", "../types/next-auth.d.ts"],
"include": [".", "../types/next-auth.d.ts", "../types/tanstack-table.d.ts"],
"exclude": ["dist", "build", "node_modules", "**/*.test.*", "**/__mocks__/*", "**/__tests__/*"]
}
18 changes: 12 additions & 6 deletions packages/features/users/components/UserTable/UserListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
isTextFilterValue,
} from "@calcom/features/data-table";
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
import classNames from "@calcom/lib/classNames";
import { WEBAPP_URL } from "@calcom/lib/constants";
import {
downloadAsCsv,
Expand Down Expand Up @@ -125,7 +126,7 @@ export function UserListTable() {
const { data, isPending, fetchNextPage, isFetching } =
trpc.viewer.organizations.listMembers.useInfiniteQuery(
{
limit: 10,
limit: 30,
searchTerm: debouncedSearchTerm,
expand: ["attributes"],
filters: columnFilters,
Expand Down Expand Up @@ -182,13 +183,13 @@ export function UserListTable() {
);
if (attributeValues.length === 0) return null;
return (
<>
<div className={classNames(attribute.type === "NUMBER" ? "flex w-full justify-center" : "")}>
{attributeValues.map((attributeValue, index) => (
<Badge key={index} variant="gray" className="mr-1">
{attributeValue.value}
</Badge>
))}
</>
</div>
);
},
filterFn: (row, id, filterValue) => {
Expand Down Expand Up @@ -237,7 +238,7 @@ export function UserListTable() {
id: "member",
accessorFn: (data) => data.email,
enableHiding: false,
size: 170,
size: 200,
header: () => {
return `Members`;
},
Expand Down Expand Up @@ -306,6 +307,7 @@ export function UserListTable() {
id: "teams",
accessorFn: (data) => data.teams.map((team) => team.name),
header: "Teams",
size: 200,
cell: ({ row, table }) => {
const { teams, accepted, email, username } = row.original;
// TODO: Implement click to filter
Expand All @@ -323,6 +325,7 @@ export function UserListTable() {
Pending
</Badge>
)}

{teams.map((team) => (
<Badge
key={team.id}
Expand Down Expand Up @@ -350,7 +353,7 @@ export function UserListTable() {
{
id: "actions",
enableHiding: false,
size: 50,
size: 80,
meta: {
sticky: { position: "right" },
},
Expand Down Expand Up @@ -392,6 +395,9 @@ export function UserListTable() {
initialState: {
columnVisibility: initalColumnVisibility,
},
defaultColumn: {
size: 150,
},
state: {
columnFilters,
rowSelection,
Expand Down Expand Up @@ -534,6 +540,7 @@ export function UserListTable() {
<DataTableFilters.ActiveFilters table={table} />
</div>
</DataTableToolbar.Root>

<div style={{ gridArea: "footer", marginTop: "1rem" }}>
<DataTablePagination table={table} totalDbDataCount={totalDBRowCount} />
</div>
Expand Down Expand Up @@ -567,7 +574,6 @@ export function UserListTable() {
</DataTableSelectionBar.Root>
)}
</DataTable>

{state.deleteMember.showModal && <DeleteMemberModal state={state} dispatch={dispatch} />}
{state.inviteMember.showModal && <InviteMemberModal dispatch={dispatch} />}
{state.impersonateMember.showModal && <ImpersonationMemberModal dispatch={dispatch} state={state} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function TableActions({
const orgId = session?.user?.org?.id;

return (
<>
<div className="flex w-full justify-center">
<ButtonGroup combined containerProps={{ className: "border-default hidden md:flex" }}>
<Tooltip content={t("view_public_page")}>
<Button
Expand Down Expand Up @@ -212,6 +212,6 @@ export function TableActions({
</DropdownMenuPortal>
</Dropdown>
</div>
</>
</div>
);
}
3 changes: 1 addition & 2 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@
"react-day-picker": "^8.10.1",
"react-hook-form": "^7.43.3",
"react-inlinesvg": "^4.1.3",
"react-select": "^5.7.0",
"react-virtual": "^2.10.4"
"react-select": "^5.7.0"
},
"devDependencies": {
"@calcom/config": "*",
Expand Down
24 changes: 21 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4147,14 +4147,14 @@ __metadata:
"@calcom/ui": "*"
"@lexical/react": ^0.9.0
"@tanstack/react-table": ^8.9.3
"@tanstack/react-virtual": ^3.10.9
"@testing-library/react-hooks": ^8.0.1
"@types/web-push": ^3.6.3
"@vercel/functions": ^1.4.0
framer-motion: ^10.12.8
lexical: ^0.9.0
react-select: ^5.7.0
react-sticky-box: ^2.0.4
react-virtual: ^2.10.4
stripe-event-types: ^3.1.0
web-push: ^3.6.7
zustand: ^4.3.2
Expand Down Expand Up @@ -4946,7 +4946,6 @@ __metadata:
react-hook-form: ^7.43.3
react-inlinesvg: ^4.1.3
react-select: ^5.7.0
react-virtual: ^2.10.4
typescript: ^4.9.4
languageName: unknown
linkType: soft
Expand Down Expand Up @@ -15285,13 +15284,32 @@ __metadata:
languageName: node
linkType: hard

"@tanstack/react-virtual@npm:^3.10.9":
version: 3.10.9
resolution: "@tanstack/react-virtual@npm:3.10.9"
dependencies:
"@tanstack/virtual-core": 3.10.9
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
checksum: a6c90118d0b084aedf0a2b02bc718df5cc1e594fb60d1dededf8a393d3e519e574e2ba67bb7adcaf8b4d6b206f6a10b37166f006bc7e50ad566475323d545b8c
languageName: node
linkType: hard

"@tanstack/table-core@npm:8.9.3":
version: 8.9.3
resolution: "@tanstack/table-core@npm:8.9.3"
checksum: 52c7e57daaa3160450fb0bde702ec0b8aab159e2b19efd1012e03b3e167acc52839f5b39578cc8bf96e91346719f400d0435a5191384c168d9477da82f276c38
languageName: node
linkType: hard

"@tanstack/virtual-core@npm:3.10.9":
version: 3.10.9
resolution: "@tanstack/virtual-core@npm:3.10.9"
checksum: df1c673040e3700ba12774ef1fec775f84342e80fb5f1586096a1ed347ee9d35b6db6829e665fed86fa3f08e86235a68bbd331fd5aedec4314c2a565384199ba
languageName: node
linkType: hard

"@tediousjs/connection-string@npm:^0.5.0":
version: 0.5.0
resolution: "@tediousjs/connection-string@npm:0.5.0"
Expand Down Expand Up @@ -38100,7 +38118,7 @@ __metadata:
languageName: node
linkType: hard

"react-virtual@npm:^2.10.4, react-virtual@npm:^2.8.2":
"react-virtual@npm:^2.8.2":
version: 2.10.4
resolution: "react-virtual@npm:2.10.4"
dependencies:
Expand Down

0 comments on commit e22fec9

Please sign in to comment.