Skip to content

Commit 677f8b8

Browse files
committed
feat: Simple column hiding and showing
https://harperdb.atlassian.net/browse/STUDIO-451
1 parent a3259a1 commit 677f8b8

File tree

6 files changed

+114
-4
lines changed

6 files changed

+114
-4
lines changed

src/components/ui/dropdownMenu.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ function DropdownMenuCheckboxItem({
8080
<DropdownMenuPrimitive.CheckboxItem
8181
data-slot="dropdown-menu-checkbox-item"
8282
className={cn(
83-
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
83+
"focus:bg-primary relative flex cursor-pointer items-center gap-2 rounded-sm" +
84+
" py-1.5 pr-2 pl-8" +
85+
" text-sm outline-hidden" +
86+
" select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50" +
87+
" [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
8488
className
8589
)}
8690
checked={checked}

src/features/instance/databases/DatabaseTableView.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { ConfirmDeletionModal } from '@/components/ConfirmDeletionModal';
22
import { Button } from '@/components/ui/button';
33
import { useInstanceClientIdParams } from '@/config/useInstanceClient';
4+
import { PickColumnsDropdown } from '@/features/instance/databases/components/PickColumnsDropdown';
45
import { TableView } from '@/features/instance/databases/components/TableView';
56
import { formatBrowseDataTableHeader } from '@/features/instance/databases/functions/formatBrowseDataTableHeader';
67
import { AddTableRowModal } from '@/features/instance/databases/modals/AddTableRowModal';
78
import { EditTableRowModal } from '@/features/instance/databases/modals/EditTableRowModal';
9+
import { ImportCSVModal } from '@/features/instance/databases/modals/ImportCSVModal';
810
import { useDeleteTableMutation } from '@/features/instance/operations/mutations/deleteTable';
911
import { useDeleteTableRecords } from '@/features/instance/operations/mutations/deleteTableRecords';
1012
import { useInsertTableRecords } from '@/features/instance/operations/mutations/insertTableRecords';
@@ -15,14 +17,14 @@ import { getSearchByValueOptions } from '@/features/instance/operations/queries/
1517
import { useEffectedState } from '@/hooks/useEffectedState';
1618
import { useInstanceBrowseManagePermission, useInstanceSchemaTablePermission } from '@/hooks/usePermissions';
1719
import { useRefreshClick } from '@/hooks/useRefreshClick';
20+
import { useSessionStorage } from '@/hooks/useSessionStorage';
1821
import { queryClient } from '@/react-query/queryClient';
1922
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
2023
import { useNavigate, useParams } from '@tanstack/react-router';
21-
import { Row } from '@tanstack/react-table';
24+
import { Row, VisibilityState } from '@tanstack/react-table';
2225
import { ImportIcon, PlusIcon, RefreshCwIcon, Trash } from 'lucide-react';
2326
import { useCallback, useEffect, useState } from 'react';
2427
import { toast } from 'sonner';
25-
import { ImportCSVModal } from '@/features/instance/databases/modals/ImportCSVModal';
2628

2729
export function DatabaseTableView() {
2830
const allParams: {
@@ -225,6 +227,11 @@ export function DatabaseTableView() {
225227
}
226228
}, [databaseName, onDeleteTable, tableName]);
227229

230+
const [columnVisibility, setColumnVisibility] = useSessionStorage(
231+
`ColumnDisplayed/${databaseName}}/${tableName}` as 'ColumnDisplayed/{database}/{table}',
232+
{} satisfies VisibilityState,
233+
);
234+
228235
return (
229236
<>
230237
<div className="flex flex-col md:flex-row items-center justify-between space-y-3 md:space-y-0 md:space-x-3 pt-15 pb-4">
@@ -260,7 +267,12 @@ export function DatabaseTableView() {
260267
</Button>
261268
</div>
262269

263-
<div>
270+
<div className="flex space-x-2">
271+
<PickColumnsDropdown
272+
columns={dataTableColumns}
273+
columnVisibility={columnVisibility}
274+
setColumnVisibility={setColumnVisibility}
275+
/>
264276
{canManageBrowseInstance && (
265277
<Button variant="destructiveOutline" onClick={openDeleteModal}>
266278
<Trash className="inline-block " />
@@ -274,6 +286,7 @@ export function DatabaseTableView() {
274286
data={tableData?.data || []}
275287
isFetching={tableDataFetching}
276288
columns={dataTableColumns}
289+
columnVisibility={columnVisibility}
277290
onRowClick={onRowClick}
278291
onColumnClick={onColumnClick}
279292
totalPages={totalPages}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Button } from '@/components/ui/button';
2+
import {
3+
DropdownMenu,
4+
DropdownMenuCheckboxItem,
5+
DropdownMenuContent,
6+
DropdownMenuTrigger,
7+
} from '@/components/ui/dropdownMenu';
8+
import { formatBrowseDataTableHeader } from '@/features/instance/databases/functions/formatBrowseDataTableHeader';
9+
import { useToggleCallback } from '@/hooks/useToggleCallback';
10+
import { excludeFalsy } from '@/lib/arrays/excludeFalsy';
11+
import { notYetImplemented } from '@/lib/notYetImplemented';
12+
import { VisibilityState } from '@tanstack/react-table';
13+
import { Columns3CogIcon } from 'lucide-react';
14+
import { useEffect, useMemo } from 'react';
15+
16+
export function PickColumnsDropdown({
17+
columns,
18+
columnVisibility,
19+
setColumnVisibility,
20+
}: {
21+
columns: ReturnType<typeof formatBrowseDataTableHeader>['dataTableColumns'],
22+
columnVisibility: VisibilityState,
23+
setColumnVisibility: (columnVisibility: VisibilityState) => void,
24+
}) {
25+
const columnHeaders = useMemo(() => {
26+
return columns
27+
.map(c => c.header as string)
28+
.filter(excludeFalsy);
29+
}, [columns]);
30+
return (
31+
<DropdownMenu>
32+
<DropdownMenuTrigger asChild>
33+
<Button variant="ghost" onClick={notYetImplemented}>
34+
<Columns3CogIcon className="inline-block " />
35+
Columns
36+
</Button>
37+
</DropdownMenuTrigger>
38+
<DropdownMenuContent>
39+
{columnHeaders.map(columnHeader => <ColumnPicker
40+
key={columnHeader}
41+
columnHeader={columnHeader}
42+
columnVisibility={columnVisibility}
43+
setColumnVisibility={setColumnVisibility}
44+
/>)}
45+
</DropdownMenuContent>
46+
</DropdownMenu>
47+
);
48+
}
49+
50+
function ColumnPicker({
51+
columnHeader,
52+
columnVisibility,
53+
setColumnVisibility,
54+
}: {
55+
columnHeader: string,
56+
columnVisibility: VisibilityState,
57+
setColumnVisibility: (columnVisibility: VisibilityState) => void,
58+
}) {
59+
const [isChecked, onCheckedChanged] = useToggleCallback(columnVisibility[columnHeader] ?? true);
60+
useEffect(() => {
61+
if (columnVisibility[columnHeader] !== isChecked) {
62+
setColumnVisibility({
63+
...columnVisibility,
64+
[columnHeader]: isChecked,
65+
});
66+
}
67+
}, [columnHeader, columnVisibility, isChecked, setColumnVisibility]);
68+
return (
69+
<DropdownMenuCheckboxItem key={columnHeader} checked={isChecked} onClick={onCheckedChanged}>
70+
{columnHeader}
71+
</DropdownMenuCheckboxItem>
72+
);
73+
}

src/features/instance/databases/components/TableView.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import {
1313
getPaginationRowModel,
1414
Row,
1515
useReactTable,
16+
VisibilityState,
1617
} from '@tanstack/react-table';
1718
import { ArrowLeftIcon, ArrowRightIcon } from 'lucide-react';
1819
import { Dispatch, SetStateAction, useCallback } from 'react';
1920

2021
interface BrowseDataTableProps<TData, TValue> {
2122
columns: ColumnDef<TData, TValue>[];
23+
columnVisibility: VisibilityState;
2224
data: TData[];
2325
isFetching?: boolean;
2426
totalPages: number;
@@ -33,6 +35,7 @@ interface BrowseDataTableProps<TData, TValue> {
3335

3436
export function TableView<TData, TValue>({
3537
columns,
38+
columnVisibility,
3639
data,
3740
isFetching,
3841
totalPages,
@@ -54,6 +57,9 @@ export function TableView<TData, TValue>({
5457
defaultColumn: {
5558
minSize: 1,
5659
},
60+
state: {
61+
columnVisibility,
62+
},
5763
rowCount: totalRecords,
5864
getCoreRowModel: getCoreRowModel(),
5965
getPaginationRowModel: getPaginationRowModel(),

src/hooks/useToggleCallback.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { MouseEvent, useCallback, useState } from 'react';
2+
3+
export function useToggleCallback(defaultValue?: boolean) {
4+
const [state, setState] = useState<boolean>(defaultValue || false);
5+
const onClick = useCallback((e: MouseEvent) => {
6+
e.preventDefault();
7+
setState((checked: boolean) => {
8+
return !checked;
9+
});
10+
return false;
11+
}, []);
12+
return [state, onClick] as const;
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export interface SessionStorageKeys {
22
'FolderOpened/{instanceId}/{key}': true;
3+
'ColumnDisplayed/{database}/{table}': true;
34
}

0 commit comments

Comments
 (0)