Skip to content

Commit

Permalink
Txs table component (#16)
Browse files Browse the repository at this point in the history
* Add react-table dependency

* Add shadcn Tasks components

* Expose PopoverClose

* Add adapted filters for future tags

* Add useDebounce hook

* Add txs columns

* Add filters toolbar

* Add txs table
  • Loading branch information
abefernan authored Oct 15, 2024
1 parent 24bbcd3 commit f16da3a
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 0 deletions.
96 changes: 96 additions & 0 deletions components/txs-table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"use client";

import { useTxs } from "@/hooks/api";
import { useDebounce } from "@/hooks/use-debounce";
import { Tx } from "@/types/txs";
import {
ColumnDef,
ColumnFiltersState,
SortingState,
VisibilityState,
getCoreRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { useState } from "react";
import { DataTable } from "../data-table";
import { DataTableColumnHeader } from "../data-table/data-table-column-header";
import { DataTablePagination } from "../data-table/data-table-pagination";
import { txsColumns } from "./txs-columns";
import { DataTableToolbar } from "./txs-table-toolbar";

export function TxsTable() {
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
tags: false,
});
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [sorting, setSorting] = useState<SortingState>([]);

const operationNameValue = columnFilters.find(
(filter) => filter.id === "operationName",
)?.value;
const operationName = useDebounce(
typeof operationNameValue === "string" && operationNameValue.length
? operationNameValue
: "execute_tx",
);

const tags =
(columnFilters.find((filter) => filter.id === "tags")?.value as
| Map<string, string>
| undefined) ?? undefined;

const tagsColumns: ColumnDef<Tx>[] = Array.from(tags?.keys() ?? []).map(
(tagKey) => ({
accessorKey: tagKey,
header: ({ column }) => (
<DataTableColumnHeader column={column} title={tagKey} />
),
cell: ({ row }) => (
<div className="max-w-[500px] truncate font-medium">
{(row.getValue("tags") as Map<string, string>).get(tagKey)}
</div>
),
//NOTE - Don't UI filter, query API
filterFn: () => true,
}),
);

const columns = [...txsColumns, ...tagsColumns];

const { isPending, error, data: txs } = useTxs(operationName, tags);
const data = (txs ?? []) as Tx[];

const table = useReactTable({
columns,
data,
state: { columnVisibility, columnFilters, sorting },
onColumnVisibilityChange: setColumnVisibility,
onColumnFiltersChange: setColumnFilters,
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});

return (
<div className="space-y-4">
<DataTableToolbar table={table} />
<div className="rounded-md border">
<DataTable
status={{ isPending, error }}
table={table}
rowLink={{ url: "/", field: "traceId" }}
/>
</div>
<DataTablePagination table={table} />
</div>
);
}
57 changes: 57 additions & 0 deletions components/txs-table/txs-columns.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Tx } from "@/types/txs";
import { ColumnDef } from "@tanstack/react-table";
import { DataTableColumnHeader } from "../data-table/data-table-column-header";

export const txsColumns: ColumnDef<Tx>[] = [
{
accessorKey: "traceId",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Trace" />
),
cell: ({ row }) => (
<div className="max-w-[500px] font-medium">{row.getValue("traceId")}</div>
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "spanId",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Span" />
),
cell: ({ row }) => (
<div className="max-w-[500px] font-medium">{row.getValue("spanId")}</div>
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "operationName",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Operation" />
),
cell: ({ row }) => (
<div className="max-w-[500px] font-medium">
{row.getValue("operationName")}
</div>
),
//NOTE - Don't UI filter, query API
filterFn: () => true,
},
{
accessorKey: "tags",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Tags" />
),
cell: ({ row }) => (
<div className="max-w-[500px] truncate font-medium">
{Array.from((row.getValue("tags") as Map<string, string>).keys()).join(
", ",
)}
</div>
),
//NOTE - Don't UI filter, query API
filterFn: () => true,
enableHiding: false,
},
];
132 changes: 132 additions & 0 deletions components/txs-table/txs-table-toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Cross2Icon } from "@radix-ui/react-icons";
import { Table } from "@tanstack/react-table";
import { DataTableKvFilter } from "../data-table/data-table-kv-filter";
import { DataTableViewOptions } from "../data-table/data-table-view-options";

const getSelectedValue = <TData,>(table: Table<TData>) => {
if (
!table.getColumn("operationName")?.getFilterValue() &&
!table.getColumn("tags")?.getFilterValue()
) {
return "empty";
}

if ((table.getColumn("operationName")?.getFilterValue() as string) ?? "") {
return "custom";
}

const tags = table.getColumn("tags")?.getFilterValue() as
| Map<string, string>
| undefined;

if (tags?.size === 1 && tags?.get("raw_tx") === "*") {
return "simulations";
}

if (tags?.size === 1 && tags?.get("tx_hash") === "*") {
return "broadcasted";
}

return "custom";
};

interface DataTableToolbarProps<TData> {
table: Table<TData>;
}

export function DataTableToolbar<TData>({
table,
}: DataTableToolbarProps<TData>) {
return (
<div className="flex justify-between">
<div className="flex flex-wrap gap-2">
<Select
value={getSelectedValue(table)}
onValueChange={(value) => {
switch (value) {
case "simulations": {
table
.getColumn("tags")
?.setFilterValue(new Map([["raw_tx", "*"]]));
break;
}
case "broadcasted": {
table
.getColumn("tags")
?.setFilterValue(new Map([["tx_hash", "*"]]));
break;
}
default: {
table.resetColumnFilters();
}
}
}}
>
<SelectTrigger className="w-[220px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Filters</SelectLabel>
<SelectItem
value="empty"
className="hidden"
disabled
aria-disabled
>
Empty filter
</SelectItem>
<SelectItem
value="custom"
className="hidden"
disabled
aria-disabled
>
Custom filter
</SelectItem>
<SelectItem value="simulations">Failed simulations</SelectItem>
<SelectItem value="broadcasted">
Broadcasted transactions
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Input
placeholder="Filter operation…"
value={
(table.getColumn("operationName")?.getFilterValue() as string) ?? ""
}
onChange={(event) =>
table.getColumn("operationName")?.setFilterValue(event.target.value)
}
className="h-8 w-[150px] lg:w-[250px]"
/>
{table.getColumn("tags") && (
<DataTableKvFilter column={table.getColumn("tags")} title="Tag" />
)}
{table.getState().columnFilters.length > 0 && (
<Button
variant="ghost"
onClick={() => table.resetColumnFilters()}
className="h-8 px-2 lg:px-3"
>
Reset
<Cross2Icon className="ml-2 h-4 w-4" />
</Button>
)}
</div>
<DataTableViewOptions table={table} />
</div>
);
}
17 changes: 17 additions & 0 deletions hooks/use-debounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect, useState } from "react";

export function useDebounce<T>(value: T, delay = 1000): T {
const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedValue(value);
}, delay);

return () => {
clearTimeout(timeout);
};
}, [value, delay]);

return debouncedValue;
}

0 comments on commit f16da3a

Please sign in to comment.