diff --git a/packages/eui/changelogs/upcoming/8135.md b/packages/eui/changelogs/upcoming/8135.md new file mode 100644 index 00000000000..03d2cdf4ac9 --- /dev/null +++ b/packages/eui/changelogs/upcoming/8135.md @@ -0,0 +1,4 @@ +**Bug fixes** + +- Fixed an `EuiDataGrid` bug where column actions where not clickable when `EuiDataGrid` with `columnVisibility.canDragAndDropColumns` was used inside a modal + diff --git a/packages/eui/src-docs/src/views/datagrid/schema_columns/column_dragging.js b/packages/eui/src-docs/src/views/datagrid/schema_columns/column_dragging.js index b363d54b33c..fd3e11e4d60 100644 --- a/packages/eui/src-docs/src/views/datagrid/schema_columns/column_dragging.js +++ b/packages/eui/src-docs/src/views/datagrid/schema_columns/column_dragging.js @@ -1,41 +1,20 @@ -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { faker } from '@faker-js/faker'; -import { - EuiDataGrid, - EuiAvatar, - EuiToolTip, - EuiButtonIcon, -} from '../../../../../src/components'; - -const CustomHeaderCell = ({ title }) => ( - <> - {title} - - - - -); +import { EuiDataGrid, EuiAvatar } from '../../../../../src/components'; const columns = [ { id: 'avatar', initialWidth: 40, isResizable: false, - actions: false, }, { id: 'name', - displayAsText: 'Name', - display: , + initialWidth: 100, }, { id: 'email', - display: , }, { id: 'city', @@ -67,21 +46,42 @@ for (let i = 1; i < 5; i++) { } export default () => { + const [pagination, setPagination] = useState({ pageIndex: 0 }); + const [visibleColumns, setVisibleColumns] = useState( columns.map(({ id }) => id) ); + const setPageIndex = useCallback( + (pageIndex) => + setPagination((pagination) => ({ ...pagination, pageIndex })), + [] + ); + const setPageSize = useCallback( + (pageSize) => + setPagination((pagination) => ({ + ...pagination, + pageSize, + pageIndex: 0, + })), + [] + ); + return ( data[rowIndex][columnId]} + pagination={{ + ...pagination, + onChangeItemsPerPage: setPageSize, + onChangePage: setPageIndex, + }} /> ); }; diff --git a/packages/eui/src/components/datagrid/body/header/draggable_columns.spec.tsx b/packages/eui/src/components/datagrid/body/header/draggable_columns.spec.tsx index 7b78578823a..a8ad5d81e55 100644 --- a/packages/eui/src/components/datagrid/body/header/draggable_columns.spec.tsx +++ b/packages/eui/src/components/datagrid/body/header/draggable_columns.spec.tsx @@ -12,6 +12,7 @@ import React, { useState } from 'react'; import { EuiDataGrid, EuiDataGridProps } from '../../index'; +import { EuiModal, EuiModalBody } from '../../../modal'; describe('draggable columns', () => { const columns = [ @@ -284,4 +285,40 @@ describe('draggable columns', () => { cy.get('[data-popover-open]').should('not.exist'); }); }); + + describe('inside a modal', () => { + it('should execute column actions on click', () => { + cy.realMount( + {}}> + + + + + ); + + cy.get('[data-test-subj=dataGridHeaderCell-a]').realHover(); + cy.wait(50); // wait until actions button transition is progressed enough for the button to be clickable + cy.get('[data-test-subj=dataGridHeaderCellActionButton-a]').realClick(); + cy.get('[data-popover-open]').should('have.focus'); + + cy.get( + '.euiListGroupItem:last-child .euiListGroupItem__button' + ).realClick(); + + cy.get('[data-test-subj=dataGridHeaderCell-a]').should( + 'have.attr', + 'data-gridcell-column-index', + '1' + ); + cy.get('[data-test-subj=dataGridHeaderCell-b]').should( + 'have.attr', + 'data-gridcell-column-index', + '0' + ); + + cy.get('[data-test-subj=euiDataGridHeaderColumnActions]').should( + 'not.exist' + ); + }); + }); }); diff --git a/packages/eui/src/components/datagrid/body/header/draggable_columns.tsx b/packages/eui/src/components/datagrid/body/header/draggable_columns.tsx index 7c754013184..be12c9a2669 100644 --- a/packages/eui/src/components/datagrid/body/header/draggable_columns.tsx +++ b/packages/eui/src/components/datagrid/body/header/draggable_columns.tsx @@ -132,16 +132,23 @@ export const DraggableColumn: FunctionComponent<{ const { setFocusedCell } = useContext(DataGridFocusContext); const handleOnMouseDown: MouseEventHandler = useCallback( (e) => { - const openFocusTrap = document.querySelector( + const openFocusTraps = document.querySelectorAll( '[data-focus-lock-disabled="false"]' ); - if ( - !!openFocusTrap && // If a focus trap is open somewhere on the page - !openFocusTrap.contains(e.target as Node) && // & the focus trap doesn't belong to this header - e.target !== actionsPopoverToggle // & we're not closing the actions popover toggle - ) { + const validOpenFocusTraps = [...openFocusTraps].filter( + (focusTrap) => !focusTrap.contains(e.currentTarget as Node) // remove containing focus traps (e.g. modals or flyouts) + ); + + const shouldDispatchEvent = validOpenFocusTraps.some( + (focusTrap) => + !!focusTrap && // If there is a focus trap open + !focusTrap.contains(e.target as Node) && // & if it doesn't contain the target + e.target !== actionsPopoverToggle // & we're not closing the actions popover toggle + ); + + if (shouldDispatchEvent) { // Trick the focus trap lib into registering an outside click - - // the drag/drop lib otherwise otherwise prevents the event 💀 + // the drag/drop lib otherwise prevents the event 💀 document.dispatchEvent(new MouseEvent('mousedown')); } setTimeout(() => {