فهرست منبع

fix(dashboard): Persist user-defined column order in saved views (#3988)

Co-authored-by: Michael Bromley <michael@michaelbromley.co.uk>
Bruce Wayne 4 هفته پیش
والد
کامیت
e14d5622b7

+ 18 - 3
packages/dashboard/src/lib/components/data-table/data-table-context.tsx

@@ -1,8 +1,10 @@
 'use client';
-
+import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
 import { ColumnFiltersState, SortingState, Table } from '@tanstack/react-table';
 import React, { createContext, ReactNode, useContext } from 'react';
 
+export type ColumnConfig = { columnOrder: string[]; columnVisibility: Record<string, boolean> };
+
 interface DataTableContextValue {
     columnFilters: ColumnFiltersState;
     setColumnFilters: React.Dispatch<React.SetStateAction<ColumnFiltersState>>;
@@ -16,7 +18,7 @@ interface DataTableContextValue {
     onRefresh?: () => void;
     isLoading?: boolean;
     table?: Table<any>;
-    handleApplyView: (filters: ColumnFiltersState, searchTerm?: string) => void;
+    handleApplyView: (filters: ColumnFiltersState, columnConfig: ColumnConfig, searchTerm?: string) => void;
 }
 
 const DataTableContext = createContext<DataTableContextValue | undefined>(undefined);
@@ -52,7 +54,13 @@ export function DataTableProvider({
     isLoading,
     table,
 }: DataTableProviderProps) {
-    const handleApplyView = (filters: ColumnFiltersState, viewSearchTerm?: string) => {
+    const { setTableSettings } = useUserSettings();
+
+    const handleApplyView = (
+        filters: ColumnFiltersState,
+        columnConfig: ColumnConfig,
+        viewSearchTerm?: string,
+    ) => {
         setColumnFilters(filters);
         if (viewSearchTerm !== undefined && onSearchTermChange) {
             setSearchTerm(viewSearchTerm);
@@ -61,6 +69,13 @@ export function DataTableProvider({
         if (onFilterChange && table) {
             onFilterChange(table, filters);
         }
+
+        if (pageId && columnConfig.columnOrder) {
+            setTableSettings(pageId, 'columnOrder', columnConfig.columnOrder);
+        }
+        if (pageId && columnConfig.columnVisibility) {
+            setTableSettings(pageId, 'columnVisibility', columnConfig.columnVisibility);
+        }
     };
 
     const value: DataTableContextValue = {

+ 21 - 0
packages/dashboard/src/lib/components/data-table/save-view-dialog.tsx

@@ -7,6 +7,8 @@ import { Input } from '../ui/input.js';
 import { Label } from '../ui/label.js';
 import { RadioGroup, RadioGroupItem } from '../ui/radio-group.js';
 import { toast } from 'sonner';
+import { usePage } from '@/vdb/hooks/use-page.js';
+import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
 
 interface SaveViewDialogProps {
     open: boolean;
@@ -25,6 +27,21 @@ export const SaveViewDialog: React.FC<SaveViewDialogProps> = ({
     const [scope, setScope] = useState<'user' | 'global'>('user');
     const [saving, setSaving] = useState(false);
     const { saveView, userViews, globalViews, canManageGlobalViews } = useSavedViews();
+    const { pageId } = usePage();
+    const { settings } = useUserSettings();
+
+    const defaultVisibility = {
+        id: false,
+        createdAt: false,
+        updatedAt: false,
+        type: false,
+        currencyCode: false,
+    }
+    const tableSettings = pageId ? settings.tableSettings?.[pageId] : undefined;
+    const columnVisibility = pageId
+        ? (tableSettings?.columnVisibility ?? defaultVisibility)
+        : defaultVisibility;
+    const columnOrder = pageId ? (tableSettings?.columnOrder ?? []) : [];
 
     const handleSave = async () => {
         if (!name.trim()) {
@@ -45,6 +62,10 @@ export const SaveViewDialog: React.FC<SaveViewDialogProps> = ({
                 name: name.trim(),
                 scope,
                 filters,
+                columnConfig : {
+                    columnVisibility,
+                    columnOrder,
+                },
                 searchTerm,
             });
             toast.success(`View "${name}" saved successfully`);

+ 1 - 1
packages/dashboard/src/lib/components/data-table/views-sheet.tsx

@@ -44,7 +44,7 @@ export const ViewsSheet: React.FC<ViewsSheetProps> = ({ open, onOpenChange, type
     const isGlobal = type === 'global';
 
     const handleViewApply = (view: SavedView) => {
-        handleApplyView(view.filters, view.searchTerm);
+        handleApplyView(view.filters,view.columnConfig, view.searchTerm);
         const viewName = view.name;
         const message = isGlobal ? t`Applied global view "${viewName}"` : t`Applied view "${viewName}"`;
         toast.success(message);

+ 1 - 0
packages/dashboard/src/lib/hooks/use-saved-views.ts

@@ -113,6 +113,7 @@ export function useSavedViews() {
             scope: input.scope,
             filters: input.filters,
             searchTerm: input.searchTerm,
+            columnConfig: input.columnConfig,
             pageId,
             blockId: blockId === 'default' ? undefined : blockId,
             createdAt: new Date().toISOString(),

+ 3 - 0
packages/dashboard/src/lib/types/saved-views.ts

@@ -1,10 +1,12 @@
 import { ColumnFiltersState } from '@tanstack/react-table';
+import { ColumnConfig } from '../components/data-table/data-table-context.js';
 
 export interface SavedView {
     id: string;
     name: string;
     scope: 'user' | 'global';
     filters: ColumnFiltersState;
+    columnConfig: ColumnConfig;
     searchTerm?: string;
     pageId?: string;
     blockId?: string;
@@ -28,6 +30,7 @@ export interface SaveViewInput {
     name: string;
     scope: 'user' | 'global';
     filters: ColumnFiltersState;
+    columnConfig: ColumnConfig;
     searchTerm?: string;
 }