From 8e6613f704de05dc1178b4208071ffa768257d01 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Sun, 15 Mar 2020 20:54:43 -0700 Subject: [PATCH 01/34] header menu boilerplate --- .../datagrid/_data_grid_header_row.scss | 9 +++ .../datagrid/data_grid_header_cell.tsx | 61 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/components/datagrid/_data_grid_header_row.scss b/src/components/datagrid/_data_grid_header_row.scss index 658ec05c6ae..09d1a09d56c 100644 --- a/src/components/datagrid/_data_grid_header_row.scss +++ b/src/components/datagrid/_data_grid_header_row.scss @@ -39,10 +39,19 @@ // We only truncate if the cell is not a control column. &:not(.euiDataGridHeaderCell--controlColumn) { + .euiDataGridHeaderCell__content { @include euiTextTruncate; overflow: hidden; white-space: nowrap; + flex-grow: 1; + } + + .euiDataGridHeaderCell__popover { + flex-grow: 0; + flex-basis: auto; + width: auto; + padding-left: $euiSizeXS; } } } diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 1b4995dd2c8..71ab0c6a9bd 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -11,6 +11,9 @@ import classnames from 'classnames'; import { EuiDataGridHeaderRowPropsSpecificProps } from './data_grid_header_row'; import { keyCodes } from '../../services'; import { EuiDataGridColumnResizer } from './data_grid_column_resizer'; +import { EuiPopover } from '../popover/popover'; +import { EuiListGroup } from '../list_group/list_group'; +import { EuiIcon } from '../icon/icon'; import { EuiScreenReaderOnly } from '../accessibility'; import tabbable from 'tabbable'; import { EuiDataGridColumn } from './data_grid_types'; @@ -90,6 +93,7 @@ export const EuiDataGridHeaderCell: FunctionComponent< const isFocused = focusedCell != null && focusedCell[0] === index && focusedCell[1] === -1; const [isCellEntered, setIsCellEntered] = useState(false); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); useEffect(() => { if (headerRef.current) { @@ -213,6 +217,47 @@ export const EuiDataGridHeaderCell: FunctionComponent< } }, [headerIsInteractive, isFocused, setIsCellEntered, setFocusedCell, index]); + console.log(schema); + + const columnOptions = [ + { + label: 'Hide column', + href: '#/display/list-group', + iconType: 'eyeClosed', + size: 'xs', + color: 'text', + }, + { + label: 'Sort schema asc', + href: '#/display/list-group', + isActive: true, + iconType: 'sortUp', + size: 'xs', + color: 'text', + }, + { + label: 'Sort schema desc', + href: '#/display/list-group', + iconType: 'sortDown', + size: 'xs', + color: 'text', + }, + { + label: 'Move left', + href: '#/display/list-group', + iconType: 'sortLeft', + size: 'xs', + color: 'text', + }, + { + label: 'Move right', + href: '#/display/list-group', + iconType: 'sortRight', + size: 'xs', + color: 'text', + }, + ]; + return (
{sortString}
)} + setIsPopoverOpen(true)}> + + + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)}> +
+ +
+
); }; From 674b4c770083b12a1a834d2577242a782326343a Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Mon, 20 Jul 2020 19:58:10 +0200 Subject: [PATCH 02/34] Enable column option "Hide column" --- .../__snapshots__/data_grid.test.tsx.snap | 112 ++++++++++++++++ src/components/datagrid/column_selector.tsx | 4 +- src/components/datagrid/data_grid.tsx | 20 ++- .../datagrid/data_grid_header_cell.tsx | 126 ++++++++++-------- .../datagrid/data_grid_header_row.tsx | 8 ++ 5 files changed, 207 insertions(+), 63 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 054fefd80b1..a5ebfad9015 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -302,6 +302,20 @@ Array [ > A +
+
+ +
+
B
+
+
+ +
+
A
+
+
+ +
+
B
+
+
+ +
+
Column A
+
+
+ +
+
+
+
+ +
+
A
+
+
+ +
+
B
+
+
+ +
+
{ +): [ReactElement, EuiDataGridColumn[], (columns: string[]) => void] => { const allowColumnHiding = getShowColumnSelectorValue( showColumnSelector, 'allowHide' @@ -280,5 +280,5 @@ export const useColumnSelector = ( [availableColumns, visibleColumns] ); - return [columnSelector, orderedVisibleColumns]; + return [columnSelector, orderedVisibleColumns, setVisibleColumns]; }; diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index ce5d1c6be35..2d4a32639e8 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -64,7 +64,10 @@ import { useColumnSelector } from './column_selector'; import { useStyleSelector, startingStyles } from './style_selector'; import { EuiTablePagination } from '../table/table_pagination'; import { EuiFocusTrap } from '../focus_trap'; -import { EuiResizeObserver } from '../observer/resize_observer'; +import { + EuiResizeObserver, + useResizeObserver, +} from '../observer/resize_observer'; import { EuiDataGridInMemoryRenderer } from './data_grid_inmemory_renderer'; import { useMergedSchema, @@ -75,7 +78,7 @@ import { import { useColumnSorting } from './column_sorting'; import { EuiMutationObserver } from '../observer/mutation_observer'; import { DataGridContext } from './data_grid_context'; -import { useResizeObserver } from '../observer/resize_observer/resize_observer'; +import { EuiListGroupItemProps } from '../list_group'; // Used to short-circuit some async browser behaviour that is difficult to account for in tests const IS_JEST_ENVIRONMENT = global.hasOwnProperty('_isJest'); @@ -101,6 +104,10 @@ type CommonGridProps = CommonProps & * An array of #EuiDataGridColumnVisibility objects. Defines which columns are visible in the grid and the order they are displayed. */ columnVisibility: EuiDataGridColumnVisibility; + /** + * An array of #EuiListGroupItemProps that can be used to overwrite the internally used columnOptions that provide functionality like moving columns left, right + */ + columnOptions?: EuiListGroupItemProps[]; /** * An array of custom #EuiDataGridSchemaDetector objects. You can inject custom schemas to the grid to define the classnames applied */ @@ -667,6 +674,7 @@ export const EuiDataGrid: FunctionComponent = props => { trailingControlColumns = emptyArrayDefault, columns, columnVisibility, + columnOptions, schemaDetectors, rowCount, renderCellValue, @@ -736,7 +744,11 @@ export const EuiDataGrid: FunctionComponent = props => { {} ); - const [columnSelector, orderedVisibleColumns] = useColumnSelector( + const [ + columnSelector, + orderedVisibleColumns, + setVisibleColumns, + ] = useColumnSelector( columns, columnVisibility, checkOrDefaultToolBarDiplayOptions(toolbarVisibility, 'showColumnSelector'), @@ -1013,10 +1025,12 @@ export const EuiDataGrid: FunctionComponent = props => { } columns={orderedVisibleColumns} columnWidths={columnWidths} + columnOptions={columnOptions} defaultColumnWidth={ defaultColumnWidth } setColumnWidth={setColumnWidth} + setVisibleColumns={setVisibleColumns} schema={mergedSchema} sorting={sorting} headerIsInteractive={ diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 28c58c7d68a..dc3d3da7077 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -37,11 +37,12 @@ import { EuiIcon } from '../icon/icon'; import { EuiScreenReaderOnly } from '../accessibility'; import tabbable from 'tabbable'; import { EuiDataGridColumn } from './data_grid_types'; +import { EuiListGroupItemProps } from '../list_group'; export interface EuiDataGridHeaderCellProps extends Omit< EuiDataGridHeaderRowPropsSpecificProps, - 'columns' | 'leadingControlColumns' + 'leadingControlColumns' > { column: EuiDataGridColumn; index: number; @@ -54,10 +55,13 @@ export const EuiDataGridHeaderCell: FunctionComponent< const { column, index, + columns, columnWidths, + columnOptions, schema, defaultColumnWidth, setColumnWidth, + setVisibleColumns, sorting, focusedCell, setFocusedCell, @@ -264,47 +268,51 @@ export const EuiDataGridHeaderCell: FunctionComponent< setFocusedCell, index, ]); - - console.log(schema); - - const columnOptions = [ - { - label: 'Hide column', - href: '#/display/list-group', - iconType: 'eyeClosed', - size: 'xs', - color: 'text', - }, - { - label: 'Sort schema asc', - href: '#/display/list-group', - isActive: true, - iconType: 'sortUp', - size: 'xs', - color: 'text', - }, - { - label: 'Sort schema desc', - href: '#/display/list-group', - iconType: 'sortDown', - size: 'xs', - color: 'text', - }, - { - label: 'Move left', - href: '#/display/list-group', - iconType: 'sortLeft', - size: 'xs', - color: 'text', - }, - { - label: 'Move right', - href: '#/display/list-group', - iconType: 'sortRight', - size: 'xs', - color: 'text', - }, - ]; + const usedColumnOptions = + columnOptions && columnOptions.length + ? columnOptions + : ([ + { + label: 'Hide column', + onClick: () => + setVisibleColumns( + columns.filter(col => col.id !== column.id).map(col => col.id) + ), + iconType: 'eyeClosed', + size: 'xs', + color: 'text', + }, + /** + { + label: 'Sort schema asc', + isActive: true, + iconType: 'sortUp', + size: 'xs', + color: 'text', + }, + { + label: 'Sort schema desc', + iconType: 'sortDown', + size: 'xs', + color: 'text', + }, + { + label: 'Move left', + iconType: 'sortLeft', + size: 'xs', + color: 'text', + onClick: () => + setVisibleColumns( + columns.filter(col => col.id !== column.id).map(col => col.id) + ), + }, + { + label: 'Move right', + iconType: 'sortRight', + size: 'xs', + color: 'text', + },**/ + ] as EuiListGroupItemProps[]); return (
{sortString}
)} - setIsPopoverOpen(true)}> - - - } - isOpen={isPopoverOpen} - closePopover={() => setIsPopoverOpen(false)}> -
- -
-
+ {usedColumnOptions && usedColumnOptions.length && ( + setIsPopoverOpen(true)}> + + + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)}> +
+ +
+
+ )}
); }; diff --git a/src/components/datagrid/data_grid_header_row.tsx b/src/components/datagrid/data_grid_header_row.tsx index 8457c1345d0..8fcaae4d48b 100644 --- a/src/components/datagrid/data_grid_header_row.tsx +++ b/src/components/datagrid/data_grid_header_row.tsx @@ -31,15 +31,18 @@ import { EuiDataGridSchema } from './data_grid_schema'; import { EuiDataGridDataRowProps } from './data_grid_data_row'; import { EuiDataGridHeaderCell } from './data_grid_header_cell'; import { EuiDataGridControlHeaderCell } from './data_grid_control_header_cell'; +import { EuiListGroupItemProps } from '../list_group'; export interface EuiDataGridHeaderRowPropsSpecificProps { leadingControlColumns?: EuiDataGridControlColumn[]; trailingControlColumns?: EuiDataGridControlColumn[]; columns: EuiDataGridColumn[]; columnWidths: EuiDataGridColumnWidths; + columnOptions?: EuiListGroupItemProps[]; schema: EuiDataGridSchema; defaultColumnWidth?: number | null; setColumnWidth: (columnId: string, width: number) => void; + setVisibleColumns: (columnId: string[]) => void; sorting?: EuiDataGridSorting; focusedCell?: EuiDataGridFocusedCell; setFocusedCell: EuiDataGridDataRowProps['onCellFocus']; @@ -60,9 +63,11 @@ const EuiDataGridHeaderRow = forwardRef< columns, schema, columnWidths, + columnOptions, defaultColumnWidth, className, setColumnWidth, + setVisibleColumns, sorting, focusedCell, setFocusedCell, @@ -96,12 +101,15 @@ const EuiDataGridHeaderRow = forwardRef< Date: Tue, 21 Jul 2020 08:44:39 +0200 Subject: [PATCH 03/34] Enable column options for sorting --- .../datagrid/data_grid_header_cell.tsx | 56 ++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index dc3d3da7077..8a266f3d4a2 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -31,13 +31,12 @@ import classnames from 'classnames'; import { EuiDataGridHeaderRowPropsSpecificProps } from './data_grid_header_row'; import { keys } from '../../services'; import { EuiDataGridColumnResizer } from './data_grid_column_resizer'; -import { EuiPopover } from '../popover/popover'; -import { EuiListGroup } from '../list_group/list_group'; -import { EuiIcon } from '../icon/icon'; +import { EuiPopover } from '../popover'; +import { EuiListGroup, EuiListGroupItemProps } from '../list_group'; +import { EuiIcon } from '../icon'; import { EuiScreenReaderOnly } from '../accessibility'; import tabbable from 'tabbable'; -import { EuiDataGridColumn } from './data_grid_types'; -import { EuiListGroupItemProps } from '../list_group'; +import { EuiDataGridColumn, EuiDataGridSorting } from './data_grid_types'; export interface EuiDataGridHeaderCellProps extends Omit< @@ -268,6 +267,33 @@ export const EuiDataGridHeaderCell: FunctionComponent< setFocusedCell, index, ]); + const sortingIdx = sorting + ? sorting.columns.findIndex(col => col.id === column.id) + : -1; + const sortBy = (direction: 'asc' | 'desc' = 'asc') => { + if (!sorting) return; + + const newSorting = + sortingIdx >= 0 + ? //replace existing entry + Object.values({ + ...sorting.columns, + [sortingIdx]: { + id: column.id, + direction: direction, + }, + }) + : //append entry + [ + ...sorting.columns, + { + id: column.id, + direction: direction, + }, + ]; + + sorting.onSort(newSorting as EuiDataGridSorting['columns']); + }; const usedColumnOptions = columnOptions && columnOptions.length ? columnOptions @@ -282,20 +308,36 @@ export const EuiDataGridHeaderCell: FunctionComponent< size: 'xs', color: 'text', }, - /** + { label: 'Sort schema asc', - isActive: true, + onClick: () => { + sortBy('asc'); + }, + isDisabled: !sorting || column.isSortable === false, + isActive: + sorting && + sortingIdx >= 0 && + sorting.columns[sortingIdx].direction === 'asc', iconType: 'sortUp', size: 'xs', color: 'text', }, { label: 'Sort schema desc', + onClick: () => { + sortBy('desc'); + }, + isDisabled: !sorting || column.isSortable === false, + isActive: + sorting && + sortingIdx >= 0 && + sorting.columns[sortingIdx].direction === 'desc', iconType: 'sortDown', size: 'xs', color: 'text', }, + /** { label: 'Move left', iconType: 'sortLeft', From d6be83ee31111220ec3dc1b8145a58fe7ebcb3ec Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 21 Jul 2020 09:15:41 +0200 Subject: [PATCH 04/34] Enable column options for moving columns left/right --- .../datagrid/data_grid_header_cell.tsx | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 8a266f3d4a2..345e8a6162f 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -294,6 +294,19 @@ export const EuiDataGridHeaderCell: FunctionComponent< sorting.onSort(newSorting as EuiDataGridSorting['columns']); }; + const changePosition = (moveFromIdx: number, moveToIdx: number) => { + const col1 = columns[moveFromIdx] as EuiDataGridColumn; + const col2 = columns[moveToIdx] as EuiDataGridColumn; + + const newColumns = Object.values({ + ...columns, + [moveFromIdx]: col2, + [moveToIdx]: col1, + }) as EuiDataGridColumn[]; + setVisibleColumns(newColumns.map(col => col.id)); + }; + const colIdx = columns.findIndex(col => col.id === column.id); + const usedColumnOptions = columnOptions && columnOptions.length ? columnOptions @@ -312,6 +325,7 @@ export const EuiDataGridHeaderCell: FunctionComponent< { label: 'Sort schema asc', onClick: () => { + setIsPopoverOpen(false); sortBy('asc'); }, isDisabled: !sorting || column.isSortable === false, @@ -326,6 +340,7 @@ export const EuiDataGridHeaderCell: FunctionComponent< { label: 'Sort schema desc', onClick: () => { + setIsPopoverOpen(false); sortBy('desc'); }, isDisabled: !sorting || column.isSortable === false, @@ -337,23 +352,28 @@ export const EuiDataGridHeaderCell: FunctionComponent< size: 'xs', color: 'text', }, - /** { label: 'Move left', iconType: 'sortLeft', size: 'xs', color: 'text', - onClick: () => - setVisibleColumns( - columns.filter(col => col.id !== column.id).map(col => col.id) - ), + onClick: () => { + setIsPopoverOpen(false); + changePosition(colIdx, colIdx - 1); + }, + isDisabled: colIdx === 0, }, { label: 'Move right', iconType: 'sortRight', size: 'xs', color: 'text', - },**/ + onClick: () => { + setIsPopoverOpen(false); + changePosition(colIdx, colIdx + 1); + }, + isDisabled: colIdx === columns.length - 1, + }, ] as EuiListGroupItemProps[]); return ( From 9ef37528c0ec17c315851a7354b800e6fec74a67 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 23 Jul 2020 07:03:46 +0200 Subject: [PATCH 05/34] Fix moving column left / right --- src/components/datagrid/column_selector.tsx | 32 +++++++++++++++++-- src/components/datagrid/data_grid.tsx | 2 ++ .../datagrid/data_grid_header_cell.tsx | 25 +++++++-------- .../datagrid/data_grid_header_row.tsx | 3 ++ 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/components/datagrid/column_selector.tsx b/src/components/datagrid/column_selector.tsx index 7efec4f5dae..5281a1caa4b 100644 --- a/src/components/datagrid/column_selector.tsx +++ b/src/components/datagrid/column_selector.tsx @@ -61,7 +61,12 @@ export const useColumnSelector = ( columnVisibility: EuiDataGridColumnVisibility, showColumnSelector: EuiDataGridToolBarVisibilityOptions['showColumnSelector'], displayValues: { [key: string]: string } -): [ReactElement, EuiDataGridColumn[], (columns: string[]) => void] => { +): [ + ReactElement, + EuiDataGridColumn[], + (columns: string[]) => void, + (colFrom: string, colTo: string) => void +] => { const allowColumnHiding = getShowColumnSelectorValue( showColumnSelector, 'allowHide' @@ -279,6 +284,29 @@ export const useColumnSelector = ( .filter(column => column != null), [availableColumns, visibleColumns] ); + /** + * Used for moving columns left/right, available in the headers actions menu + */ + const switchColumnPos = (fromColId: string, toColId: string) => { + const moveFromIdx = sortedColumns.indexOf(fromColId); + const moveToIdx = sortedColumns.indexOf(toColId); + + const nextSortedColumns = Object.values({ + ...sortedColumns, + [moveFromIdx]: toColId, + [moveToIdx]: fromColId, + }) as string[]; + setSortedColumns(nextSortedColumns); + const nextVisibleColumns = nextSortedColumns.filter(columnId => + visibleColumnIds.has(columnId) + ); + setVisibleColumns(nextVisibleColumns); + }; - return [columnSelector, orderedVisibleColumns, setVisibleColumns]; + return [ + columnSelector, + orderedVisibleColumns, + setVisibleColumns, + switchColumnPos, + ]; }; diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index 2d4a32639e8..a36b2f2a297 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -748,6 +748,7 @@ export const EuiDataGrid: FunctionComponent = props => { columnSelector, orderedVisibleColumns, setVisibleColumns, + switchColumnPos, ] = useColumnSelector( columns, columnVisibility, @@ -1031,6 +1032,7 @@ export const EuiDataGrid: FunctionComponent = props => { } setColumnWidth={setColumnWidth} setVisibleColumns={setVisibleColumns} + switchColumnPos={switchColumnPos} schema={mergedSchema} sorting={sorting} headerIsInteractive={ diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 345e8a6162f..3b38a6fa24f 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -61,6 +61,7 @@ export const EuiDataGridHeaderCell: FunctionComponent< defaultColumnWidth, setColumnWidth, setVisibleColumns, + switchColumnPos, sorting, focusedCell, setFocusedCell, @@ -132,9 +133,9 @@ export const EuiDataGridHeaderCell: FunctionComponent< const disableInteractives = useCallback(() => { if (headerRef.current) { const tababbles = tabbable(headerRef.current); - if (tababbles.length > 1) { + if (tababbles.length > 2) { console.warn( - `EuiDataGridHeaderCell expects at most 1 tabbable element, ${ + `EuiDataGridHeaderCell expects at most 2 tabbable element, ${ tababbles.length } found instead` ); @@ -294,17 +295,7 @@ export const EuiDataGridHeaderCell: FunctionComponent< sorting.onSort(newSorting as EuiDataGridSorting['columns']); }; - const changePosition = (moveFromIdx: number, moveToIdx: number) => { - const col1 = columns[moveFromIdx] as EuiDataGridColumn; - const col2 = columns[moveToIdx] as EuiDataGridColumn; - const newColumns = Object.values({ - ...columns, - [moveFromIdx]: col2, - [moveToIdx]: col1, - }) as EuiDataGridColumn[]; - setVisibleColumns(newColumns.map(col => col.id)); - }; const colIdx = columns.findIndex(col => col.id === column.id); const usedColumnOptions = @@ -359,7 +350,10 @@ export const EuiDataGridHeaderCell: FunctionComponent< color: 'text', onClick: () => { setIsPopoverOpen(false); - changePosition(colIdx, colIdx - 1); + const targetCol = columns[colIdx - 1]; + if (targetCol) { + switchColumnPos(column.id, targetCol.id); + } }, isDisabled: colIdx === 0, }, @@ -370,7 +364,10 @@ export const EuiDataGridHeaderCell: FunctionComponent< color: 'text', onClick: () => { setIsPopoverOpen(false); - changePosition(colIdx, colIdx + 1); + const targetCol = columns[colIdx + 1]; + if (targetCol) { + switchColumnPos(column.id, targetCol.id); + } }, isDisabled: colIdx === columns.length - 1, }, diff --git a/src/components/datagrid/data_grid_header_row.tsx b/src/components/datagrid/data_grid_header_row.tsx index 8fcaae4d48b..9d57426c996 100644 --- a/src/components/datagrid/data_grid_header_row.tsx +++ b/src/components/datagrid/data_grid_header_row.tsx @@ -43,6 +43,7 @@ export interface EuiDataGridHeaderRowPropsSpecificProps { defaultColumnWidth?: number | null; setColumnWidth: (columnId: string, width: number) => void; setVisibleColumns: (columnId: string[]) => void; + switchColumnPos: (colFromId: string, colToId: string) => void; sorting?: EuiDataGridSorting; focusedCell?: EuiDataGridFocusedCell; setFocusedCell: EuiDataGridDataRowProps['onCellFocus']; @@ -68,6 +69,7 @@ const EuiDataGridHeaderRow = forwardRef< className, setColumnWidth, setVisibleColumns, + switchColumnPos, sorting, focusedCell, setFocusedCell, @@ -110,6 +112,7 @@ const EuiDataGridHeaderRow = forwardRef< schema={schema} setColumnWidth={setColumnWidth} setVisibleColumns={setVisibleColumns} + switchColumnPos={switchColumnPos} defaultColumnWidth={defaultColumnWidth} sorting={sorting} headerIsInteractive={headerIsInteractive} From 1527ccac22c6b6e531b9b6e246661fe2679d8b9f Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 6 Aug 2020 15:18:05 +0200 Subject: [PATCH 06/34] Fix header row detection, migrate to use EuiButtonIcon --- .../__snapshots__/data_grid.test.tsx.snap | 64 ++++++++++++++++--- src/components/datagrid/data_grid.tsx | 19 +++--- .../datagrid/data_grid_header_cell.tsx | 46 ++++++++++--- 3 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index a5ebfad9015..339abb4f85b 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -309,8 +309,14 @@ Array [
- @@ -341,8 +347,14 @@ Array [
- @@ -889,8 +901,14 @@ Array [
- @@ -921,8 +939,14 @@ Array [
- @@ -1760,8 +1784,14 @@ Array [
- @@ -1794,8 +1824,14 @@ Array [
- @@ -2324,8 +2360,14 @@ Array [
- @@ -2356,8 +2398,14 @@ Array [
- diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index f6cb0552a69..6dbddf539ea 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -638,14 +638,17 @@ export const EuiDataGrid: FunctionComponent = props => { const [{ target }] = records; // find the wrapping header div - let headerRow = target.parentElement; - while ( - headerRow && - (headerRow.getAttribute('data-test-subj') || '').indexOf( - 'dataGridHeader' - ) === -1 - ) { - headerRow = headerRow.parentElement; + let headerRow = null; + let currentRow = target.parentElement; + while (!headerRow && currentRow) { + if ( + currentRow && + currentRow.getAttribute('data-test-subj') === 'dataGridHeader' + ) { + headerRow = currentRow; + } else { + currentRow = currentRow.parentElement; + } } if (headerRow) { diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index beac0f73d87..2b0c7622f39 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -33,10 +33,11 @@ import { keys } from '../../services'; import { EuiDataGridColumnResizer } from './data_grid_column_resizer'; import { EuiPopover } from '../popover'; import { EuiListGroup, EuiListGroupItemProps } from '../list_group'; -import { EuiIcon } from '../icon'; import { EuiScreenReaderOnly } from '../accessibility'; import tabbable from 'tabbable'; import { EuiDataGridColumn, EuiDataGridSorting } from './data_grid_types'; +import { EuiButtonIcon } from '../button/button_icon'; +import { EuiI18n } from '../i18n'; export interface EuiDataGridHeaderCellProps extends Omit< @@ -299,7 +300,12 @@ export const EuiDataGridHeaderCell: FunctionComponent + ), onClick: () => setVisibleColumns( columns.filter(col => col.id !== column.id).map(col => col.id) @@ -310,7 +316,12 @@ export const EuiDataGridHeaderCell: FunctionComponent + ), onClick: () => { setIsPopoverOpen(false); sortBy('asc'); @@ -325,7 +336,12 @@ export const EuiDataGridHeaderCell: FunctionComponent + ), onClick: () => { setIsPopoverOpen(false); sortBy('desc'); @@ -340,7 +356,12 @@ export const EuiDataGridHeaderCell: FunctionComponent + ), iconType: 'sortLeft', size: 'xs', color: 'text', @@ -354,7 +375,12 @@ export const EuiDataGridHeaderCell: FunctionComponent + ), iconType: 'sortRight', size: 'xs', color: 'text', @@ -399,9 +425,11 @@ export const EuiDataGridHeaderCell: FunctionComponent setIsPopoverOpen(true)}> - - + setIsPopoverOpen(true)} + iconType="arrowDown" + aria-label={'Header actions'} + /> } isOpen={isPopoverOpen} closePopover={() => setIsPopoverOpen(false)}> From 75eff282b4d4bdf5824d58bb5e0299f0d42b58a4 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Sat, 22 Aug 2020 11:46:27 +0200 Subject: [PATCH 07/34] Make column actions configureable --- src-docs/src/views/datagrid/datagrid.js | 14 ++ src/components/datagrid/column_actions.tsx | 195 ++++++++++++++++++ src/components/datagrid/data_grid.tsx | 7 - .../datagrid/data_grid_header_cell.tsx | 151 ++------------ .../datagrid/data_grid_header_row.tsx | 4 - src/components/datagrid/data_grid_types.ts | 14 ++ 6 files changed, 238 insertions(+), 147 deletions(-) create mode 100644 src/components/datagrid/column_actions.tsx diff --git a/src-docs/src/views/datagrid/datagrid.js b/src-docs/src/views/datagrid/datagrid.js index 7064f0fa65e..1ff3df1214f 100644 --- a/src-docs/src/views/datagrid/datagrid.js +++ b/src-docs/src/views/datagrid/datagrid.js @@ -48,6 +48,20 @@ const columns = [ }, { id: 'account', + actions: { + showHide: { label: 'Custom hide label' }, + showMoveLeft: false, + showMoveRight: false, + additional: [ + { + label: 'Custom action', + onClick: () => alert('🎉'), + iconType: 'cheer', + size: 'xs', + color: 'text', + }, + ], + }, }, { id: 'date', diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx new file mode 100644 index 00000000000..b9270884be5 --- /dev/null +++ b/src/components/datagrid/column_actions.tsx @@ -0,0 +1,195 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { EuiDataGridColumn, EuiDataGridSorting } from './data_grid_types'; +import { EuiI18n } from '../i18n'; +import { EuiListGroupItemProps } from '../list_group'; +import React from 'react'; + +export function getColumnActions( + column: EuiDataGridColumn, + columns: EuiDataGridColumn[], + setVisibleColumns: (columnId: string[]) => void, + setIsPopoverOpen: (value: boolean) => void, + sorting: EuiDataGridSorting | undefined, + switchColumnPos: (colFromId: string, colToId: string) => void +) { + if (column.actions === false) { + return []; + } + const colIdx = columns.findIndex(col => col.id === column.id); + const sortingIdx = sorting + ? sorting.columns.findIndex(col => col.id === column.id) + : -1; + const sortBy = (direction: 'asc' | 'desc' = 'asc') => { + if (!sorting) { + return; + } + + const newSorting = + sortingIdx >= 0 + ? //replace existing entry + Object.values({ + ...sorting.columns, + [sortingIdx]: { + id: column.id, + direction: direction, + }, + }) + : //append entry + [ + ...sorting.columns, + { + id: column.id, + direction: direction, + }, + ]; + + sorting.onSort(newSorting as EuiDataGridSorting['columns']); + }; + const onClickHideColumn = () => + setVisibleColumns( + columns.filter(col => col.id !== column.id).map(col => col.id) + ); + + const onClickSortAsc = () => { + setIsPopoverOpen(false); + sortBy('asc'); + }; + + const onClickSortDesc = () => { + setIsPopoverOpen(false); + sortBy('desc'); + }; + + const onClickMoveLeft = () => { + setIsPopoverOpen(false); + const targetCol = columns[colIdx - 1]; + if (targetCol) { + switchColumnPos(column.id, targetCol.id); + } + }; + + const onClickMoveRight = () => { + setIsPopoverOpen(false); + const targetCol = columns[colIdx + 1]; + if (targetCol) { + switchColumnPos(column.id, targetCol.id); + } + }; + + const result = []; + if (column.actions?.showHide !== false) { + const option = { + label: ( + + ), + onClick: onClickHideColumn, + iconType: 'eyeClosed', + size: 'xs', + color: 'text', + }; + if (typeof column.actions?.showHide === 'object') { + result.push({ ...option, ...column.actions?.showHide }); + } else { + result.push(option); + } + } + + if (column.actions?.showSortAsc !== false && sorting) { + const option = { + label: ( + + ), + onClick: onClickSortAsc, + isDisabled: column.isSortable === false, + isActive: + sortingIdx >= 0 && sorting.columns[sortingIdx].direction === 'asc', + iconType: 'sortUp', + size: 'xs', + color: 'text', + }; + if (typeof column.actions?.showSortAsc === 'object') { + result.push({ ...option, ...column.actions?.showSortAsc }); + } else { + result.push(option); + } + } + + if (column.actions?.showSortDesc !== false && sorting) { + const option = { + label: ( + + ), + onClick: onClickSortDesc, + isDisabled: column.isSortable === false, + isActive: + sortingIdx >= 0 && sorting.columns[sortingIdx].direction === 'desc', + iconType: 'sortDown', + size: 'xs', + color: 'text', + }; + if (typeof column.actions?.showSortDesc === 'object') { + result.push({ ...option, ...column.actions?.showSortDesc }); + } else { + result.push(option); + } + } + + if (column.actions?.showMoveLeft !== false) { + const option = { + label: , + iconType: 'sortLeft', + size: 'xs', + color: 'text', + onClick: onClickMoveLeft, + isDisabled: colIdx === 0, + }; + if (typeof column.actions?.showMoveLeft === 'object') { + result.push({ ...option, ...column.actions?.showMoveLeft }); + } else { + result.push(option); + } + } + + if (column.actions?.showMoveRight !== false) { + const option = { + label: ( + + ), + iconType: 'sortRight', + size: 'xs', + color: 'text', + onClick: onClickMoveRight, + isDisabled: colIdx === columns.length - 1, + }; + if (typeof column.actions?.showMoveRight === 'object') { + result.push({ ...option, ...column.actions?.showMoveRight }); + } else { + result.push(option); + } + } + if (column.actions?.additional) { + return [ + ...result, + ...column.actions?.additional, + ] as EuiListGroupItemProps[]; + } + return result as EuiListGroupItemProps[]; +} diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index 8ca14c22f7e..1a3ea61a79a 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -78,7 +78,6 @@ import { import { useColumnSorting } from './column_sorting'; import { EuiMutationObserver } from '../observer/mutation_observer'; import { DataGridContext } from './data_grid_context'; -import { EuiListGroupItemProps } from '../list_group'; // Used to short-circuit some async browser behaviour that is difficult to account for in tests const IS_JEST_ENVIRONMENT = global.hasOwnProperty('_isJest'); @@ -104,10 +103,6 @@ type CommonGridProps = CommonProps & * An array of #EuiDataGridColumnVisibility objects. Defines which columns are visible in the grid and the order they are displayed. */ columnVisibility: EuiDataGridColumnVisibility; - /** - * An array of #EuiListGroupItemProps that can be used to overwrite the internally used columnOptions that provide functionality like moving columns left, right - */ - columnOptions?: EuiListGroupItemProps[]; /** * An array of custom #EuiDataGridSchemaDetector objects. You can inject custom schemas to the grid to define the classnames applied */ @@ -691,7 +686,6 @@ export const EuiDataGrid: FunctionComponent = props => { trailingControlColumns = emptyArrayDefault, columns, columnVisibility, - columnOptions, schemaDetectors, rowCount, renderCellValue, @@ -1039,7 +1033,6 @@ export const EuiDataGrid: FunctionComponent = props => { } columns={orderedVisibleColumns} columnWidths={columnWidths} - columnOptions={columnOptions} defaultColumnWidth={ defaultColumnWidth } diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 2b0c7622f39..5d2cd7579b5 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -32,12 +32,12 @@ import { EuiDataGridHeaderRowPropsSpecificProps } from './data_grid_header_row'; import { keys } from '../../services'; import { EuiDataGridColumnResizer } from './data_grid_column_resizer'; import { EuiPopover } from '../popover'; -import { EuiListGroup, EuiListGroupItemProps } from '../list_group'; +import { EuiListGroup } from '../list_group'; import { EuiScreenReaderOnly } from '../accessibility'; import tabbable from 'tabbable'; -import { EuiDataGridColumn, EuiDataGridSorting } from './data_grid_types'; +import { EuiDataGridColumn } from './data_grid_types'; import { EuiButtonIcon } from '../button/button_icon'; -import { EuiI18n } from '../i18n'; +import { getColumnActions } from './column_actions'; export interface EuiDataGridHeaderCellProps extends Omit< @@ -55,7 +55,6 @@ export const EuiDataGridHeaderCell: FunctionComponent headerRef.current!.blur()); e.preventDefault(); @@ -208,7 +207,7 @@ export const EuiDataGridHeaderCell: FunctionComponent { if (headerRef.current) { - if (headerRef.current.contains(document.activeElement) === false) { + if (!headerRef.current.contains(document.activeElement)) { setIsCellEntered(false); } } @@ -265,135 +264,15 @@ export const EuiDataGridHeaderCell: FunctionComponent col.id === column.id) - : -1; - const sortBy = (direction: 'asc' | 'desc' = 'asc') => { - if (!sorting) return; - const newSorting = - sortingIdx >= 0 - ? //replace existing entry - Object.values({ - ...sorting.columns, - [sortingIdx]: { - id: column.id, - direction: direction, - }, - }) - : //append entry - [ - ...sorting.columns, - { - id: column.id, - direction: direction, - }, - ]; - - sorting.onSort(newSorting as EuiDataGridSorting['columns']); - }; - - const colIdx = columns.findIndex(col => col.id === column.id); - - const usedColumnOptions = - columnOptions && columnOptions.length - ? columnOptions - : ([ - { - label: ( - - ), - onClick: () => - setVisibleColumns( - columns.filter(col => col.id !== column.id).map(col => col.id) - ), - iconType: 'eyeClosed', - size: 'xs', - color: 'text', - }, - - { - label: ( - - ), - onClick: () => { - setIsPopoverOpen(false); - sortBy('asc'); - }, - isDisabled: !sorting || column.isSortable === false, - isActive: - sorting && - sortingIdx >= 0 && - sorting.columns[sortingIdx].direction === 'asc', - iconType: 'sortUp', - size: 'xs', - color: 'text', - }, - { - label: ( - - ), - onClick: () => { - setIsPopoverOpen(false); - sortBy('desc'); - }, - isDisabled: !sorting || column.isSortable === false, - isActive: - sorting && - sortingIdx >= 0 && - sorting.columns[sortingIdx].direction === 'desc', - iconType: 'sortDown', - size: 'xs', - color: 'text', - }, - { - label: ( - - ), - iconType: 'sortLeft', - size: 'xs', - color: 'text', - onClick: () => { - setIsPopoverOpen(false); - const targetCol = columns[colIdx - 1]; - if (targetCol) { - switchColumnPos(column.id, targetCol.id); - } - }, - isDisabled: colIdx === 0, - }, - { - label: ( - - ), - iconType: 'sortRight', - size: 'xs', - color: 'text', - onClick: () => { - setIsPopoverOpen(false); - const targetCol = columns[colIdx + 1]; - if (targetCol) { - switchColumnPos(column.id, targetCol.id); - } - }, - isDisabled: colIdx === columns.length - 1, - }, - ] as EuiListGroupItemProps[]); + const columnOptions = getColumnActions( + column, + columns, + setVisibleColumns, + setIsPopoverOpen, + sorting, + switchColumnPos + ); return (
{sortString}
)} - {usedColumnOptions && usedColumnOptions.length && ( + {columnOptions && columnOptions.length && ( setIsPopoverOpen(false)}>
- +
)} diff --git a/src/components/datagrid/data_grid_header_row.tsx b/src/components/datagrid/data_grid_header_row.tsx index 9d57426c996..1d393558840 100644 --- a/src/components/datagrid/data_grid_header_row.tsx +++ b/src/components/datagrid/data_grid_header_row.tsx @@ -31,14 +31,12 @@ import { EuiDataGridSchema } from './data_grid_schema'; import { EuiDataGridDataRowProps } from './data_grid_data_row'; import { EuiDataGridHeaderCell } from './data_grid_header_cell'; import { EuiDataGridControlHeaderCell } from './data_grid_control_header_cell'; -import { EuiListGroupItemProps } from '../list_group'; export interface EuiDataGridHeaderRowPropsSpecificProps { leadingControlColumns?: EuiDataGridControlColumn[]; trailingControlColumns?: EuiDataGridControlColumn[]; columns: EuiDataGridColumn[]; columnWidths: EuiDataGridColumnWidths; - columnOptions?: EuiListGroupItemProps[]; schema: EuiDataGridSchema; defaultColumnWidth?: number | null; setColumnWidth: (columnId: string, width: number) => void; @@ -64,7 +62,6 @@ const EuiDataGridHeaderRow = forwardRef< columns, schema, columnWidths, - columnOptions, defaultColumnWidth, className, setColumnWidth, @@ -106,7 +103,6 @@ const EuiDataGridHeaderRow = forwardRef< columns={columns} index={index + leadingControlColumns.length} columnWidths={columnWidths} - columnOptions={columnOptions} focusedCell={focusedCell} setFocusedCell={setFocusedCell} schema={schema} diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 4c2a74e431d..913a1dcbf9c 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -19,6 +19,7 @@ import { ComponentType, ReactNode } from 'react'; import { EuiDataGridCellProps } from './data_grid_cell'; +import { EuiListGroupItemProps } from '../list_group'; export interface EuiDataGridControlColumn { /** @@ -76,6 +77,19 @@ export interface EuiDataGridColumn { * Display name as text for column. This can be used to display column name in column selector and column sorting where `display` won't be used. If not used `id` will be shown as column name in column selector and column sorting. */ displayAsText?: string; + /** + * Configuration of column actions. + */ + actions?: false | EuiDataGridColumnActions; +} + +export interface EuiDataGridColumnActions { + showHide?: boolean | EuiListGroupItemProps; + showMoveLeft?: boolean | EuiListGroupItemProps; + showMoveRight?: boolean | EuiListGroupItemProps; + showSortAsc?: boolean | EuiListGroupItemProps; + showSortDesc?: boolean | EuiListGroupItemProps; + additional?: EuiListGroupItemProps[]; } export interface EuiDataGridColumnVisibility { From 39eef30935fa737c4118d338b9aabf6507d316ac Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Mon, 24 Aug 2020 11:40:36 +0200 Subject: [PATCH 08/34] Document types --- src/components/datagrid/data_grid_types.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 913a1dcbf9c..cc11c76c398 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -78,17 +78,35 @@ export interface EuiDataGridColumn { */ displayAsText?: string; /** - * Configuration of column actions. + * Configuration of column actions. Can be used to disable or configure the actions displayed in the header column */ actions?: false | EuiDataGridColumnActions; } export interface EuiDataGridColumnActions { + /** + * Configure the action to hide a column, provided EuiListGroupItemProps are merged + */ showHide?: boolean | EuiListGroupItemProps; + /** + * Configure the action that switches the actual column with the column to the left side, provided EuiListGroupItemProps are merged + */ showMoveLeft?: boolean | EuiListGroupItemProps; + /** + * Configure the action that switches the actual column with the column to the right side, provided EuiListGroupItemProps are merged + */ showMoveRight?: boolean | EuiListGroupItemProps; + /** + * Configure the action to sort ascending by the actual column, provided EuiListGroupItemProps are merged + */ showSortAsc?: boolean | EuiListGroupItemProps; + /** + * Configure the action to sort ascending by the actual column, provided EuiListGroupItemProps are merged + */ showSortDesc?: boolean | EuiListGroupItemProps; + /** + * Append additional actions + */ additional?: EuiListGroupItemProps[]; } From 23f741414cd0b8deaafe1293e5cc2c14a841e3ee Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Mon, 24 Aug 2020 11:45:29 +0200 Subject: [PATCH 09/34] Fix tests --- .../__snapshots__/data_grid.test.tsx.snap | 16 ++++++++-------- .../datagrid/data_grid_header_cell.tsx | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 10bcdcdcc0f..839eded4d21 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -305,7 +305,7 @@ Array [
`Sorted by ${col.id} ${col.direction}`) .join(' then '); - screenReaderId = htmlIdGenerator()(); ariaProps['aria-describedby'] = screenReaderId; } } @@ -311,7 +310,8 @@ export const EuiDataGridHeaderCell: FunctionComponent } isOpen={isPopoverOpen} - closePopover={() => setIsPopoverOpen(false)}> + closePopover={() => setIsPopoverOpen(false)} + ownFocus>
From 805105bb4ddf0ba0e71c89a64f10e8071cebeece Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 07:50:04 +0200 Subject: [PATCH 10/34] Improve columns_actions.tsx types --- src/components/datagrid/column_actions.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index b9270884be5..6a9a1519142 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -94,7 +94,7 @@ export function getColumnActions( } }; - const result = []; + const result: EuiListGroupItemProps[] = []; if (column.actions?.showHide !== false) { const option = { label: ( @@ -104,7 +104,7 @@ export function getColumnActions( iconType: 'eyeClosed', size: 'xs', color: 'text', - }; + } as EuiListGroupItemProps; if (typeof column.actions?.showHide === 'object') { result.push({ ...option, ...column.actions?.showHide }); } else { @@ -124,7 +124,7 @@ export function getColumnActions( iconType: 'sortUp', size: 'xs', color: 'text', - }; + } as EuiListGroupItemProps; if (typeof column.actions?.showSortAsc === 'object') { result.push({ ...option, ...column.actions?.showSortAsc }); } else { @@ -144,7 +144,7 @@ export function getColumnActions( iconType: 'sortDown', size: 'xs', color: 'text', - }; + } as EuiListGroupItemProps; if (typeof column.actions?.showSortDesc === 'object') { result.push({ ...option, ...column.actions?.showSortDesc }); } else { @@ -160,7 +160,7 @@ export function getColumnActions( color: 'text', onClick: onClickMoveLeft, isDisabled: colIdx === 0, - }; + } as EuiListGroupItemProps; if (typeof column.actions?.showMoveLeft === 'object') { result.push({ ...option, ...column.actions?.showMoveLeft }); } else { @@ -178,7 +178,7 @@ export function getColumnActions( color: 'text', onClick: onClickMoveRight, isDisabled: colIdx === columns.length - 1, - }; + } as EuiListGroupItemProps; if (typeof column.actions?.showMoveRight === 'object') { result.push({ ...option, ...column.actions?.showMoveRight }); } else { @@ -191,5 +191,5 @@ export function getColumnActions( ...column.actions?.additional, ] as EuiListGroupItemProps[]; } - return result as EuiListGroupItemProps[]; + return result; } From 319058b1a93dadbcdeee4a9c2de0f8a34714d3fa Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 07:51:06 +0200 Subject: [PATCH 11/34] Update src/components/datagrid/column_actions.tsx Co-authored-by: Chandler Prall --- src/components/datagrid/column_actions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index b9270884be5..7a3ff773214 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -180,7 +180,7 @@ export function getColumnActions( isDisabled: colIdx === columns.length - 1, }; if (typeof column.actions?.showMoveRight === 'object') { - result.push({ ...option, ...column.actions?.showMoveRight }); + result.push({ ...option, ...column.actions.showMoveRight }); } else { result.push(option); } From fba5db381a24d30d6e4b92a0340d8c375937d272 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 07:51:23 +0200 Subject: [PATCH 12/34] Update src/components/datagrid/column_actions.tsx Co-authored-by: Chandler Prall --- src/components/datagrid/column_actions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index 7a3ff773214..506b1091c62 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -162,7 +162,7 @@ export function getColumnActions( isDisabled: colIdx === 0, }; if (typeof column.actions?.showMoveLeft === 'object') { - result.push({ ...option, ...column.actions?.showMoveLeft }); + result.push({ ...option, ...column.actions.showMoveLeft }); } else { result.push(option); } From 6e7a37c62b97e7597ba5b59468d89bcdd0f969cf Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 08:01:09 +0200 Subject: [PATCH 13/34] Add header action label i18n --- src/components/datagrid/data_grid_header_cell.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 22551f5cd85..f4a7a6ce626 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -38,6 +38,7 @@ import tabbable from 'tabbable'; import { EuiDataGridColumn } from './data_grid_types'; import { EuiButtonIcon } from '../button/button_icon'; import { getColumnActions } from './column_actions'; +import { useEuiI18n } from '../i18n'; export interface EuiDataGridHeaderCellProps extends Omit< @@ -77,6 +78,10 @@ export const EuiDataGridHeaderCell: FunctionComponent id)); @@ -306,7 +311,7 @@ export const EuiDataGridHeaderCell: FunctionComponent setIsPopoverOpen(true)} iconType="arrowDown" - aria-label={'Header actions'} + aria-label={actionButtonAriaLabel} /> } isOpen={isPopoverOpen} From 324b6c0ec59bd77073e67e290fd562620eee4cde Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 09:33:30 +0200 Subject: [PATCH 14/34] Undo header interactives detection --- src/components/datagrid/data_grid.tsx | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index 1a3ea61a79a..e143d72f1d8 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -633,17 +633,14 @@ export const EuiDataGrid: FunctionComponent = props => { const [{ target }] = records; // find the wrapping header div - let headerRow = null; - let currentRow = target.parentElement; - while (!headerRow && currentRow) { - if ( - currentRow && - currentRow.getAttribute('data-test-subj') === 'dataGridHeader' - ) { - headerRow = currentRow; - } else { - currentRow = currentRow.parentElement; - } + let headerRow = target.parentElement; + while ( + headerRow && + (headerRow.getAttribute('data-test-subj') || '').indexOf( + 'dataGridHeader' + ) === -1 + ) { + headerRow = headerRow.parentElement; } if (headerRow) { From 54f7dc775701ead885aa408fe512b09c88a9c215 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 09:49:01 +0200 Subject: [PATCH 15/34] Extract logic of columns selector into helper function - to prevent logic diverging --- src/components/datagrid/column_selector.tsx | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/datagrid/column_selector.tsx b/src/components/datagrid/column_selector.tsx index 5281a1caa4b..270e21dfeb8 100644 --- a/src/components/datagrid/column_selector.tsx +++ b/src/components/datagrid/column_selector.tsx @@ -86,6 +86,15 @@ export const useColumnSelector = ( const [isOpen, setIsOpen] = useState(false); + function setColumns(nextColumns: string[]) { + setSortedColumns(nextColumns); + + const nextVisibleColumns = nextColumns.filter(id => + visibleColumnIds.has(id) + ); + setVisibleColumns(nextVisibleColumns); + } + function onDragEnd({ source: { index: sourceIndex }, destination, @@ -96,12 +105,7 @@ export const useColumnSelector = ( sourceIndex, destinationIndex ); - setSortedColumns(nextSortedColumns); - - const nextVisibleColumns = nextSortedColumns.filter(id => - visibleColumnIds.has(id) - ); - setVisibleColumns(nextVisibleColumns); + setColumns(nextSortedColumns); } const numberOfHiddenFields = availableColumns.length - visibleColumns.length; @@ -296,11 +300,7 @@ export const useColumnSelector = ( [moveFromIdx]: toColId, [moveToIdx]: fromColId, }) as string[]; - setSortedColumns(nextSortedColumns); - const nextVisibleColumns = nextSortedColumns.filter(columnId => - visibleColumnIds.has(columnId) - ); - setVisibleColumns(nextVisibleColumns); + setColumns(nextSortedColumns); }; return [ From 9ab3b6c148aa764e2c03776e6f8c7131d5e56e7e Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 10:17:00 +0200 Subject: [PATCH 16/34] Remove EuiPopover id since it's not used --- .../datagrid/__snapshots__/data_grid.test.tsx.snap | 8 -------- src/components/datagrid/data_grid_header_cell.tsx | 1 - 2 files changed, 9 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 839eded4d21..ea554f21fc8 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -305,7 +305,6 @@ Array [
Date: Thu, 27 Aug 2020 10:24:21 +0200 Subject: [PATCH 17/34] Prevent displaying 0 when column actions are set to false --- src-docs/src/views/datagrid/datagrid.js | 1 + src/components/datagrid/data_grid_header_cell.tsx | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src-docs/src/views/datagrid/datagrid.js b/src-docs/src/views/datagrid/datagrid.js index 1ff3df1214f..435772b5981 100644 --- a/src-docs/src/views/datagrid/datagrid.js +++ b/src-docs/src/views/datagrid/datagrid.js @@ -79,6 +79,7 @@ const columns = [ defaultSortDirection: 'desc', initialWidth: 65, isResizable: false, + actions: false, }, ]; diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 0118ff1dd4c..cbf356080cd 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -269,7 +269,7 @@ export const EuiDataGridHeaderCell: FunctionComponent 0; + return (
{sortString}
)} - {columnOptions && columnOptions.length && ( + {showColumnActions && ( setIsPopoverOpen(false)} ownFocus>
- +
)} From 5aaf8878ef95864d1d03ba825061c2a0ee172597 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 11:29:16 +0200 Subject: [PATCH 18/34] Refactor switchColumnPos code --- src/components/datagrid/column_selector.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/datagrid/column_selector.tsx b/src/components/datagrid/column_selector.tsx index 270e21dfeb8..b282e31169c 100644 --- a/src/components/datagrid/column_selector.tsx +++ b/src/components/datagrid/column_selector.tsx @@ -294,12 +294,12 @@ export const useColumnSelector = ( const switchColumnPos = (fromColId: string, toColId: string) => { const moveFromIdx = sortedColumns.indexOf(fromColId); const moveToIdx = sortedColumns.indexOf(toColId); - - const nextSortedColumns = Object.values({ - ...sortedColumns, - [moveFromIdx]: toColId, - [moveToIdx]: fromColId, - }) as string[]; + if (moveFromIdx === -1 || moveToIdx === -1) { + return; + } + const nextSortedColumns = [...sortedColumns]; + nextSortedColumns.splice(moveFromIdx, 1); + nextSortedColumns.splice(moveToIdx, 0, fromColId); setColumns(nextSortedColumns); }; From 8d7098dc9c7a949c8fe7906d4472402d804bdf6d Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 27 Aug 2020 19:20:19 +0200 Subject: [PATCH 19/34] Allow unsorting of columns by column actions --- .../datagrid/_data_grid_header_row.scss | 5 ++ src/components/datagrid/column_actions.tsx | 63 ++++++++++++------- src/components/datagrid/column_selector.tsx | 12 ++-- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/components/datagrid/_data_grid_header_row.scss b/src/components/datagrid/_data_grid_header_row.scss index 09d1a09d56c..d86c94b1a65 100644 --- a/src/components/datagrid/_data_grid_header_row.scss +++ b/src/components/datagrid/_data_grid_header_row.scss @@ -56,6 +56,11 @@ } } +.euiDataGridHeader__action--selected { + // sass-lint:disable-block no-important + font-weight: $euiFontWeightBold !important; +} + // Header alternates // Often these need extra specificity because they need to gracefully clash with the border settings diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index 33e9d5c1e6b..6b4fa887679 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -34,6 +34,7 @@ export function getColumnActions( return []; } const colIdx = columns.findIndex(col => col.id === column.id); + const sortingIdx = sorting ? sorting.columns.findIndex(col => col.id === column.id) : -1; @@ -42,26 +43,36 @@ export function getColumnActions( return; } - const newSorting = - sortingIdx >= 0 - ? //replace existing entry - Object.values({ - ...sorting.columns, - [sortingIdx]: { - id: column.id, - direction: direction, - }, - }) - : //append entry - [ - ...sorting.columns, - { - id: column.id, - direction: direction, - }, - ]; - - sorting.onSort(newSorting as EuiDataGridSorting['columns']); + if ( + sortingIdx >= 0 && + sorting.columns[sortingIdx]?.direction === direction + ) { + // unsort if the same current and new direction are same + const newColumns = sorting.columns.filter( + (val, idx) => idx !== sortingIdx + ); + sorting.onSort(newColumns); + } else if (sortingIdx >= 0) { + // replace existing sort + const newColumns = Object.values({ + ...sorting.columns, + [sortingIdx]: { + id: column.id, + direction: direction, + }, + }); + sorting.onSort(newColumns as EuiDataGridSorting['columns']); + } else { + // add new sort + const newColumns = [ + ...sorting.columns, + { + id: column.id, + direction: direction, + }, + ]; + sorting.onSort(newColumns as EuiDataGridSorting['columns']); + } }; const onClickHideColumn = () => setVisibleColumns( @@ -119,8 +130,10 @@ export function getColumnActions( ), onClick: onClickSortAsc, isDisabled: column.isSortable === false, - isActive: - sortingIdx >= 0 && sorting.columns[sortingIdx].direction === 'asc', + className: + sortingIdx >= 0 && sorting.columns[sortingIdx].direction === 'asc' + ? 'euiDataGridHeader__action--selected' + : '', iconType: 'sortUp', size: 'xs', color: 'text', @@ -139,8 +152,10 @@ export function getColumnActions( ), onClick: onClickSortDesc, isDisabled: column.isSortable === false, - isActive: - sortingIdx >= 0 && sorting.columns[sortingIdx].direction === 'desc', + className: + sortingIdx >= 0 && sorting.columns[sortingIdx].direction === 'desc' + ? 'euiDataGridHeader__action--selected' + : '', iconType: 'sortDown', size: 'xs', color: 'text', diff --git a/src/components/datagrid/column_selector.tsx b/src/components/datagrid/column_selector.tsx index 270e21dfeb8..b282e31169c 100644 --- a/src/components/datagrid/column_selector.tsx +++ b/src/components/datagrid/column_selector.tsx @@ -294,12 +294,12 @@ export const useColumnSelector = ( const switchColumnPos = (fromColId: string, toColId: string) => { const moveFromIdx = sortedColumns.indexOf(fromColId); const moveToIdx = sortedColumns.indexOf(toColId); - - const nextSortedColumns = Object.values({ - ...sortedColumns, - [moveFromIdx]: toColId, - [moveToIdx]: fromColId, - }) as string[]; + if (moveFromIdx === -1 || moveToIdx === -1) { + return; + } + const nextSortedColumns = [...sortedColumns]; + nextSortedColumns.splice(moveFromIdx, 1); + nextSortedColumns.splice(moveToIdx, 0, fromColId); setColumns(nextSortedColumns); }; From a835ac051691015525143c4c6f28797df67b9b50 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 2 Sep 2020 14:14:02 +0200 Subject: [PATCH 20/34] Add example to doc --- src-docs/src/views/datagrid/column_actions.js | 107 ++++++++++++++++++ .../views/datagrid/datagrid_schema_example.js | 2 + .../datagrid/datagrid_styling_example.js | 55 ++++++++- src/components/datagrid/data_grid_types.ts | 10 +- 4 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 src-docs/src/views/datagrid/column_actions.js diff --git a/src-docs/src/views/datagrid/column_actions.js b/src-docs/src/views/datagrid/column_actions.js new file mode 100644 index 00000000000..a5143dbf38d --- /dev/null +++ b/src-docs/src/views/datagrid/column_actions.js @@ -0,0 +1,107 @@ +import React, { useState, useCallback } from 'react'; +import { fake } from 'faker'; + +import { EuiDataGrid, EuiAvatar } from '../../../../src/components/'; + +const columns = [ + { + id: 'avatar', + initialWidth: 40, + isResizable: false, + actions: false, + }, + { + id: 'name', + initialWidth: 100, + isSortable: true, + actions: { + showHide: false, + }, + }, + { + id: 'email', + isSortable: true, + actions: { + additional: [ + { + iconType: 'heart', + label: 'Send Email', + size: 'xs', + onClick: () => + alert('🎵Return to sender, address unknown, no such number,...'), + }, + ], + }, + }, + { + id: 'city', + isSortable: true, + actions: { + showHide: { + iconType: 'cross', + label: 'Remove column', + }, + }, + }, + { + id: 'country', + }, + { + id: 'account', + }, +]; + +const data = []; + +for (let i = 1; i < 5; i++) { + data.push({ + avatar: ( + + ), + name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'), + email: fake('{{internet.email}}'), + city: fake('{{address.city}}'), + country: fake('{{address.country}}'), + account: fake('{{finance.account}}'), + }); +} + +export default () => { + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); + + const [visibleColumns, setVisibleColumns] = useState(() => + columns.map(({ id }) => id) + ); + + const setPageIndex = useCallback( + pageIndex => setPagination({ ...pagination, pageIndex }), + [pagination, setPagination] + ); + const setPageSize = useCallback( + pageSize => setPagination({ ...pagination, pageSize, pageIndex: 0 }), + [pagination, setPagination] + ); + + return ( + data[rowIndex][columnId]} + pagination={{ + ...pagination, + pageSizeOptions: [5, 10, 25], + onChangeItemsPerPage: setPageSize, + onChangePage: setPageIndex, + }} + /> + ); +}; diff --git a/src-docs/src/views/datagrid/datagrid_schema_example.js b/src-docs/src/views/datagrid/datagrid_schema_example.js index 250c816c006..a0f7328beaa 100644 --- a/src-docs/src/views/datagrid/datagrid_schema_example.js +++ b/src-docs/src/views/datagrid/datagrid_schema_example.js @@ -11,6 +11,7 @@ const dataGridSchemaHtml = renderToHtml(DataGridSchema); import { EuiDataGridColumn, + EuiDataGridColumnActions, EuiDataGridPaginationProps, EuiDataGridSorting, EuiDataGridInMemory, @@ -89,6 +90,7 @@ export const DataGridSchemaExample = { EuiDataGrid, EuiDataGridInMemory, EuiDataGridColumn, + EuiDataGridColumnActions, EuiDataGridColumnVisibility, EuiDataGridPaginationProps, EuiDataGridSorting, diff --git a/src-docs/src/views/datagrid/datagrid_styling_example.js b/src-docs/src/views/datagrid/datagrid_styling_example.js index 21dd614027b..00c7f6618bf 100644 --- a/src-docs/src/views/datagrid/datagrid_styling_example.js +++ b/src-docs/src/views/datagrid/datagrid_styling_example.js @@ -3,7 +3,12 @@ import React, { Fragment } from 'react'; import { renderToHtml } from '../../services'; import { GuideSectionTypes } from '../../components'; -import { EuiDataGrid, EuiCode, EuiCodeBlock } from '../../../../src/components'; +import { + EuiDataGrid, + EuiCode, + EuiCodeBlock, + EuiListGroupItem, +} from '../../../../src/components'; import DataGridContainer from './container'; const dataGridContainerSource = require('!!raw-loader!./container'); @@ -18,11 +23,15 @@ const dataGridControlsSource = require('!!raw-loader!./additional_controls'); const dataGridControlsHtml = renderToHtml(DataGridControls); import DataGridColumnWidths from './column_widths'; +import DataGridColumnActions from './column_actions'; const dataGridColumnWidthsSource = require('!!raw-loader!./column_widths'); const dataGridColumnWidthsHtml = renderToHtml(DataGridColumnWidths); +const dataGridColumnActionsSource = require('!!raw-loader!./column_actions'); +const dataGridColumnActionsHtml = renderToHtml(DataGridColumnActions); import { EuiDataGridColumn, + EuiDataGridColumnActions, EuiDataGridStyle, EuiDataGridToolBarVisibilityOptions, } from '!!prop-loader!../../../../src/components/datagrid/data_grid_types'; @@ -122,7 +131,7 @@ const widthsSnippet = `, }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: dataGridColumnActionsSource, + }, + { + type: GuideSectionTypes.HTML, + code: dataGridColumnActionsHtml, + }, + ], + title: 'Column actions', + text: ( + +

+ By default, columns provide actions for sorting, moving and hiding. + These can be extended with custom actions. You can customize the + actions by setting the actions value of{' '} + EuiDataGridColumn. Setting it to{' '} + false removes the action menu displayed. You can + configure it by passing an object of type{' '} + EuiDataGridColumnAction. This allows you a hide, + configure the existing actions and add new ones. +

+

+ Below, the first column provides no action, the second doesn't + provide the ability to hide the columns, the 3rd provides an + additional action, the 4th overwrites the hide action with a custom + label and icon. +

+
+ ), + components: { DataGridColumnActions }, + snippet: widthsSnippet, + props: { + EuiDataGrid, + EuiDataGridColumn, + EuiDataGridColumnActions, + EuiListGroupItem, + }, + demo: , + }, ], }; diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index cc11c76c398..8097df008de 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -85,23 +85,23 @@ export interface EuiDataGridColumn { export interface EuiDataGridColumnActions { /** - * Configure the action to hide a column, provided EuiListGroupItemProps are merged + * Show/hide/configure the action to hide a column, provided EuiListGroupItemProps are merged */ showHide?: boolean | EuiListGroupItemProps; /** - * Configure the action that switches the actual column with the column to the left side, provided EuiListGroupItemProps are merged + * Show/hide/configure the action that switches the actual column with the column to the left side, provided EuiListGroupItemProps are merged */ showMoveLeft?: boolean | EuiListGroupItemProps; /** - * Configure the action that switches the actual column with the column to the right side, provided EuiListGroupItemProps are merged + * Show/hide/configure the action that switches the actual column with the column to the right side, provided EuiListGroupItemProps are merged */ showMoveRight?: boolean | EuiListGroupItemProps; /** - * Configure the action to sort ascending by the actual column, provided EuiListGroupItemProps are merged + * Show/hide/configure the action to sort ascending by the actual column, provided EuiListGroupItemProps are merged */ showSortAsc?: boolean | EuiListGroupItemProps; /** - * Configure the action to sort ascending by the actual column, provided EuiListGroupItemProps are merged + * Show/hide/configure the action to sort descending by the actual column, provided EuiListGroupItemProps are merged */ showSortDesc?: boolean | EuiListGroupItemProps; /** From 6655f4d58dfbc669cc7b2da34dc51967466bec5d Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 2 Sep 2020 14:53:15 +0200 Subject: [PATCH 21/34] Address review comments --- src-docs/src/views/datagrid/datagrid.js | 16 ---------------- src-docs/src/views/datagrid/focus.js | 6 ++++++ src/components/datagrid/column_actions.tsx | 6 +++--- .../datagrid/data_grid_header_cell.tsx | 4 ++-- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src-docs/src/views/datagrid/datagrid.js b/src-docs/src/views/datagrid/datagrid.js index 435772b5981..1322ccd7f11 100644 --- a/src-docs/src/views/datagrid/datagrid.js +++ b/src-docs/src/views/datagrid/datagrid.js @@ -26,22 +26,6 @@ const columns = [ }, { id: 'email', - display: ( - // This is an example of an icon next to a title that still respects text truncate - - -
email
-
- - alert('Email Icon Clicked!')} - /> - -
- ), }, { id: 'location', diff --git a/src-docs/src/views/datagrid/focus.js b/src-docs/src/views/datagrid/focus.js index 2d81953a405..79932b66ee7 100644 --- a/src-docs/src/views/datagrid/focus.js +++ b/src-docs/src/views/datagrid/focus.js @@ -97,6 +97,7 @@ export default () => { ), isExpandable: false, + actions: false, }, { id: 'no-interactives is expandable', @@ -115,6 +116,7 @@ export default () => { ), + actions: false, }, { id: 'one-interactive not expandable', @@ -134,6 +136,7 @@ export default () => { ), isExpandable: false, + actions: false, }, { id: 'one-interactives is expandable', @@ -153,6 +156,7 @@ export default () => { ), + actions: false, }, { id: 'two-interactives not expandable', @@ -173,6 +177,7 @@ export default () => { ), isExpandable: false, + actions: false, }, { id: 'two-interactives is expandable', @@ -192,6 +197,7 @@ export default () => { ), + actions: false, }, ], [areHeadersInteractive] diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index 6b4fa887679..117139d7290 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -117,7 +117,7 @@ export function getColumnActions( color: 'text', } as EuiListGroupItemProps; if (typeof column.actions?.showHide === 'object') { - result.push({ ...option, ...column.actions?.showHide }); + result.push({ ...option, ...column.actions.showHide }); } else { result.push(option); } @@ -139,7 +139,7 @@ export function getColumnActions( color: 'text', } as EuiListGroupItemProps; if (typeof column.actions?.showSortAsc === 'object') { - result.push({ ...option, ...column.actions?.showSortAsc }); + result.push({ ...option, ...column.actions.showSortAsc }); } else { result.push(option); } @@ -161,7 +161,7 @@ export function getColumnActions( color: 'text', } as EuiListGroupItemProps; if (typeof column.actions?.showSortDesc === 'object') { - result.push({ ...option, ...column.actions?.showSortDesc }); + result.push({ ...option, ...column.actions.showSortDesc }); } else { result.push(option); } diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index cbf356080cd..24cd3f25467 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -135,9 +135,9 @@ export const EuiDataGridHeaderCell: FunctionComponent { if (headerRef.current) { const tababbles = tabbable(headerRef.current); - if (tababbles.length > 2) { + if (tababbles.length > 1) { console.warn( - `EuiDataGridHeaderCell expects at most 2 tabbable element, ${tababbles.length} found instead` + `EuiDataGridHeaderCell expects at most 1 tabbable element, ${tababbles.length} found instead` ); } for (let i = 0; i < tababbles.length; i++) { From 4427e208ca407f4c5f7a6ecf497bf779ac94cb52 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 3 Sep 2020 19:32:09 +0200 Subject: [PATCH 22/34] Add test --- .../__snapshots__/data_grid.test.tsx.snap | 633 ++++++++++++++++++ src/components/datagrid/data_grid.test.tsx | 80 +++ .../datagrid/data_grid_header_cell.tsx | 7 +- 3 files changed, 719 insertions(+), 1 deletion(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index ea554f21fc8..75421ea0225 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -164,6 +164,631 @@ exports[`EuiDataGrid pagination renders 1`] = `
`; +exports[`EuiDataGrid render column actions renders various column actions configurations 1`] = ` +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    +
+`; + +exports[`EuiDataGrid render column actions renders various column actions configurations 2`] = ` +
    + +
  • + + + test + + +
  • +
    +
+`; + +exports[`EuiDataGrid render column actions renders various column actions configurations 3`] = ` +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    + + } + onClick={[Function]} + showToolTip={false} + size="xs" + wrapText={false} + > +
  • + +
  • +
    + +
  • + + + test + + +
  • +
    +
+`; + +exports[`EuiDataGrid render column actions renders various column actions configurations 4`] = ` +
    + +
  • + +
  • +
    + +
  • + +
  • +
    + +
  • + +
  • +
    + +
  • + +
  • +
    + +
  • + +
  • +
    + +
  • + + + test + + +
  • +
    +
+`; + exports[`EuiDataGrid rendering renders additional toolbar controls 1`] = ` Array [
{ + it('renders various column actions configurations', () => { + const component = mount( + {}, + }} + columns={[ + { id: 'A', actions: false }, + { id: 'B', isSortable: true }, + { + id: 'C', + isSortable: true, + actions: { + showHide: false, + showMoveRight: false, + showMoveLeft: false, + showSortAsc: false, + showSortDesc: false, + additional: [{ label: 'test' }], + }, + }, + { + id: 'D', + isSortable: true, + actions: { + showHide: false, + showMoveRight: false, + showMoveLeft: false, + additional: [{ label: 'test' }], + }, + }, + { + id: 'E', + isSortable: true, + actions: { + showHide: { label: '1' }, + showSortAsc: { label: '2' }, + showSortDesc: { label: '3' }, + showMoveLeft: { label: '4' }, + showMoveRight: { label: '5' }, + additional: [{ label: 'test' }], + }, + }, + ]} + columnVisibility={{ + visibleColumns: ['A', 'B', 'C', 'D', 'E'], + setVisibleColumns: () => {}, + }} + rowCount={2} + renderCellValue={({ rowIndex, columnId }) => + `${rowIndex}-${columnId}` + } + /> + ); + + const buttonA = findTestSubject( + component, + 'dataGridHeaderCellActionButton-A' + ); + expect(buttonA.length).toBe(0); + + for (const col of ['B', 'C', 'D', 'E']) { + const button = findTestSubject( + component, + `dataGridHeaderCellActionButton-${col}` + ); + button.simulate('click'); + component.update(); + const actionGroup = findTestSubject( + component, + `dataGridHeaderCellActionGroup-${col}` + ); + expect(actionGroup).toMatchSnapshot(); + } + }); + }); + describe('keyboard controls', () => { it('supports simple arrow navigation', () => { let pagination = { diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index 24cd3f25467..43efe9479ec 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -313,13 +313,18 @@ export const EuiDataGridHeaderCell: FunctionComponent setIsPopoverOpen(true)} iconType="arrowDown" aria-label={actionButtonAriaLabel} + data-test-subj={`dataGridHeaderCellActionButton-${id}`} /> } isOpen={isPopoverOpen} closePopover={() => setIsPopoverOpen(false)} ownFocus>
- +
)} From 039e4aefa20083ed647bbf8298684d2ad90cdf98 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 4 Sep 2020 17:28:31 +0200 Subject: [PATCH 23/34] Fix test --- src/components/datagrid/data_grid.test.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index 9792da069a7..779a2af3fba 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -1912,7 +1912,11 @@ Array [ const component = mount( {}, @@ -2108,7 +2112,10 @@ Array [ const component = mount( {}, From 59fbfd4b4206c95fa43c524da6223e03f27afc2e Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 8 Sep 2020 09:21:02 +0200 Subject: [PATCH 24/34] Address review comments --- CHANGELOG.md | 1 + src-docs/src/views/datagrid/datagrid_example.js | 12 +++++++++--- src/components/datagrid/data_grid_types.ts | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 517d3540ae9..be84c8ddf3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Changed `value` prop in `EuiExpression` to not required ([#4014](https://github.com/elastic/eui/pull/4014)) - Added `fold` and `unfold` glyphs to `EuiIcon` ([#3994](https://github.com/elastic/eui/pull/3994)) +- Added column header menu to `EuiDataGrid` ([#3087](https://github.com/elastic/eui/pull/3087)) **Bug fixes** diff --git a/src-docs/src/views/datagrid/datagrid_example.js b/src-docs/src/views/datagrid/datagrid_example.js index b477cd1f922..51afb6ee3d5 100644 --- a/src-docs/src/views/datagrid/datagrid_example.js +++ b/src-docs/src/views/datagrid/datagrid_example.js @@ -26,6 +26,7 @@ import { EuiDataGridStyle, EuiDataGridToolBarVisibilityOptions, EuiDataGridColumnVisibility, + EuiDataGridColumnActions, EuiDataGridPopoverContentProps, EuiDataGridControlColumn, EuiDataGridToolBarVisibilityColumnSelectorOptions, @@ -41,9 +42,13 @@ const gridSnippet = ` // Required. There are 200 total records. rowCount={200} // Required. Sets up three columns, the last of which has a custom schema we later define down below. - // The second column B won't allow clicking in to see the content in a popup. - // The first column defines a starting width of 150px and prevents the user from resizing it - columns={[{ id: 'A', initialWidth: 150, isResizable: false }, { id: 'B', isExpandable: false }, {id: 'C', schema: 'franchise'}]} + // The second column B won't allow clicking in to see the content in a popup and doesn't show move actions in column header cell + // The first column defines a starting width of 150px, prevents the user from resizing it and no actions are displayed + columns={[ + { id: 'A', initialWidth: 150, isResizable: false, actions: false }, + { id: 'B', isExpandable: false, actions: { showMoveLeft: false, showMoveRight: false } }, + { id: 'C', schema: 'franchise'} + ]} // Optional. This allows you to initially hide columns. Users can still turn them on. columnVisibility={{ visibleColumns: ['A', 'C'], @@ -354,6 +359,7 @@ export const DataGridExample = { EuiDataGrid, EuiDataGridColumn, EuiDataGridColumnVisibility, + EuiDataGridColumnActions, EuiDataGridControlColumn, EuiDataGridInMemory, EuiDataGridPaginationProps, diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 8097df008de..078fe7fcd22 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -78,7 +78,7 @@ export interface EuiDataGridColumn { */ displayAsText?: string; /** - * Configuration of column actions. Can be used to disable or configure the actions displayed in the header column + * Configuration of column actions. Set to false to disable or use #EuiDataGridColumnActions to configure the actions displayed in the header cell of the column. */ actions?: false | EuiDataGridColumnActions; } From 3a1b6eade85b1181ef5fa8a18c915a3f1a98c506 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Thu, 10 Sep 2020 09:55:32 -0700 Subject: [PATCH 25/34] icon sizing and color --- .../__snapshots__/data_grid.test.tsx.snap | 16 ++++++++-------- .../datagrid/data_grid_header_cell.tsx | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 75421ea0225..5d5ae1bf7b4 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -936,7 +936,7 @@ Array [ > +
-
+
-
- B -
-
- +
-
+
-
- A -
-
- +
-
+
-
- B -
-
- +
-
+
-
- Column A -
-
- +
-
+
-
-
- More Elements +
+
+ More Elements +
-
-
- +
-
+
-
- A -
-
- +
-
+
-
- B -
-
- +
-
+
) : null} -
{display || id}
{sorting && sorting.columns.length >= 2 && (
{sortString}
)} - {showColumnActions && ( - setIsPopoverOpen(true)} - iconType="arrowDown" - size="s" - color="text" - aria-label={actionButtonAriaLabel} - data-test-subj={`dataGridHeaderCellActionButton-${id}`} - /> - } - isOpen={isPopoverOpen} - closePopover={() => setIsPopoverOpen(false)} - ownFocus> -
- -
-
+ {!showColumnActions ? ( +
{display || id}
+ ) : ( + )}
); From cfbc170db7ad0c7c7d4c2e14b2f189ecbf031d32 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 15 Sep 2020 12:37:31 +0200 Subject: [PATCH 27/34] Adapt CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6018faf4788..1f841f29085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Added `boolean` type to the `notification` prop of `EuiHeaderSectionItemButton` to show a simple dot ([#4008](https://github.com/elastic/eui/pull/4008)) - Added `popoverButton` and `popoverButtonBreakpoints` props to `EuiSelectableTemplateSitewide` for responsive capabilities ([#4008](https://github.com/elastic/eui/pull/4008)) - Added `isWithinMaxBreakpoint` service ([#4008](https://github.com/elastic/eui/pull/4008)) +- Added column header menu to `EuiDataGrid` ([#3087](https://github.com/elastic/eui/pull/3087)) **Bug fixes** @@ -24,7 +25,6 @@ - Added `loading` icon to `EuiComboBox` input when `isLoading` is `true` ([#4015](https://github.com/elastic/eui/pull/4015)) - Changed `value` prop in `EuiExpression` to not required ([#4014](https://github.com/elastic/eui/pull/4014)) - Added `fold` and `unfold` glyphs to `EuiIcon` ([#3994](https://github.com/elastic/eui/pull/3994)) -- Added column header menu to `EuiDataGrid` ([#3087](https://github.com/elastic/eui/pull/3087)) **Bug fixes** From ac62f858a9245827edf2882eb8a79935b4873ff4 Mon Sep 17 00:00:00 2001 From: Andrea Del Rio Date: Tue, 15 Sep 2020 09:38:08 -0700 Subject: [PATCH 28/34] fix focus in menu --- .../__snapshots__/data_grid.test.tsx.snap | 16 ++++++++-------- .../datagrid/_data_grid_header_row.scss | 4 ++++ .../datagrid/data_grid_header_cell.tsx | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 9dde0360943..d83f43925e8 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -935,7 +935,7 @@ Array [ class="euiPopover euiPopover--anchorDownRight euiDataGridHeaderCell__popover" >
{display || id}
Date: Tue, 15 Sep 2020 10:37:17 -0700 Subject: [PATCH 29/34] fix focus of menu (again) and add mixin --- .../__snapshots__/data_grid.test.tsx.snap | 16 ++++++++-------- src/components/datagrid/_data_grid_data_row.scss | 5 +---- .../datagrid/_data_grid_header_row.scss | 13 +++++-------- src/components/datagrid/_mixins.scss | 7 +++++++ .../datagrid/data_grid_header_cell.tsx | 1 - 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index d83f43925e8..9dde0360943 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -935,7 +935,7 @@ Array [ class="euiPopover euiPopover--anchorDownRight euiDataGridHeaderCell__popover" >
{display || id}
Date: Thu, 17 Sep 2020 22:35:16 +0200 Subject: [PATCH 30/34] Fix closing menu --- .../__snapshots__/data_grid.test.tsx.snap | 36 ++++++++++++------- src/components/datagrid/column_actions.tsx | 30 +++++++++++----- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 9dde0360943..46983f69c4f 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -421,14 +421,18 @@ exports[`EuiDataGrid render column actions renders various column actions config
  • - test - +
  • @@ -548,14 +552,18 @@ exports[`EuiDataGrid render column actions renders various column actions config
  • - test - +
  • @@ -768,14 +776,18 @@ exports[`EuiDataGrid render column actions renders various column actions config
  • - test - +
  • diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index 117139d7290..2fe47a8bc9f 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -16,11 +16,10 @@ * specific language governing permissions and limitations * under the License. */ - +import React from 'react'; import { EuiDataGridColumn, EuiDataGridSorting } from './data_grid_types'; import { EuiI18n } from '../i18n'; import { EuiListGroupItemProps } from '../list_group'; -import React from 'react'; export function getColumnActions( column: EuiDataGridColumn, @@ -200,11 +199,24 @@ export function getColumnActions( result.push(option); } } - if (column.actions?.additional) { - return [ - ...result, - ...column.actions?.additional, - ] as EuiListGroupItemProps[]; - } - return result; + const allActions = column.actions?.additional + ? [...result, ...column.actions?.additional] + : result; + + //wrap EuiListGroupItem onClick function to close the popover and prevet bubbling up + + return allActions.map(action => { + return { + ...action, + ...{ + onClick: (ev: React.MouseEvent) => { + ev.stopPropagation(); + setIsPopoverOpen(false); + if (action && action.onClick) { + action.onClick(ev as any); + } + }, + }, + }; + }) as EuiListGroupItemProps[]; } From a89a3854c636d8d1fd2fcf2a21c1be8d598d1041 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 18 Sep 2020 06:55:13 +0200 Subject: [PATCH 31/34] Remove any --- src/components/datagrid/column_actions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index 2fe47a8bc9f..89335135718 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -213,7 +213,7 @@ export function getColumnActions( ev.stopPropagation(); setIsPopoverOpen(false); if (action && action.onClick) { - action.onClick(ev as any); + action.onClick(ev); } }, }, From 5462b1beb605406d3433356283d1206fd57ccdf8 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 18 Sep 2020 07:36:26 +0200 Subject: [PATCH 32/34] Cleanup --- src/components/datagrid/column_actions.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/datagrid/column_actions.tsx b/src/components/datagrid/column_actions.tsx index 89335135718..fe942b30a5c 100644 --- a/src/components/datagrid/column_actions.tsx +++ b/src/components/datagrid/column_actions.tsx @@ -79,17 +79,14 @@ export function getColumnActions( ); const onClickSortAsc = () => { - setIsPopoverOpen(false); sortBy('asc'); }; const onClickSortDesc = () => { - setIsPopoverOpen(false); sortBy('desc'); }; const onClickMoveLeft = () => { - setIsPopoverOpen(false); const targetCol = columns[colIdx - 1]; if (targetCol) { switchColumnPos(column.id, targetCol.id); @@ -97,7 +94,6 @@ export function getColumnActions( }; const onClickMoveRight = () => { - setIsPopoverOpen(false); const targetCol = columns[colIdx + 1]; if (targetCol) { switchColumnPos(column.id, targetCol.id); From 7b00e400ffeaa78232762b5336fc4d50e5f432f9 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 18 Sep 2020 15:35:02 +0200 Subject: [PATCH 33/34] End the focus war --- src/components/datagrid/data_grid_header_cell.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/datagrid/data_grid_header_cell.tsx b/src/components/datagrid/data_grid_header_cell.tsx index bcc9186842e..5087c666df9 100644 --- a/src/components/datagrid/data_grid_header_cell.tsx +++ b/src/components/datagrid/data_grid_header_cell.tsx @@ -324,7 +324,7 @@ export const EuiDataGridHeaderCell: FunctionComponent setIsPopoverOpen(false)} - ownFocus> + ownFocus={isFocused}>
    Date: Fri, 18 Sep 2020 13:16:30 -0600 Subject: [PATCH 34/34] Update CHANGELOG.md quick changelog cleanup --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d34dd31c2..4eb568a2e00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Added footer row to `EuiDataGrid` via the `renderFooterCellValue` prop ([#3770](https://github.com/elastic/eui/pull/3770)) +- Added column header menu to `EuiDataGrid` ([#3087](https://github.com/elastic/eui/pull/3087)) ## [`29.0.0`](https://github.com/elastic/eui/tree/v29.0.0) @@ -9,7 +10,6 @@ - Added `boolean` type to the `notification` prop of `EuiHeaderSectionItemButton` to show a simple dot ([#4008](https://github.com/elastic/eui/pull/4008)) - Added `popoverButton` and `popoverButtonBreakpoints` props to `EuiSelectableTemplateSitewide` for responsive capabilities ([#4008](https://github.com/elastic/eui/pull/4008)) - Added `isWithinMaxBreakpoint` service ([#4008](https://github.com/elastic/eui/pull/4008)) -- Added column header menu to `EuiDataGrid` ([#3087](https://github.com/elastic/eui/pull/3087)) - Added horizontal line separator to `EuiContextMenu` ([#4018](https://github.com/elastic/eui/pull/4018)) - Added controlled pagination props to `EuiInMemoryTablee` ([#4038](https://github.com/elastic/eui/pull/4038))