1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-26 01:17:00 +02:00

feat: new columns visibility menu (#5604)

New `<ColumnsMenu />` is using it's own list of elements instead of
inferring it from table columns definition. This component doesn't need
it's internal structure to depend on react-table and it's interface.
This commit is contained in:
Tymoteusz Czech 2023-12-12 13:41:25 +01:00 committed by GitHub
parent 685489b9ad
commit 8a5a73ad7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 205 additions and 12 deletions

View File

@ -0,0 +1,41 @@
import {
Box,
Checkbox,
Divider,
IconButton,
MenuItem,
styled,
} from '@mui/material';
import { flexRow } from 'themes/themeStyles';
export const StyledBoxContainer = styled(Box)(() => ({
...flexRow,
justifyContent: 'center',
}));
export const StyledIconButton = styled(IconButton)(({ theme }) => ({
margin: theme.spacing(-1, 0),
}));
export const StyledBoxMenuHeader = styled(Box)(({ theme }) => ({
...flexRow,
justifyContent: 'space-between',
padding: theme.spacing(1, 1, 0, 4),
}));
export const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
padding: theme.spacing(0, 2),
margin: theme.spacing(0, 2),
borderRadius: theme.shape.borderRadius,
}));
export const StyledDivider = styled(Divider)(({ theme }) => ({
'&.MuiDivider-root.MuiDivider-fullWidth': {
margin: theme.spacing(0.75, 0),
},
}));
export const StyledCheckbox = styled(Checkbox)(({ theme }) => ({
padding: theme.spacing(0.75, 1),
}));

View File

@ -0,0 +1,134 @@
import { useEffect, useState, VFC } from 'react';
import {
IconButton,
ListItemIcon,
ListItemText,
MenuList,
Popover,
Tooltip,
Typography,
} from '@mui/material';
import ColumnIcon from '@mui/icons-material/ViewWeek';
import CloseIcon from '@mui/icons-material/Close';
import {
StyledBoxContainer,
StyledBoxMenuHeader,
StyledCheckbox,
StyledDivider,
StyledIconButton,
StyledMenuItem,
} from './ExperimentalColumnsMenu.styles';
interface IColumnsMenuProps {
columns: {
header?: string;
id: string;
isStatic?: boolean;
isVisible?: boolean;
}[];
onToggle?: (id: string) => void;
}
export const ExperimentalColumnsMenu: VFC<IColumnsMenuProps> = ({
columns,
onToggle,
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const onIconClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const isOpen = Boolean(anchorEl);
const id = `columns-menu`;
const menuId = `columns-menu-list-${id}`;
return (
<StyledBoxContainer>
<Tooltip title='Select columns' arrow describeChild>
<StyledIconButton
id={id}
aria-controls={isOpen ? menuId : undefined}
aria-haspopup='true'
aria-expanded={isOpen ? 'true' : undefined}
onClick={onIconClick}
type='button'
size='large'
data-loading
>
<ColumnIcon />
</StyledIconButton>
</Tooltip>
<Popover
id={menuId}
open={isOpen}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
disableScrollLock={true}
PaperProps={{
sx: (theme) => ({
borderRadius: theme.shape.borderRadius,
paddingBottom: theme.spacing(2),
}),
}}
>
<StyledBoxMenuHeader>
<Typography variant='body2'>
<strong>Columns</strong>
</Typography>
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
</StyledBoxMenuHeader>
<MenuList>
{columns.map((column) =>
column.id === 'divider' ? (
<StyledDivider />
) : (
<StyledMenuItem
key={column.id}
onClick={() => {
onToggle?.(column.id);
}}
disabled={column.isStatic === true}
>
<ListItemIcon>
<StyledCheckbox
edge='start'
checked={column.isVisible}
disableRipple
inputProps={{
'aria-labelledby': column.id,
}}
size='medium'
/>
</ListItemIcon>
<ListItemText
id={column.id}
primary={
<Typography variant='body2'>
{column.header}
</Typography>
}
/>
</StyledMenuItem>
),
)}
</MenuList>
</Popover>
</StyledBoxContainer>
);
};

View File

@ -50,7 +50,7 @@ import { FavoriteIconHeader } from 'component/common/Table/FavoriteIconHeader/Fa
import { FavoriteIconCell } from 'component/common/Table/cells/FavoriteIconCell/FavoriteIconCell';
import { ProjectEnvironmentType } from '../../ProjectFeatureToggles/hooks/useEnvironmentsRef';
import { ActionsCell } from '../../ProjectFeatureToggles/ActionsCell/ActionsCell';
import { ColumnsMenu } from '../../ProjectFeatureToggles/ColumnsMenu/ColumnsMenu';
import { ExperimentalColumnsMenu as ColumnsMenu } from './ExperimentalColumnsMenu/ExperimentalColumnsMenu';
import { useStyles } from '../../ProjectFeatureToggles/ProjectFeatureToggles.styles';
import { useFavoriteFeaturesApi } from 'hooks/api/actions/useFavoriteFeaturesApi/useFavoriteFeaturesApi';
import { FeatureTagCell } from 'component/common/Table/cells/FeatureTagCell/FeatureTagCell';
@ -333,6 +333,31 @@ export const ExperimentalProjectFeatureToggles = ({
environmentsToExport={environments.map(
({ environment }) => environment,
)}
actions={
<ColumnsMenu
columns={[
{
header: 'Last seen',
id: 'lastSeenAt',
},
{
header: 'Type',
id: 'type',
},
{
header: 'Name',
id: 'name',
},
{
header: 'Created',
id: 'createdAt',
},
{
id: 'divider',
},
]}
/>
}
/>
}
>

View File

@ -1,4 +1,4 @@
import { VFC, useState } from 'react';
import { ReactNode, VFC, useState } from 'react';
import {
Box,
IconButton,
@ -28,6 +28,7 @@ interface IProjectFeatureTogglesHeaderProps {
onChangeSearchQuery?: (query: string) => void;
dataToExport?: Pick<FeatureSchema, 'name'>[];
environmentsToExport?: string[];
actions?: ReactNode;
}
const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
@ -43,6 +44,7 @@ export const ProjectFeatureTogglesHeader: VFC<
onChangeSearchQuery,
dataToExport,
environmentsToExport,
actions,
}) => {
const projectId = useRequiredPathParam('projectId');
const headerLoadingRef = useLoading(isLoading || false);
@ -91,16 +93,7 @@ export const ProjectFeatureTogglesHeader: VFC<
/>
}
/>
{/* FIXME: columns menu */}
{/* <ColumnsMenu
allColumns={allColumns}
staticColumns={staticColumns}
dividerAfter={['createdAt']}
dividerBefore={['Actions']}
isCustomized={isCustomColumns}
setHiddenColumns={setHiddenColumns}
onCustomize={() => setIsCustomColumns(true)}
/> */}
{actions}
<PageHeader.Divider sx={{ marginLeft: 0 }} />
<ConditionallyRender
condition={featuresExportImportFlag}