diff --git a/packages/kbn-unified-data-table/__mocks__/table_context.ts b/packages/kbn-unified-data-table/__mocks__/table_context.ts index a55bea58feebf..a253b02ab5838 100644 --- a/packages/kbn-unified-data-table/__mocks__/table_context.ts +++ b/packages/kbn-unified-data-table/__mocks__/table_context.ts @@ -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, @@ -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); diff --git a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.test.tsx b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.test.tsx index 0cd04436a528a..fd402b64a4bc9 100644 --- a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.test.tsx +++ b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.test.tsx @@ -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 }); }); }); diff --git a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.tsx b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.tsx index a1adb1e9a0d76..3519bef843c4a 100644 --- a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.tsx +++ b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_control_column.tsx @@ -26,7 +26,7 @@ export const RowControlCell = ({ }: EuiDataGridCellValueElementProps & { renderControl: RowControlColumn['renderControl']; }) => { - const rowProps = useControlColumn(props); + const { record, rowIndex } = useControlColumn(props); const Control: React.FC = useMemo( () => @@ -50,17 +50,19 @@ export const RowControlCell = ({ color={color ?? 'text'} aria-label={label} onClick={() => { - onClick?.(rowProps); + if (record) { + onClick?.({ record, rowIndex }); + } }} /> ); }, - [props.columnId, rowProps] + [props.columnId, record, rowIndex] ); - return renderControl(Control, rowProps); + return record ? renderControl(Control, { record, rowIndex }) : null; }; export const getRowControlColumn = ( diff --git a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.test.tsx b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.test.tsx index e47a574144999..1c26689bd974e 100644 --- a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.test.tsx +++ b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.test.tsx @@ -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 }); }); }); diff --git a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.tsx b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.tsx index 34d4118956c7a..3d6cd19a53b1e 100644 --- a/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.tsx +++ b/packages/kbn-unified-data-table/src/components/custom_control_columns/additional_row_control/row_menu_control_column.tsx @@ -34,7 +34,7 @@ export const RowMenuControlCell = ({ }: EuiDataGridCellValueElementProps & { rowControlColumns: RowControlColumn[]; }) => { - const rowProps = useControlColumn(props); + const { record, rowIndex } = useControlColumn(props); const [isMoreActionsPopoverOpen, setIsMoreActionsPopoverOpen] = useState(false); const buttonLabel = i18n.translate('unifiedDataTable.grid.additionalRowActions', { @@ -51,7 +51,9 @@ export const RowMenuControlCell = ({ icon={iconType} color={color} onClick={() => { - onClick?.(rowProps); + if (record) { + onClick?.({ record, rowIndex }); + } setIsMoreActionsPopoverOpen(false); }} > @@ -59,7 +61,7 @@ export const RowMenuControlCell = ({ ); }, - [rowProps, setIsMoreActionsPopoverOpen] + [record, rowIndex] ); const popoverMenuItems = useMemo( @@ -68,11 +70,11 @@ export const RowMenuControlCell = ({ const Control = getControlComponent(rowControlColumn.id); return ( - {rowControlColumn.renderControl(Control, rowProps)} + {record ? rowControlColumn.renderControl(Control, { record, rowIndex }) : null} ); }), - [rowControlColumns, rowProps, getControlComponent] + [rowControlColumns, getControlComponent, record, rowIndex] ); return ( diff --git a/packages/kbn-unified-data-table/src/components/custom_control_columns/color_indicator/color_indicator_control_column.test.tsx b/packages/kbn-unified-data-table/src/components/custom_control_columns/color_indicator/color_indicator_control_column.test.tsx index a972579e5cc35..890e0c517fae9 100644 --- a/packages/kbn-unified-data-table/src/components/custom_control_columns/color_indicator/color_indicator_control_column.test.tsx +++ b/packages/kbn-unified-data-table/src/components/custom_control_columns/color_indicator/color_indicator_control_column.test.tsx @@ -39,6 +39,6 @@ describe('ColorIndicatorControlColumn', () => { /> ); - expect(getRowIndicator).toHaveBeenCalledWith(contextMock.rows[1], expect.any(Object)); + expect(getRowIndicator).toHaveBeenCalledWith(contextMock.getRowByIndex(1), expect.any(Object)); }); }); diff --git a/packages/kbn-unified-data-table/src/components/data_table.tsx b/packages/kbn-unified-data-table/src/components/data_table.tsx index 556e445eda4b9..7eeab83fdecb7 100644 --- a/packages/kbn-unified-data-table/src/components/data_table.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.tsx @@ -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'; @@ -629,11 +629,11 @@ export const UnifiedDataTable = ({ ); }, [currentPageSize, setPagination]); - const unifiedDataTableContextValue = useMemo( + const unifiedDataTableContextValue = useMemo( () => ({ expanded: expandedDoc, setExpanded: setExpandedDoc, - rows: displayedRows, + getRowByIndex: (index: number) => displayedRows[index], onFilter, dataView, isDarkMode: darkMode, @@ -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) => { @@ -907,6 +907,7 @@ export const UnifiedDataTable = ({ }, [ canSetExpandedDoc, controlColumnIds, + displayedRows, externalControlColumns, getRowIndicator, rowAdditionalLeadingControls, diff --git a/packages/kbn-unified-data-table/src/components/data_table_columns.tsx b/packages/kbn-unified-data-table/src/components/data_table_columns.tsx index 4ef0636093f8d..c5bba429ed934 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_columns.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_columns.tsx @@ -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, @@ -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({ diff --git a/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_json.tsx b/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_json.tsx index ba10b27a3cbdb..21b6265f989f4 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_json.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_json.tsx @@ -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 = ({ + rows, toastNotifications, onCompleted, }) => { const [isProcessing, setIsProcessing] = useState(false); - const { rows, selectedDocsState, isPlainRecord } = useContext(UnifiedDataTableContext); + const { selectedDocsState, isPlainRecord } = useContext(UnifiedDataTableContext); const { getSelectedDocsOrderedByRows } = selectedDocsState; return ( diff --git a/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_text.tsx b/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_text.tsx index 6978589e8fa9f..8dddbd24f2df3 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_text.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_copy_rows_as_text.tsx @@ -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 = ({ + rows, toastNotifications, columns, onCompleted, }) => { const [isProcessing, setIsProcessing] = useState(false); - const { valueToStringConverter, dataView, rows, selectedDocsState } = + const { valueToStringConverter, dataView, selectedDocsState } = useContext(UnifiedDataTableContext); const { isDocSelected } = selectedDocsState; diff --git a/packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx index 85db2c10885cd..85ce60d78aa16 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx @@ -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'; @@ -49,6 +53,7 @@ describe('document selection', () => { const contextMock = { ...dataTableContextMock, }; + const SelectAllButton = getSelectAllButton(dataTableContextRowsMock); const component = mountWithIntl( @@ -65,6 +70,7 @@ describe('document selection', () => { ...dataTableContextMock, selectedDocsState: buildSelectedDocsState(['i::1::']), }; + const SelectAllButton = getSelectAllButton(dataTableContextRowsMock); const component = mountWithIntl( @@ -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, @@ -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, @@ -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, @@ -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, @@ -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(), @@ -357,7 +363,7 @@ describe('document selection', () => { ); expect(findTestSubject(component, 'unifiedDataTableSelectionBtn').text()).toBe( - `Selected${dataTableContextMock.rows.length}` + `Selected${dataTableContextRowsMock.length}` ); expect(findTestSubject(component, 'dscGridSelectAllDocs').exists()).toBe(false); @@ -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, diff --git a/packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx b/packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx index ee6eee93539f9..b6b8ab20cc577 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx @@ -45,6 +45,10 @@ export const SelectButton = (props: EuiDataGridCellValueElementProps) => { values: { rowNumber: rowIndex + 1 }, }); + if (!record) { + return null; + } + return ( { ); }; -export const SelectAllButton = () => { - const { selectedDocsState, pageIndex, pageSize, rows } = useContext(UnifiedDataTableContext); +export const getSelectAllButton = (rows: DataTableRecord[]) => () => { + const { selectedDocsState, pageIndex, pageSize } = useContext(UnifiedDataTableContext); const { getCountOfFilteredSelectedDocs, deselectSomeDocs, selectMoreDocs } = selectedDocsState; const docIdsFromCurrentPage = useMemo(() => { return getDocIdsForCurrentPage(rows, pageIndex, pageSize); - }, [rows, pageIndex, pageSize]); + }, [pageIndex, pageSize]); const countOfSelectedDocs = useMemo(() => { return docIdsFromCurrentPage?.length @@ -200,6 +204,7 @@ export function DataTableDocumentToolbarBtn({ // Copy results to clipboard as text , @@ -272,17 +278,18 @@ export function DataTableDocumentToolbarBtn({ , ]; }, [ - isFilterActive, - isPlainRecord, - setIsFilterActive, - clearAllSelectedDocs, + enableComparisonMode, selectedDocsCount, docIdsInSelectionOrder, - enableComparisonMode, setIsCompareActive, toastNotifications, columns, closePopover, + rows, + isFilterActive, + isPlainRecord, + setIsFilterActive, + clearAllSelectedDocs, ]); const toggleSelectionToolbar = useCallback( diff --git a/packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx index 45aac02e368b4..4da41705efe9a 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx @@ -35,12 +35,12 @@ describe('Data table view button ', function () { ); const button = findTestSubject(component, 'docTableExpandToggleColumn'); await button.simulate('click'); - expect(contextMock.setExpanded).toHaveBeenCalledWith(dataTableContextMock.rows[0]); + expect(contextMock.setExpanded).toHaveBeenCalledWith(dataTableContextMock.getRowByIndex(0)); }); it('when the current document is expanded, setExpanded is called with undefined', async () => { const contextMock = { ...dataTableContextMock, - expanded: dataTableContextMock.rows[0], + expanded: dataTableContextMock.getRowByIndex(0), }; const component = mountWithIntl( @@ -63,7 +63,7 @@ describe('Data table view button ', function () { it('when another document is expanded, setExpanded is called with the current document', async () => { const contextMock = { ...dataTableContextMock, - expanded: dataTableContextMock.rows[0], + expanded: dataTableContextMock.getRowByIndex(0), }; const component = mountWithIntl( @@ -81,6 +81,6 @@ describe('Data table view button ', function () { ); const button = findTestSubject(component, 'docTableExpandToggleColumn'); await button.simulate('click'); - expect(contextMock.setExpanded).toHaveBeenCalledWith(dataTableContextMock.rows[1]); + expect(contextMock.setExpanded).toHaveBeenCalledWith(dataTableContextMock.getRowByIndex(1)); }); }); diff --git a/packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx b/packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx index c5a57ee98dc30..f5bb21bc0c95d 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx @@ -31,7 +31,7 @@ export const ExpandButton = (props: EuiDataGridCellValueElementProps) => { defaultMessage: 'Toggle dialog with details', }); - const testSubj = record.isAnchor + const testSubj = record?.isAnchor ? 'docTableExpandToggleColumnAnchor' : 'docTableExpandToggleColumn'; @@ -44,7 +44,7 @@ export const ExpandButton = (props: EuiDataGridCellValueElementProps) => { } }, [isCurrentRowExpanded, setPressed, pressed]); - if (!setExpanded) { + if (!setExpanded || !record) { return null; } diff --git a/packages/kbn-unified-data-table/src/components/default_cell_actions.tsx b/packages/kbn-unified-data-table/src/components/default_cell_actions.tsx index 620151c9d9701..0be9803633825 100644 --- a/packages/kbn-unified-data-table/src/components/default_cell_actions.tsx +++ b/packages/kbn-unified-data-table/src/components/default_cell_actions.tsx @@ -24,10 +24,10 @@ function onFilterCell( mode: '+' | '-', field: DataViewField ) { - const row = context.rows[rowIndex]; - const value = row.flattened[columnId]; + const row = context.getRowByIndex(rowIndex); - if (field && context.onFilter) { + if (row && field && context.onFilter) { + const value = row.flattened[columnId]; context.onFilter(field, value, mode); } } diff --git a/packages/kbn-unified-data-table/src/hooks/use_control_column.ts b/packages/kbn-unified-data-table/src/hooks/use_control_column.ts index 302193cec6b44..64745f51d408f 100644 --- a/packages/kbn-unified-data-table/src/hooks/use_control_column.ts +++ b/packages/kbn-unified-data-table/src/hooks/use_control_column.ts @@ -16,14 +16,14 @@ export const useControlColumn = ({ rowIndex, setCellProps, }: Pick): { - record: DataTableRecord; + record?: DataTableRecord; rowIndex: number; } => { - const { expanded, rows } = useContext(UnifiedDataTableContext); - const record = useMemo(() => rows[rowIndex], [rows, rowIndex]); + const { expanded, getRowByIndex } = useContext(UnifiedDataTableContext); + const record = useMemo(() => getRowByIndex(rowIndex), [getRowByIndex, rowIndex]); useEffect(() => { - if (record.isAnchor) { + if (record?.isAnchor) { setCellProps({ className: 'unifiedDataTable__cell--highlight', }); diff --git a/packages/kbn-unified-data-table/src/table_context.tsx b/packages/kbn-unified-data-table/src/table_context.tsx index f8f18f7ef6b9a..204453416b6f8 100644 --- a/packages/kbn-unified-data-table/src/table_context.tsx +++ b/packages/kbn-unified-data-table/src/table_context.tsx @@ -17,7 +17,7 @@ import type { UseSelectedDocsState } from './hooks/use_selected_docs'; export interface DataTableContext { expanded?: DataTableRecord | undefined; setExpanded?: (hit?: DataTableRecord) => void; - rows: DataTableRecord[]; + getRowByIndex: (index: number) => DataTableRecord | undefined; onFilter?: DocViewFilterFn; dataView: DataView; isDarkMode: boolean; diff --git a/packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx b/packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx index 33ad7cb7ba095..749a2b34e579c 100644 --- a/packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx +++ b/packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx @@ -7,14 +7,19 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { dataTableContextComplexMock, dataTableContextMock } from '../../__mocks__/table_context'; +import { + dataTableContextComplexMock, + dataTableContextComplexRowsMock, + dataTableContextMock, + dataTableContextRowsMock, +} from '../../__mocks__/table_context'; import { servicesMock } from '../../__mocks__/services'; import { convertValueToString, convertNameToString } from './convert_value_to_string'; describe('convertValueToString', () => { it('should convert a keyword value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'keyword_key', @@ -29,7 +34,7 @@ describe('convertValueToString', () => { it('should convert a text value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'text_message', @@ -44,7 +49,7 @@ describe('convertValueToString', () => { it('should convert a text value to text (not for CSV)', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'text_message', @@ -59,7 +64,7 @@ describe('convertValueToString', () => { it('should convert a multiline text value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'text_message', @@ -75,7 +80,7 @@ describe('convertValueToString', () => { it('should convert a number value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'number_price', @@ -90,7 +95,7 @@ describe('convertValueToString', () => { it('should convert a date value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'date', @@ -105,7 +110,7 @@ describe('convertValueToString', () => { it('should convert a date nanos value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'date_nanos', @@ -120,7 +125,7 @@ describe('convertValueToString', () => { it('should convert a date nanos value to text (not for CSV)', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'date_nanos', @@ -135,7 +140,7 @@ describe('convertValueToString', () => { it('should convert a boolean value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'bool_enabled', @@ -150,7 +155,7 @@ describe('convertValueToString', () => { it('should convert a binary value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'binary_blob', @@ -165,7 +170,7 @@ describe('convertValueToString', () => { it('should convert a binary value to text (not for CSV)', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'binary_blob', @@ -180,7 +185,7 @@ describe('convertValueToString', () => { it('should convert an object value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'object_user.first', @@ -195,7 +200,7 @@ describe('convertValueToString', () => { it('should convert a nested value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'nested_user', @@ -212,7 +217,7 @@ describe('convertValueToString', () => { it('should convert a flattened value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'flattened_labels', @@ -227,7 +232,7 @@ describe('convertValueToString', () => { it('should convert a range value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'range_time_frame', @@ -244,7 +249,7 @@ describe('convertValueToString', () => { it('should convert a rank features value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'rank_features', @@ -259,7 +264,7 @@ describe('convertValueToString', () => { it('should convert a histogram value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'histogram', @@ -274,7 +279,7 @@ describe('convertValueToString', () => { it('should convert a IP value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'ip_addr', @@ -289,7 +294,7 @@ describe('convertValueToString', () => { it('should convert a IP value to text (not for CSV)', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'ip_addr', @@ -304,7 +309,7 @@ describe('convertValueToString', () => { it('should convert a version value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'version', @@ -319,7 +324,7 @@ describe('convertValueToString', () => { it('should convert a version value to text (not for CSV)', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'version', @@ -334,7 +339,7 @@ describe('convertValueToString', () => { it('should convert a vector value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'vector', @@ -349,7 +354,7 @@ describe('convertValueToString', () => { it('should convert a geo point value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'geo_point', @@ -364,7 +369,7 @@ describe('convertValueToString', () => { it('should convert a geo point object value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'geo_point', @@ -379,7 +384,7 @@ describe('convertValueToString', () => { it('should convert an array value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'array_tags', @@ -394,7 +399,7 @@ describe('convertValueToString', () => { it('should convert a shape value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'geometry', @@ -411,7 +416,7 @@ describe('convertValueToString', () => { it('should convert a runtime value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'runtime_number', @@ -426,7 +431,7 @@ describe('convertValueToString', () => { it('should convert a scripted value to text', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'scripted_string', @@ -441,7 +446,7 @@ describe('convertValueToString', () => { it('should convert a scripted value to text (not for CSV)', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'scripted_string', @@ -456,7 +461,7 @@ describe('convertValueToString', () => { it('should return an empty string and not fail', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'unknown', @@ -471,7 +476,7 @@ describe('convertValueToString', () => { it('should return an empty string when rowIndex is out of range', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'unknown', @@ -486,7 +491,7 @@ describe('convertValueToString', () => { it('should return _source value', () => { const result = convertValueToString({ - rows: dataTableContextMock.rows, + rows: dataTableContextRowsMock, dataView: dataTableContextMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: '_source', @@ -509,7 +514,7 @@ describe('convertValueToString', () => { it('should return a formatted _source value', () => { const result = convertValueToString({ - rows: dataTableContextMock.rows, + rows: dataTableContextRowsMock, dataView: dataTableContextMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: '_source', @@ -526,7 +531,7 @@ describe('convertValueToString', () => { it('should escape formula', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'array_tags', @@ -540,7 +545,7 @@ describe('convertValueToString', () => { expect(result.withFormula).toBe(true); const result2 = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'scripted_string', @@ -556,7 +561,7 @@ describe('convertValueToString', () => { it('should not escape formulas when not for CSV', () => { const result = convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, columnId: 'array_tags', diff --git a/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx b/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx index cb5050e503ca9..86675c5fbc707 100644 --- a/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx +++ b/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx @@ -7,7 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { dataTableContextComplexMock } from '../../__mocks__/table_context'; +import { + dataTableContextComplexMock, + dataTableContextComplexRowsMock, +} from '../../__mocks__/table_context'; import { servicesMock } from '../../__mocks__/services'; import { copyValueToClipboard, @@ -25,7 +28,7 @@ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}); describe('copyValueToClipboard', () => { const valueToStringConverter: ValueToStringConverter = (rowIndex, columnId, options) => convertValueToString({ - rows: dataTableContextComplexMock.rows, + rows: dataTableContextComplexRowsMock, dataView: dataTableContextComplexMock.dataView, fieldFormats: servicesMock.fieldFormats, rowIndex, @@ -198,7 +201,7 @@ describe('copyValueToClipboard', () => { const result = await copyRowsAsJsonToClipboard({ toastNotifications: servicesMock.toastNotifications, - selectedRows: [dataTableContextComplexMock.rows[0]], + selectedRows: [dataTableContextComplexMock.getRowByIndex(0)!], }); const output =