add column ordering

This commit is contained in:
2024-07-14 16:59:11 +02:00
parent 7ff64879c1
commit 1c976ecda1
5 changed files with 112 additions and 19 deletions

Binary file not shown.

View File

@@ -11,6 +11,9 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@fontsource/inter": "^5.0.19", "@fontsource/inter": "^5.0.19",
"@hookform/resolvers": "^3.9.0", "@hookform/resolvers": "^3.9.0",
"@it-incubator/prettier-config": "^0.1.2", "@it-incubator/prettier-config": "^0.1.2",

View File

@@ -5,13 +5,42 @@ import {
DropdownMenuContent, DropdownMenuContent,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui"; } from "@/components/ui";
import type { Table } from "@tanstack/react-table"; import {
DndContext,
type DragEndEvent,
KeyboardSensor,
PointerSensor,
closestCenter,
useSensor,
useSensors,
} from "@dnd-kit/core";
import {
SortableContext,
arrayMove,
sortableKeyboardCoordinates,
useSortable,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import type { Column, Table } from "@tanstack/react-table";
import { GripVertical } from "lucide-react";
import type { Dispatch, SetStateAction } from "react";
export function ColumnsDropdown<T>({ export function ColumnsDropdown<T>({
table, table,
columnOrder,
setColumnOrder,
}: { }: {
table: Table<T>; table: Table<T>;
columnOrder: string[];
setColumnOrder: Dispatch<SetStateAction<string[]>>;
}) { }) {
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
return ( return (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@@ -20,22 +49,69 @@ export function ColumnsDropdown<T>({
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
{table <DndContext
.getAllColumns() sensors={sensors}
.filter((column) => column.getCanHide()) collisionDetection={closestCenter}
.map((column) => { onDragEnd={handleDragEnd}
return ( >
<DropdownMenuCheckboxItem <SortableContext
key={column.id} items={columnOrder}
onSelect={(e) => e.preventDefault()} strategy={verticalListSortingStrategy}
checked={column.getIsVisible()} >
onCheckedChange={column.toggleVisibility} {columnOrder.map((columnId) => {
> const column = table.getColumn(columnId);
{column.id} if (!column) return null;
</DropdownMenuCheckboxItem> return <SortableItem key={column.id} column={column} />;
); })}
})} </SortableContext>
</DndContext>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
); );
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (active.id !== over?.id) {
setColumnOrder((items) => {
const oldIndex = items.findIndex((id) => id === active.id);
const newIndex = items.findIndex((id) => id === over.id);
return arrayMove(items, oldIndex, newIndex);
});
}
}
} }
const SortableItem = ({ column }: { column: Column<any> }) => {
const {
attributes,
listeners,
setNodeRef,
setActivatorNodeRef,
transform,
transition,
} = useSortable({ id: column.id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
};
return (
<DropdownMenuCheckboxItem
ref={setNodeRef}
style={style}
{...attributes}
key={column.id}
onSelect={(e) => e.preventDefault()}
checked={column.getIsVisible()}
onCheckedChange={column.toggleVisibility}
>
<div className="flex items-center gap-2 justify-between w-full">
{column.id}
<button ref={setActivatorNodeRef} {...listeners} className={"shrink-0"}>
<GripVertical />
</button>
</div>
</DropdownMenuCheckboxItem>
);
};

View File

@@ -20,6 +20,7 @@ const buildColumns = ({
accessorKey: column_name, accessorKey: column_name,
title: column_name, title: column_name,
size: 300, size: 300,
id: column_name,
header: () => { header: () => {
return ( return (
<div <div

View File

@@ -24,7 +24,7 @@ import {
useReactTable, useReactTable,
} from "@tanstack/react-table"; } from "@tanstack/react-table";
import { Rows3 } from "lucide-react"; import { Rows3 } from "lucide-react";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { useLocalStorage } from "usehooks-ts"; import { useLocalStorage } from "usehooks-ts";
import { z } from "zod"; import { z } from "zod";
@@ -42,6 +42,7 @@ export const Route = createFileRoute("/db/$dbName/tables/$tableName/data")({
function Component() { function Component() {
const { tableName, dbName } = Route.useParams(); const { tableName, dbName } = Route.useParams();
const { filters, setFilters } = useFilters(Route.fullPath); const { filters, setFilters } = useFilters(Route.fullPath);
const [whereQuery, setWhereQuery] = useState(""); const [whereQuery, setWhereQuery] = useState("");
const [columnSizing, setColumnSizing] = useLocalStorage<ColumnSizingState>( const [columnSizing, setColumnSizing] = useLocalStorage<ColumnSizingState>(
@@ -64,7 +65,13 @@ function Component() {
const sortingState = useMemo(() => sortByToState(filters), [filters]); const sortingState = useMemo(() => sortByToState(filters), [filters]);
const columns = useColumns({ dbName, tableName }); const columns = useColumns({ dbName, tableName });
const [columnOrder, setColumnOrder] = useState<string[]>(() =>
columns.map((c) => c.id ?? ""),
);
useEffect(() => {
if (columnOrder.length !== 0) return;
setColumnOrder(columns.map((c) => c.id ?? ""));
}, [columns, columnOrder.length]);
const { data, refetch } = useTableDataQuery({ const { data, refetch } = useTableDataQuery({
whereQuery, whereQuery,
tableName, tableName,
@@ -115,12 +122,14 @@ function Component() {
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
manualPagination: true, manualPagination: true,
manualSorting: true, manualSorting: true,
onColumnOrderChange: setColumnOrder,
onColumnSizingChange: setColumnSizing, onColumnSizingChange: setColumnSizing,
onColumnVisibilityChange: setColumnVisibility, onColumnVisibilityChange: setColumnVisibility,
onPaginationChange: handlePaginationChange, onPaginationChange: handlePaginationChange,
onSortingChange: handleSortingChange, onSortingChange: handleSortingChange,
rowCount: data?.count ?? 0, rowCount: data?.count ?? 0,
state: { state: {
columnOrder,
sorting: sortingState, sorting: sortingState,
columnSizing: columnSizing, columnSizing: columnSizing,
columnVisibility, columnVisibility,
@@ -136,7 +145,11 @@ function Component() {
<Rows3 /> {tableName} <Rows3 /> {tableName}
<WhereClauseForm onSubmit={handleWhereClauseFormSubmit} /> <WhereClauseForm onSubmit={handleWhereClauseFormSubmit} />
</h1> </h1>
<ColumnsDropdown table={table} /> <ColumnsDropdown
table={table}
columnOrder={columnOrder}
setColumnOrder={setColumnOrder}
/>
<p> <p>
Rows: <strong>{data?.count}</strong> Rows: <strong>{data?.count}</strong>
</p> </p>