From 838cd6d0d5e26cf5c40d5a2a0374a62efcabb950 Mon Sep 17 00:00:00 2001 From: Egbert Bouman Date: Thu, 14 Nov 2024 15:42:10 +0100 Subject: [PATCH 1/2] Add sorting to all tables --- .../ui/src/components/ui/simple-table.tsx | 33 ++++++++++++++- src/tribler/ui/src/dialogs/SaveAs.tsx | 8 ++-- src/tribler/ui/src/lib/utils.ts | 8 ---- .../ui/src/pages/Debug/Asyncio/Tasks.tsx | 12 +++--- .../ui/src/pages/Debug/DHT/Buckets.tsx | 8 ++-- .../ui/src/pages/Debug/DHT/Statistics.tsx | 6 +-- .../ui/src/pages/Debug/General/index.tsx | 6 +-- .../ui/src/pages/Debug/IPv8/Details.tsx | 12 +++--- .../ui/src/pages/Debug/IPv8/Overlays.tsx | 26 ++++++------ .../ui/src/pages/Debug/Libtorrent/index.tsx | 6 +-- .../ui/src/pages/Debug/Tunnels/Circuits.tsx | 18 ++++---- .../ui/src/pages/Debug/Tunnels/Exits.tsx | 12 +++--- .../ui/src/pages/Debug/Tunnels/Peers.tsx | 12 +++--- .../ui/src/pages/Debug/Tunnels/Relays.tsx | 14 +++---- .../ui/src/pages/Debug/Tunnels/Swarms.tsx | 18 ++++---- src/tribler/ui/src/pages/Downloads/Files.tsx | 8 ++-- src/tribler/ui/src/pages/Downloads/Peers.tsx | 16 ++++---- .../ui/src/pages/Downloads/Trackers.tsx | 9 ++-- src/tribler/ui/src/pages/Downloads/index.tsx | 41 +++++-------------- src/tribler/ui/src/pages/Popular/index.tsx | 10 ++--- src/tribler/ui/src/pages/Search/index.tsx | 10 ++--- 21 files changed, 146 insertions(+), 147 deletions(-) diff --git a/src/tribler/ui/src/components/ui/simple-table.tsx b/src/tribler/ui/src/components/ui/simple-table.tsx index 8589526119..6ee2a1c17f 100644 --- a/src/tribler/ui/src/components/ui/simple-table.tsx +++ b/src/tribler/ui/src/components/ui/simple-table.tsx @@ -1,17 +1,46 @@ import { SetStateAction, useEffect, useRef, useState } from 'react'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { getCoreRowModel, useReactTable, flexRender, getFilteredRowModel, getPaginationRowModel, getExpandedRowModel, getSortedRowModel } from '@tanstack/react-table'; -import type { ColumnDef, Row, PaginationState, RowSelectionState, ColumnFiltersState, ExpandedState } from '@tanstack/react-table'; +import type { ColumnDef, Row, PaginationState, RowSelectionState, ColumnFiltersState, ExpandedState, ColumnDefTemplate, HeaderContext } from '@tanstack/react-table'; import { cn } from '@/lib/utils'; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel } from './select'; import { Button } from './button'; -import { ChevronLeftIcon, ChevronRightIcon, DoubleArrowLeftIcon, DoubleArrowRightIcon } from '@radix-ui/react-icons'; +import { ArrowDownIcon, ArrowUpIcon, ChevronLeftIcon, ChevronRightIcon, DoubleArrowLeftIcon, DoubleArrowRightIcon } from '@radix-ui/react-icons'; import * as SelectPrimitive from "@radix-ui/react-select" import type { Table as ReactTable } from '@tanstack/react-table'; import { useTranslation } from 'react-i18next'; import { useResizeObserver } from '@/hooks/useResizeObserver'; +export function getHeader(name: string, translate: boolean = true, addSorting: boolean = true): ColumnDefTemplate> | undefined { + if (!addSorting) { + return () => { + const { t } = useTranslation(); + return {translate ? t(name) : name}; + } + } + + return ({ column }) => { + const { t } = useTranslation(); + return ( +
+ column.toggleSorting()}> + {translate ? t(name) : name} + {column.getIsSorted() === "desc" ? ( + + ) : column.getIsSorted() === "asc" ? ( + + ) : ( + <> + )} + +
+ ) + } +} + interface ReactTableProps { data: T[]; columns: ColumnDef[]; diff --git a/src/tribler/ui/src/dialogs/SaveAs.tsx b/src/tribler/ui/src/dialogs/SaveAs.tsx index 82877390d5..260841b123 100644 --- a/src/tribler/ui/src/dialogs/SaveAs.tsx +++ b/src/tribler/ui/src/dialogs/SaveAs.tsx @@ -1,9 +1,9 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useEffect, useMemo, useState } from "react"; import toast from 'react-hot-toast'; import { triblerService } from "@/services/tribler.service"; import { isErrorDict } from "@/services/reporting"; -import { filesToTree, fixTreeProps, formatBytes, getFilesFromMetainfo, getRowSelection, getSelectedFilesFromTree, translateHeader } from "@/lib/utils"; +import { filesToTree, fixTreeProps, formatBytes, getFilesFromMetainfo, getRowSelection, getSelectedFilesFromTree } from "@/lib/utils"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { DialogProps } from "@radix-ui/react-dialog"; @@ -32,7 +32,7 @@ function startDownloadCallback(response: any, t: TFunction) { const getFileColumns = ({ onSelectedFiles }: { onSelectedFiles: (row: Row) => void }): ColumnDef[] => [ { accessorKey: "name", - header: translateHeader('Name'), + header: getHeader('Name'), cell: ({ row }) => { return (
{ return (
diff --git a/src/tribler/ui/src/lib/utils.ts b/src/tribler/ui/src/lib/utils.ts index 7a3f34be3b..a57ca7ea62 100644 --- a/src/tribler/ui/src/lib/utils.ts +++ b/src/tribler/ui/src/lib/utils.ts @@ -7,7 +7,6 @@ import es from 'javascript-time-ago/locale/es' import pt from 'javascript-time-ago/locale/pt' import ru from 'javascript-time-ago/locale/ru' import zh from 'javascript-time-ago/locale/zh' -import Cookies from "js-cookie"; import { useTranslation } from "react-i18next"; import { triblerService } from "@/services/tribler.service"; import { FileLink, FileTreeItem } from "@/models/file.model"; @@ -141,13 +140,6 @@ export function getRowSelection(input: any[], selected_func: (item: any) => bool return selection; } -export function translateHeader(name: string) { - return () => { - const { t } = useTranslation(); - return t(name); - } -} - export function filterDuplicates(data: any[], key: string) { const seen = new Set(); return data.filter(item => { diff --git a/src/tribler/ui/src/pages/Debug/Asyncio/Tasks.tsx b/src/tribler/ui/src/pages/Debug/Asyncio/Tasks.tsx index 06aa34d93e..12964a3999 100644 --- a/src/tribler/ui/src/pages/Debug/Asyncio/Tasks.tsx +++ b/src/tribler/ui/src/pages/Debug/Asyncio/Tasks.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { ColumnDef } from "@tanstack/react-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; @@ -11,26 +11,26 @@ import { formatTimeDiff } from "@/lib/utils"; const taskColumns: ColumnDef[] = [ { accessorKey: "taskmanager", - header: "Taskmanager", + header: getHeader("Taskmanager", false), }, { accessorKey: "name", - header: "Name", + header: getHeader("Name", false), cell: ({ row }) => { return {row.original.name} }, }, { accessorKey: "running", - header: "Running?", + header: getHeader("Running?", false), }, { accessorKey: "interval", - header: "Interval", + header: getHeader("Interval", false), }, { accessorKey: "start_time", - header: "Started", + header: getHeader("Started", false), cell: ({ row }) => { return row.original.start_time && {formatTimeDiff(row.original.start_time)} }, diff --git a/src/tribler/ui/src/pages/Debug/DHT/Buckets.tsx b/src/tribler/ui/src/pages/Debug/DHT/Buckets.tsx index 099f828428..9ba1507b06 100644 --- a/src/tribler/ui/src/pages/Debug/DHT/Buckets.tsx +++ b/src/tribler/ui/src/pages/Debug/DHT/Buckets.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -11,18 +11,18 @@ import { useInterval } from '@/hooks/useInterval'; const bucketColumns: ColumnDef[] = [ { accessorKey: "prefix", - header: "Prefix", + header: getHeader("Prefix", false), }, { accessorKey: "last_changed", - header: "Last changed", + header: getHeader("Last changed", false), cell: ({ row }) => { return {formatTimeDiff(row.original.last_changed)} }, }, { accessorKey: "peer", - header: "# Peers", + header: getHeader("# Peers", false), cell: ({ row }) => { return {row.original.peers.length} }, diff --git a/src/tribler/ui/src/pages/Debug/DHT/Statistics.tsx b/src/tribler/ui/src/pages/Debug/DHT/Statistics.tsx index 2ca4928472..a5c2efdd7a 100644 --- a/src/tribler/ui/src/pages/Debug/DHT/Statistics.tsx +++ b/src/tribler/ui/src/pages/Debug/DHT/Statistics.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -10,11 +10,11 @@ import { useInterval } from '@/hooks/useInterval'; const statisticColumns: ColumnDef[] = [ { accessorKey: "key", - header: "Key", + header: getHeader("Key", false), }, { accessorKey: "value", - header: "Value", + header: getHeader("Value", false), cell: ({ row }) => { return {row.original.value} }, diff --git a/src/tribler/ui/src/pages/Debug/General/index.tsx b/src/tribler/ui/src/pages/Debug/General/index.tsx index 277f5329b0..b027451018 100644 --- a/src/tribler/ui/src/pages/Debug/General/index.tsx +++ b/src/tribler/ui/src/pages/Debug/General/index.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { formatBytes } from "@/lib/utils"; import { KeyValue } from "@/models/keyvalue.model"; import { triblerService } from "@/services/tribler.service"; @@ -11,11 +11,11 @@ import { useInterval } from '@/hooks/useInterval'; const generalColumns: ColumnDef[] = [ { accessorKey: "key", - header: "Key", + header: getHeader("Key", false), }, { accessorKey: "value", - header: "Value", + header: getHeader("Value", false), }, ] diff --git a/src/tribler/ui/src/pages/Debug/IPv8/Details.tsx b/src/tribler/ui/src/pages/Debug/IPv8/Details.tsx index 7c7aa500c8..b6d9b43d83 100644 --- a/src/tribler/ui/src/pages/Debug/IPv8/Details.tsx +++ b/src/tribler/ui/src/pages/Debug/IPv8/Details.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -10,11 +10,11 @@ import { useInterval } from '@/hooks/useInterval'; const statisticColumns: ColumnDef[] = [ { accessorKey: "name", - header: "Name", + header: getHeader("Name", false), }, { accessorKey: "bytes_up", - header: "Upload (MB)", + header: getHeader("Upload (MB)", false), cell: ({ row }) => { if (row.original.identifier < 0) { return } return {(row.original.bytes_up / 1024 ** 2).toFixed(3)} @@ -22,7 +22,7 @@ const statisticColumns: ColumnDef[] = [ }, { accessorKey: "bytes_down", - header: "Download (MB)", + header: getHeader("Download (MB)", false), cell: ({ row }) => { if (row.original.identifier < 0) { return } return {(row.original.bytes_down / 1024 ** 2).toFixed(3)} @@ -30,7 +30,7 @@ const statisticColumns: ColumnDef[] = [ }, { accessorKey: "num_up", - header: "# Msgs sent", + header: getHeader("# Msgs sent", false), cell: ({ row }) => { if (row.original.identifier < 0) { return } return {row.original.num_up} @@ -38,7 +38,7 @@ const statisticColumns: ColumnDef[] = [ }, { accessorKey: "num_down", - header: "# Msgs received", + header: getHeader("# Msgs received", false), cell: ({ row }) => { if (row.original.identifier < 0) { return } return {row.original.num_down} diff --git a/src/tribler/ui/src/pages/Debug/IPv8/Overlays.tsx b/src/tribler/ui/src/pages/Debug/IPv8/Overlays.tsx index 86df29eb8b..93f68b983f 100644 --- a/src/tribler/ui/src/pages/Debug/IPv8/Overlays.tsx +++ b/src/tribler/ui/src/pages/Debug/IPv8/Overlays.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { ColumnDef } from "@tanstack/react-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; @@ -12,25 +12,25 @@ import { useResizeObserver } from "@/hooks/useResizeObserver"; const overlayColumns: ColumnDef[] = [ { accessorKey: "overlay_name", - header: "Name", + header: getHeader("Name", false), }, { accessorKey: "id", - header: "Community ID", + header: getHeader("Community ID", false), cell: ({ row }) => { return {row.original.id.slice(0, 10)} }, }, { accessorKey: "my_peer", - header: "My peer", + header: getHeader("My peer", false), cell: ({ row }) => { return {row.original.my_peer.slice(0, 10)} }, }, { accessorKey: "peers", - header: "Peers", + header: getHeader("Peers", false), cell: ({ row }) => { return ( [] = [ }, { accessorKey: "statistics.bytes_up", - header: "Upload (MB)", + header: getHeader("Upload (MB)", false), cell: ({ row }) => { if (Object.keys(row.original.statistics).length === 0) { return 'N/A' } return {(row.original.statistics.bytes_up / 1024 ** 2).toFixed(3)} @@ -50,7 +50,7 @@ const overlayColumns: ColumnDef[] = [ }, { accessorKey: "statistics.bytes_down", - header: "Download (MB)", + header: getHeader("Download (MB)", false), cell: ({ row }) => { if (Object.keys(row.original.statistics).length === 0) { return 'N/A' } return {(row.original.statistics.bytes_down / 1024 ** 2).toFixed(3)} @@ -58,7 +58,7 @@ const overlayColumns: ColumnDef[] = [ }, { accessorKey: "statistics.num_up", - header: "# Msg sent", + header: getHeader("# Msg sent", false), cell: ({ row }) => { if (Object.keys(row.original.statistics).length === 0) { return 'N/A' } return {row.original.statistics.num_up} @@ -66,7 +66,7 @@ const overlayColumns: ColumnDef[] = [ }, { accessorKey: "statistics.num_down", - header: "# Msg received", + header: getHeader("# Msg received", false), cell: ({ row }) => { if (Object.keys(row.original.statistics).length === 0) { return 'N/A' } return {row.original.statistics.num_down} @@ -74,7 +74,7 @@ const overlayColumns: ColumnDef[] = [ }, { accessorKey: "statistics.diff_time", - header: "Diff (sec)", + header: getHeader("Diff (sec)", false), cell: ({ row }) => { if (Object.keys(row.original.statistics).length === 0) { return 'N/A' } return {row.original.statistics.diff_time.toFixed(3)} @@ -85,15 +85,15 @@ const overlayColumns: ColumnDef[] = [ const peerColumns: ColumnDef[] = [ { accessorKey: "ip", - header: "IP", + header: getHeader("IP", false), }, { accessorKey: "port", - header: "Port", + header: getHeader("Port", false), }, { accessorKey: "public_key", - header: "Public key", + header: getHeader("Public key", false), cell: ({ row }) => { return

{row.original.public_key}

}, diff --git a/src/tribler/ui/src/pages/Debug/Libtorrent/index.tsx b/src/tribler/ui/src/pages/Debug/Libtorrent/index.tsx index fff29a719c..eb6453d1f5 100644 --- a/src/tribler/ui/src/pages/Debug/Libtorrent/index.tsx +++ b/src/tribler/ui/src/pages/Debug/Libtorrent/index.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { KeyValue } from "@/models/keyvalue.model"; @@ -12,11 +12,11 @@ import { useInterval } from '@/hooks/useInterval'; export const libtorrentColumns: ColumnDef[] = [ { accessorKey: "key", - header: "Key", + header: getHeader("Key", false), }, { accessorKey: "value", - header: "Value", + header: getHeader("Value", false), }, ] diff --git a/src/tribler/ui/src/pages/Debug/Tunnels/Circuits.tsx b/src/tribler/ui/src/pages/Debug/Tunnels/Circuits.tsx index 0e136f51c4..5855d7a782 100644 --- a/src/tribler/ui/src/pages/Debug/Tunnels/Circuits.tsx +++ b/src/tribler/ui/src/pages/Debug/Tunnels/Circuits.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -11,47 +11,47 @@ import { useInterval } from '@/hooks/useInterval'; const circuitColumns: ColumnDef[] = [ { accessorKey: "circuit_id", - header: "Circuit ID", + header: getHeader("Circuit ID", false), }, { accessorKey: "actual_hops", - header: "Hops", + header: getHeader("Hops", false), cell: ({ row }) => { return {row.original.actual_hops} / {row.original.goal_hops} }, }, { accessorKey: "type", - header: "Type", + header: getHeader("Type", false), }, { accessorKey: "state", - header: "State", + header: getHeader("State", false), }, { accessorKey: "bytes_up", - header: "Up", + header: getHeader("Up", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_up)} }, }, { accessorKey: "bytes_down", - header: "Down", + header: getHeader("Down", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_down)} }, }, { accessorKey: "uptime", - header: "Uptime", + header: getHeader("Uptime", false), cell: ({ row }) => { return {formatTimeDiff(row.original.creation_time)} }, }, { accessorKey: "exit_flags", - header: "Exit flags", + header: getHeader("Exit flags", false), cell: ({ row }) => { return {formatFlags(row.original.exit_flags)} }, diff --git a/src/tribler/ui/src/pages/Debug/Tunnels/Exits.tsx b/src/tribler/ui/src/pages/Debug/Tunnels/Exits.tsx index e67d0d0f4e..17a206ffb9 100644 --- a/src/tribler/ui/src/pages/Debug/Tunnels/Exits.tsx +++ b/src/tribler/ui/src/pages/Debug/Tunnels/Exits.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -11,29 +11,29 @@ import { useInterval } from '@/hooks/useInterval'; const exitColumns: ColumnDef[] = [ { accessorKey: "circuit_from", - header: "From circuit", + header: getHeader("From circuit", false), }, { accessorKey: "enabled", - header: "Enabled?", + header: getHeader("Enabled?", false), }, { accessorKey: "bytes_up", - header: "Up", + header: getHeader("Up", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_up)} }, }, { accessorKey: "bytes_down", - header: "Down", + header: getHeader("Down", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_down)} }, }, { accessorKey: "uptime", - header: "Uptime", + header: getHeader("Uptime", false), cell: ({ row }) => { return {formatTimeDiff(row.original.creation_time)} }, diff --git a/src/tribler/ui/src/pages/Debug/Tunnels/Peers.tsx b/src/tribler/ui/src/pages/Debug/Tunnels/Peers.tsx index 643876a916..82549801ff 100644 --- a/src/tribler/ui/src/pages/Debug/Tunnels/Peers.tsx +++ b/src/tribler/ui/src/pages/Debug/Tunnels/Peers.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -11,23 +11,23 @@ import { useInterval } from '@/hooks/useInterval'; const peerColumns: ColumnDef[] = [ { accessorKey: "ip", - header: "IP", + header: getHeader("IP", false), }, { accessorKey: "port", - header: "Port", + header: getHeader("Port", false), }, { accessorKey: "mid", - header: "Mid", + header: getHeader("Mid", false), }, { accessorKey: "is_key_compatible", - header: "Key compatible?", + header: getHeader("Key compatible?", false), }, { accessorKey: "flags", - header: "Flags", + header: getHeader("Flags", false), cell: ({ row }) => { return {formatFlags(row.original.flags)} }, diff --git a/src/tribler/ui/src/pages/Debug/Tunnels/Relays.tsx b/src/tribler/ui/src/pages/Debug/Tunnels/Relays.tsx index 1c23af349e..0b7436c373 100644 --- a/src/tribler/ui/src/pages/Debug/Tunnels/Relays.tsx +++ b/src/tribler/ui/src/pages/Debug/Tunnels/Relays.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { ColumnDef } from "@tanstack/react-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; @@ -11,33 +11,33 @@ import { useInterval } from '@/hooks/useInterval'; const relayColumns: ColumnDef[] = [ { accessorKey: "circuit_from", - header: "From circuit", + header: getHeader("From circuit", false), }, { accessorKey: "circuit_to", - header: "To circuit", + header: getHeader("To circuit", false), }, { accessorKey: "is_rendezvous", - header: "Rendezvous?", + header: getHeader("Rendezvous?", false), }, { accessorKey: "bytes_up", - header: "Up", + header: getHeader("Up", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_up)} }, }, { accessorKey: "bytes_down", - header: "Down", + header: getHeader("Down", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_down)} }, }, { accessorKey: "uptime", - header: "Uptime", + header: getHeader("Uptime", false), cell: ({ row }) => { return {formatTimeDiff(row.original.creation_time)} }, diff --git a/src/tribler/ui/src/pages/Debug/Tunnels/Swarms.tsx b/src/tribler/ui/src/pages/Debug/Tunnels/Swarms.tsx index c276e50928..40a1586715 100644 --- a/src/tribler/ui/src/pages/Debug/Tunnels/Swarms.tsx +++ b/src/tribler/ui/src/pages/Debug/Tunnels/Swarms.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useState } from "react"; import { ipv8Service } from "@/services/ipv8.service"; import { isErrorDict } from "@/services/reporting"; @@ -11,41 +11,41 @@ import { useInterval } from '@/hooks/useInterval'; const swarmColumns: ColumnDef[] = [ { accessorKey: "info_hash", - header: "Infohash", + header: getHeader("Infohash", false), }, { accessorKey: "num_seeders", - header: "# Seeders", + header: getHeader("# Seeders", false), }, { accessorKey: "num_connections", - header: "# Connections", + header: getHeader("# Connections", false), }, { accessorKey: "num_connections_incomplete", - header: "# Pending", + header: getHeader("# Pending", false), }, { accessorKey: "seeding", - header: "Seeding?", + header: getHeader("Seeding?", false), }, { accessorKey: "last_lookup", - header: "Last lookup", + header: getHeader("Last lookup", false), cell: ({ row }) => { return {formatTimeDiff(row.original.last_lookup)} }, }, { accessorKey: "bytes_up", - header: "Up", + header: getHeader("Up", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_down)} }, }, { accessorKey: "bytes_down", - header: "Down", + header: getHeader("Down", false), cell: ({ row }) => { return {formatBytes(row.original.bytes_down)} }, diff --git a/src/tribler/ui/src/pages/Downloads/Files.tsx b/src/tribler/ui/src/pages/Downloads/Files.tsx index d71438e92e..c592d4dd51 100644 --- a/src/tribler/ui/src/pages/Downloads/Files.tsx +++ b/src/tribler/ui/src/pages/Downloads/Files.tsx @@ -5,7 +5,7 @@ import { Download } from "@/models/download.model"; import { Dispatch, MutableRefObject, SetStateAction, useEffect, useMemo, useRef, useState } from "react"; import { isErrorDict } from "@/services/reporting"; import { triblerService } from "@/services/tribler.service"; -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { ChevronDown, ChevronRight } from "lucide-react"; import { Checkbox } from "@/components/ui/checkbox"; import { filesToTree, formatBytes, getSelectedFilesFromTree } from "@/lib/utils"; @@ -13,7 +13,7 @@ import { useTranslation } from "react-i18next"; const getFileColumns = ({ onSelectedFiles }: { onSelectedFiles: (row: Row) => void }): ColumnDef[] => [ { - header: "Path", + header: getHeader("Path"), accessorKey: "path", cell: ({ row }) => { return ( @@ -36,7 +36,7 @@ const getFileColumns = ({ onSelectedFiles }: { onSelectedFiles: (row: Row { return ( @@ -48,7 +48,7 @@ const getFileColumns = ({ onSelectedFiles }: { onSelectedFiles: (row: Row { return {((row.original.progress || 0) * 100).toFixed(1)}% diff --git a/src/tribler/ui/src/pages/Downloads/Peers.tsx b/src/tribler/ui/src/pages/Downloads/Peers.tsx index 81dc32fd94..f77c564217 100644 --- a/src/tribler/ui/src/pages/Downloads/Peers.tsx +++ b/src/tribler/ui/src/pages/Downloads/Peers.tsx @@ -1,8 +1,8 @@ import { ColumnDef } from "@tanstack/react-table"; -import { formatBytes, translateHeader } from "@/lib/utils"; +import { formatBytes } from "@/lib/utils"; import { Download } from "@/models/download.model"; import { Peer } from "@/models/bittorrentpeer.model"; -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; const peerFlags = (peer: Peer) => { @@ -37,42 +37,42 @@ const peerFlags = (peer: Peer) => { const peerColumns: ColumnDef[] = [ { accessorKey: "ip", - header: translateHeader('PeerIpPort'), + header: getHeader('PeerIpPort'), cell: ({ row }) => { return {row.original.ip} ({row.original.port}) }, }, { accessorKey: "completed", - header: translateHeader('Completed'), + header: getHeader('Completed'), cell: ({ row }) => { return {(row.original.completed * 100).toFixed(0)}% }, }, { accessorKey: "downrate", - header: translateHeader('SpeedDown'), + header: getHeader('SpeedDown'), cell: ({ row }) => { return {formatBytes(row.original.downrate)}/s }, }, { accessorKey: "uprate", - header: translateHeader('SpeedUp'), + header: getHeader('SpeedUp'), cell: ({ row }) => { return {formatBytes(row.original.uprate)}/s }, }, { accessorKey: "flags", - header: translateHeader('Flags'), + header: getHeader('Flags'), cell: ({ row }) => { return {peerFlags(row.original)} }, }, { accessorKey: "extended_version", - header: translateHeader('Client'), + header: getHeader('Client'), }, ] diff --git a/src/tribler/ui/src/pages/Downloads/Trackers.tsx b/src/tribler/ui/src/pages/Downloads/Trackers.tsx index e58479a62c..97e449074f 100644 --- a/src/tribler/ui/src/pages/Downloads/Trackers.tsx +++ b/src/tribler/ui/src/pages/Downloads/Trackers.tsx @@ -1,8 +1,7 @@ import { useState } from "react"; import toast from 'react-hot-toast'; -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { translateHeader } from "@/lib/utils"; import { Download } from "@/models/download.model"; import { Tracker } from "@/models/tracker.model "; import { ColumnDef } from "@tanstack/react-table"; @@ -27,15 +26,15 @@ export default function Trackers({ download }: { download: Download }) { const trackerColumns: ColumnDef[] = [ { accessorKey: "url", - header: translateHeader('Name'), + header: getHeader('Name'), }, { accessorKey: "status", - header: translateHeader('Status'), + header: getHeader('Status'), }, { accessorKey: "peers", - header: translateHeader('Peers'), + header: getHeader('Peers'), }, { header: "", diff --git a/src/tribler/ui/src/pages/Downloads/index.tsx b/src/tribler/ui/src/pages/Downloads/index.tsx index 17a7fa48dd..33f7b63a37 100644 --- a/src/tribler/ui/src/pages/Downloads/index.tsx +++ b/src/tribler/ui/src/pages/Downloads/index.tsx @@ -1,15 +1,12 @@ import Actions from "./Actions"; import DownloadDetails from "./Details"; -import SimpleTable from "@/components/ui/simple-table" +import SimpleTable, { getHeader } from "@/components/ui/simple-table" import { Download } from "@/models/download.model"; -import { Button } from "@/components/ui/button"; import { Progress } from "@/components/ui/progress" -import { capitalize, formatBytes, translateHeader } from "@/lib/utils"; +import { capitalize, formatBytes } from "@/lib/utils"; import { isErrorDict } from "@/services/reporting"; import { triblerService } from "@/services/tribler.service"; -import { CaretSortIcon } from "@radix-ui/react-icons"; import { ColumnDef } from "@tanstack/react-table" -import { ArrowDownIcon, ArrowUpIcon } from "lucide-react"; import { Card, CardHeader } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { @@ -35,39 +32,21 @@ const downloadColumns: ColumnDef[] = [ { accessorKey: "name", minSize: 0, - header: ({ column }) => { - const { t } = useTranslation(); - return ( - - ) - }, + header: getHeader('Name'), cell: ({ row }) => { return {row.original.name} }, }, { accessorKey: "size", - header: translateHeader('Size'), + header: getHeader('Size'), cell: ({ row }) => { return {formatBytes(row.original.size)} }, }, { accessorKey: "status", - header: translateHeader('Status'), + header: getHeader('Status'), cell: ({ row }) => { return (
@@ -83,35 +62,35 @@ const downloadColumns: ColumnDef[] = [ }, { accessorKey: "num_seeds", - header: translateHeader('Seeds'), + header: getHeader('Seeds'), cell: ({ row }) => { return {row.original.num_connected_seeds} ({row.original.num_seeds}) }, }, { accessorKey: "num_peers", - header: translateHeader('Peers'), + header: getHeader('Peers'), cell: ({ row }) => { return {row.original.num_connected_peers} ({row.original.num_peers}) }, }, { accessorKey: "speed_down", - header: translateHeader('SpeedDown'), + header: getHeader('SpeedDown'), cell: ({ row }) => { return {formatBytes(row.original.speed_down)}/s }, }, { accessorKey: "speed_up", - header: translateHeader('SpeedUp'), + header: getHeader('SpeedUp'), cell: ({ row }) => { return {formatBytes(row.original.speed_up)}/s }, }, { accessorKey: "hops", - header: translateHeader('Hops'), + header: getHeader('Hops'), }, ] diff --git a/src/tribler/ui/src/pages/Popular/index.tsx b/src/tribler/ui/src/pages/Popular/index.tsx index 3a9d6eed11..c58ade3ac7 100644 --- a/src/tribler/ui/src/pages/Popular/index.tsx +++ b/src/tribler/ui/src/pages/Popular/index.tsx @@ -1,11 +1,11 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import SaveAs from "@/dialogs/SaveAs"; import { useCallback, useEffect, useMemo, useState } from "react"; import { triblerService } from "@/services/tribler.service"; import { isErrorDict } from "@/services/reporting"; import { Torrent } from "@/models/torrent.model"; import { ColumnDef } from "@tanstack/react-table"; -import { categoryIcon, filterDuplicates, formatBytes, formatTimeAgo, getMagnetLink, translateHeader } from "@/lib/utils"; +import { categoryIcon, filterDuplicates, formatBytes, formatTimeAgo, getMagnetLink } from "@/lib/utils"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { useInterval } from '@/hooks/useInterval'; @@ -29,7 +29,7 @@ const getColumns = ({ onDownload }: { onDownload: (torrent: Torrent) => void }): }, { accessorKey: "name", - header: translateHeader('Name'), + header: getHeader('Name'), cell: ({ row }) => { return void }): }, { accessorKey: "size", - header: translateHeader('Size'), + header: getHeader('Size'), cell: ({ row }) => { return {formatBytes(row.original.size)} }, }, { accessorKey: "created", - header: translateHeader('Created'), + header: getHeader('Created'), cell: ({ row }) => { return {formatTimeAgo(row.original.created)} }, diff --git a/src/tribler/ui/src/pages/Search/index.tsx b/src/tribler/ui/src/pages/Search/index.tsx index 8d920ceccd..35ac8fa9ab 100644 --- a/src/tribler/ui/src/pages/Search/index.tsx +++ b/src/tribler/ui/src/pages/Search/index.tsx @@ -1,4 +1,4 @@ -import SimpleTable from "@/components/ui/simple-table"; +import SimpleTable, { getHeader } from "@/components/ui/simple-table"; import { useCallback, useEffect, useMemo, useState } from "react"; import { triblerService } from "@/services/tribler.service"; import { isErrorDict } from "@/services/reporting"; @@ -30,7 +30,7 @@ const getColumns = ({ onDownload }: { onDownload: (torrent: Torrent) => void }): }, { accessorKey: "name", - header: "Name", + header: getHeader("Name"), cell: ({ row }) => { return void }): }, { accessorKey: "size", - header: "Size", + header: getHeader("Size"), cell: ({ row }) => { return {formatBytes(row.original.size)} }, }, { accessorKey: "num_seeders", - header: "Health", + header: getHeader("Health"), cell: ({ row }) => { return }, }, { accessorKey: "created", - header: "Created", + header: getHeader("Created"), cell: ({ row }) => { return {formatTimeAgo(row.original.created)} }, From f9f59193b83596e3f6566fe5a6791a93cc7bc9ff Mon Sep 17 00:00:00 2001 From: Egbert Bouman Date: Thu, 14 Nov 2024 15:54:23 +0100 Subject: [PATCH 2/2] Store sorting state for download/popular/search tables --- .../ui/src/components/ui/simple-table.tsx | 26 ++++++++++++++++--- src/tribler/ui/src/pages/Downloads/index.tsx | 1 + src/tribler/ui/src/pages/Popular/index.tsx | 1 + src/tribler/ui/src/pages/Search/index.tsx | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/tribler/ui/src/components/ui/simple-table.tsx b/src/tribler/ui/src/components/ui/simple-table.tsx index 6ee2a1c17f..d5c4885860 100644 --- a/src/tribler/ui/src/components/ui/simple-table.tsx +++ b/src/tribler/ui/src/components/ui/simple-table.tsx @@ -1,7 +1,7 @@ import { SetStateAction, useEffect, useRef, useState } from 'react'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { getCoreRowModel, useReactTable, flexRender, getFilteredRowModel, getPaginationRowModel, getExpandedRowModel, getSortedRowModel } from '@tanstack/react-table'; -import type { ColumnDef, Row, PaginationState, RowSelectionState, ColumnFiltersState, ExpandedState, ColumnDefTemplate, HeaderContext } from '@tanstack/react-table'; +import type { ColumnDef, Row, PaginationState, RowSelectionState, ColumnFiltersState, ExpandedState, ColumnDefTemplate, HeaderContext, SortingState } from '@tanstack/react-table'; import { cn } from '@/lib/utils'; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel } from './select'; import { Button } from './button'; @@ -41,6 +41,15 @@ export function getHeader(name: string, translate: boolean = true, addSorting } } +function getStoredSortingState(key?: string) { + if (key) { + let sortingString = localStorage.getItem(key); + if (sortingString) { + return JSON.parse(sortingString); + } + } +} + interface ReactTableProps { data: T[]; columns: ColumnDef[]; @@ -58,6 +67,7 @@ interface ReactTableProps { filters?: { id: string, value: string }[]; maxHeight?: string | number; expandable?: boolean; + storeSortingState?: string; } function SimpleTable({ @@ -75,7 +85,8 @@ function SimpleTable({ allowMultiSelect, filters, maxHeight, - expandable + expandable, + storeSortingState }: ReactTableProps) { const [pagination, setPagination] = useState({ pageIndex: pageIndex ?? 0, @@ -84,6 +95,7 @@ function SimpleTable({ const [rowSelection, setRowSelection] = useState(initialRowSelection || {}); const [columnFilters, setColumnFilters] = useState(filters || []) const [expanded, setExpanded] = useState({}); + const [sorting, setSorting] = useState(getStoredSortingState(storeSortingState) || []); const table = useReactTable({ data, @@ -98,7 +110,8 @@ function SimpleTable({ pagination, rowSelection, columnFilters, - expanded + expanded, + sorting }, getFilteredRowModel: getFilteredRowModel(), onColumnFiltersChange: setColumnFilters, @@ -107,6 +120,7 @@ function SimpleTable({ if (allowSelect || allowSelectCheckbox || allowMultiSelect) setRowSelection(arg); }, onExpandedChange: setExpanded, + onSortingChange: setSorting, getSubRows: (row: any) => row?.subRows, }); @@ -133,6 +147,12 @@ function SimpleTable({ } }, [filters]) + useEffect(() => { + if (storeSortingState) { + localStorage.setItem(storeSortingState, JSON.stringify(sorting)); + } + }, [sorting]); + // For some reason the ScrollArea scrollbar is only shown when it's set to a specific height. // So, we wrap it in a parent div, monitor its size, and set the height of the table accordingly. const parentRef = useRef(null); diff --git a/src/tribler/ui/src/pages/Downloads/index.tsx b/src/tribler/ui/src/pages/Downloads/index.tsx index 33f7b63a37..1afb407ac3 100644 --- a/src/tribler/ui/src/pages/Downloads/index.tsx +++ b/src/tribler/ui/src/pages/Downloads/index.tsx @@ -194,6 +194,7 @@ export default function Downloads({ statusFilter }: { statusFilter: number[] }) allowMultiSelect={true} onSelectedRowsChange={setSelectedDownloads} maxHeight={Math.max((parentRect?.height ?? 50)-50, 50)} + storeSortingState="download-sorting" />
diff --git a/src/tribler/ui/src/pages/Popular/index.tsx b/src/tribler/ui/src/pages/Popular/index.tsx index c58ade3ac7..35a749c992 100644 --- a/src/tribler/ui/src/pages/Popular/index.tsx +++ b/src/tribler/ui/src/pages/Popular/index.tsx @@ -111,6 +111,7 @@ export default function Popular() { ) diff --git a/src/tribler/ui/src/pages/Search/index.tsx b/src/tribler/ui/src/pages/Search/index.tsx index 35ac8fa9ab..1384342249 100644 --- a/src/tribler/ui/src/pages/Search/index.tsx +++ b/src/tribler/ui/src/pages/Search/index.tsx @@ -150,6 +150,7 @@ export default function Search() { )