Skip to content

Commit

Permalink
[DataGrid] Improve filters (#635)
Browse files Browse the repository at this point in the history
* added badge and toolti[

* refactor on filters and columns

* add disableMultipleColumnsFiltering

* fix double click on switch

* fix classname

* cleanup

* review

* public component

* fix toolbar style

* yarn prettier

* added icon column reorder

* fix transition in column menu

* fix scroll issue on doc

* Refactor panel, fix opening

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>
  • Loading branch information
dtassone and oliviertassinari authored Nov 25, 2020
1 parent 52d39e2 commit d523270
Show file tree
Hide file tree
Showing 30 changed files with 380 additions and 299 deletions.
4 changes: 2 additions & 2 deletions packages/grid/_modules_/grid/GridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { GridDataContainer } from './components/styled-wrappers/GridDataContaine
import { GridRoot } from './components/styled-wrappers/GridRoot';
import { GridWindow } from './components/styled-wrappers/GridWindow';
import { GridToolbar } from './components/styled-wrappers/GridToolbar';
import { ColumnsToolbarButton } from './components/toolbar/columnsToolbarButton';
import { FilterToolbarButton } from './components/toolbar/filterToolbarButton';
import { ColumnsToolbarButton } from './components/toolbar/ColumnsToolbarButton';
import { FilterToolbarButton } from './components/toolbar/FilterToolbarButton';
import { Viewport } from './components/viewport';
import { Watermark } from './components/watermark';
import { DATA_CONTAINER_CSS_CLASS } from './constants/cssClassesConstants';
Expand Down
5 changes: 5 additions & 0 deletions packages/grid/_modules_/grid/components/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@ export const LoadIcon = createSvgIcon(
<path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" />,
'Load',
);

export const DragIcon = createSvgIcon(
<path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />,
'Drag',
);
6 changes: 5 additions & 1 deletion packages/grid/_modules_/grid/components/menu/GridMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ClickAwayListener, Grow, MenuList, Paper, Popper } from '@material-ui/core';
import * as React from 'react';
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
import Grow from '@material-ui/core/Grow';
import MenuList from '@material-ui/core/MenuList';
import Paper from '@material-ui/core/Paper';
import Popper from '@material-ui/core/Popper';

export interface MenuProps {
open: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MenuItem } from '@material-ui/core';
import * as React from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import { useGridSelector } from '../../../hooks/features/core/useGridSelector';
import { optionsSelector } from '../../../hooks/utils/useOptionsProp';
import { ApiContext } from '../../api-context';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MenuItem } from '@material-ui/core';
import * as React from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import { ApiContext } from '../../api-context';
import { FilterItemProps } from './FilterItemProps';

Expand All @@ -14,5 +14,9 @@ export const HideColMenuItem: React.FC<FilterItemProps> = ({ column, onClick })
[apiRef, column?.field, onClick],
);

if (!column) {
return null;
}

return <MenuItem onClick={toggleColumn}>Hide</MenuItem>;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MenuItem } from '@material-ui/core';
import * as React from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import { useGridSelector } from '../../../hooks/features/core/useGridSelector';
import { sortModelSelector } from '../../../hooks/features/sorting/sortingSelector';
import { SortDirection } from '../../../models/sortModel';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ export const useStyles = makeStyles(
'& .MuiDataGrid-toolbar': {
display: 'flex',
alignItems: 'center',
minHeight: 35, // Match MUI Small Button height
backgroundColor: theme.palette.background.default,
border: `1px solid ${borderColor}`,
padding: 4,
},
'& .MuiDataGrid-columnsContainer': {
position: 'absolute',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IconButton } from '@material-ui/core';
import * as React from 'react';
import Button from '@material-ui/core/Button';
import { PreferencePanelsValue } from '../../hooks/features/preferencesPanel/preferencesPanelValue';
import { useIcons } from '../../hooks/utils/useIcons';
import { ApiContext } from '../api-context';
Expand All @@ -14,8 +14,13 @@ export const ColumnsToolbarButton: React.FC<{}> = () => {
}, [apiRef]);

