mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-14 01:16:17 +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:
parent
685489b9ad
commit
8a5a73ad7d
@ -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),
|
||||||
|
}));
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
@ -50,7 +50,7 @@ import { FavoriteIconHeader } from 'component/common/Table/FavoriteIconHeader/Fa
|
|||||||
import { FavoriteIconCell } from 'component/common/Table/cells/FavoriteIconCell/FavoriteIconCell';
|
import { FavoriteIconCell } from 'component/common/Table/cells/FavoriteIconCell/FavoriteIconCell';
|
||||||
import { ProjectEnvironmentType } from '../../ProjectFeatureToggles/hooks/useEnvironmentsRef';
|
import { ProjectEnvironmentType } from '../../ProjectFeatureToggles/hooks/useEnvironmentsRef';
|
||||||
import { ActionsCell } from '../../ProjectFeatureToggles/ActionsCell/ActionsCell';
|
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 { useStyles } from '../../ProjectFeatureToggles/ProjectFeatureToggles.styles';
|
||||||
import { useFavoriteFeaturesApi } from 'hooks/api/actions/useFavoriteFeaturesApi/useFavoriteFeaturesApi';
|
import { useFavoriteFeaturesApi } from 'hooks/api/actions/useFavoriteFeaturesApi/useFavoriteFeaturesApi';
|
||||||
import { FeatureTagCell } from 'component/common/Table/cells/FeatureTagCell/FeatureTagCell';
|
import { FeatureTagCell } from 'component/common/Table/cells/FeatureTagCell/FeatureTagCell';
|
||||||
@ -333,6 +333,31 @@ export const ExperimentalProjectFeatureToggles = ({
|
|||||||
environmentsToExport={environments.map(
|
environmentsToExport={environments.map(
|
||||||
({ environment }) => environment,
|
({ environment }) => environment,
|
||||||
)}
|
)}
|
||||||
|
actions={
|
||||||
|
<ColumnsMenu
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
header: 'Last seen',
|
||||||
|
id: 'lastSeenAt',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Type',
|
||||||
|
id: 'type',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Name',
|
||||||
|
id: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Created',
|
||||||
|
id: 'createdAt',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'divider',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { VFC, useState } from 'react';
|
import { ReactNode, VFC, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
IconButton,
|
IconButton,
|
||||||
@ -28,6 +28,7 @@ interface IProjectFeatureTogglesHeaderProps {
|
|||||||
onChangeSearchQuery?: (query: string) => void;
|
onChangeSearchQuery?: (query: string) => void;
|
||||||
dataToExport?: Pick<FeatureSchema, 'name'>[];
|
dataToExport?: Pick<FeatureSchema, 'name'>[];
|
||||||
environmentsToExport?: string[];
|
environmentsToExport?: string[];
|
||||||
|
actions?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
|
const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
|
||||||
@ -43,6 +44,7 @@ export const ProjectFeatureTogglesHeader: VFC<
|
|||||||
onChangeSearchQuery,
|
onChangeSearchQuery,
|
||||||
dataToExport,
|
dataToExport,
|
||||||
environmentsToExport,
|
environmentsToExport,
|
||||||
|
actions,
|
||||||
}) => {
|
}) => {
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
const headerLoadingRef = useLoading(isLoading || false);
|
const headerLoadingRef = useLoading(isLoading || false);
|
||||||
@ -91,16 +93,7 @@ export const ProjectFeatureTogglesHeader: VFC<
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* FIXME: columns menu */}
|
{actions}
|
||||||
{/* <ColumnsMenu
|
|
||||||
allColumns={allColumns}
|
|
||||||
staticColumns={staticColumns}
|
|
||||||
dividerAfter={['createdAt']}
|
|
||||||
dividerBefore={['Actions']}
|
|
||||||
isCustomized={isCustomColumns}
|
|
||||||
setHiddenColumns={setHiddenColumns}
|
|
||||||
onCustomize={() => setIsCustomColumns(true)}
|
|
||||||
/> */}
|
|
||||||
<PageHeader.Divider sx={{ marginLeft: 0 }} />
|
<PageHeader.Divider sx={{ marginLeft: 0 }} />
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={featuresExportImportFlag}
|
condition={featuresExportImportFlag}
|
||||||
|
Loading…
Reference in New Issue
Block a user