Skip to content

Commit

Permalink
[8.x] [Unified Data Table] Prevent `undefined` errors when …
Browse files Browse the repository at this point in the history
…row accessed via `rows[rowIndex]` (#193791) (#193908)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Unified Data Table] Prevent `undefined` errors when row
accessed via `rows[rowIndex]`
(#193791)](#193791)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Davis
McPhee","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-09-24T18:36:11Z","message":"[Unified
Data Table] Prevent `undefined` errors when row accessed via
`rows[rowIndex]` (#193791)\n\n## Summary\r\n\r\nThis PR fixes an issue
present in 8.15, but which no longer exists after\r\nlater refactoring,
where saved search panels (possibly only ES|QL\r\npanels? It was hard to
nail down since involved a race condition) could\r\nfail in dashboards
when adding Unified Search filters that reduce the\r\nnumber of results
in the grid.\r\n\r\nI'm still not 100% sure what the source of the issue
was since it\r\ninvolved a race condition (didn't fail consistently for
me locally) and\r\ninternal EUI data grid code, but I have a hunch. The
`undefined` errors\r\noccurred when trying to access a row by index from
`DataTableContext` in\r\ncertain cell renderers during the first render
after search results had\r\nchanged. I believe what was happening was
the change to\r\n`DataTableContext` triggered a re-render of the cells
before EUI data\r\ngrid internally updated its state, resulting in
attempts to access rows\r\nfrom within the cell renderers that no longer
existed in the updated\r\n`DataTableContext`, and causing `undefined`
reference errors.\r\n\r\nI'm making these changes in `main` instead of
`8.15` directly because\r\nthe updated approach is generally a safer way
to retrieve rows and\r\nprevent similar issues in the future. Previously
we added `rows` to\r\n`DataTableContext` and retrieved a single row by
index using bracket\r\nnotation, which can potentially return
`undefined`, but TypeScript does\r\nnot protect against it for us.
Instead I've updated `DataTableContext`\r\nwith a `getRowByIndex` method
that correctly returns `DataTableRecord |\r\nundefined` and forces
consumers to explicitly handle the `undefined`\r\nscenario.\r\n\r\nThe
PR will require some manual backporting to 8.15 since some
things\r\nhave changed since then, but it shouldn't be
difficult.\r\n\r\n### Checklist\r\n\r\n- [ ] Any text added follows
[EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[
]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas
added for features that require explanation or tutorials\r\n- [x] [Unit
or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is
usable by keyboard only (learn more\r\nabout [keyboard
accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[ ] If a plugin configuration key changed, check if it needs to
be\r\nallowlisted in the cloud and added to the
[docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n-
[ ] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[ ] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n###
For maintainers\r\n\r\n- [ ] This was checked for breaking API changes
and was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"6ff07918b0490fa7d66202376073a337da55c73e","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Discover","release_note:fix","v9.0.0","Team:DataDiscovery","backport:prev-minor","backport:prev-major","Feature:UnifiedDataTable"],"title":"[Unified
Data Table] Prevent `undefined` errors when row accessed via
`rows[rowIndex]`","number":193791,"url":"https://github.com/elastic/kibana/pull/193791","mergeCommit":{"message":"[Unified
Data Table] Prevent `undefined` errors when row accessed via
`rows[rowIndex]` (#193791)\n\n## Summary\r\n\r\nThis PR fixes an issue
present in 8.15, but which no longer exists after\r\nlater refactoring,
where saved search panels (possibly only ES|QL\r\npanels? It was hard to
nail down since involved a race condition) could\r\nfail in dashboards
when adding Unified Search filters that reduce the\r\nnumber of results
in the grid.\r\n\r\nI'm still not 100% sure what the source of the issue
was since it\r\ninvolved a race condition (didn't fail consistently for
me locally) and\r\ninternal EUI data grid code, but I have a hunch. The
`undefined` errors\r\noccurred when trying to access a row by index from
`DataTableContext` in\r\ncertain cell renderers during the first render
after search results had\r\nchanged. I believe what was happening was
the change to\r\n`DataTableContext` triggered a re-render of the cells
before EUI data\r\ngrid internally updated its state, resulting in
attempts to access rows\r\nfrom within the cell renderers that no longer
existed in the updated\r\n`DataTableContext`, and causing `undefined`
reference errors.\r\n\r\nI'm making these changes in `main` instead of
`8.15` directly because\r\nthe updated approach is generally a safer way
to retrieve rows and\r\nprevent similar issues in the future. Previously
we added `rows` to\r\n`DataTableContext` and retrieved a single row by
index using bracket\r\nnotation, which can potentially return
`undefined`, but TypeScript does\r\nnot protect against it for us.
Instead I've updated `DataTableContext`\r\nwith a `getRowByIndex` method
that correctly returns `DataTableRecord |\r\nundefined` and forces
consumers to explicitly handle the `undefined`\r\nscenario.\r\n\r\nThe
PR will require some manual backporting to 8.15 since some
things\r\nhave changed since then, but it shouldn't be
difficult.\r\n\r\n### Checklist\r\n\r\n- [ ] Any text added follows
[EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[
]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas
added for features that require explanation or tutorials\r\n- [x] [Unit
or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is
usable by keyboard only (learn more\r\nabout [keyboard
accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[ ] If a plugin configuration key changed, check if it needs to
be\r\nallowlisted in the cloud and added to the
[docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n-
[ ] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[ ] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n###
For maintainers\r\n\r\n- [ ] This was checked for breaking API changes
and was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"6ff07918b0490fa7d66202376073a337da55c73e"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193791","number":193791,"mergeCommit":{"message":"[Unified
Data Table] Prevent `undefined` errors when row accessed via
`rows[rowIndex]` (#193791)\n\n## Summary\r\n\r\nThis PR fixes an issue
present in 8.15, but which no longer exists after\r\nlater refactoring,
where saved search panels (possibly only ES|QL\r\npanels? It was hard to
nail down since involved a race condition) could\r\nfail in dashboards
when adding Unified Search filters that reduce the\r\nnumber of results
in the grid.\r\n\r\nI'm still not 100% sure what the source of the issue
was since it\r\ninvolved a race condition (didn't fail consistently for
me locally) and\r\ninternal EUI data grid code, but I have a hunch. The
`undefined` errors\r\noccurred when trying to access a row by index from
`DataTableContext` in\r\ncertain cell renderers during the first render
after search results had\r\nchanged. I believe what was happening was
the change to\r\n`DataTableContext` triggered a re-render of the cells
before EUI data\r\ngrid internally updated its state, resulting in
attempts to access rows\r\nfrom within the cell renderers that no longer
existed in the updated\r\n`DataTableContext`, and causing `undefined`
reference errors.\r\n\r\nI'm making these changes in `main` instead of
`8.15` directly because\r\nthe updated approach is generally a safer way
to retrieve rows and\r\nprevent similar issues in the future. Previously
we added `rows` to\r\n`DataTableContext` and retrieved a single row by
index using bracket\r\nnotation, which can potentially return
`undefined`, but TypeScript does\r\nnot protect against it for us.
Instead I've updated `DataTableContext`\r\nwith a `getRowByIndex` method
that correctly returns `DataTableRecord |\r\nundefined` and forces
consumers to explicitly handle the `undefined`\r\nscenario.\r\n\r\nThe
PR will require some manual backporting to 8.15 since some
things\r\nhave changed since then, but it shouldn't be
difficult.\r\n\r\n### Checklist\r\n\r\n- [ ] Any text added follows
[EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[
]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas
added for features that require explanation or tutorials\r\n- [x] [Unit
or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is
usable by keyboard only (learn more\r\nabout [keyboard
accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[ ] If a plugin configuration key changed, check if it needs to
be\r\nallowlisted in the cloud and added to the
[docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n-
[ ] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[ ] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n###
For maintainers\r\n\r\n- [ ] This was checked for breaking API changes
and was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"6ff07918b0490fa7d66202376073a337da55c73e"}}]}]
BACKPORT-->

Co-authored-by: Davis McPhee <[email protected]>
  • Loading branch information
kibanamachine and davismcphee authored Sep 24, 2024
1 parent be2edae commit bdfccd2
Show file tree
Hide file tree
Showing 19 changed files with 153 additions and 108 deletions.
27 changes: 17 additions & 10 deletions packages/kbn-unified-data-table/__mocks__/table_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,14 @@ import { servicesMock } from './services';
import { DataTableContext } from '../src/table_context';
import { convertValueToString } from '../src/utils/convert_value_to_string';
import { buildDataTableRecord } from '@kbn/discover-utils';
import type { DataTableRecord, EsHitRecord } from '@kbn/discover-utils/types';
import type { DataTableRecord } from '@kbn/discover-utils/types';
import type { UseSelectedDocsState } from '../src/hooks/use_selected_docs';

const buildTableContext = (dataView: DataView, rows: EsHitRecord[]): DataTableContext => {
const usedRows = rows.map((row) => {
return buildDataTableRecord(row, dataView);
});

const buildTableContext = (dataView: DataView, rows: DataTableRecord[]): DataTableContext => {
return {
expanded: undefined,
setExpanded: jest.fn(),
rows: usedRows,
getRowByIndex: jest.fn((index) => rows[index]),
onFilter: jest.fn(),
dataView,
isDarkMode: false,
Expand All @@ -38,16 +34,27 @@ const buildTableContext = (dataView: DataView, rows: EsHitRecord[]): DataTableCo
rowIndex,
columnId,
fieldFormats: servicesMock.fieldFormats,
rows: usedRows,
rows,
dataView,
options,
}),
};
};

export const dataTableContextMock = buildTableContext(dataViewMock, esHitsMock);
export const dataTableContextRowsMock = esHitsMock.map((row) =>
buildDataTableRecord(row, dataViewMock)
);

export const dataTableContextMock = buildTableContext(dataViewMock, dataTableContextRowsMock);

export const dataTableContextComplexRowsMock = esHitsComplex.map((row) =>
buildDataTableRecord(row, dataViewComplexMock)
);

export const dataTableContextComplexMock = buildTableContext(dataViewComplexMock, esHitsComplex);
export const dataTableContextComplexMock = buildTableContext(
dataViewComplexMock,
dataTableContextComplexRowsMock
);

export function buildSelectedDocsState(selectedDocIds: string[]): UseSelectedDocsState {
const selectedDocsSet = new Set(selectedDocIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ describe('getRowControlColumn', () => {

button.click();

expect(mockClick).toHaveBeenCalledWith({ record: contextMock.rows[1], rowIndex: 1 });
expect(mockClick).toHaveBeenCalledWith({ record: contextMock.getRowByIndex(1), rowIndex: 1 });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const RowControlCell = ({
}: EuiDataGridCellValueElementProps & {
renderControl: RowControlColumn['renderControl'];
}) => {
const rowProps = useControlColumn(props);
const { record, rowIndex } = useControlColumn(props);

const Control: React.FC<RowControlProps> = useMemo(
() =>
Expand All @@ -50,17 +50,19 @@ export const RowControlCell = ({
color={color ?? 'text'}
aria-label={label}
onClick={() => {
onClick?.(rowProps);
if (record) {
onClick?.({ record, rowIndex });
}
}}
/>
</EuiToolTip>
</DataTableRowControl>
);
},
[props.columnId, rowProps]
[props.columnId, record, rowIndex]
);

return renderControl(Control, rowProps);
return record ? renderControl(Control, { record, rowIndex }) : null;
};

export const getRowControlColumn = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@ describe('getRowMenuControlColumn', () => {
expect(button).toBeInTheDocument();

button.click();
expect(mockClick).toHaveBeenCalledWith({ record: contextMock.rows[1], rowIndex: 1 });
expect(mockClick).toHaveBeenCalledWith({ record: contextMock.getRowByIndex(1), rowIndex: 1 });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const RowMenuControlCell = ({
}: EuiDataGridCellValueElementProps & {
rowControlColumns: RowControlColumn[];
}) => {
const rowProps = useControlColumn(props);
const { record, rowIndex } = useControlColumn(props);
const [isMoreActionsPopoverOpen, setIsMoreActionsPopoverOpen] = useState<boolean>(false);

const buttonLabel = i18n.translate('unifiedDataTable.grid.additionalRowActions', {
Expand All @@ -51,15 +51,17 @@ export const RowMenuControlCell = ({
icon={iconType}
color={color}
onClick={() => {
onClick?.(rowProps);
if (record) {
onClick?.({ record, rowIndex });
}
setIsMoreActionsPopoverOpen(false);
}}
>
{label}
</EuiContextMenuItem>
);
},
[rowProps, setIsMoreActionsPopoverOpen]
[record, rowIndex]
);

const popoverMenuItems = useMemo(
Expand All @@ -68,11 +70,11 @@ export const RowMenuControlCell = ({
const Control = getControlComponent(rowControlColumn.id);
return (
<Fragment key={rowControlColumn.id}>
{rowControlColumn.renderControl(Control, rowProps)}
{record ? rowControlColumn.renderControl(Control, { record, rowIndex }) : null}
</Fragment>
);
}),
[rowControlColumns, rowProps, getControlComponent]
[rowControlColumns, getControlComponent, record, rowIndex]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ describe('ColorIndicatorControlColumn', () => {
/>
</UnifiedDataTableContext.Provider>
);
expect(getRowIndicator).toHaveBeenCalledWith(contextMock.rows[1], expect.any(Object));
expect(getRowIndicator).toHaveBeenCalledWith(contextMock.getRowByIndex(1), expect.any(Object));
});
});
9 changes: 5 additions & 4 deletions packages/kbn-unified-data-table/src/components/data_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import {
SELECT_ROW,
OPEN_DETAILS,
} from './data_table_columns';
import { UnifiedDataTableContext } from '../table_context';
import { DataTableContext, UnifiedDataTableContext } from '../table_context';
import { getSchemaDetectors } from './data_table_schema';
import { DataTableDocumentToolbarBtn } from './data_table_document_selection';
import { useRowHeightsOptions } from '../hooks/use_row_heights_options';
Expand Down Expand Up @@ -629,11 +629,11 @@ export const UnifiedDataTable = ({
);
}, [currentPageSize, setPagination]);

const unifiedDataTableContextValue = useMemo(
const unifiedDataTableContextValue = useMemo<DataTableContext>(
() => ({
expanded: expandedDoc,
setExpanded: setExpandedDoc,
rows: displayedRows,
getRowByIndex: (index: number) => displayedRows[index],
onFilter,
dataView,
isDarkMode: darkMode,
Expand Down Expand Up @@ -876,7 +876,7 @@ export const UnifiedDataTable = ({
const canSetExpandedDoc = Boolean(setExpandedDoc && !!renderDocumentView);

const leadingControlColumns: EuiDataGridControlColumn[] = useMemo(() => {
const defaultControlColumns = getLeadControlColumns(canSetExpandedDoc);
const defaultControlColumns = getLeadControlColumns({ rows: displayedRows, canSetExpandedDoc });
const internalControlColumns = controlColumnIds
? // reorder the default controls as per controlColumnIds
controlColumnIds.reduce((acc, id) => {
Expand Down Expand Up @@ -907,6 +907,7 @@ export const UnifiedDataTable = ({
}, [
canSetExpandedDoc,
controlColumnIds,
displayedRows,
externalControlColumns,
getRowIndicator,
rowAdditionalLeadingControls,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ import {
import { type DataView, DataViewField } from '@kbn/data-views-plugin/public';
import { ToastsStart, IUiSettingsClient } from '@kbn/core/public';
import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
import type { DataTableRecord } from '@kbn/discover-utils';
import { ExpandButton } from './data_table_expand_button';
import { CustomGridColumnsConfiguration, UnifiedDataTableSettings } from '../types';
import type { ValueToStringConverter, DataTableColumnsMeta } from '../types';
import { buildCellActions } from './default_cell_actions';
import { getSchemaByKbnType } from './data_table_schema';
import { SelectButton, SelectAllButton } from './data_table_document_selection';
import { SelectButton, getSelectAllButton } from './data_table_document_selection';
import {
defaultTimeColumnWidth,
ROWS_HEIGHT_OPTIONS,
Expand Down Expand Up @@ -73,18 +74,24 @@ const openDetails = {
rowCellRender: ExpandButton,
};

const select = {
const getSelect = (rows: DataTableRecord[]) => ({
id: SELECT_ROW,
width: DEFAULT_CONTROL_COLUMN_WIDTH,
rowCellRender: SelectButton,
headerCellRender: SelectAllButton,
};
headerCellRender: getSelectAllButton(rows),
});

export function getLeadControlColumns(canSetExpandedDoc: boolean) {
export function getLeadControlColumns({
rows,
canSetExpandedDoc,
}: {
rows: DataTableRecord[];
canSetExpandedDoc: boolean;
}) {
if (!canSetExpandedDoc) {
return [select];
return [getSelect(rows)];
}
return [openDetails, select];
return [openDetails, getSelect(rows)];
}

function buildEuiGridColumn({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import React, { useContext, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiContextMenuItem } from '@elastic/eui';
import type { ToastsStart } from '@kbn/core/public';
import type { DataTableRecord } from '@kbn/discover-utils';
import { copyRowsAsJsonToClipboard } from '../utils/copy_value_to_clipboard';
import { UnifiedDataTableContext } from '../table_context';

interface DataTableCopyRowsAsJsonProps {
rows: DataTableRecord[];
toastNotifications: ToastsStart;
onCompleted: () => void;
}

export const DataTableCopyRowsAsJson: React.FC<DataTableCopyRowsAsJsonProps> = ({
rows,
toastNotifications,
onCompleted,
}) => {
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const { rows, selectedDocsState, isPlainRecord } = useContext(UnifiedDataTableContext);
const { selectedDocsState, isPlainRecord } = useContext(UnifiedDataTableContext);
const { getSelectedDocsOrderedByRows } = selectedDocsState;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ import { uniq } from 'lodash';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiContextMenuItem } from '@elastic/eui';
import type { ToastsStart } from '@kbn/core/public';
import { calcFieldCounts } from '@kbn/discover-utils';
import { DataTableRecord, calcFieldCounts } from '@kbn/discover-utils';
import { copyRowsAsTextToClipboard } from '../utils/copy_value_to_clipboard';
import { UnifiedDataTableContext } from '../table_context';

interface DataTableCopyRowsAsTextProps {
rows: DataTableRecord[];
toastNotifications: ToastsStart;
columns: string[];
onCompleted: () => void;
}

export const DataTableCopyRowsAsText: React.FC<DataTableCopyRowsAsTextProps> = ({
rows,
toastNotifications,
columns,
onCompleted,
}) => {
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const { valueToStringConverter, dataView, rows, selectedDocsState } =
const { valueToStringConverter, dataView, selectedDocsState } =
useContext(UnifiedDataTableContext);
const { isDocSelected } = selectedDocsState;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ import {
DataTableCompareToolbarBtn,
DataTableDocumentToolbarBtn,
SelectButton,
SelectAllButton,
getSelectAllButton,
} from './data_table_document_selection';
import { buildSelectedDocsState, dataTableContextMock } from '../../__mocks__/table_context';
import {
buildSelectedDocsState,
dataTableContextMock,
dataTableContextRowsMock,
} from '../../__mocks__/table_context';
import { UnifiedDataTableContext } from '../table_context';
import { getDocId } from '@kbn/discover-utils';
import { render, screen } from '@testing-library/react';
Expand Down Expand Up @@ -49,6 +53,7 @@ describe('document selection', () => {
const contextMock = {
...dataTableContextMock,
};
const SelectAllButton = getSelectAllButton(dataTableContextRowsMock);

const component = mountWithIntl(
<UnifiedDataTableContext.Provider value={contextMock}>
Expand All @@ -65,6 +70,7 @@ describe('document selection', () => {
...dataTableContextMock,
selectedDocsState: buildSelectedDocsState(['i::1::']),
};
const SelectAllButton = getSelectAllButton(dataTableContextRowsMock);

const component = mountWithIntl(
<UnifiedDataTableContext.Provider value={contextMock}>
Expand Down Expand Up @@ -197,7 +203,7 @@ describe('document selection', () => {
const props = {
isPlainRecord: false,
isFilterActive: false,
rows: dataTableContextMock.rows,
rows: dataTableContextRowsMock,
selectedDocsState: buildSelectedDocsState(['i::1::', 'i::2::']),
setIsFilterActive: jest.fn(),
enableComparisonMode: true,
Expand Down Expand Up @@ -242,7 +248,7 @@ describe('document selection', () => {
const props = {
isPlainRecord: false,
isFilterActive: false,
rows: dataTableContextMock.rows,
rows: dataTableContextRowsMock,
selectedDocsState: buildSelectedDocsState(['i::1::']),
setIsFilterActive: jest.fn(),
enableComparisonMode: true,
Expand Down Expand Up @@ -271,7 +277,7 @@ describe('document selection', () => {
const props = {
isPlainRecord: false,
isFilterActive: false,
rows: dataTableContextMock.rows,
rows: dataTableContextRowsMock,
selectedDocsState: buildSelectedDocsState(['i::1::', 'i::2::']),
setIsFilterActive: jest.fn(),
enableComparisonMode: true,
Expand Down Expand Up @@ -307,7 +313,7 @@ describe('document selection', () => {
const props = {
isPlainRecord: false,
isFilterActive: false,
rows: dataTableContextMock.rows,
rows: dataTableContextRowsMock,
selectedDocsState: buildSelectedDocsState(['i::1::', 'i::2::']),
setIsFilterActive: jest.fn(),
enableComparisonMode: true,
Expand Down Expand Up @@ -336,8 +342,8 @@ describe('document selection', () => {
const props = {
isPlainRecord: false,
isFilterActive: false,
rows: dataTableContextMock.rows,
selectedDocsState: buildSelectedDocsState(dataTableContextMock.rows.map((row) => row.id)),
rows: dataTableContextRowsMock,
selectedDocsState: buildSelectedDocsState(dataTableContextRowsMock.map((row) => row.id)),
setIsFilterActive: jest.fn(),
enableComparisonMode: true,
setIsCompareActive: jest.fn(),
Expand All @@ -357,7 +363,7 @@ describe('document selection', () => {
</UnifiedDataTableContext.Provider>
);
expect(findTestSubject(component, 'unifiedDataTableSelectionBtn').text()).toBe(
`Selected${dataTableContextMock.rows.length}`
`Selected${dataTableContextRowsMock.length}`
);

expect(findTestSubject(component, 'dscGridSelectAllDocs').exists()).toBe(false);
Expand All @@ -368,7 +374,7 @@ describe('document selection', () => {
const props = {
isPlainRecord: false,
isFilterActive: false,
rows: dataTableContextMock.rows,
rows: dataTableContextRowsMock,
selectedDocsState: buildSelectedDocsState([]),
setIsFilterActive: jest.fn(),
enableComparisonMode: true,
Expand Down
Loading

0 comments on commit bdfccd2

Please sign in to comment.