added hidden init columns

This commit is contained in:
Jonathan Summers-Muir committed 2025-04-19 20:18:19 +08:00
1 parent 013bc63765
commit 8a43fac91b
6 files changed
+199 -2

No files matched your search

@@ -1,4 +1,4 @@
import { forwardRef, memo, useRef } from 'react'
import { forwardRef, memo, useRef, useMemo } from 'react'
import DataGrid, { CalculatedColumn, DataGridHandle } from 'react-data-grid'
import { handleCopyCell } from 'components/grid/SupabaseGrid.utils'
@@ -10,6 +10,7 @@ import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { useTableEditorStateSnapshot } from 'state/table-editor'
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
import { useTableColumnVisibility } from 'components/grid/hooks/useTableColumnVisibility'
import { Button, cn } from 'ui'
import { GenericSkeletonLoader } from 'ui-patterns'
import type { Filter, GridProps, SupaRow } from '../../types'
@@ -52,6 +53,12 @@ export const Grid = memo(
) => {
const tableEditorSnap = useTableEditorStateSnapshot()
const snap = useTableEditorTableStateSnapshot()
const { hiddenColumns } = useTableColumnVisibility()
const visibleColumns = useMemo(() => {
if (!snap.gridColumns) return []
return snap.gridColumns.filter((col) => !hiddenColumns.has(col.key))
}, [snap.gridColumns, hiddenColumns])
const onRowsChange = useOnRowsChange(rows)
@@ -182,7 +189,7 @@ export const Grid = memo(
ref={ref}
className={`${gridClass} flex-grow`}
rowClass={rowClass}
columns={snap.gridColumns as CalculatedColumn<any, any>[]}
columns={visibleColumns as CalculatedColumn<any, any>[]}
rows={rows ?? []}
renderers={{ renderRow: RowRenderer }}
rowKeyGetter={rowKeyGetter}
@@ -0,0 +1,68 @@
import { useParams } from 'common'
import { Settings2 } from 'lucide-react'
import {
Button,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuTrigger,
Tooltip,
TooltipContent,
TooltipTrigger,
} from 'ui'
import { useTableColumnVisibility } from 'components/grid/hooks/useTableColumnVisibility'
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
export const ColumnVisibility = () => {
const snap = useTableEditorTableStateSnapshot()
const { hiddenColumns, hideColumn, showColumn } = useTableColumnVisibility()
const handleToggleColumnVisibility = (columnKey: string, isVisible: boolean) => {
if (isVisible) {
showColumn(columnKey)
} else {
hideColumn(columnKey)
}
}
const columns = snap.table?.columns ?? []
if (columns.length === 0) {
return null
}
return (
<DropdownMenu>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
type="text"
icon={<Settings2 size={14} strokeWidth={1.5} />}
className="rounded px-1.5"
/>
</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent side="bottom">Show/hide columns</TooltipContent>
</Tooltip>
<DropdownMenuContent side="bottom" align="start" className="max-h-[300px] overflow-y-auto">
{columns.map((column) => {
const columnKey = column.name
const isVisible = !hiddenColumns.has(columnKey)
return (
<DropdownMenuCheckboxItem
key={columnKey}
checked={isVisible}
onSelect={(e) => e.preventDefault()}
onCheckedChange={() => handleToggleColumnVisibility(columnKey, !isVisible)}
>
{column.name}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
)
}
@@ -36,6 +36,7 @@ import {
Separator,
SonnerProgress,
} from 'ui'
import { ColumnVisibility } from './ColumnVisibility'
import FilterPopover from './filter/FilterPopover'
import { SortPopover } from './sort'
// [Joshen] CSV exports require this guard as a fail-safe if the table is
@@ -110,6 +111,7 @@ const DefaultHeader = () => {
<div className="flex items-center gap-2">
<FilterPopover filters={urlFilters} onApplyFilters={onApplyFilters} />
<SortPopover sorts={urlSorts} onApplySorts={onApplySorts} />
<ColumnVisibility />
</div>
{canAddNew && (
<>
@@ -0,0 +1,33 @@
import { useCallback } from 'react'
import { useParams } from 'common'
import { getTabsStore, updateTabHiddenColumns } from 'state/tabs'
export function useSaveColumnVisibilityToTabs() {
const { ref: projectRef } = useParams()
const saveHiddenColumnsToTab = useCallback(
(hiddenColumnsSet: Set<string>) => {
if (!projectRef) {
console.warn('[useSaveColumnVisibilityToTabs] Missing projectRef, cannot save state.')
return
}
// Get the current active tab ID directly within the callback
// This ensures we use the latest active tab when the save occurs
const tabsState = getTabsStore(projectRef)
const activeTabId = tabsState.activeTab
if (activeTabId) {
const hiddenColumnsArray = Array.from(hiddenColumnsSet).sort()
updateTabHiddenColumns(projectRef, activeTabId, hiddenColumnsArray)
} else {
console.warn(
'[useSaveColumnVisibilityToTabs] No active tab found, cannot save hidden columns state.'
)
}
},
[projectRef] // Dependency on projectRef
)
return { saveHiddenColumnsToTab }
}
@@ -0,0 +1,62 @@
import { useCallback, useMemo } from 'react'
import { useUrlState } from 'hooks/ui/useUrlState'
// Import the hook for saving to tabs store
import { useSaveColumnVisibilityToTabs } from './useSaveColumnVisibilityToTabs'
// Comma-separated string in URL, Set<string> in hook
const URL_PARAM_KEY = 'hidden_cols'
export function useTableColumnVisibility() {
const [params, setParams] = useUrlState()
// Get the function to save to tabs store
const { saveHiddenColumnsToTab } = useSaveColumnVisibilityToTabs()
const urlHiddenColumnsString = useMemo(() => {
const val = params[URL_PARAM_KEY]
return typeof val === 'string' ? val : ''
}, [params])
const hiddenColumnsSet = useMemo(() => {
return new Set<string>(urlHiddenColumnsString ? urlHiddenColumnsString.split(',') : [])
}, [urlHiddenColumnsString])
const setHiddenColumnsUrl = useCallback(
(newHiddenColumns: Set<string>) => {
const newUrlString = Array.from(newHiddenColumns).sort().join(',')
setParams((prevParams) => ({
...prevParams,
[URL_PARAM_KEY]: newUrlString || undefined, // Remove param if empty
}))
// Call save to tabs store whenever the whole set changes via URL
saveHiddenColumnsToTab(newHiddenColumns)
},
[setParams, saveHiddenColumnsToTab] // Add saveHiddenColumnsToTab dependency
)
// Function to conveniently hide a single column
const hideColumnUrl = useCallback(
(columnName: string) => {
const newSet = new Set(hiddenColumnsSet)
newSet.add(columnName)
setHiddenColumnsUrl(newSet) // This will now also trigger saveHiddenColumnsToTab
},
[hiddenColumnsSet, setHiddenColumnsUrl]
)
// Function to conveniently show a single column
const showColumnUrl = useCallback(
(columnName: string) => {
const newSet = new Set(hiddenColumnsSet)
newSet.delete(columnName)
setHiddenColumnsUrl(newSet) // This will now also trigger saveHiddenColumnsToTab
},
[hiddenColumnsSet, setHiddenColumnsUrl]
)
return {
hiddenColumns: hiddenColumnsSet, // The current Set<string> of hidden columns from URL
setHiddenColumnsUrl, // Function to update the URL param with a full Set
hideColumn: hideColumnUrl, // Function to hide a specific column (updates URL)
showColumn: showColumnUrl, // Function to show a specific column (updates URL)
}
}
+25
View File
@@ -31,6 +31,8 @@ export interface Tab {
isPreview?: boolean // Optional flag indicating if the tab is in preview mode
createdAt?: Date // Optional timestamp for when the tab was created
updatedAt?: Date // Optional timestamp for when the tab was last updated
// Stores the names of columns hidden by the user for this specific tab (session state)
hiddenColumns?: string[]
}
// Interface representing the state of tabs
@@ -390,3 +392,26 @@ export function removeTabsByEditor(ref: string | undefined, type: 'table' | 'sql
removeTabs(ref, tabIdsToRemove)
}
/**
* Action to update hidden columns for a specific tab in the tabs store.
*
* @param ref Project ref.
* @param tabId ID of the tab to update.
* @param hiddenColumns Array of column names to be marked as hidden.
* @returns {void}
*/
export const updateTabHiddenColumns = (
ref: string | undefined,
tabId: string,
hiddenColumns: string[]
) => {
if (!ref) return
const store = getTabsStore(ref)
if (store.tabsMap[tabId]) {
// Update the hiddenColumns array for the specified tab
store.tabsMap[tabId].hiddenColumns = hiddenColumns
// Update the timestamp to reflect the change
store.tabsMap[tabId].updatedAt = new Date()
}
}