From 20566d0262eafc022aad635c4fbf880b6c2a5506 Mon Sep 17 00:00:00 2001 From: Cee Chen <549407+cee-chen@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:06:21 -0700 Subject: [PATCH] Upgrade EUI to v95.10.1 (#192026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `v95.9.0`⏩`v95.10.1` > [!note] > **EuiDataGrid**'s header cells have received a major UX change in order to support interactive children within header content. Column header actions now must be hovered and then clicked directly, or opened with the Enter key, as opposed to being able to click the entire header cell to see the actions popover. _[Questions? Please see our Kibana upgrade FAQ.](https://github.com/elastic/eui/blob/main/wiki/eui-team-processes/upgrading-kibana.md#faq-for-kibana-teams)_ --- ## [`v95.10.0`](https://github.com/elastic/eui/releases/v95.10.0) - Updated `EuiDataGrid` to support interactive header cell content ([#7898](https://github.com/elastic/eui/pull/7898)) - Updated `EuiSearchBar`'s `field_value_selection` filter type with a new `autoSortOptions` config, allowing consumers to configure whether or not selected options are automatically sorted to the top of the filter list ([#7958](https://github.com/elastic/eui/pull/7958)) - Updated `getDefaultEuiMarkdownPlugins` to support the following new default plugin configurations: ([#7985](https://github.com/elastic/eui/pull/7985)) - `parsingConfig.linkValidator`, which allows configuring `allowRelative` and `allowProtocols` - `parsingConfig.emoji`, which allows configuring emoticon parsing - `processingConfig.linkProps`, which allows configuring rendered links with any props that `EuiLink` accepts - See our **Markdown plugins** documentation for example `EuiMarkdownFormat` and `EuiMarkdownEditor` usage - Updated `EuiDatePicker` to support `append` and `prepend` nodes in its form control layout ([#7987](https://github.com/elastic/eui/pull/7987)) **Bug fixes** - Fixed border rendering bug with inline `EuiDatePicker`s with `shadow={false}` ([#7987](https://github.com/elastic/eui/pull/7987)) - Fixed `EuiSuperSelect`'s placeholder text color to match other form controls ([#7995](https://github.com/elastic/eui/pull/7995)) **Accessibility** - Improved the keyboard navigation and screen reader output for `EuiDataGrid` header cells ([#7898](https://github.com/elastic/eui/pull/7898)) ## [`v95.10.1`](https://github.com/elastic/eui/releases/v95.10.1) **Bug fixes** - Fixed a visual bug in compact density `EuiDataGrid`s, where the header cell height would increase when the actions button became visible ([#7999](https://github.com/elastic/eui/pull/7999)) --------- Co-authored-by: Lene Gadewoll --- package.json | 2 +- .../__snapshots__/i18n_service.test.tsx.snap | 4 +- .../src/i18n_eui_mapping.tsx | 15 ++++- .../src/components/data_table.test.tsx | 55 +++++++++++-------- src/dev/license_checker/config.ts | 2 +- test/accessibility/apps/discover.ts | 2 +- .../apps/context/_discover_navigation.ts | 10 ++-- .../context/classic/_discover_navigation.ts | 10 ++-- .../group2_data_grid1/_data_grid_context.ts | 10 ++-- .../management/data_views/_scripted_fields.ts | 35 ++++-------- test/functional/services/data_grid.ts | 21 ++++++- .../components/data_table/index.test.tsx | 2 +- .../datatable/components/table_basic.test.tsx | 2 +- .../translations/translations/fr-FR.json | 2 +- .../translations/translations/ja-JP.json | 2 +- .../translations/translations/zh-CN.json | 2 +- .../test/functional/page_objects/lens_page.ts | 5 +- .../page_objects/triggers_actions_ui_page.ts | 9 +-- .../pages/alerts/table_storage.ts | 28 ++-------- .../svl_triggers_actions_ui_page.ts | 9 +-- .../common/context/_discover_navigation.ts | 10 ++-- yarn.lock | 8 +-- 22 files changed, 123 insertions(+), 122 deletions(-) diff --git a/package.json b/package.json index 3078275e1b9f85..d8a83da6a87557 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "@elastic/ecs": "^8.11.1", "@elastic/elasticsearch": "^8.15.0", "@elastic/ems-client": "8.5.3", - "@elastic/eui": "95.9.0", + "@elastic/eui": "95.10.1", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", diff --git a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap index 4f04a571c845bf..2285da518ce293 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap +++ b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap @@ -90,10 +90,12 @@ exports[`#start() returns \`Context\` component 1`] = ` "euiDataGrid.screenReaderNotice": "Cell contains interactive content.", "euiDataGridCell.expansionEnterPrompt": "Press the Enter key to expand this cell.", "euiDataGridCell.focusTrapEnterPrompt": "Press the Enter key to interact with this cell's contents.", + "euiDataGridCell.focusTrapExitPrompt": "Exited cell content.", "euiDataGridCell.position": [Function], "euiDataGridCellActions.expandButtonTitle": "Click or hit enter to interact with cell content", + "euiDataGridHeaderCell.actionsButtonAriaLabel": [Function], + "euiDataGridHeaderCell.actionsEnterKeyInstructions": "Press the Enter key to view this column's actions", "euiDataGridHeaderCell.actionsPopoverScreenReaderText": "To navigate through the list of column actions, press the Tab or Up and Down arrow keys.", - "euiDataGridHeaderCell.headerActions": "Click to view column header actions", "euiDataGridHeaderCell.sortedByAscendingFirst": [Function], "euiDataGridHeaderCell.sortedByAscendingMultiple": [Function], "euiDataGridHeaderCell.sortedByAscendingSingle": "Sorted ascending", diff --git a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx index 52b0a5c916aecf..c81aca1e5b4e6e 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx +++ b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx @@ -542,16 +542,25 @@ export const getEuiContextMapping = (): EuiTokensObject => { 'core.euiDataGridCell.focusTrapEnterPrompt', { defaultMessage: "Press the Enter key to interact with this cell's contents." } ), + 'euiDataGridCell.focusTrapExitPrompt': i18n.translate( + 'core.euiDataGridCell.focusTrapExitPrompt', + { defaultMessage: 'Exited cell content.' } + ), 'euiDataGridCellActions.expandButtonTitle': i18n.translate( 'core.euiDataGridCellActions.expandButtonTitle', { defaultMessage: 'Click or hit enter to interact with cell content', } ), - 'euiDataGridHeaderCell.headerActions': i18n.translate( - 'core.euiDataGridHeaderCell.headerActions', + 'euiDataGridHeaderCell.actionsButtonAriaLabel': ({ title }: EuiValues) => + i18n.translate('core.euiDataGridHeaderCell.actionsButtonAriaLabel', { + defaultMessage: '{title}. Click to view column header actions.', + values: { title }, + }), + 'euiDataGridHeaderCell.actionsEnterKeyInstructions': i18n.translate( + 'core.euiDataGridHeaderCell.actionsEnterKeyInstructions', { - defaultMessage: 'Click to view column header actions', + defaultMessage: "Press the Enter key to view this column's actions", } ), 'euiDataGridHeaderCell.sortedByAscendingSingle': i18n.translate( diff --git a/packages/kbn-unified-data-table/src/components/data_table.test.tsx b/packages/kbn-unified-data-table/src/components/data_table.test.tsx index ec8ffc38853458..c797701facdcc9 100644 --- a/packages/kbn-unified-data-table/src/components/data_table.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.test.tsx @@ -15,6 +15,7 @@ import { EuiDataGridCellValueElementProps, EuiDataGridCustomBodyProps, } from '@elastic/eui'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { act } from 'react-dom/test-utils'; import { findTestSubject } from '@elastic/eui/lib/test'; @@ -385,7 +386,7 @@ describe('UnifiedDataTable', () => { expect( screen.queryByTestId('dataGridHeaderCellActionGroup-message') ).not.toBeInTheDocument(); - await userEvent.click(screen.getByRole('button', { name: 'message' })); + await userEvent.click(screen.getByTestId('dataGridHeaderCellActionButton-message')); expect(screen.getByTestId('dataGridHeaderCellActionGroup-message')).toBeInTheDocument(); expect(screen.getByTestId('gridEditFieldButton')).toBeInTheDocument(); }, @@ -399,7 +400,7 @@ describe('UnifiedDataTable', () => { expect( screen.queryByTestId('dataGridHeaderCellActionGroup-message') ).not.toBeInTheDocument(); - await userEvent.click(screen.getByRole('button', { name: 'message' })); + await userEvent.click(screen.getByTestId('dataGridHeaderCellActionButton-message')); expect(screen.getByTestId('dataGridHeaderCellActionGroup-message')).toBeInTheDocument(); expect(screen.queryByTestId('gridEditFieldButton')).not.toBeInTheDocument(); }, @@ -458,7 +459,8 @@ describe('UnifiedDataTable', () => { }); describe('sorting', () => { - const getButton = (name: string) => screen.getByRole('button', { name }); + const getColumnActions = (name: string) => + screen.getByTestId(`dataGridHeaderCellActionButton-${name}`); const getCellValuesByColumn = () => { const columns = screen .getAllByRole('columnheader') @@ -497,12 +499,11 @@ describe('UnifiedDataTable', () => { 'message_8', 'message_9', ]); - await userEvent.click(getButton('message')); + await userEvent.click(getColumnActions('message')); + await waitForEuiPopoverOpen(); // Column sort button incorrectly renders as "Sort " instead // of "Sort Z-A" in Jest tests, so we need to find it by index - await userEvent.click(screen.getAllByRole('button', { name: /Sort/ })[2], { - pointerEventsCheck: 0, - }); + await userEvent.click(screen.getAllByRole('button', { name: /Sort/ })[2]); await waitFor(() => { values = getCellValuesByColumn(); expect(values.message).toEqual([ @@ -544,12 +545,11 @@ describe('UnifiedDataTable', () => { 'message_8', 'message_9', ]); - await userEvent.click(getButton('message')); + await userEvent.click(getColumnActions('message')); + await waitForEuiPopoverOpen(); // Column sort button incorrectly renders as "Sort " instead // of "Sort Z-A" in Jest tests, so we need to find it by index - await userEvent.click(screen.getAllByRole('button', { name: /Sort/ })[2], { - pointerEventsCheck: 0, - }); + await userEvent.click(screen.getAllByRole('button', { name: /Sort/ })[2]); await waitFor(() => { values = getCellValuesByColumn(); expect(values.message).toEqual([ @@ -1100,9 +1100,8 @@ describe('UnifiedDataTable', () => { await selectDocument(esHitsMock[0]); await selectDocument(esHitsMock[1]); await openSelectedRowsMenu(); - await userEvent.click(await screen.findByTestId('unifiedDataTableCompareSelectedDocuments'), { - pointerEventsCheck: 0, - }); + await waitForEuiPopoverOpen(); + await userEvent.click(await screen.findByTestId('unifiedDataTableCompareSelectedDocuments')); await screen.findByText('Comparing 2 documents'); // EuiDataGrid makes state updates after calling requestAnimationFrame, which can lead // to "Can't perform a React state update on an unmounted component." warnings in tests, @@ -1259,7 +1258,15 @@ describe('UnifiedDataTable', () => { const EUI_DEFAULT_COLUMN_WIDTH = '100px'; const getColumnHeader = (name: string) => screen.getByRole('columnheader', { name }); const queryColumnHeader = (name: string) => screen.queryByRole('columnheader', { name }); - const getButton = (name: string) => screen.getByRole('button', { name }); + const openColumnActions = async (name: string) => { + const actionsButton = screen.getByTestId(`dataGridHeaderCellActionButton-${name}`); + await userEvent.click(actionsButton); + await waitForEuiPopoverOpen(); + }; + const clickColumnAction = async (name: string) => { + const action = screen.getByRole('button', { name }); + await userEvent.click(action); + }; const queryButton = (name: string) => screen.queryByRole('button', { name }); it( @@ -1277,8 +1284,8 @@ describe('UnifiedDataTable', () => { expect(getColumnHeader('message')).toHaveStyle({ width: EUI_DEFAULT_COLUMN_WIDTH }); expect(getColumnHeader('extension')).toHaveStyle({ width: '50px' }); expect(getColumnHeader('bytes')).toHaveStyle({ width: '50px' }); - await userEvent.click(getButton('message')); - await userEvent.click(getButton('Remove column'), { pointerEventsCheck: 0 }); + await openColumnActions('message'); + await clickColumnAction('Remove column'); await waitFor(() => { expect(queryColumnHeader('message')).not.toBeInTheDocument(); }); @@ -1302,8 +1309,8 @@ describe('UnifiedDataTable', () => { expect(getColumnHeader('message')).toHaveStyle({ width: EUI_DEFAULT_COLUMN_WIDTH }); expect(getColumnHeader('extension')).toHaveStyle({ width: EUI_DEFAULT_COLUMN_WIDTH }); expect(getColumnHeader('bytes')).toHaveStyle({ width: '50px' }); - await userEvent.click(getButton('message')); - await userEvent.click(getButton('Remove column'), { pointerEventsCheck: 0 }); + await openColumnActions('message'); + await clickColumnAction('Remove column'); await waitFor(() => { expect(queryColumnHeader('message')).not.toBeInTheDocument(); }); @@ -1326,21 +1333,21 @@ describe('UnifiedDataTable', () => { }, }); expect(getColumnHeader('@timestamp')).toHaveStyle({ width: '50px' }); - await userEvent.click(getButton('@timestamp')); - await userEvent.click(getButton('Reset width'), { pointerEventsCheck: 0 }); + await openColumnActions('@timestamp'); + await clickColumnAction('Reset width'); await waitFor(() => { expect(getColumnHeader('@timestamp')).toHaveStyle({ width: `${defaultTimeColumnWidth}px`, }); }); expect(getColumnHeader('message')).toHaveStyle({ width: EUI_DEFAULT_COLUMN_WIDTH }); - await userEvent.click(getButton('message')); + await openColumnActions('message'); expect(queryButton('Reset width')).not.toBeInTheDocument(); await waitFor(() => { expect(getColumnHeader('extension')).toHaveStyle({ width: '50px' }); }); - await userEvent.click(getButton('extension')); - await userEvent.click(getButton('Reset width'), { pointerEventsCheck: 0 }); + await openColumnActions('extension'); + await clickColumnAction('Reset width'); await waitFor(() => { expect(getColumnHeader('extension')).toHaveStyle({ width: EUI_DEFAULT_COLUMN_WIDTH }); }); diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index cb7049e00f684e..7f6a9e53f66783 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -87,7 +87,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.3': ['Elastic License 2.0'], - '@elastic/eui@95.9.0': ['Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0'], + '@elastic/eui@95.10.1': ['Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary '@bufbuild/protobuf@1.2.1': ['Apache-2.0'], // license (Apache-2.0 AND BSD-3-Clause) diff --git a/test/accessibility/apps/discover.ts b/test/accessibility/apps/discover.ts index f94bc2d3c427e0..169cdcca0f5832 100644 --- a/test/accessibility/apps/discover.ts +++ b/test/accessibility/apps/discover.ts @@ -159,7 +159,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('a11y test for data-grid actions on columns', async () => { - await testSubjects.click('dataGridHeaderCellActionButton-Carrier'); + await dataGrid.openColMenuByField('Carrier'); await a11y.testAppSnapshot(); }); diff --git a/test/functional/apps/context/_discover_navigation.ts b/test/functional/apps/context/_discover_navigation.ts index 37dd92a8be50ce..e8213b54e6e9b9 100644 --- a/test/functional/apps/context/_discover_navigation.ts +++ b/test/functional/apps/context/_discover_navigation.ts @@ -58,6 +58,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace({}); }); + it('should open the context view with the same columns', async () => { + const columnNames = await dataGrid.getHeaderFields(); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); + }); + it('should open the context view with the selected document as anchor and allows selecting next anchor', async () => { /** * Helper function to get the first timestamp of the document table @@ -95,11 +100,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should open the context view with the same columns', async () => { - const columnNames = await dataGrid.getHeaderFields(); - expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); - }); - it('should open the context view with the filters disabled', async () => { let disabledFilterCounter = 0; for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { diff --git a/test/functional/apps/context/classic/_discover_navigation.ts b/test/functional/apps/context/classic/_discover_navigation.ts index a0bd5847544c50..476a4bfac9e18a 100644 --- a/test/functional/apps/context/classic/_discover_navigation.ts +++ b/test/functional/apps/context/classic/_discover_navigation.ts @@ -57,6 +57,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace({}); }); + it('should open the context view with the same columns', async () => { + const columnNames = await docTable.getHeaderFields(); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); + }); + it('should open the context view with the selected document as anchor and allows selecting next anchor', async () => { /** * Helper function to get the first timestamp of the document table @@ -93,11 +98,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should open the context view with the same columns', async () => { - const columnNames = await docTable.getHeaderFields(); - expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); - }); - it('should open the context view with the filters disabled', async () => { let disabledFilterCounter = 0; for (const [_, value, columnId] of TEST_FILTER_COLUMN_NAMES) { diff --git a/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts index cbd9221311f16e..0757304199d8a8 100644 --- a/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts +++ b/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts @@ -63,6 +63,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await timePicker.resetDefaultAbsoluteRangeViaUiSettings(); }); + it('should open the context view with the same columns', async () => { + const columnNames = await dataGrid.getHeaderFields(); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); + }); + it('should open the context view with the selected document as anchor', async () => { // check the anchor timestamp in the context view await retry.waitFor('selected document timestamp matches anchor timestamp ', async () => { @@ -82,11 +87,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should open the context view with the same columns', async () => { - const columnNames = await dataGrid.getHeaderFields(); - expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); - }); - it('should open the context view with the filters disabled', async () => { let disabledFilterCounter = 0; for (const [_, value, columnId] of TEST_FILTER_COLUMN_NAMES) { diff --git a/test/functional/apps/management/data_views/_scripted_fields.ts b/test/functional/apps/management/data_views/_scripted_fields.ts index d87e5e602297b6..b5697ab30eae6d 100644 --- a/test/functional/apps/management/data_views/_scripted_fields.ts +++ b/test/functional/apps/management/data_views/_scripted_fields.ts @@ -33,7 +33,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const testSubjects = getService('testSubjects'); const filterBar = getService('filterBar'); - const find = getService('find'); const dataGrid = getService('dataGrid'); const PageObjects = getPageObjects([ 'common', @@ -60,16 +59,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.unsetTime(); }); - /** - * @param field field name to sort - * @param optionIndex index of the option to choose in dropdown - */ - const clickSort = async (field: string, optionIndex: number) => { - await testSubjects.click(`dataGridHeaderCell-${field}`); - const optionButtons = await find.allByCssSelector('.euiListGroupItem__button'); - await optionButtons[optionIndex].click(); - }; - it('should not allow saving of invalid scripts', async function () { await PageObjects.settings.navigateTo(); await PageObjects.settings.clickKibanaIndexPatterns(); @@ -170,13 +159,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // add a test to sort numeric scripted field it('should sort scripted field value in Discover', async function () { - await clickSort(scriptedPainlessFieldName, 1); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName, 1); await PageObjects.common.sleep(500); // after the first click on the scripted field, it becomes secondary sort after time. // click on the timestamp twice to make it be the secondary sort key. - await clickSort('@timestamp', 1); - await clickSort('@timestamp', 0); + await dataGrid.clickColumnActionAt('@timestamp', 1); + await dataGrid.clickColumnActionAt('@timestamp', 0); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { @@ -184,11 +173,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181-1'); }); - await clickSort(scriptedPainlessFieldName, 2); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName, 2); // after the first click on the scripted field, it becomes primary sort after time. // click on the scripted field twice then, makes it be the secondary sort key. - await clickSort(scriptedPainlessFieldName, 2); - await clickSort(scriptedPainlessFieldName, 2); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName, 2); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName, 2); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { @@ -275,25 +264,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // add a test to sort string scripted field it('should sort scripted field value in Discover', async function () { - await clickSort(scriptedPainlessFieldName2, 1); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName2, 1); // await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); await PageObjects.common.sleep(500); // after the first click on the scripted field, it becomes secondary sort after time. // click on the timestamp twice to make it be the secondary sort key. - await clickSort('@timestamp', 1); - await clickSort('@timestamp', 0); + await dataGrid.clickColumnActionAt('@timestamp', 1); + await dataGrid.clickColumnActionAt('@timestamp', 0); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { const rowData = (await dataGrid.getRowsText())[0]; expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594bad'); }); - await clickSort(scriptedPainlessFieldName2, 2); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName2, 2); // after the first click on the scripted field, it becomes primary sort after time. // click on the scripted field twice then, makes it be the secondary sort key. - await clickSort(scriptedPainlessFieldName2, 2); - await clickSort(scriptedPainlessFieldName2, 2); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName2, 2); + await dataGrid.clickColumnActionAt(scriptedPainlessFieldName2, 2); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index 880b761d0f22f1..de8f523b268ab3 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -386,7 +386,7 @@ export class DataGridService extends FtrService { public async getHeaderFields(): Promise { const result = await this.find.allByCssSelector( - '.euiDataGridHeaderCell__button > .euiDataGridHeaderCell__content' + '.euiDataGridHeaderCell:not(.euiDataGridHeaderCell--controlColumn) .euiDataGridHeaderCell__content' ); const textArr = []; @@ -428,15 +428,27 @@ export class DataGridService extends FtrService { public async openColMenuByField(field: string) { await this.retry.waitFor('header cell action being displayed', async () => { // to prevent flakiness - await this.testSubjects.click(`dataGridHeaderCell-${field}`); + await this.testSubjects.moveMouseTo(`dataGridHeaderCell-${field}`); + await this.testSubjects.click(`dataGridHeaderCellActionButton-${field}`); return await this.testSubjects.exists(`dataGridHeaderCellActionGroup-${field}`); }); } + public async clickColumnActionAt(field: string, index: number) { + await this.openColMenuByField(field); + const actionsGroup = await this.testSubjects.find(`dataGridHeaderCellActionGroup-${field}`); + const actionButtons = await actionsGroup.findAllByTagName('button'); + await actionButtons[index].click(); + } + private async clickColumnMenuField(field?: string) { if (field) { await this.openColMenuByField(field); } else { + const columns = await this.find.allByCssSelector( + '.euiDataGridHeaderCell:not(.euiDataGridHeaderCell--controlColumn)' + ); + await columns[0].moveMouseTo(); await this.find.clickByCssSelector('.euiDataGridHeaderCell__button'); } } @@ -461,6 +473,11 @@ export class DataGridService extends FtrService { await this.find.clickByButtonText('Move left'); } + public async clickHideColumn(field?: string) { + await this.clickColumnMenuField(field); + await this.find.clickByButtonText('Hide column'); + } + public async clickRemoveColumn(field?: string) { await this.clickColumnMenuField(field); await this.find.clickByButtonText('Remove column'); diff --git a/x-pack/packages/security-solution/data_table/components/data_table/index.test.tsx b/x-pack/packages/security-solution/data_table/components/data_table/index.test.tsx index b4109583431674..f8183c51e46781 100644 --- a/x-pack/packages/security-solution/data_table/components/data_table/index.test.tsx +++ b/x-pack/packages/security-solution/data_table/components/data_table/index.test.tsx @@ -269,7 +269,7 @@ describe('DataTable', () => { ); // click the `@timestamp` column header to display the popover - fireEvent.click(screen.getByText('@timestamp')); + fireEvent.click(screen.getByTestId('dataGridHeaderCellActionButton-@timestamp')); // click the `Remove column` action in the popover fireEvent.click(await screen.getByText(REMOVE_COLUMN)); diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx index 6148bda17e5f4a..7ca9137f938fbf 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx @@ -172,7 +172,7 @@ describe('DatatableComponent', () => { test('it should render hide, reset, and sort actions on header even when it is in read only mode', async () => { renderDatatableComponent({ renderMode: 'view' }); - await userEvent.click(screen.getByRole('button', { name: 'a' })); + await userEvent.click(screen.getByTestId('dataGridHeaderCellActionButton-a')); const actionPopover = screen.getByRole('dialog'); const actions = within(actionPopover) .getAllByRole('button') diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index a90bac2feed944..94c3218ae520be 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -765,7 +765,7 @@ "core.euiDataGridCell.position": "{columnId}, colonne {col}, ligne {row}", "core.euiDataGridCellActions.expandButtonTitle": "Cliquez ou appuyez sur Entrée pour interagir avec le contenu de la cellule.", "core.euiDataGridHeaderCell.actionsPopoverScreenReaderText": "Pour naviguer dans la liste des actions de la colonne, appuyez sur la touche Tab ou sur les flèches vers le haut et vers le bas.", - "core.euiDataGridHeaderCell.headerActions": "Cliquez pour afficher les actions d'en-tête de colonne", + "core.euiDataGridHeaderCell.actionsButtonAriaLabel": "{title}. Cliquez pour afficher les actions d'en-tête de colonne", "core.euiDataGridHeaderCell.sortedByAscendingFirst": "Trié par {columnId}, ordre croissant", "core.euiDataGridHeaderCell.sortedByAscendingMultiple": ", puis par {columnId}, ordre croissant", "core.euiDataGridHeaderCell.sortedByAscendingSingle": "Trié par ordre croissant", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 43dd8f770ac1ed..45c1da388c176c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -767,7 +767,7 @@ "core.euiDataGridCell.position": "{columnId}, 列{col}, 行{row}", "core.euiDataGridCellActions.expandButtonTitle": "クリックするか enter を押すと、セルのコンテンツとインタラクトできます。", "core.euiDataGridHeaderCell.actionsPopoverScreenReaderText": "列アクションのリストを移動するには、Tabまたは上下矢印キーを押します。", - "core.euiDataGridHeaderCell.headerActions": "クリックすると、列ヘッダーアクションが表示されます", + "core.euiDataGridHeaderCell.actionsButtonAriaLabel": "{title}。クリックすると、列ヘッダーアクションが表示されます", "core.euiDataGridHeaderCell.sortedByAscendingFirst": "{columnId}の昇順で並べ替え", "core.euiDataGridHeaderCell.sortedByAscendingMultiple": "、{columnId}の昇順で並べ替え", "core.euiDataGridHeaderCell.sortedByAscendingSingle": "昇順で並べ替えます", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 02aa5c9d475c1b..55aa6ce129ae8b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -765,7 +765,7 @@ "core.euiDataGridCell.position": "{columnId},列 {col},行 {row}", "core.euiDataGridCellActions.expandButtonTitle": "单击或按 Enter 键以便与单元格内容进行交互", "core.euiDataGridHeaderCell.actionsPopoverScreenReaderText": "要在列操作列表中导航,请按 Tab 键或向上和向下箭头键。", - "core.euiDataGridHeaderCell.headerActions": "单击以查看列标题操作", + "core.euiDataGridHeaderCell.actionsButtonAriaLabel": "{title}。单击以查看列标题操作", "core.euiDataGridHeaderCell.sortedByAscendingFirst": "按 {columnId} 排序,升序", "core.euiDataGridHeaderCell.sortedByAscendingMultiple": ",然后按 {columnId} 排序,升序", "core.euiDataGridHeaderCell.sortedByAscendingSingle": "已升序", diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index bf38c4e1bdebe4..4b2ece9a7ca926 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -1257,8 +1257,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont async changeTableSortingBy(colIndex = 0, direction: 'none' | 'ascending' | 'descending') { const el = await this.getDatatableHeader(colIndex); - await el.moveMouseTo({ xOffset: 0, yOffset: -20 }); // Prevent the first data row's cell actions from overlapping/intercepting the header click - await el.click(); + await el.moveMouseTo({ xOffset: 0, yOffset: -16 }); // Prevent the first data row's cell actions from overlapping/intercepting the header click + const popoverToggle = await el.findByClassName('euiDataGridHeaderCell__button'); + await popoverToggle.click(); let buttonEl; if (direction !== 'none') { buttonEl = await find.byCssSelector( diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 137e9ef6f6f2bc..1880400dc37c54 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -16,6 +16,7 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) const retry = getService('retry'); const testSubjects = getService('testSubjects'); const rules = getService('rules'); + const dataGrid = getService('dataGrid'); function getRowItemData(row: CustomCheerio, $: CustomCheerioStatic) { return { @@ -221,15 +222,11 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await columnsButton.click(); }, async sortEventLogColumn(columnId: string, direction: string) { - await testSubjects.click(`dataGridHeaderCell-${columnId}`); - const popover = await testSubjects.find(`dataGridHeaderCellActionGroup-${columnId}`); - const popoverListItems = await popover.findAllByCssSelector('li'); - if (direction === 'asc') { - await popoverListItems[1].click(); + await dataGrid.clickColumnActionAt(columnId, 1); } if (direction === 'desc') { - await popoverListItems[2].click(); + await dataGrid.clickColumnActionAt(columnId, 2); } }, async clickAlertsPageShowQueryMenuButton() { diff --git a/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts b/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts index 33a2c5e7bc44c4..c39472715a3536 100644 --- a/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts +++ b/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts @@ -16,6 +16,7 @@ export default ({ getService, getPageObject }: FtrProviderContext) => { const observability = getService('observability'); const esArchiver = getService('esArchiver'); const testSubjects = getService('testSubjects'); + const dataGrid = getService('dataGrid'); before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); @@ -29,42 +30,23 @@ export default ({ getService, getPageObject }: FtrProviderContext) => { it('remembers column changes', async () => { await observability.alerts.common.navigateToTimeWithData(); - const durationColumnButton = await testSubjects.find( - 'dataGridHeaderCellActionButton-kibana.alert.duration.us' - ); - await durationColumnButton.click(); - const columnMenu = await testSubjects.find( - 'dataGridHeaderCellActionGroup-kibana.alert.duration.us' - ); - const removeButton = await columnMenu.findByCssSelector('[title="Hide column"]'); - await removeButton.click(); + await dataGrid.clickHideColumn('kibana.alert.duration.us'); await observability.alerts.common.navigateToTimeWithData(); const durationColumnExists = await testSubjects.exists( - 'dataGridHeaderCellActionButton-kibana.alert.duration.us' + 'dataGridHeaderCell-kibana.alert.duration.us' ); - expect(durationColumnExists).to.be(false); }); it('remembers sorting changes', async () => { await observability.alerts.common.navigateToTimeWithData(); - const triggeredColumnButton = await testSubjects.find( - 'dataGridHeaderCellActionButton-kibana.alert.start' - ); - await triggeredColumnButton.click(); - const columnMenu = await testSubjects.find( - 'dataGridHeaderCellActionGroup-kibana.alert.start' - ); - const sortButton = await columnMenu.findByCssSelector('[title="Sort Old-New"]'); - await sortButton.click(); + await dataGrid.clickDocSortAsc('kibana.alert.start'); await observability.alerts.common.navigateToTimeWithData(); - const triggeredColumnHeading = await testSubjects.find( - 'dataGridHeaderCell-kibana.alert.start' - ); + const triggeredColumnHeading = await dataGrid.getHeaderElement('kibana.alert.start'); expect(await triggeredColumnHeading.getAttribute('aria-sort')).to.be('ascending'); }); }); diff --git a/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts b/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts index a2289ce1a2662f..983eaf813f9999 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_triggers_actions_ui_page.ts @@ -16,6 +16,7 @@ export function SvlTriggersActionsPageProvider({ getService }: FtrProviderContex const retry = getService('retry'); const testSubjects = getService('testSubjects'); const rules = getService('rules'); + const dataGrid = getService('dataGrid'); function getRowItemData(row: CustomCheerio, $: CustomCheerioStatic) { return { @@ -221,15 +222,11 @@ export function SvlTriggersActionsPageProvider({ getService }: FtrProviderContex await columnsButton.click(); }, async sortEventLogColumn(columnId: string, direction: string) { - await testSubjects.click(`dataGridHeaderCell-${columnId}`); - const popover = await testSubjects.find(`dataGridHeaderCellActionGroup-${columnId}`); - const popoverListItems = await popover.findAllByCssSelector('li'); - if (direction === 'asc') { - await popoverListItems[1].click(); + await dataGrid.clickColumnActionAt(columnId, 1); } if (direction === 'desc') { - await popoverListItems[2].click(); + await dataGrid.clickColumnActionAt(columnId, 2); } }, }; diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts b/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts index dccd6723507d5f..9e5ee000f324f8 100644 --- a/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts @@ -64,6 +64,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace({}); }); + it('should open the context view with the same columns', async () => { + const columnNames = await dataGrid.getHeaderFields(); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); + }); + it('should open the context view with the selected document as anchor and allows selecting next anchor', async () => { /** * Helper function to get the first timestamp of the document table @@ -101,11 +106,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should open the context view with the same columns', async () => { - const columnNames = await dataGrid.getHeaderFields(); - expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); - }); - it('should open the context view with the filters disabled', async () => { let disabledFilterCounter = 0; for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { diff --git a/yarn.lock b/yarn.lock index b984c1145b972f..d57afd7e910c7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1741,10 +1741,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@95.9.0": - version "95.9.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-95.9.0.tgz#23fbafd7613fb6b41b4925ec4977a0c1e075b455" - integrity sha512-Ppna5bGjamttqHdwhYYrdXOprF3OpEY0schX7mOVJmtpcBtp7wAMYQq/bBELBVb7idO4NytbzI1Q6R6NYs5Tdg== +"@elastic/eui@95.10.1": + version "95.10.1" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-95.10.1.tgz#f3fb356ad49ba45e42981e39748693ba392567fe" + integrity sha512-1kqyx/NfiQE/bKMf1E3uJEpYZnQnPBrI5zO0l2FB+fs7Naf7wT7zq1VFRzNLn/r1x6mnou8wJ+VlouHCI+prLw== dependencies: "@hello-pangea/dnd" "^16.6.0" "@types/lodash" "^4.14.202"