Переглянути джерело

feat(dashboard): Persist table config to userSettings

Michael Bromley 9 місяців тому
батько
коміт
363e167839

+ 7 - 0
packages/dashboard/src/lib/components/data-table/data-table.tsx

@@ -41,6 +41,7 @@ interface DataTableProps<TData, TValue> {
     onPageChange?: (table: TableType<TData>, page: number, itemsPerPage: number) => void;
     onSortChange?: (table: TableType<TData>, sorting: SortingState) => void;
     onFilterChange?: (table: TableType<TData>, columnFilters: ColumnFilter[]) => void;
+    onColumnVisibilityChange?: (table: TableType<TData>, columnVisibility: VisibilityState) => void;
     onSearchTermChange?: (searchTerm: string) => void;
     defaultColumnVisibility?: VisibilityState;
     facetedFilters?: { [key: string]: FacetedFilter | undefined };
@@ -64,6 +65,7 @@ export function DataTable<TData, TValue>({
     onSortChange,
     onFilterChange,
     onSearchTermChange,
+    onColumnVisibilityChange,
     defaultColumnVisibility,
     facetedFilters,
     disableViewOptions,
@@ -117,6 +119,11 @@ export function DataTable<TData, TValue>({
     useEffect(() => {
         onFilterChange?.(table, columnFilters);
     }, [columnFilters]);
+
+    useEffect(() => {
+        onColumnVisibilityChange?.(table, columnVisibility);
+    }, [columnVisibility]);
+
     return (
         <>
             <div className="flex justify-between items-start">

+ 4 - 1
packages/dashboard/src/lib/components/shared/paginated-list-data-table.tsx

@@ -28,7 +28,7 @@ import {
     SortingState,
     Table,
 } from '@tanstack/react-table';
-import { AccessorKeyColumnDef, ColumnDef, Row, TableOptions } from '@tanstack/table-core';
+import { AccessorKeyColumnDef, ColumnDef, Row, TableOptions, VisibilityState } from '@tanstack/table-core';
 import { EllipsisIcon, TrashIcon } from 'lucide-react';
 import React, { useMemo } from 'react';
 import { toast } from 'sonner';
@@ -196,6 +196,7 @@ export interface PaginatedListDataTableProps<
     onPageChange: (table: Table<any>, page: number, perPage: number) => void;
     onSortChange: (table: Table<any>, sorting: SortingState) => void;
     onFilterChange: (table: Table<any>, filters: ColumnFiltersState) => void;
+    onColumnVisibilityChange?: (table: Table<any>, columnVisibility: VisibilityState) => void;
     facetedFilters?: FacetedFilterConfig<T>;
     rowActions?: RowAction<PaginatedListItemFields<T>>[];
     disableViewOptions?: boolean;
@@ -227,6 +228,7 @@ export function PaginatedListDataTable<
     onPageChange,
     onSortChange,
     onFilterChange,
+    onColumnVisibilityChange,
     facetedFilters,
     rowActions,
     disableViewOptions,
@@ -416,6 +418,7 @@ export function PaginatedListDataTable<
                 onPageChange={onPageChange}
                 onSortChange={onSortChange}
                 onFilterChange={onFilterChange}
+                onColumnVisibilityChange={onColumnVisibilityChange}
                 onSearchTermChange={onSearchTermChange ? term => setSearchTerm(term) : undefined}
                 defaultColumnVisibility={columnVisibility}
                 facetedFilters={facetedFilters}

+ 18 - 3
packages/dashboard/src/lib/framework/page/list-page.tsx

@@ -11,7 +11,9 @@ import { TypedDocumentNode } from '@graphql-typed-document-node/core';
 import { AnyRoute, AnyRouter, useNavigate } from '@tanstack/react-router';
 import { ColumnFiltersState, SortingState, Table } from '@tanstack/react-table';
 import { TableOptions } from '@tanstack/table-core';
+import { useUserSettings } from '@/hooks/use-user-settings.js';
 import { ResultOf } from 'gql.tada';
+
 import { addCustomFields } from '../document-introspection/add-custom-fields.js';
 import {
     FullWidthPageBlock,
@@ -81,12 +83,17 @@ export function ListPage<
     const route = typeof routeOrFn === 'function' ? routeOrFn() : routeOrFn;
     const routeSearch = route.useSearch();
     const navigate = useNavigate<AnyRouter>({ from: route.fullPath });
+    const { setTableSettings, settings } = useUserSettings();
+    const tableSettings = pageId ? settings.tableSettings?.[pageId] : undefined;
 
     const pagination = {
         page: routeSearch.page ? parseInt(routeSearch.page) : 1,
-        itemsPerPage: routeSearch.perPage ? parseInt(routeSearch.perPage) : 10,
+        itemsPerPage: routeSearch.perPage ? parseInt(routeSearch.perPage) : tableSettings?.pageSize ?? 10,
     };
 
+    const columnVisibility = pageId ? tableSettings?.columnVisibility : defaultVisibility;
+    const columnOrder = pageId ? tableSettings?.columnOrder : defaultColumnOrder;
+
     const sorting: SortingState = (routeSearch.sort ?? '')
         .split(',')
         .filter((s: string) => s.length)
@@ -138,8 +145,8 @@ export function ListPage<
                         transformVariables={transformVariables}
                         customizeColumns={customizeColumns as any}
                         additionalColumns={additionalColumns as any}
-                        defaultColumnOrder={defaultColumnOrder}
-                        defaultVisibility={defaultVisibility}
+                        defaultColumnOrder={columnOrder as any}
+                        defaultVisibility={columnVisibility as any}
                         onSearchTermChange={onSearchTermChange}
                         page={pagination.page}
                         itemsPerPage={pagination.itemsPerPage}
@@ -147,6 +154,9 @@ export function ListPage<
                         columnFilters={routeSearch.filters}
                         onPageChange={(table, page, perPage) => {
                             persistListStateToUrl(table, { page, perPage });
+                            if (pageId) {
+                                setTableSettings(pageId, 'pageSize', perPage);
+                            }
                         }}
                         onSortChange={(table, sorting) => {
                             persistListStateToUrl(table, { sort: sorting });
@@ -154,6 +164,11 @@ export function ListPage<
                         onFilterChange={(table, filters) => {
                             persistListStateToUrl(table, { filters });
                         }}
+                        onColumnVisibilityChange={(table, columnVisibility) => {
+                            if (pageId) {
+                                setTableSettings(pageId, 'columnVisibility', columnVisibility);
+                            }
+                        }}
                         facetedFilters={facetedFilters}
                         rowActions={rowActions}
                         setTableOptions={setTableOptions}

+ 22 - 0
packages/dashboard/src/lib/providers/user-settings.tsx

@@ -1,6 +1,12 @@
 import React, { createContext, useState, useEffect } from 'react';
 import { Theme } from './theme-provider.js';
 
+export interface TableSettings {
+    columnVisibility?: Record<string, boolean>;
+    columnOrder?: string[];
+    pageSize?: number;
+}
+
 export interface UserSettings {
     displayLanguage: string;
     displayLocale?: string;
@@ -11,6 +17,7 @@ export interface UserSettings {
     activeChannelId: string;
     devMode: boolean;
     hasSeenOnboarding: boolean;
+    tableSettings?: Record<string, TableSettings>;
 }
 
 const defaultSettings: UserSettings = {
@@ -23,6 +30,7 @@ const defaultSettings: UserSettings = {
     activeChannelId: '',
     devMode: false,
     hasSeenOnboarding: false,
+    tableSettings: {},
 };
 
 export interface UserSettingsContextType {
@@ -36,6 +44,11 @@ export interface UserSettingsContextType {
     setActiveChannelId: (channelId: string) => void;
     setDevMode: (devMode: boolean) => void;
     setHasSeenOnboarding: (hasSeen: boolean) => void;
+    setTableSettings: <K extends keyof TableSettings>(
+        tableId: string,
+        key: K,
+        value: TableSettings[K],
+    ) => void;
 }
 
 export const UserSettingsContext = createContext<UserSettingsContextType | undefined>(undefined);
@@ -83,6 +96,15 @@ export const UserSettingsProvider: React.FC<React.PropsWithChildren<{}>> = ({ ch
         setActiveChannelId: channelId => updateSetting('activeChannelId', channelId),
         setDevMode: devMode => updateSetting('devMode', devMode),
         setHasSeenOnboarding: hasSeen => updateSetting('hasSeenOnboarding', hasSeen),
+        setTableSettings: (tableId, key, value) => {
+            setSettings(prev => ({
+                ...prev,
+                tableSettings: {
+                    ...prev.tableSettings,
+                    [tableId]: { ...(prev.tableSettings?.[tableId] || {}), [key]: value },
+                },
+            }));
+        },
     };
 
     return <UserSettingsContext.Provider value={contextValue}>{children}</UserSettingsContext.Provider>;