mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
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`
This commit is contained in:
parent
c0c1dba9b0
commit
17b747ea8f
@ -45,7 +45,6 @@ const PaginatedProjectOverview = () => {
|
||||
<StyledContentContainer>
|
||||
<StyledProjectToggles>
|
||||
<ExperimentalProjectFeatureToggles
|
||||
style={{ width: '100%', margin: 0 }}
|
||||
environments={environments}
|
||||
storageKey='project-features'
|
||||
/>
|
||||
|
@ -96,14 +96,17 @@ export const ExperimentalColumnsMenu: VFC<IColumnsMenuProps> = ({
|
||||
<MenuList>
|
||||
{columns.map((column) =>
|
||||
column.id === 'divider' ? (
|
||||
<StyledDivider />
|
||||
<StyledDivider key='divider' />
|
||||
) : (
|
||||
<StyledMenuItem
|
||||
key={column.id}
|
||||
onClick={() => {
|
||||
onToggle?.(column.id);
|
||||
}}
|
||||
disabled={column.isStatic === true}
|
||||
disabled={
|
||||
column.isStatic === true &&
|
||||
column.isVisible === true
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<StyledCheckbox
|
||||
|
@ -91,25 +91,26 @@ import { type FeatureSearchResponseSchema } from 'openapi';
|
||||
import { FeatureNameCell } from 'component/common/Table/cells/FeatureNameCell/FeatureNameCell';
|
||||
import { FeatureToggleCell } from './FeatureToggleCell/FeatureToggleCell';
|
||||
import { ProjectOverviewFilters } from './ProjectOverviewFilters';
|
||||
import { useDefaultColumnVisibility } from './hooks/useDefaultColumnVisibility';
|
||||
|
||||
interface IExperimentalProjectFeatureTogglesProps {
|
||||
environments: IProject['environments'];
|
||||
style?: CSSProperties;
|
||||
refreshInterval?: number;
|
||||
storageKey?: string;
|
||||
}
|
||||
|
||||
const staticColumns = ['Select', 'Actions', 'name', 'favorite'];
|
||||
const formatEnvironmentColumnId = (environment: string) =>
|
||||
`environment:${environment}`;
|
||||
|
||||
const columnHelper = createColumnHelper<FeatureSearchResponseSchema>();
|
||||
|
||||
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 }) => (
|
||||
<MemoizedRowSelectCell
|
||||
noPadding
|
||||
@ -177,6 +178,7 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
),
|
||||
}),
|
||||
columnHelper.accessor('favorite', {
|
||||
id: 'favorite',
|
||||
header: () => (
|
||||
<FavoriteIconHeader
|
||||
isActive={tableState.favoritesFirst}
|
||||
@ -196,10 +198,10 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
enableSorting: false,
|
||||
meta: {
|
||||
align: 'center',
|
||||
// hideInMenu: true,
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor('lastSeenAt', {
|
||||
id: 'lastSeenAt',
|
||||
header: 'Last seen',
|
||||
cell: ({ row: { original } }) => (
|
||||
<MemoizedFeatureEnvironmentSeenCell
|
||||
@ -213,6 +215,7 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor('type', {
|
||||
id: 'type',
|
||||
header: 'Type',
|
||||
cell: FeatureTypeCell,
|
||||
meta: {
|
||||
@ -220,6 +223,7 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor('name', {
|
||||
id: 'name',
|
||||
header: 'Name',
|
||||
cell: FeatureNameCell,
|
||||
meta: {
|
||||
@ -227,6 +231,7 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor('createdAt', {
|
||||
id: 'createdAt',
|
||||
header: 'Created',
|
||||
cell: DateCell,
|
||||
}),
|
||||
@ -252,8 +257,8 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
) || false,
|
||||
}),
|
||||
{
|
||||
id: `environment:${name}`,
|
||||
header: loading ? '' : name,
|
||||
id: formatEnvironmentColumnId(name),
|
||||
header: name,
|
||||
meta: {
|
||||
align: 'center',
|
||||
},
|
||||
@ -287,7 +292,7 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
},
|
||||
),
|
||||
],
|
||||
[projectId, environments, loading, tableState.favoritesFirst, refetch],
|
||||
[projectId, environments, tableState.favoritesFirst, refetch],
|
||||
);
|
||||
|
||||
const placeholderData = useMemo(
|
||||
@ -319,15 +324,41 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
}
|
||||
return features;
|
||||
}, [loading, features]);
|
||||
const allColumnIds = useMemo(
|
||||
() => 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<string, boolean> = {
|
||||
...columnVisibility,
|
||||
[columnId]: !isVisible,
|
||||
};
|
||||
setTableState({
|
||||
columns: Object.keys(newColumnVisibility).filter(
|
||||
(columnId) => newColumnVisibility[columnId],
|
||||
),
|
||||
});
|
||||
},
|
||||
[columnVisibility, setTableState],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageContent
|
||||
@ -351,23 +382,41 @@ export const ExperimentalProjectFeatureToggles = ({
|
||||
{
|
||||
header: 'Last seen',
|
||||
id: 'lastSeenAt',
|
||||
isVisible: columnVisibility.lastSeenAt,
|
||||
},
|
||||
{
|
||||
header: 'Type',
|
||||
id: 'type',
|
||||
isVisible: columnVisibility.type,
|
||||
},
|
||||
{
|
||||
header: 'Name',
|
||||
id: 'name',
|
||||
isVisible: columnVisibility.name,
|
||||
isStatic: true,
|
||||
},
|
||||
{
|
||||
header: 'Created',
|
||||
id: 'createdAt',
|
||||
isVisible: columnVisibility.createdAt,
|
||||
},
|
||||
{
|
||||
id: 'divider',
|
||||
},
|
||||
...environments.map(({ environment }) => ({
|
||||
header: environment,
|
||||
id: formatEnvironmentColumnId(
|
||||
environment,
|
||||
),
|
||||
isVisible:
|
||||
columnVisibility[
|
||||
formatEnvironmentColumnId(
|
||||
environment,
|
||||
)
|
||||
],
|
||||
})),
|
||||
]}
|
||||
onToggle={onToggleColumnVisibility}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -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),
|
||||
]);
|
||||
};
|
@ -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<VisibilityState> =>
|
||||
(newVisibility) => {
|
||||
@ -132,7 +132,7 @@ const createPaginationState = (tableState: {
|
||||
});
|
||||
|
||||
const createColumnVisibilityState = (tableState: {
|
||||
columns?: TableStateColumnsType;
|
||||
columns?: TableStateColumns;
|
||||
}) =>
|
||||
tableState.columns
|
||||
? {
|
||||
@ -152,35 +152,50 @@ export const withTableState = <T extends Object>(
|
||||
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<TableOptions<T>, '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,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user