From 889266b32494af4dff8a881832eb6215017676b1 Mon Sep 17 00:00:00 2001 From: merge-check <140916359+agentHits@users.noreply.github.com> Date: Tue, 27 Oct 2026 15:54:41 -0400 Subject: [PATCH] build: upgrade @tanstack/react-table to v9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Что: @tanstack/react-table ^8.21.3 -> ^9.3.1 в apps/dokploy. Все 13 таблиц в apps/dokploy/components переведены с useReactTable на useTable: у каждой таблицы модульный объект features (tableFeatures) с нужными фичами (сортировка, пагинация, видимость колонок, фильтрация, выбор строк), row models create*RowModel вместо get*RowModel и явный реестр функций сортировки/фильтрации (alphanumeric, datetime, text; includesString, equals), чтобы 'auto' работал как в v8. ColumnDef получил параметр typeof features, VisibilityState -> ColumnVisibilityState, table.getState() -> table.state, sortingFn -> sortFn (тома Docker). DataTable в swarm/applications ограничен TData extends RowData. Зачем: волна 3 мажорных обновлений UI-библиотек. Слой совместимости useLegacyTable (@tanstack/react-table/legacy) не использован: в v9 он помечен deprecated и временным, тянет все фичи. Риски: в v9 API доступно только для зарегистрированных фич; 'auto' сортировка/фильтрация находит только зарегистрированные функции. Поведение таблиц в браузере локально не проверялось. Проверки: bun run typecheck - ок; bunx biome check по 18 файлам - ок; bun audit --audit-level=moderate - уязвимостей нет; smoke-скрипт с useTable и теми же features (сортировка, includesString, equals, пагинация, скрытие колонок) - ок. Тестов на таблицы в __test__ нет. next build не запускался (соберёт CI). Co-Authored-By: Claude Opus 5.5 --- .../dashboard/application/domains/columns.tsx | 6 +- .../application/domains/show-domains.tsx | 52 ++++++++++++---- .../deployments/show-deployments-table.tsx | 33 +++++++--- .../docker/disk-usage/show-disk-usage.tsx | 37 ++++++++---- .../docker/events/show-docker-events.tsx | 41 +++++++++---- .../dashboard/docker/images/show-images.tsx | 37 ++++++++---- .../dashboard/docker/show/columns.tsx | 4 +- .../dashboard/docker/show/show-containers.tsx | 52 ++++++++++++---- .../dashboard/docker/volumes/show-volumes.tsx | 39 ++++++++---- .../dashboard/networks/show-networks.tsx | 37 ++++++++---- .../components/dashboard/requests/columns.tsx | 3 +- .../dashboard/requests/requests-table.tsx | 48 +++++++++++---- .../settings/dns/show-dns-records.tsx | 37 ++++++++---- .../settings/sessions/show-sessions.tsx | 37 ++++++++---- .../dashboard/swarm/applications/columns.tsx | 3 +- .../swarm/applications/data-table.tsx | 60 ++++++++++++++----- .../proprietary/audit-logs/columns.tsx | 3 +- .../proprietary/audit-logs/data-table.tsx | 37 +++++++++--- apps/dokploy/package.json | 2 +- bun.lock | 10 +++- 20 files changed, 426 insertions(+), 152 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/domains/columns.tsx b/apps/dokploy/components/dashboard/application/domains/columns.tsx index 506bb9cb85..982b770032 100644 --- a/apps/dokploy/components/dashboard/application/domains/columns.tsx +++ b/apps/dokploy/components/dashboard/application/domains/columns.tsx @@ -24,7 +24,7 @@ import { import type { RouterOutputs } from "@/utils/api"; import { DnsHelperModal } from "./dns-helper-modal"; import { AddDomain } from "./handle-domain"; -import type { ValidationStates } from "./show-domains"; +import type { features, ValidationStates } from "./show-domains"; export type Domain = | RouterOutputs["domain"]["byApplicationId"][0] @@ -56,7 +56,7 @@ export const createColumns = ({ serverIp, canCreateDomain, canDeleteDomain, -}: ColumnsProps): ColumnDef[] => [ +}: ColumnsProps): ColumnDef[] => [ ...(type === "compose" ? [ { @@ -72,7 +72,7 @@ export const createColumns = ({ ); }, - } satisfies ColumnDef, + } satisfies ColumnDef, ] : []), { diff --git a/apps/dokploy/components/dashboard/application/domains/show-domains.tsx b/apps/dokploy/components/dashboard/application/domains/show-domains.tsx index f4206ee95d..542380d879 100644 --- a/apps/dokploy/components/dashboard/application/domains/show-domains.tsx +++ b/apps/dokploy/components/dashboard/application/domains/show-domains.tsx @@ -1,13 +1,23 @@ import { type ColumnFiltersState, + type ColumnVisibilityState, + columnFilteringFeature, + columnVisibilityFeature, + createFilteredRowModel, + createPaginatedRowModel, + createSortedRowModel, + filterFn_equals, + filterFn_includesString, flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, + rowPaginationFeature, + rowSelectionFeature, + rowSortingFeature, type SortingState, - useReactTable, - type VisibilityState, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { CheckCircle2, @@ -67,6 +77,26 @@ import { AddDomain } from "./handle-domain"; import { HandleForwardAuth } from "./handle-forward-auth"; import { COMPOSE_REDEPLOY_TOAST, ComposeRedeployAlert } from "./redeploy-hint"; +export const features = tableFeatures({ + columnFilteringFeature, + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + rowSelectionFeature, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + filterFns: { + equals: filterFn_equals, + includesString: filterFn_includesString, + }, + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + export type ValidationState = { isLoading: boolean; isValid?: boolean; @@ -119,7 +149,8 @@ export const ShowDomains = ({ id, type }: Props) => { }); const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); - const [columnVisibility, setColumnVisibility] = useState({}); + const [columnVisibility, setColumnVisibility] = + useState({}); const [rowSelection, setRowSelection] = useState({}); const { data: ip } = api.settings.getIp.useQuery(); @@ -232,15 +263,12 @@ export const ShowDomains = ({ id, type }: Props) => { canDeleteDomain, }); - const table = useReactTable({ + const table = useTable({ + features, data: data ?? [], columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { diff --git a/apps/dokploy/components/dashboard/deployments/show-deployments-table.tsx b/apps/dokploy/components/dashboard/deployments/show-deployments-table.tsx index ad860745a0..6c534889ce 100644 --- a/apps/dokploy/components/dashboard/deployments/show-deployments-table.tsx +++ b/apps/dokploy/components/dashboard/deployments/show-deployments-table.tsx @@ -1,13 +1,19 @@ "use client"; import { + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import type { inferRouterOutputs } from "@trpc/server"; import { @@ -43,6 +49,19 @@ import { import type { AppRouter } from "@/server/api/root"; import { api } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + type DeploymentRow = inferRouterOutputs["deployment"]["allCentralized"][number]; @@ -445,7 +464,8 @@ export function ShowDeploymentsTable({ [], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredData, columns, state: { @@ -454,9 +474,6 @@ export function ShowDeploymentsTable({ }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( diff --git a/apps/dokploy/components/dashboard/docker/disk-usage/show-disk-usage.tsx b/apps/dokploy/components/dashboard/docker/disk-usage/show-disk-usage.tsx index 0ce4f21ea2..f7bcc2df95 100644 --- a/apps/dokploy/components/dashboard/docker/disk-usage/show-disk-usage.tsx +++ b/apps/dokploy/components/dashboard/docker/disk-usage/show-disk-usage.tsx @@ -2,13 +2,19 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import type { inferRouterOutputs } from "@trpc/server"; import { @@ -46,6 +52,19 @@ import { import type { AppRouter } from "@/server/api/root"; import { api } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + type DiskUsageItem = inferRouterOutputs["dockerDiskUsage"]["getDiskUsage"][number]; type BuildCacheBase = @@ -176,7 +195,7 @@ export const ShowDiskUsage = ({ serverId }: Props) => { } }; - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { accessorKey: "id", @@ -263,7 +282,8 @@ export const ShowDiskUsage = ({ serverId }: Props) => { [], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredData, columns, getRowId: (row) => row.key, @@ -273,9 +293,6 @@ export const ShowDiskUsage = ({ serverId }: Props) => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( @@ -395,7 +412,7 @@ export const ShowDiskUsage = ({ serverId }: Props) => { {table.getPageCount() > 1 && (
- Page {table.getState().pagination.pageIndex + 1} of{" "} + Page {table.state.pagination.pageIndex + 1} of{" "} {table.getPageCount()}
diff --git a/apps/dokploy/components/dashboard/docker/events/show-docker-events.tsx b/apps/dokploy/components/dashboard/docker/events/show-docker-events.tsx index 8a6d76db89..90ae2e3de1 100644 --- a/apps/dokploy/components/dashboard/docker/events/show-docker-events.tsx +++ b/apps/dokploy/components/dashboard/docker/events/show-docker-events.tsx @@ -1,12 +1,18 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { Activity, ArrowUpDown, Loader2, RefreshCw } from "lucide-react"; import { useMemo, useState } from "react"; @@ -37,6 +43,19 @@ import { } from "@/components/ui/table"; import { api, type RouterOutputs } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + interface Props { serverId?: string; } @@ -153,7 +172,7 @@ export const ShowDockerEvents = ({ serverId }: Props) => { }); }, [events, search]); - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { id: "time", @@ -228,7 +247,8 @@ export const ShowDockerEvents = ({ serverId }: Props) => { [], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredEvents, columns, getRowId: (row) => row.key, @@ -238,9 +258,6 @@ export const ShowDockerEvents = ({ serverId }: Props) => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( @@ -362,7 +379,7 @@ export const ShowDockerEvents = ({ serverId }: Props) => { {table.getPageCount() > 1 && (
- Page {table.getState().pagination.pageIndex + 1} of{" "} + Page {table.state.pagination.pageIndex + 1} of{" "} {table.getPageCount()}
@@ -371,8 +388,8 @@ export const ShowDockerEvents = ({ serverId }: Props) => { type="number" min={1} max={table.getPageCount()} - defaultValue={table.getState().pagination.pageIndex + 1} - key={table.getState().pagination.pageIndex} + defaultValue={table.state.pagination.pageIndex + 1} + key={table.state.pagination.pageIndex} onKeyDown={(e) => { if (e.key !== "Enter") return; const value = Number( diff --git a/apps/dokploy/components/dashboard/docker/images/show-images.tsx b/apps/dokploy/components/dashboard/docker/images/show-images.tsx index bb694f1282..fd6a945b8e 100644 --- a/apps/dokploy/components/dashboard/docker/images/show-images.tsx +++ b/apps/dokploy/components/dashboard/docker/images/show-images.tsx @@ -2,13 +2,19 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import type { inferRouterOutputs } from "@trpc/server"; import { ArrowUpDown, Eye, Layers, Loader2, Trash2 } from "lucide-react"; @@ -56,6 +62,19 @@ import { import type { AppRouter } from "@/server/api/root"; import { api } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + type ImageBase = inferRouterOutputs["dockerImage"]["getImages"][number]; type ImageRow = ImageBase & { key: string }; @@ -226,7 +245,7 @@ export const ShowImages = ({ serverId }: Props) => { } }; - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { accessorKey: "Repository", @@ -304,7 +323,8 @@ export const ShowImages = ({ serverId }: Props) => { [serverId], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredData, columns, getRowId: (row) => row.key, @@ -314,9 +334,6 @@ export const ShowImages = ({ serverId }: Props) => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( @@ -410,7 +427,7 @@ export const ShowImages = ({ serverId }: Props) => { {table.getPageCount() > 1 && (
- Page {table.getState().pagination.pageIndex + 1} of{" "} + Page {table.state.pagination.pageIndex + 1} of{" "} {table.getPageCount()}
diff --git a/apps/dokploy/components/dashboard/docker/show/columns.tsx b/apps/dokploy/components/dashboard/docker/show/columns.tsx index 3a105aefa5..4732b9a4a0 100644 --- a/apps/dokploy/components/dashboard/docker/show/columns.tsx +++ b/apps/dokploy/components/dashboard/docker/show/columns.tsx @@ -19,9 +19,9 @@ import { ShowContainerNetworks } from "../networks/show-container-networks"; import { RemoveContainerDialog } from "../remove/remove-container"; import { DockerTerminalModal } from "../terminal/docker-terminal-modal"; import { UploadFileModal } from "../upload/upload-file-modal"; -import type { Container } from "./show-containers"; +import type { Container, features } from "./show-containers"; -export const columns: ColumnDef[] = [ +export const columns: ColumnDef[] = [ { accessorKey: "name", header: ({ column }) => { diff --git a/apps/dokploy/components/dashboard/docker/show/show-containers.tsx b/apps/dokploy/components/dashboard/docker/show/show-containers.tsx index f5766f7c41..07f4097e8e 100644 --- a/apps/dokploy/components/dashboard/docker/show/show-containers.tsx +++ b/apps/dokploy/components/dashboard/docker/show/show-containers.tsx @@ -1,13 +1,23 @@ import { type ColumnFiltersState, + type ColumnVisibilityState, + columnFilteringFeature, + columnVisibilityFeature, + createFilteredRowModel, + createPaginatedRowModel, + createSortedRowModel, + filterFn_equals, + filterFn_includesString, flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, + rowPaginationFeature, + rowSelectionFeature, + rowSortingFeature, type SortingState, - useReactTable, - type VisibilityState, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { ChevronDown, Container, RefreshCw } from "lucide-react"; import * as React from "react"; @@ -43,6 +53,27 @@ import { } from "@/components/ui/table"; import { api, type RouterOutputs } from "@/utils/api"; import { columns } from "./columns"; + +export const features = tableFeatures({ + columnFilteringFeature, + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + rowSelectionFeature, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + filterFns: { + equals: filterFn_equals, + includesString: filterFn_includesString, + }, + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + export type Container = NonNullable< RouterOutputs["docker"]["getContainers"] >[0]; @@ -77,18 +108,15 @@ export const ShowContainers = ({ serverId }: Props) => { [], ); const [columnVisibility, setColumnVisibility] = - React.useState({}); + React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); - const table = useReactTable({ + const table = useTable({ + features, data: data ?? [], columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { diff --git a/apps/dokploy/components/dashboard/docker/volumes/show-volumes.tsx b/apps/dokploy/components/dashboard/docker/volumes/show-volumes.tsx index d8c76662f9..c5dc406e63 100644 --- a/apps/dokploy/components/dashboard/docker/volumes/show-volumes.tsx +++ b/apps/dokploy/components/dashboard/docker/volumes/show-volumes.tsx @@ -2,13 +2,19 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import type { inferRouterOutputs } from "@trpc/server"; import { @@ -54,6 +60,19 @@ import { import type { AppRouter } from "@/server/api/root"; import { api } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + type VolumeRow = inferRouterOutputs["dockerVolume"]["getVolumes"][number]; @@ -183,7 +202,7 @@ export const ShowVolumes = ({ serverId }: Props) => { return list.filter((volume) => volume.Name.toLowerCase().includes(query)); }, [volumes, globalFilter]); - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { accessorKey: "Name", @@ -218,7 +237,7 @@ export const ShowVolumes = ({ serverId }: Props) => { { id: "Size", header: ({ column }) => , - sortingFn: (a, b) => + sortFn: (a, b) => parseSize(sizeByName.get(a.original.Name) ?? undefined) - parseSize(sizeByName.get(b.original.Name) ?? undefined), cell: ({ row }) => @@ -297,7 +316,8 @@ export const ShowVolumes = ({ serverId }: Props) => { [serverId, removeVolume, utils, sizeByName, isLoadingSizes], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredData, columns, state: { @@ -306,9 +326,6 @@ export const ShowVolumes = ({ serverId }: Props) => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( @@ -401,7 +418,7 @@ export const ShowVolumes = ({ serverId }: Props) => { {table.getPageCount() > 1 && (
- Page {table.getState().pagination.pageIndex + 1} of{" "} + Page {table.state.pagination.pageIndex + 1} of{" "} {table.getPageCount()}
diff --git a/apps/dokploy/components/dashboard/networks/show-networks.tsx b/apps/dokploy/components/dashboard/networks/show-networks.tsx index d87278b1e8..cdc45a0ff8 100644 --- a/apps/dokploy/components/dashboard/networks/show-networks.tsx +++ b/apps/dokploy/components/dashboard/networks/show-networks.tsx @@ -2,13 +2,19 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import type { inferRouterOutputs } from "@trpc/server"; import { @@ -54,6 +60,19 @@ import { import type { AppRouter } from "@/server/api/root"; import { api } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + type NetworkRow = inferRouterOutputs["network"]["all"][number]; interface Props { @@ -154,7 +173,7 @@ export const ShowNetworks = ({ serverId }: Props) => { return list; }, [networks, driverFilter, globalFilter]); - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { accessorKey: "name", @@ -326,7 +345,8 @@ export const ShowNetworks = ({ serverId }: Props) => { [verified, syncStatus, missingIds, removeNetwork, recreateMutation, utils], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredData, columns, state: { @@ -335,9 +355,6 @@ export const ShowNetworks = ({ serverId }: Props) => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( @@ -461,7 +478,7 @@ export const ShowNetworks = ({ serverId }: Props) => { {table.getPageCount() > 1 && (
- Page {table.getState().pagination.pageIndex + 1} of{" "} + Page {table.state.pagination.pageIndex + 1} of{" "} {table.getPageCount()}
diff --git a/apps/dokploy/components/dashboard/requests/columns.tsx b/apps/dokploy/components/dashboard/requests/columns.tsx index 7322dc098d..00be39251e 100644 --- a/apps/dokploy/components/dashboard/requests/columns.tsx +++ b/apps/dokploy/components/dashboard/requests/columns.tsx @@ -3,6 +3,7 @@ import { format } from "date-fns"; import { ArrowUpDown } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import type { features } from "./requests-table"; import type { LogEntry } from "./show-requests"; export const getStatusColor = (status: number) => { @@ -42,7 +43,7 @@ const formatDuration = (nanos: number) => { return `${(ms / 1000).toFixed(2)} s`; }; -export const columns: ColumnDef[] = [ +export const columns: ColumnDef[] = [ { accessorKey: "level", header: () => { diff --git a/apps/dokploy/components/dashboard/requests/requests-table.tsx b/apps/dokploy/components/dashboard/requests/requests-table.tsx index c8ca5f3f38..3511aa0e53 100644 --- a/apps/dokploy/components/dashboard/requests/requests-table.tsx +++ b/apps/dokploy/components/dashboard/requests/requests-table.tsx @@ -1,13 +1,23 @@ import { type ColumnFiltersState, + type ColumnVisibilityState, + columnFilteringFeature, + columnVisibilityFeature, + createFilteredRowModel, + createSortedRowModel, + filterFn_equals, + filterFn_includesString, flexRender, - getCoreRowModel, - getFilteredRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSelectionFeature, + rowSortingFeature, type SortingState, - useReactTable, - type VisibilityState, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import copy from "copy-to-clipboard"; import { @@ -54,6 +64,25 @@ import { columns, getStatusColor } from "./columns"; import type { LogEntry } from "./show-requests"; import { DataTableFacetedFilter } from "./status-request-filter"; +export const features = tableFeatures({ + columnFilteringFeature, + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + rowSelectionFeature, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { + equals: filterFn_equals, + includesString: filterFn_includesString, + }, + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + export const priorities = [ { label: "100 - 199", @@ -94,7 +123,8 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => { const [search, setSearch] = useState(""); const [selectedRow, setSelectedRow] = useState(); const [sorting, setSorting] = useState([]); - const [columnVisibility, setColumnVisibility] = useState({}); + const [columnVisibility, setColumnVisibility] = + useState({}); const [rowSelection, setRowSelection] = useState({}); const [columnFilters, setColumnFilters] = useState([]); const [pagination, setPagination] = useState({ @@ -132,16 +162,14 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => { return -1; }, [statsLogs?.totalCount, pagination.pageSize]); - const table = useReactTable({ + const table = useTable({ + features, data: statsLogs?.data ?? [], columns, onPaginationChange: setPagination, onSortingChange: setSorting, pageCount: pageCount, onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, manualPagination: true, diff --git a/apps/dokploy/components/dashboard/settings/dns/show-dns-records.tsx b/apps/dokploy/components/dashboard/settings/dns/show-dns-records.tsx index 1264b66966..eaec1f1483 100644 --- a/apps/dokploy/components/dashboard/settings/dns/show-dns-records.tsx +++ b/apps/dokploy/components/dashboard/settings/dns/show-dns-records.tsx @@ -1,12 +1,18 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { ArrowLeft, @@ -64,6 +70,19 @@ import { } from "./dns-record-panel"; import { DnsRecordTypeBadge } from "./dns-record-type-badge"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + interface Props { dnsProviderId: string; zoneId: string; @@ -159,7 +178,7 @@ export const ShowDnsRecords = ({ dnsProviderId, zoneId }: Props) => { .finally(() => setDeletingId(null)); }; - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { accessorKey: "type", @@ -233,7 +252,7 @@ export const ShowDnsRecords = ({ dnsProviderId, zoneId }: Props) => { ); }, - } satisfies ColumnDef, + } satisfies ColumnDef, ] : []), { @@ -303,7 +322,8 @@ export const ShowDnsRecords = ({ dnsProviderId, zoneId }: Props) => { const resetToFirstPage = () => setPagination((previous) => ({ ...previous, pageIndex: 0 })); - const table = useReactTable({ + const table = useTable({ + features, data: filteredRecords, columns, getRowId: (row) => row.id, @@ -313,9 +333,6 @@ export const ShowDnsRecords = ({ dnsProviderId, zoneId }: Props) => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( diff --git a/apps/dokploy/components/dashboard/settings/sessions/show-sessions.tsx b/apps/dokploy/components/dashboard/settings/sessions/show-sessions.tsx index 6f0eab1e21..b7e1ed2092 100644 --- a/apps/dokploy/components/dashboard/settings/sessions/show-sessions.tsx +++ b/apps/dokploy/components/dashboard/settings/sessions/show-sessions.tsx @@ -1,12 +1,18 @@ import { type ColumnDef, + columnVisibilityFeature, + createPaginatedRowModel, + createSortedRowModel, flexRender, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, type PaginationState, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { format } from "date-fns"; import { ArrowUpDown, Loader2, LogOut, Smartphone } from "lucide-react"; @@ -40,6 +46,19 @@ import { } from "@/components/ui/table"; import { api } from "@/utils/api"; +const features = tableFeatures({ + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + type SessionRow = { id: string; userId: string; @@ -139,7 +158,7 @@ export const ShowSessions = () => { return list; }, [sessions, statusFilter, userFilter, isOwner, globalFilter]); - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { id: "user", @@ -259,7 +278,8 @@ export const ShowSessions = () => { [isRevoking, handleRevoke], ); - const table = useReactTable({ + const table = useTable({ + features, data: filteredData, columns, state: { @@ -268,9 +288,6 @@ export const ShowSessions = () => { }, onSortingChange: setSorting, onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), }); return ( @@ -400,7 +417,7 @@ export const ShowSessions = () => { {table.getPageCount() > 1 && (
- Page {table.getState().pagination.pageIndex + 1} of{" "} + Page {table.state.pagination.pageIndex + 1} of{" "} {table.getPageCount()}
diff --git a/apps/dokploy/components/dashboard/swarm/applications/columns.tsx b/apps/dokploy/components/dashboard/swarm/applications/columns.tsx index c23f57d77c..5fd7631d46 100644 --- a/apps/dokploy/components/dashboard/swarm/applications/columns.tsx +++ b/apps/dokploy/components/dashboard/swarm/applications/columns.tsx @@ -9,6 +9,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { ShowDockerModalStackLogs } from "../../docker/logs/show-docker-modal-stack-logs"; +import type { features } from "./data-table"; export interface ApplicationList { ID: string; @@ -24,7 +25,7 @@ export interface ApplicationList { serverId: string; } -export const columns: ColumnDef[] = [ +export const columns: ColumnDef[] = [ { accessorKey: "ID", accessorFn: (row) => row.ID, diff --git a/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx b/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx index b1691ffe5a..c234d3e495 100644 --- a/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx +++ b/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx @@ -3,14 +3,25 @@ import { type ColumnDef, type ColumnFiltersState, + type ColumnVisibilityState, + columnFilteringFeature, + columnVisibilityFeature, + createFilteredRowModel, + createPaginatedRowModel, + createSortedRowModel, + filterFn_equals, + filterFn_includesString, flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, + type RowData, + rowPaginationFeature, + rowSelectionFeature, + rowSortingFeature, type SortingState, - useReactTable, - type VisibilityState, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { ChevronDown } from "lucide-react"; import React from "react"; @@ -31,36 +42,53 @@ import { TableRow, } from "@/components/ui/table"; -interface DataTableProps { - columns: ColumnDef[]; +export const features = tableFeatures({ + columnFilteringFeature, + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + rowSelectionFeature, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + paginatedRowModel: createPaginatedRowModel(), + filterFns: { + equals: filterFn_equals, + includesString: filterFn_includesString, + }, + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + +interface DataTableProps { + columns: ColumnDef[]; data: TData[]; } -export function DataTable({ +export function DataTable({ columns, data, -}: DataTableProps) { +}: DataTableProps) { const [sorting, setSorting] = React.useState([]); const [columnFilters, setColumnFilters] = React.useState( [], ); const [columnVisibility, setColumnVisibility] = - React.useState({}); + React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); const [_pagination, _setPagination] = React.useState({ pageIndex: 0, //initial page index pageSize: 8, //default page size }); - const table = useReactTable({ + const table = useTable({ + features, data, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { diff --git a/apps/dokploy/components/proprietary/audit-logs/columns.tsx b/apps/dokploy/components/proprietary/audit-logs/columns.tsx index 65770a5700..5dbe629150 100644 --- a/apps/dokploy/components/proprietary/audit-logs/columns.tsx +++ b/apps/dokploy/components/proprietary/audit-logs/columns.tsx @@ -27,6 +27,7 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; +import type { features } from "./data-table"; const ACTION_CONFIG: Record< string, @@ -148,7 +149,7 @@ function MetadataCell({ metadata }: { metadata: string | null }) { ); } -export const columns: ColumnDef[] = [ +export const columns: ColumnDef[] = [ { accessorKey: "createdAt", header: ({ column }) => ( diff --git a/apps/dokploy/components/proprietary/audit-logs/data-table.tsx b/apps/dokploy/components/proprietary/audit-logs/data-table.tsx index a1b66fde63..5775e37d70 100644 --- a/apps/dokploy/components/proprietary/audit-logs/data-table.tsx +++ b/apps/dokploy/components/proprietary/audit-logs/data-table.tsx @@ -3,12 +3,19 @@ import type { AuditLog } from "@dokploy/server/db/schema"; import { type ColumnDef, + type ColumnVisibilityState, + columnFilteringFeature, + columnVisibilityFeature, + createSortedRowModel, flexRender, - getCoreRowModel, - getSortedRowModel, + rowPaginationFeature, + rowSortingFeature, type SortingState, - useReactTable, - type VisibilityState, + sortFn_alphanumeric, + sortFn_datetime, + sortFn_text, + tableFeatures, + useTable, } from "@tanstack/react-table"; import { format } from "date-fns"; import { CalendarIcon, ChevronDown, X } from "lucide-react"; @@ -44,6 +51,19 @@ import { TableRow, } from "@/components/ui/table"; +export const features = tableFeatures({ + columnFilteringFeature, + rowSortingFeature, + rowPaginationFeature, + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), + sortFns: { + alphanumeric: sortFn_alphanumeric, + datetime: sortFn_datetime, + text: sortFn_text, + }, +}); + const ACTION_OPTIONS = [ { value: "create", label: "Created" }, { value: "update", label: "Updated" }, @@ -114,7 +134,7 @@ export interface AuditLogFilters { } interface DataTableProps { - columns: ColumnDef[]; + columns: ColumnDef[]; data: AuditLog[]; total: number; pageIndex: number; @@ -145,14 +165,13 @@ export function DataTable({ { id: "createdAt", desc: true }, ]); const [columnVisibility, setColumnVisibility] = - React.useState({}); + React.useState({}); - const table = useReactTable({ + const table = useTable({ + features, data, columns, onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), onColumnVisibilityChange: setColumnVisibility, manualPagination: true, manualFiltering: true, diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 9f924f845a..3d05fa4ca3 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -79,7 +79,7 @@ "@stripe/stripe-js": "4.10.0", "@tailwindcss/typography": "0.5.20", "@tanstack/react-query": "^5.105.0", - "@tanstack/react-table": "^8.21.3", + "@tanstack/react-table": "^9.3.1", "@trpc/client": "^11.19.0", "@trpc/next": "^11.19.0", "@trpc/react-query": "^11.19.0", diff --git a/bun.lock b/bun.lock index 83cbd232bb..1cc32dda71 100644 --- a/bun.lock +++ b/bun.lock @@ -79,7 +79,7 @@ "@stripe/stripe-js": "4.10.0", "@tailwindcss/typography": "0.5.20", "@tanstack/react-query": "^5.105.0", - "@tanstack/react-table": "^8.21.3", + "@tanstack/react-table": "^9.3.1", "@trpc/client": "^11.19.0", "@trpc/next": "^11.19.0", "@trpc/react-query": "^11.19.0", @@ -1483,11 +1483,15 @@ "@tanstack/react-query": ["@tanstack/react-query@5.105.0", "", { "dependencies": { "@tanstack/query-core": "5.105.0" }, "peerDependencies": { "@types/react": "^18 || ^19", "react": "^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-y+hMuDERvgg6ay1da0V1a6ZC0ZONt7dELxSFkqRZuwm7p1TTZs0MoXrPlBRflIpRoYjvzQVYxycnLImpFLhWrw=="], - "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="], + "@tanstack/react-store": ["@tanstack/react-store@0.11.2", "", { "dependencies": { "@tanstack/store": "0.11.2", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-oj5O5DmiMWE+ih+SioX2ayC1kbK7d3fpLx0B75fPJr9nY3zU+hoW010yr64qXsY/9fyiLVE2bn5mGNV3owm8RQ=="], + + "@tanstack/react-table": ["@tanstack/react-table@9.3.1", "", { "dependencies": { "@tanstack/react-store": "^0.11.2", "@tanstack/table-core": "9.3.1" }, "peerDependencies": { "react": ">=18" } }, "sha512-E6Ya5TnY6EaGyZYIUqig/29Lr/gJSAubQkLJFqiWkUl5nRCr0Xr9hvJot+NiRTtG+TzGxHTiqUW3bnLtQxlHug=="], "@tanstack/react-virtual": ["@tanstack/react-virtual@3.14.10", "", { "dependencies": { "@tanstack/virtual-core": "3.17.8" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw=="], - "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], + "@tanstack/store": ["@tanstack/store@0.11.2", "", {}, "sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q=="], + + "@tanstack/table-core": ["@tanstack/table-core@9.3.1", "", { "dependencies": { "@tanstack/store": "^0.11.2" } }, "sha512-zQvlxSNi2qGM3L4jh85Z6hqMfdIR5qOfD9KHOU32nuKFJGN0RlJ7UvV1lsPb1fPVhpFYI0VP3jJGxLdLDpTKjQ=="], "@tanstack/virtual-core": ["@tanstack/virtual-core@3.17.8", "", {}, "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA=="],