return (
<IconButton onClick={showColumns} color="primary" aria-label="Show Column Selector">
{iconElement}
</IconButton>
<Button
onClick={showColumns}
color="primary"
aria-label="Show Column Selector"
startIcon={iconElement}
>
Columns
</Button>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import Badge from '@material-ui/core/Badge';
import Button from '@material-ui/core/Button';
import Tooltip from '@material-ui/core/Tooltip';
import * as React from 'react';
import { columnLookupSelector } from '../../hooks/features/columns/columnsSelector';
import { useGridSelector } from '../../hooks/features/core/useGridSelector';
import {
activeFilterItemsSelector,
filterItemsCounterSelector,
} from '../../hooks/features/filter/filterSelector';
import { useIcons } from '../../hooks/utils/useIcons';
import { optionsSelector } from '../../hooks/utils/useOptionsProp';
import { ApiContext } from '../api-context';

export const FilterToolbarButton: React.FC<{}> = () => {
const apiRef = React.useContext(ApiContext);
const options = useGridSelector(apiRef, optionsSelector);
const counter = useGridSelector(apiRef, filterItemsCounterSelector);
const activeFilters = useGridSelector(apiRef, activeFilterItemsSelector);
const lookup = useGridSelector(apiRef, columnLookupSelector);
const tooltipContentNode = React.useMemo(() => {
if (counter === 0) {
return 'Show Filters';
}
return (
<div>
{counter} active filter(s)
<ul>
{activeFilters.map((item) => (
<li key={item.id}>
{lookup[item.columnField!].headerName || item.columnField} {item.operatorValue}{' '}
{item.value}
</li>
))}
</ul>
</div>
);
}, [counter, activeFilters, lookup]);

const icons = useIcons();
const filterIconElement = React.createElement(icons.ColumnFiltering!, {});
const showFilter = React.useCallback(() => {
apiRef!.current.showFilterPanel();
}, [apiRef]);

if (options.disableColumnFilter) {
return null;
}

return (
<Tooltip title={tooltipContentNode} enterDelay={1000}>
<Button
onClick={showFilter}
color="primary"
aria-label="Show Filters"
startIcon={
<Badge badgeContent={counter} color="primary">
{filterIconElement}
</Badge>
}
>
Filters
</Button>
</Tooltip>
);
};

This file was deleted.

112 changes: 84 additions & 28 deletions packages/grid/_modules_/grid/components/tools/ColumnsPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
import * as React from 'react';
import FormControl from '@material-ui/core/FormControl';
import IconButton from '@material-ui/core/IconButton';
import Switch from '@material-ui/core/Switch';
import Button from '@material-ui/core/Button';
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import GridList from '@material-ui/core/GridList';
import ListItem from '@material-ui/core/ListItem';
import * as React from 'react';
import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';
import { allColumnsSelector } from '../../hooks/features/columns/columnsSelector';
import { useGridSelector } from '../../hooks/features/core/useGridSelector';
import { PREVENT_HIDE_PREFERENCES } from '../../constants/index';
import { optionsSelector } from '../../hooks/utils/useOptionsProp';
import { ApiContext } from '../api-context';
import { DragIcon } from '../icons/index';

const useStyles = makeStyles(() => ({
gridListRoot: {
maxWidth: '100%',
columnsListContainer: {
paddingTop: 8,
paddingLeft: 12,
},
column: {
display: 'flex',
justifyContent: 'space-between',
padding: '2px 4px',
},
switch: {
marginRight: 4,
},
dragIconRoot: {
justifyContent: 'flex-end',
},
}));

export const ColumnsPanel: React.FC<{}> = () => {
const classes = useStyles();

const apiRef = React.useContext(ApiContext);
const searchInputRef = React.useRef<HTMLInputElement>(null);
const columns = useGridSelector(apiRef, allColumnsSelector);

const dontHidePreferences = React.useCallback(
(event: React.ChangeEvent<{}>) => {
apiRef!.current.publishEvent(PREVENT_HIDE_PREFERENCES, {});
event.preventDefault();
},
[apiRef],
);
const { disableColumnReorder } = useGridSelector(apiRef, optionsSelector);
const [searchValue, setSearchValue] = React.useState('');

const toggleColumn = React.useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
dontHidePreferences(event);
apiRef!.current.toggleColumn(event.target.name, !event.target.checked);
(event: React.MouseEvent<HTMLButtonElement>) => {
const { name } = event.target as HTMLInputElement;
apiRef!.current.toggleColumn(name);
},
[apiRef, dontHidePreferences],
[apiRef],
);

const toggleAllColumns = React.useCallback(
Expand All @@ -52,28 +61,75 @@ export const ColumnsPanel: React.FC<{}> = () => {
const showAllColumns = React.useCallback(() => toggleAllColumns(false), [toggleAllColumns]);
const hideAllColumns = React.useCallback(() => toggleAllColumns(true), [toggleAllColumns]);

const onSearchColumnValueChange = React.useCallback((event) => {
setSearchValue(event.target.value.toLowerCase());
}, []);

const currentColumns = React.useMemo(
() =>
!searchValue
? columns
: columns.filter(
(column) =>
column.field.toLowerCase().indexOf(searchValue) > -1 ||
(column.headerName && column.headerName.toLowerCase().indexOf(searchValue) > -1),
),
[columns, searchValue],
);

React.useEffect(() => {
if (searchInputRef && searchInputRef.current) {
searchInputRef.current.focus();
}
});

return (
<React.Fragment>
<div className="panelMainContainer">
<GridList cellHeight={'auto'} className={classes.gridListRoot}>
{columns.map((column) => (
<ListItem key={column.field}>
<div className="MuiDataGridPanel-header">
<TextField
label="Find column"
placeholder="Column Title"
inputRef={searchInputRef}
value={searchValue}
onChange={onSearchColumnValueChange}
type="text"
fullWidth
/>
</div>
<div className="MuiDataGridPanel-container">
<div className={classes.columnsListContainer}>
{currentColumns.map((column) => (
<div key={column.field} className={classes.column}>
<FormControlLabel
control={
<Checkbox
<Switch
className={classes.switch}
checked={!column.hide}
onChange={toggleColumn}
onClick={toggleColumn}
name={column.field}
color="primary"
size="small"
/>
}
label={column.headerName || column.field}
/>
</ListItem>
{!disableColumnReorder && (
<FormControl draggable className={classes.dragIconRoot}>
<IconButton
aria-label="Drag to reorder column"
title="Reorder Column"
size="small"
disabled
>
<DragIcon />
</IconButton>
</FormControl>
)}
</div>
))}
</GridList>
</div>
</div>
<div className="panelFooter">
<div className="MuiDataGridPanel-footer">
<Button onClick={hideAllColumns} color="primary">
Hide All
</Button>
Expand Down
Loading

0 comments on commit d523270

Please sign in to comment.