diff --git a/frontend/src/components/db-table-view/columns-dropdown.tsx b/frontend/src/components/db-table-view/columns-dropdown.tsx index b9d4eb8..6a00db2 100644 --- a/frontend/src/components/db-table-view/columns-dropdown.tsx +++ b/frontend/src/components/db-table-view/columns-dropdown.tsx @@ -73,7 +73,7 @@ export function ColumnsDropdown({ if (active.id !== over?.id) { setColumnOrder((items) => { const oldIndex = items.findIndex((id) => id === active.id); - const newIndex = items.findIndex((id) => id === over.id); + const newIndex = items.findIndex((id) => id === over?.id); return arrayMove(items, oldIndex, newIndex); }); @@ -81,7 +81,7 @@ export function ColumnsDropdown({ } } -const SortableItem = ({ column }: { column: Column }) => { +const SortableItem = ({ column }: { column: Column }) => { const { attributes, listeners, diff --git a/frontend/src/components/db-table-view/columns.tsx b/frontend/src/components/db-table-view/columns.tsx index abd96ff..a8fd73b 100644 --- a/frontend/src/components/db-table-view/columns.tsx +++ b/frontend/src/components/db-table-view/columns.tsx @@ -4,7 +4,7 @@ import { useSettingsStore } from "@/state"; import type { ColumnDef } from "@tanstack/react-table"; import { useMemo } from "react"; -const buildColumns = ({ +const buildColumns = ({ columns, formatDates, showImagesPreview, @@ -13,8 +13,8 @@ const buildColumns = ({ formatDates: boolean; showImagesPreview: boolean; -}): ColumnDef[] => { - if (!columns) return [] as ColumnDef[]; +}): ColumnDef[] => { + if (!columns) return [] as ColumnDef[]; return columns.map(({ column_name, udt_name, data_type }) => ({ accessorKey: column_name, @@ -67,6 +67,9 @@ const buildColumns = ({ ); } + if (typeof finalValue === "boolean") { + finalValue = finalValue ? "true" : "false"; + } return (
); }, - })) as ColumnDef[]; + })) as ColumnDef[]; }; export const useColumns = ({ diff --git a/frontend/src/components/db-table-view/data-table.tsx b/frontend/src/components/db-table-view/data-table.tsx deleted file mode 100644 index a9c3c97..0000000 --- a/frontend/src/components/db-table-view/data-table.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { - TableScrollContainer, - TableView, -} from "@/components/db-table-view/table"; -import { DataTablePagination } from "@/components/ui"; -import { useTableDataQuery } from "@/services/db"; -import { - type OnChangeFn, - type PaginationState, - type SortingState, - type VisibilityState, - getCoreRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { Rows3 } from "lucide-react"; -import { useCallback, useState } from "react"; -import { useColumns } from "./columns"; -import { ColumnsDropdown } from "./columns-dropdown"; -import { - WhereClauseForm, - type WhereClauseFormValues, -} from "./where-clause-form"; - -export const DataTable = ({ - tableName, - dbName, - pageIndex, - pageSize, - onPageSizeChange, - onPageIndexChange, -}: { - tableName: string; - pageIndex: number; - dbName: string; - pageSize: number; - onPageIndexChange: (pageIndex: number) => void; - onPageSizeChange: (pageSize: number) => void; -}) => { - const columns = useColumns({ dbName, tableName }); - const [whereQuery, setWhereQuery] = useState(""); - const [sorting, setSorting] = useState([]); - const [columnVisibility, setColumnVisibility] = useState({}); - - const { data, refetch } = useTableDataQuery({ - whereQuery, - tableName, - dbName, - perPage: pageSize, - page: pageIndex, - sortDesc: sorting[0]?.desc, - sortField: sorting[0]?.id, - }); - - const handleWhereClauseFormSubmit = useCallback( - ({ whereClause }: WhereClauseFormValues) => { - if (whereClause === whereQuery) { - void refetch(); - return; - } - setWhereQuery(whereClause); - }, - [whereQuery, refetch], - ); - - const paginationUpdater: OnChangeFn = (args) => { - if (typeof args === "function") { - const newArgs = args({ - pageIndex, - pageSize, - }); - if (newArgs.pageSize !== pageSize) { - onPageSizeChange(newArgs.pageSize); - } else if (newArgs.pageIndex !== pageIndex) { - onPageIndexChange(newArgs.pageIndex); - } - } else { - onPageSizeChange(args.pageSize); - onPageIndexChange(args.pageIndex); - } - }; - - const table = useReactTable({ - data: data?.data ?? [], - columns, - columnResizeMode: "onChange", - getCoreRowModel: getCoreRowModel(), - onColumnVisibilityChange: setColumnVisibility, - rowCount: data?.count ?? 0, - manualSorting: true, - onSortingChange: setSorting, - state: { - sorting, - columnVisibility, - pagination: { - pageIndex, - pageSize, - }, - }, - onPaginationChange: paginationUpdater, - manualPagination: true, - }); - - return ( -
-
-

- {tableName} - -

- -

- Rows: {data?.count} -

-
- -
- - - -
- -
- ); -}; diff --git a/frontend/src/components/db-table-view/reset-state-dropdown.tsx b/frontend/src/components/db-table-view/reset-state-dropdown.tsx new file mode 100644 index 0000000..e146c9a --- /dev/null +++ b/frontend/src/components/db-table-view/reset-state-dropdown.tsx @@ -0,0 +1,35 @@ +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + Tooltip, +} from "@/components/ui"; +import type { Table } from "@tanstack/react-table"; +import { RotateCcw } from "lucide-react"; + +export const ResetStateDropdown = ({ table }: { table: Table }) => { + return ( + + + + + + + + table.resetColumnOrder()}> + Reset Column Order + + table.resetColumnSizing()}> + Reset Column Sizing + + table.resetColumnVisibility()}> + Reset Column Visibility + + + + ); +}; diff --git a/frontend/src/components/sidebar/sidebar.tsx b/frontend/src/components/sidebar/sidebar.tsx index ae3bbb0..7f6dae7 100644 --- a/frontend/src/components/sidebar/sidebar.tsx +++ b/frontend/src/components/sidebar/sidebar.tsx @@ -94,7 +94,6 @@ function SidebarContent() { aria-label={"Explore Data"} to={"/db/$dbName/tables/$tableName/data"} params={{ tableName: table.table_name, dbName: dbName }} - search={{ pageIndex: 0, pageSize: 10 }} > diff --git a/frontend/src/routes/auth/login.tsx b/frontend/src/routes/auth/login.tsx index 3ab04a3..03f1e7c 100644 --- a/frontend/src/routes/auth/login.tsx +++ b/frontend/src/routes/auth/login.tsx @@ -21,7 +21,12 @@ import { useSessionStore } from "@/state/db-session-store"; import { zodResolver } from "@hookform/resolvers/zod"; import { createFileRoute } from "@tanstack/react-router"; import { useState } from "react"; -import { type Control, useForm } from "react-hook-form"; +import { + type Control, + type FieldPath, + type FieldValues, + useForm, +} from "react-hook-form"; import { z } from "zod"; export const Route = createFileRoute("/auth/login")({ @@ -56,7 +61,7 @@ function ConnectionStringForm({ onSubmit={handleSubmit(onSubmit)} id={"login-form"} > - + - + ({ control, + name, }: { - control: Control; + control: Control; + name: FieldPath; }) { return (
- + diff --git a/frontend/src/routes/db/$dbName/tables/$tableName/data.tsx b/frontend/src/routes/db/$dbName/tables/$tableName/data.tsx index 492267e..584870a 100644 --- a/frontend/src/routes/db/$dbName/tables/$tableName/data.tsx +++ b/frontend/src/routes/db/$dbName/tables/$tableName/data.tsx @@ -1,5 +1,6 @@ import { useColumns } from "@/components/db-table-view/columns"; import { ColumnsDropdown } from "@/components/db-table-view/columns-dropdown"; +import { ResetStateDropdown } from "@/components/db-table-view/reset-state-dropdown"; import { TableScrollContainer, TableView, @@ -29,8 +30,8 @@ import { useLocalStorage } from "usehooks-ts"; import { z } from "zod"; const tableSearchSchema = z.object({ - pageSize: z.number().catch(10), - pageIndex: z.number().catch(0), + pageSize: z.number().optional(), + pageIndex: z.number().optional(), sortField: z.string().optional(), sortDesc: z.boolean().optional(), }); @@ -42,6 +43,7 @@ export const Route = createFileRoute("/db/$dbName/tables/$tableName/data")({ function Component() { const { tableName, dbName } = Route.useParams(); + const columns = useColumns({ dbName, tableName }); const { filters, setFilters } = useFilters(Route.fullPath); const [whereQuery, setWhereQuery] = useState(""); @@ -54,6 +56,15 @@ function Component() { `columnVisibility-${dbName}-${tableName}`, {}, ); + const [columnOrder, setColumnOrder] = useLocalStorage( + `columnOrder-${dbName}-${tableName}`, + () => columns.map((c) => c.id ?? ""), + ); + + useEffect(() => { + if (columnOrder.length === columns.length) return; + setColumnOrder(columns.map((c) => c.id ?? "")); + }, [columns, columnOrder.length, setColumnOrder]); const paginationState = useMemo( () => ({ @@ -64,20 +75,13 @@ function Component() { ); const sortingState = useMemo(() => sortByToState(filters), [filters]); - const columns = useColumns({ dbName, tableName }); - const [columnOrder, setColumnOrder] = useState(() => - columns.map((c) => c.id ?? ""), - ); - useEffect(() => { - if (columnOrder.length !== 0) return; - setColumnOrder(columns.map((c) => c.id ?? "")); - }, [columns, columnOrder.length]); + const { data, refetch } = useTableDataQuery({ whereQuery, tableName, dbName, - perPage: filters.pageSize, - page: filters.pageIndex, + perPage: filters.pageSize ?? DEFAULT_PAGE_SIZE, + page: filters.pageIndex ?? DEFAULT_PAGE_INDEX, sortField: filters.sortField, sortDesc: filters.sortDesc, }); @@ -150,6 +154,7 @@ function Component() { columnOrder={columnOrder} setColumnOrder={setColumnOrder} /> +

Rows: {data?.count}

diff --git a/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx b/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx index ed9fa3c..ae5579f 100644 --- a/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx +++ b/frontend/src/routes/db/$dbName/tables/$tableName/index.tsx @@ -97,10 +97,6 @@ function TableDetailsTable() { Explore data