From 17b747ea8ffc79ec6563adf1f232176c89eee450 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:08:16 +0100 Subject: [PATCH] feat: project features - new columns visibility handling (#5605) In `ExperimentalProjectTable.tsx`, changes have been made to the columns configuration in order to handle column visibiilty. This includes adding id property to every column. Logic responsible for dynamically adjusts column visibility based on screen size was moved to new hook, `useDefaultColumnVisibility` --- .../ExperimentalProjectFeatures.tsx | 1 - .../ExperimentalColumnsMenu.tsx | 7 +- .../ExperimentalProjectTable.tsx | 65 ++++++++++++++--- .../hooks/useDefaultColumnVisibility.ts | 62 ++++++++++++++++ frontend/src/utils/withTableState.ts | 71 +++++++++++-------- 5 files changed, 167 insertions(+), 39 deletions(-) create mode 100644 frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/hooks/useDefaultColumnVisibility.ts diff --git a/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectFeatures.tsx b/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectFeatures.tsx index 00f817c5b3..f07211159a 100644 --- a/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectFeatures.tsx +++ b/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectFeatures.tsx @@ -45,7 +45,6 @@ const PaginatedProjectOverview = () => { diff --git a/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/ExperimentalColumnsMenu/ExperimentalColumnsMenu.tsx b/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/ExperimentalColumnsMenu/ExperimentalColumnsMenu.tsx index f5cc8acad4..0be87b472b 100644 --- a/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/ExperimentalColumnsMenu/ExperimentalColumnsMenu.tsx +++ b/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/ExperimentalColumnsMenu/ExperimentalColumnsMenu.tsx @@ -96,14 +96,17 @@ export const ExperimentalColumnsMenu: VFC = ({ {columns.map((column) => column.id === 'divider' ? ( - + ) : ( { onToggle?.(column.id); }} - disabled={column.isStatic === true} + disabled={ + column.isStatic === true && + column.isVisible === true + } > + `environment:${environment}`; const columnHelper = createColumnHelper(); export const ExperimentalProjectFeatureToggles = ({ environments, - style, refreshInterval = 15 * 1000, storageKey = 'project-feature-toggles', }: IExperimentalProjectFeatureTogglesProps) => { const projectId = useRequiredPathParam('projectId'); + const stateConfig = { offset: withDefault(NumberParam, 0), limit: withDefault(NumberParam, DEFAULT_PAGE_LIMIT), @@ -158,7 +159,7 @@ export const ExperimentalProjectFeatureToggles = ({ const columns = useMemo( () => [ columnHelper.display({ - id: 'Select', + id: 'select', header: ({ table }) => ( ( ( columns.map((column) => column.id).filter(Boolean) as string[], + [columns], + ); + + const defaultColumnVisibility = useDefaultColumnVisibility(allColumnIds); const table = useReactTable( withTableState(tableState, setTableState, { columns, data, enableRowSelection: true, + state: { + columnVisibility: defaultColumnVisibility, + }, }), ); + const { columnVisibility } = table.getState(); + const onToggleColumnVisibility = useCallback( + (columnId) => { + const isVisible = columnVisibility[columnId]; + const newColumnVisibility: Record = { + ...columnVisibility, + [columnId]: !isVisible, + }; + setTableState({ + columns: Object.keys(newColumnVisibility).filter( + (columnId) => newColumnVisibility[columnId], + ), + }); + }, + [columnVisibility, setTableState], + ); + return ( <> ({ + header: environment, + id: formatEnvironmentColumnId( + environment, + ), + isVisible: + columnVisibility[ + formatEnvironmentColumnId( + environment, + ) + ], + })), ]} + onToggle={onToggleColumnVisibility} /> } /> diff --git a/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/hooks/useDefaultColumnVisibility.ts b/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/hooks/useDefaultColumnVisibility.ts new file mode 100644 index 0000000000..83e8b49913 --- /dev/null +++ b/frontend/src/component/project/Project/ExperimentalProjectFeatures/ExperimentalProjectTable/hooks/useDefaultColumnVisibility.ts @@ -0,0 +1,62 @@ +import { useCallback } from 'react'; +import { useMediaQuery, useTheme } from '@mui/material'; +import { type VisibilityState } from '@tanstack/react-table'; + +const staticColumns = ['select', 'actions', 'name', 'favorite']; + +const formatAsColumnVisibility = ( + allColumns: string[], + visibleColumns: string[], +): VisibilityState => + allColumns.reduce( + (acc, columnId) => ({ + ...acc, + [columnId]: visibleColumns.includes(columnId), + }), + {}, + ); + +export const useDefaultColumnVisibility = (allColumnIds: string[]) => { + const theme = useTheme(); + const isTinyScreen = useMediaQuery(theme.breakpoints.down('sm')); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); + const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg')); + + const showEnvironments = useCallback( + (environmentsToShow: number = 0) => + allColumnIds + .filter((id) => id.startsWith('environment:') !== false) + .slice(0, environmentsToShow), + [allColumnIds], + ); + + if (isTinyScreen) { + return formatAsColumnVisibility(allColumnIds, [ + ...staticColumns, + 'createdAt', + ]); + } + if (isSmallScreen) { + return formatAsColumnVisibility(allColumnIds, [ + ...staticColumns, + 'createdAt', + ...showEnvironments(1), + ]); + } + if (isMediumScreen) { + return formatAsColumnVisibility(allColumnIds, [ + ...staticColumns, + 'createdAt', + 'type', + ...showEnvironments(1), + ]); + } + + return formatAsColumnVisibility(allColumnIds, [ + ...staticColumns, + 'lastSeenAt', + 'createdAt', + 'type', + ...showEnvironments(3), + ]); +}; diff --git a/frontend/src/utils/withTableState.ts b/frontend/src/utils/withTableState.ts index 6a221e8996..9731a62d4c 100644 --- a/frontend/src/utils/withTableState.ts +++ b/frontend/src/utils/withTableState.ts @@ -7,7 +7,7 @@ import { getCoreRowModel, } from '@tanstack/react-table'; -type TableStateColumnsType = (string | null)[] | null; +type TableStateColumns = (string | null)[] | null | undefined; const createOnSortingChange = ( @@ -79,10 +79,10 @@ const createOnPaginationChange = const createOnColumnVisibilityChange = ( tableState: { - columns?: TableStateColumnsType; + columns?: TableStateColumns; }, setTableState: (newState: { - columns?: TableStateColumnsType; + columns?: TableStateColumns; }) => void, ): OnChangeFn => (newVisibility) => { @@ -132,7 +132,7 @@ const createPaginationState = (tableState: { }); const createColumnVisibilityState = (tableState: { - columns?: TableStateColumnsType; + columns?: TableStateColumns; }) => tableState.columns ? { @@ -152,35 +152,50 @@ export const withTableState = ( sortOrder: string; limit: number; offset: number; - columns?: TableStateColumnsType; + columns?: TableStateColumns; }, setTableState: (newState: { sortBy?: string; sortOrder?: string; limit?: number; offset?: number; - columns?: TableStateColumnsType; + columns?: TableStateColumns; }) => void, options: Omit, 'getCoreRowModel'>, -) => ({ - getCoreRowModel: getCoreRowModel(), - enableSorting: true, - enableMultiSort: false, - manualPagination: true, - manualSorting: true, - enableSortingRemoval: false, - enableHiding: true, - onPaginationChange: createOnPaginationChange(tableState, setTableState), - onSortingChange: createOnSortingChange(tableState, setTableState), - onColumnVisibilityChange: createOnColumnVisibilityChange( - tableState, - setTableState, - ), - ...options, - state: { - ...createSortingState(tableState), - ...createPaginationState(tableState), - ...createColumnVisibilityState(tableState), - ...(options.state || {}), - }, -}); +) => { + const hideAllColumns = Object.fromEntries( + Object.keys(options.state?.columnVisibility || {}).map((column) => [ + column, + false, + ]), + ); + const columnVisibility = tableState.columns + ? { + ...hideAllColumns, + ...createColumnVisibilityState(tableState).columnVisibility, + } + : options.state?.columnVisibility; + + return { + getCoreRowModel: getCoreRowModel(), + enableSorting: true, + enableMultiSort: false, + manualPagination: true, + manualSorting: true, + enableSortingRemoval: false, + enableHiding: true, + onPaginationChange: createOnPaginationChange(tableState, setTableState), + onSortingChange: createOnSortingChange(tableState, setTableState), + onColumnVisibilityChange: createOnColumnVisibilityChange( + tableState, + setTableState, + ), + ...options, + state: { + ...createSortingState(tableState), + ...createPaginationState(tableState), + ...(options.state || {}), + columnVisibility, + }, + }; +};