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..13059f2881711 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 @@ -182,7 +182,13 @@ function buildEuiGridColumn({ cellActions = columnCellActions; } else { cellActions = dataViewField - ? buildCellActions(dataViewField, toastNotifications, valueToStringConverter, onFilter) + ? buildCellActions( + dataViewField, + isPlainRecord, + toastNotifications, + valueToStringConverter, + onFilter + ) : []; if (columnCellActions?.length && cellActionsHandling === 'append') { diff --git a/packages/kbn-unified-data-table/src/components/default_cell_actions.test.tsx b/packages/kbn-unified-data-table/src/components/default_cell_actions.test.tsx index 628d3b5a29697..d097a2becd035 100644 --- a/packages/kbn-unified-data-table/src/components/default_cell_actions.test.tsx +++ b/packages/kbn-unified-data-table/src/components/default_cell_actions.test.tsx @@ -45,6 +45,7 @@ describe('Default cell actions ', function () { it('should not show cell actions for unfilterable fields', async () => { const cellActions = buildCellActions( { name: 'foo', filterable: false } as DataViewField, + false, servicesMock.toastNotifications, dataTableContextMock.valueToStringConverter ); @@ -61,6 +62,7 @@ describe('Default cell actions ', function () { it('should show filter actions for filterable fields', async () => { const cellActions = buildCellActions( { name: 'foo', filterable: true } as DataViewField, + false, servicesMock.toastNotifications, dataTableContextMock.valueToStringConverter, jest.fn() @@ -71,6 +73,7 @@ describe('Default cell actions ', function () { it('should show Copy action for _source field', async () => { const cellActions = buildCellActions( { name: '_source', type: '_source', filterable: false } as DataViewField, + false, servicesMock.toastNotifications, dataTableContextMock.valueToStringConverter ); @@ -87,65 +90,97 @@ describe('Default cell actions ', function () { const component = mountWithIntl( } - rowIndex={1} - colIndex={1} - columnId="extension" - isExpanded={false} + cellActionProps={{ + Component: (props: any) => , + rowIndex: 1, + colIndex: 1, + columnId: 'extension', + isExpanded: false, + }} + field={{ name: 'extension', filterable: true } as DataViewField} + isPlainRecord={false} /> ); const button = findTestSubject(component, 'filterForButton'); await button.simulate('click'); - expect(dataTableContextMock.onFilter).toHaveBeenCalledWith({}, 'jpg', '+'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + { name: 'extension', filterable: true }, + 'jpg', + '+' + ); }); it('triggers filter function when FilterInBtn is clicked for a non-provided value', async () => { const component = mountWithIntl( } - rowIndex={0} - colIndex={1} - columnId="extension" - isExpanded={false} + cellActionProps={{ + Component: (props: any) => , + rowIndex: 0, + colIndex: 1, + columnId: 'extension', + isExpanded: false, + }} + field={{ name: 'extension', filterable: true } as DataViewField} + isPlainRecord={false} /> ); const button = findTestSubject(component, 'filterForButton'); await button.simulate('click'); - expect(dataTableContextMock.onFilter).toHaveBeenCalledWith({}, undefined, '+'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + { name: 'extension', filterable: true }, + undefined, + '+' + ); }); it('triggers filter function when FilterInBtn is clicked for an empty string value', async () => { const component = mountWithIntl( } - rowIndex={4} - colIndex={1} - columnId="message" - isExpanded={false} + cellActionProps={{ + Component: (props: any) => , + rowIndex: 4, + colIndex: 1, + columnId: 'message', + isExpanded: false, + }} + field={{ name: 'message', filterable: true } as DataViewField} + isPlainRecord={false} /> ); const button = findTestSubject(component, 'filterForButton'); await button.simulate('click'); - expect(dataTableContextMock.onFilter).toHaveBeenCalledWith({}, '', '+'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + { name: 'message', filterable: true }, + '', + '+' + ); }); it('triggers filter function when FilterOutBtn is clicked', async () => { const component = mountWithIntl( } - rowIndex={1} - colIndex={1} - columnId="extension" - isExpanded={false} + cellActionProps={{ + Component: (props: any) => , + rowIndex: 1, + colIndex: 1, + columnId: 'extension', + isExpanded: false, + }} + field={{ name: 'extension', filterable: true } as DataViewField} + isPlainRecord={false} /> ); const button = findTestSubject(component, 'filterOutButton'); await button.simulate('click'); - expect(dataTableContextMock.onFilter).toHaveBeenCalledWith({}, 'jpg', '-'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + { name: 'extension', filterable: true }, + 'jpg', + '-' + ); }); it('triggers clipboard copy when CopyBtn is clicked', async () => { const component = mountWithIntl( 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..ce7b354fc8dc1 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 @@ -32,11 +32,25 @@ function onFilterCell( } } -export const FilterInBtn = ( - { Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps, - field: DataViewField -) => { +const esqlMultivalueFilteringDisabled = i18n.translate( + 'unifiedDataTable.grid.esqlMultivalueFilteringDisabled', + { + defaultMessage: 'Multivalue filtering is not supported in ES|QL', + } +); + +export const FilterInBtn = ({ + cellActionProps: { Component, rowIndex, columnId }, + field, + isPlainRecord, +}: { + cellActionProps: EuiDataGridColumnCellActionProps; + field: DataViewField; + isPlainRecord: boolean | undefined; +}) => { const context = useContext(UnifiedDataTableContext); + const filteringDisabled = + isPlainRecord && Array.isArray(context.rows[rowIndex]?.flattened[columnId]); const buttonTitle = i18n.translate('unifiedDataTable.grid.filterForAria', { defaultMessage: 'Filter for this {value}', values: { value: columnId }, @@ -49,7 +63,8 @@ export const FilterInBtn = ( }} iconType="plusInCircle" aria-label={buttonTitle} - title={buttonTitle} + title={filteringDisabled ? esqlMultivalueFilteringDisabled : buttonTitle} + disabled={filteringDisabled} data-test-subj="filterForButton" > {i18n.translate('unifiedDataTable.grid.filterFor', { @@ -59,11 +74,18 @@ export const FilterInBtn = ( ); }; -export const FilterOutBtn = ( - { Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps, - field: DataViewField -) => { +export const FilterOutBtn = ({ + cellActionProps: { Component, rowIndex, columnId }, + field, + isPlainRecord, +}: { + cellActionProps: EuiDataGridColumnCellActionProps; + field: DataViewField; + isPlainRecord: boolean | undefined; +}) => { const context = useContext(UnifiedDataTableContext); + const filteringDisabled = + isPlainRecord && Array.isArray(context.rows[rowIndex]?.flattened[columnId]); const buttonTitle = i18n.translate('unifiedDataTable.grid.filterOutAria', { defaultMessage: 'Filter out this {value}', values: { value: columnId }, @@ -76,7 +98,8 @@ export const FilterOutBtn = ( }} iconType="minusInCircle" aria-label={buttonTitle} - title={buttonTitle} + title={filteringDisabled ? esqlMultivalueFilteringDisabled : buttonTitle} + disabled={filteringDisabled} data-test-subj="filterOutButton" > {i18n.translate('unifiedDataTable.grid.filterOut', { @@ -120,6 +143,7 @@ export function buildCopyValueButton( export function buildCellActions( field: DataViewField, + isPlainRecord: boolean | undefined, toastNotifications: ToastsStart, valueToStringConverter: ValueToStringConverter, onFilter?: DocViewFilterFn @@ -127,16 +151,18 @@ export function buildCellActions( return [ ...(onFilter && field.filterable ? [ - ({ Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps) => - FilterInBtn( - { Component, rowIndex, columnId } as EuiDataGridColumnCellActionProps, - field - ), - ({ Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps) => - FilterOutBtn( - { Component, rowIndex, columnId } as EuiDataGridColumnCellActionProps, - field - ), + (cellActionProps: EuiDataGridColumnCellActionProps) => + FilterInBtn({ + cellActionProps, + field, + isPlainRecord, + }), + (cellActionProps: EuiDataGridColumnCellActionProps) => + FilterOutBtn({ + cellActionProps, + field, + isPlainRecord, + }), ] : []), ({ Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps) =>