From 2bce38fd2a903cc4b7df9503e368c152d354fe73 Mon Sep 17 00:00:00 2001 From: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Date: Wed, 7 May 2025 10:54:36 +0100 Subject: [PATCH] feat(v3): table designs (#21147) --- .../data-table/components/DataTable.tsx | 28 ++++++++++------ .../components/DataTableWrapper.tsx | 8 +++-- .../ee/teams/components/MemberList.tsx | 32 +++++++++++-------- .../UserTable/PlatformManagedUsersTable.tsx | 1 - .../components/UserTable/UserListTable.tsx | 1 - .../ui/components/pagination/Pagination.tsx | 2 +- packages/ui/components/table/TableNew.tsx | 6 +--- 7 files changed, 45 insertions(+), 33 deletions(-) diff --git a/packages/features/data-table/components/DataTable.tsx b/packages/features/data-table/components/DataTable.tsx index 08f666c586..1d882c9d15 100644 --- a/packages/features/data-table/components/DataTable.tsx +++ b/packages/features/data-table/components/DataTable.tsx @@ -39,6 +39,7 @@ export type DataTablePropsFromWrapper = { headerClassName?: string; rowClassName?: string; paginationMode?: "infinite" | "standard"; + hasWrapperContext?: boolean; }; export type DataTableProps = DataTablePropsFromWrapper & { @@ -64,6 +65,7 @@ export function DataTable({ headerClassName, rowClassName, paginationMode = "infinite", + hasWrapperContext = false, ...rest }: DataTableProps & React.ComponentPropsWithoutRef<"div">) { const { rows } = table.getRowModel(); @@ -104,7 +106,10 @@ export function DataTable({ return (
({ onScroll={onScroll} className={classNames( "relative overflow-auto", - "scrollbar-thin border-subtle relative rounded-md border", + "scrollbar-thin relative rounded-md ", paginationMode === "infinite" && "h-[80dvh]", // Set a fixed height for the container containerClassName )} style={{ gridArea: "body" }}> {table.getHeaderGroups().map((headerGroup: HeaderGroup) => ( - + {headerGroup.headers.map((header: Header) => { const { column } = header; return ( @@ -155,7 +163,6 @@ export function DataTable({ }} className={classNames( "relative flex shrink-0 items-center", - "bg-subtle", column.getIsPinned() && "top-0 z-20 sm:sticky" )}> @@ -164,7 +171,7 @@ export function DataTable({ 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", + "group absolute right-0 top-0 h-full w-[5px] cursor-col-resize touch-none select-none opacity-0 hover:opacity-50", header.column.getIsResizing() && "!opacity-75" )}>
@@ -279,7 +286,10 @@ function DataTableBody({ } return ( - + {rowsToRender.map(({ row, virtualItem }) => ( rowVirtualizer.measureElement(node) : undefined} @@ -307,7 +317,7 @@ function DataTableBody({ width: `var(--col-${kebabCase(cell.column.id)}-size)`, }} className={classNames( - "flex shrink-0 items-center overflow-hidden", + "bg-default group-hover:!bg-muted group-data-[state=selected]:bg-subtle flex shrink-0 items-center overflow-hidden", variant === "compact" && "p-0", column.getIsPinned() && "bg-default group-hover:!bg-muted group-data-[state=selected]:bg-subtle sm:sticky" @@ -351,7 +361,7 @@ const TableHeadLabel = ({ header }: { header: Header }) => { open && "bg-muted" )}>
diff --git a/packages/features/data-table/components/DataTableWrapper.tsx b/packages/features/data-table/components/DataTableWrapper.tsx index be3b4777e1..0ac9b18e27 100644 --- a/packages/features/data-table/components/DataTableWrapper.tsx +++ b/packages/features/data-table/components/DataTableWrapper.tsx @@ -1,6 +1,6 @@ "use client"; -import type { VisibilityState } from "@tanstack/react-table"; +import type { Row, VisibilityState } from "@tanstack/react-table"; // eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { useEffect, useRef } from "react"; @@ -22,6 +22,7 @@ type BaseDataTableWrapperProps = Omit< EmptyView?: React.ReactNode; LoaderView?: React.ReactNode; tableContainerRef?: React.RefObject; + onRowMouseclick?: (row: Row) => void; }; type InfinitePaginationProps = BaseDataTableWrapperProps & { @@ -61,6 +62,7 @@ export function DataTableWrapper({ children, tableContainerRef: externalRef, paginationMode, + onRowMouseclick, }: DataTableWrapperProps) { const internalRef = useRef(null); const tableContainerRef = externalRef || internalRef; @@ -130,13 +132,15 @@ export function DataTableWrapper({ headerClassName={headerClassName} rowClassName={rowClassName} paginationMode={paginationMode} + onRowMouseclick={onRowMouseclick} + hasWrapperContext={true} onScroll={ paginationMode === "infinite" ? (e: Pick, "target">) => fetchMoreOnBottomReached(e.target as HTMLDivElement) : undefined }> -
+
table={table} totalRowCount={totalRowCount} diff --git a/packages/features/ee/teams/components/MemberList.tsx b/packages/features/ee/teams/components/MemberList.tsx index 64a81aa0f5..e5dfb369b0 100644 --- a/packages/features/ee/teams/components/MemberList.tsx +++ b/packages/features/ee/teams/components/MemberList.tsx @@ -19,10 +19,10 @@ import type { Dispatch, SetStateAction } from "react"; import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner"; import { Dialog } from "@calcom/features/components/controlled-dialog"; import { - DataTable, DataTableProvider, DataTableToolbar, DataTableFilters, + DataTableWrapper, DataTableSelectionBar, useDataTable, useFetchMoreOnBottomReached, @@ -305,7 +305,6 @@ function MemberListContent(props: Props) { checked={table.getIsAllPageRowsSelected()} onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" - className="translate-y-[2px]" /> ), cell: ({ row }) => ( @@ -660,18 +659,27 @@ function MemberListContent(props: Props) { return ( <> - fetchMoreOnBottomReached(e.target as HTMLDivElement)}> - -
+ paginationMode="infinite" + hasNextPage={hasNextPage} + fetchNextPage={fetchNextPage} + isFetching={isFetching} + totalRowCount={totalRowCount} + ToolbarLeft={ + <> - + + + } + ToolbarRight={ + <> + {isAdminOrOwner && ( )} -
-
- -
-
- + + }> {numberOfSelectedRows >= 2 && dynamicLinkVisible && ( @@ -715,7 +719,7 @@ function MemberListContent(props: Props) { /> )} -
+ {state.deleteMember.showModal && ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" - className="translate-y-[2px]" /> ), cell: ({ row }) => ( diff --git a/packages/features/users/components/UserTable/UserListTable.tsx b/packages/features/users/components/UserTable/UserListTable.tsx index 694e377f1b..9e0a8a73f5 100644 --- a/packages/features/users/components/UserTable/UserListTable.tsx +++ b/packages/features/users/components/UserTable/UserListTable.tsx @@ -257,7 +257,6 @@ function UserListTableContent() { checked={table.getIsAllPageRowsSelected()} onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" - className="translate-y-[2px]" /> ), cell: ({ row }) => ( diff --git a/packages/ui/components/pagination/Pagination.tsx b/packages/ui/components/pagination/Pagination.tsx index ca99447d57..b5bd4b7a34 100644 --- a/packages/ui/components/pagination/Pagination.tsx +++ b/packages/ui/components/pagination/Pagination.tsx @@ -68,7 +68,7 @@ export const Pagination = ({ const endItem = Math.min(currentPage * pageSize, totalItems); return ( -
+