diff --git a/web/src/common/Table.css b/web/src/common/Table.css index 4b80c2c..c6e2fdd 100644 --- a/web/src/common/Table.css +++ b/web/src/common/Table.css @@ -1,81 +1,128 @@ -/* .StandardTable [data-sticky-td] { - position: sticky; - } */ - -.StandardTable { - max-height: calc(100vh - 280px); +.Table__container { + min-height: 300px; + max-height: calc(100vh - 250px); overflow: auto; - position: relative; - width: 100%; - background-color: inherit; } +.Table { + + width: 100%; -.StandardTable__row { - @apply border-b border-solid border-gray-200; - /* width: 100%; */ + background: inherit; } -.StandardTable__row:last-child { - border-bottom: 0; +.Table__table { + min-width: 100%; + background: inherit; + /* text-indent: 0; */ + /* border-color: inherit; */ + border-collapse: collapse; } -.StandardTable__row:last-child .StandardTable__cell { - /* border-bottom: 0; */ +.Table__table__header { + top: 0; } -.StandardTable__cell { - @apply px-2 py-2 overflow-hidden flex items-center; - /* border-bottom: 1px solid theme("colors.primary.main"); */ - min-width: 0; +.Table__pagination { + justify-content: flex-end; + bottom: 0; } -.StandardTable__cell:first-child { - @apply pl-4; +.Table__table__header, +.Table__table__footer { + font-weight: bold; } -.StandardTable__cell:last-child { - @apply pr-4; +.Table__table__header, +/* .Table__table__footer, */ +.Table__pagination { + position: sticky; + z-index: 10; } -[data-sticky-td] { - /* @apply bg-primary-shade4; */ +.Table__table__header__row, +.Table__table__body__row, +.Table__table__footer__row { + border-bottom: 1px solid lightgray; } -.StandardTable__header { - @apply rounded-xl font-bold; - position: sticky; - top: 0; - z-index: 4; +.Table__table__header__row--relative, +.Table__table__body__row--relative, +.Table__table__footer__row--relative { + display: flex; + min-width: 100%; } -.StandardTable__header__row { - @apply bg-secondary-light text-secondary-contrastText h-12; +.Table__table__header__row--absolute, +.Table__table__body__row--absolute, +.Table__table__footer__row--absolute { + display: flex; + position: relative; + height: 40px; } -.StandardTable__header__row__cell { +.Table__table__header__row__cell, +.Table__table__body__row__cell, +.Table__table__footer__row__cell { + position: relative; + background-color: white; + padding: 8px; + /* height: 48px; */ + text-align: left; } -.StandardTable__body { +.Table__table__header__row__cell--relative, +.Table__table__body__row__cell--relative, +.Table__table__footer__row__cell--relative { + flex: 1 0 auto; } -.StandardTable__body__row { +.Table__table__header__row__cell--absolute, +.Table__table__body__row__cell--absolute, +.Table__table__footer__row__cell--absolute { + position: absolute; + height: 40px; } -.StandardTable__body__row__cell { +.Table__loading, +.Table__empty, +.Table__error { + display: flex; + justify-content: center; + padding: 16px; } -.StandardTable__pagination { +.Table__loading, +.Table__empty, +.Table__error, +.Table__pagination { position: sticky; - bottom: 0; left: 0; right: 0; - z-index: 4; - display: flex; - justify-content: flex-end; - background-color: inherit; } -.StandardTable__pagination__item { - background-color: inherit; - /* border-top: 1px solid theme("colors.secondary.main"); */ +.Table__resizer { + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 5px; + background: rgba(0, 0, 0, 0.5); + cursor: col-resize; + user-select: none; + touch-action: none; +} + +.Table__resizer.Table__resizing { + background: blue; + opacity: 1; +} + +@media (hover: hover) { + .Table__resizer { + opacity: 0; + } + + *:hover > .Table__resizer { + opacity: 1; + } } diff --git a/web/src/common/Table.tsx b/web/src/common/Table.tsx index f41e83f..c5250cb 100644 --- a/web/src/common/Table.tsx +++ b/web/src/common/Table.tsx @@ -9,12 +9,12 @@ import { import clsx from "clsx"; import TablePagination from "./TablePagination"; import "./Table.css"; -import { ReactNode } from "react"; +import React, { ReactNode, Ref } from "react"; interface TableProps { variant: "default" | "absolute" | "relative"; instance: TanTable; - classes: { + classes?: { [P in | "root" | "row" @@ -33,6 +33,8 @@ interface TableProps { | "footer"]: string; }; flexRender: Function; + virtualizationInstance: any; + virtualization: boolean; onReload: () => void; Root: any; RootProps: (instance: TanTable, props: TableProps) => any; @@ -139,9 +141,13 @@ interface TableProps { * * @param {TableProps} props */ -function Table(props: any) { - return props.renderRoot(props.instance, props); -} +const Table = React.forwardRef((props: any, ref: Ref) => { + return ( +
+ {props.renderRoot(props.instance, props)} +
+ ); +}); /** * @type {TableProps} @@ -149,7 +155,8 @@ function Table(props: any) { Table.defaultProps = { header: true, footer: false, - pagination: true, + pagination: false, + virtualization: false, flexRender, renderRoot, renderTable, @@ -405,6 +412,14 @@ function renderBody(instance: TanTable, props: TableProps) { // const isRelative = props.variant === "relative"; const Body = props.Body || isDefault ? "tbody" : "div"; const BodyProps = props.BodyProps?.(instance, props); + const { rows } = instance.getRowModel(); + console.log("rows.length", rows); + const { virtualItems: virtualRows, totalSize } = props.virtualizationInstance; + const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0; + const paddingBottom = + virtualRows.length > 0 + ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) + : 0; return ( , props: TableProps) { ), }} > - {BodyProps?.children || - instance - .getPaginationRowModel() - .rows.map((bodyRow) => props.renderBodyRow(bodyRow, instance, props))} + <> + {props.virtualization ? ( + <> + {paddingTop > 0 && ( + + + + )} + {virtualRows.map((virtualRow: any) => + props.renderBodyRow(rows[virtualRow.index], instance, props) + )} + {paddingBottom > 0 && ( + + + + )} + + ) : ( + BodyProps?.children || + instance + .getPaginationRowModel() + .rows.map((bodyRow) => + props.renderBodyRow(bodyRow, instance, props) + ) + )} + ); } diff --git a/web/src/common/useTable.tsx b/web/src/common/useTable.tsx index 598cb64..d1e8a29 100644 --- a/web/src/common/useTable.tsx +++ b/web/src/common/useTable.tsx @@ -1,9 +1,4 @@ -import { - useReactTable, - getPaginationRowModel, - TableOptions, - getCoreRowModel, -} from "@tanstack/react-table"; +import { useReactTable, TableOptions } from "@tanstack/react-table"; /** * @@ -12,15 +7,9 @@ import { */ function useTable(options: TableOptions) { return useReactTable({ - // getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), debugTable: true, ...options, data: options.data || [], - // defaultColumn: { - // // cell: (info) => {info.getValue()}, - // ...options?.defaultColumn, - // }, }); } diff --git a/web/src/server/ServerDetailServicesTabPanelProcess.tsx b/web/src/server/ServerDetailServicesTabPanelProcess.tsx index b475730..06f2ea9 100644 --- a/web/src/server/ServerDetailServicesTabPanelProcess.tsx +++ b/web/src/server/ServerDetailServicesTabPanelProcess.tsx @@ -1,4 +1,5 @@ import { getCoreRowModel } from "@tanstack/react-table"; +import { useVirtual } from "react-virtual"; import Table from "common/Table"; import useTable from "common/useTable"; import React from "react"; @@ -19,37 +20,33 @@ export default function ServerDetailServicesTabPanelProcess( props: ServerDetailServicesTabPanelProcessType ) { const tableInstance = useTable({ - getCoreRowModel: getCoreRowModel(), - initialState: { pagination: { pageSize: 30 } }, - columns, data, + columns, + getCoreRowModel: getCoreRowModel(), }); + + const tableContainerRef = React.useRef(null); + + const { rows } = tableInstance.getRowModel(); + + const rowVirtualizer = useVirtual({ + parentRef: tableContainerRef, + size: rows.length, + overscan: 10, + }); + return ( -
- - +
); } const columns = [ - // { - // header: "Name", - // footer: (props) => props.column.id, - // columns: [ - // { - // accessorKey: "firstname", - // cell: (info) => info.getValue(), - // footer: (props) => props.column.id - // }, - // { - // accessorFn: (row) => row.lastName, - // id: "lastname", - // cell: (info) => info.getValue(), - // header: () => Last Name, - // footer: (props) => props.column.id - // } - // ] - // }, { header: "First Name", accessorKey: "firstname", @@ -68,7 +65,7 @@ const columns = [ }, ]; -const data = Array(100).fill({ +const data = Array(1000).fill({ firstname: "Joseph", lastname: "Edache", message: "Hello",