mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Discover] [ES|QL] Disable ES|QL multivalue filtering in Unified Doc Viewer (#194232)
## Summary This PR disables ES|QL multivalue filtering in Unified Doc Viewer, similar to what we did for Unified Data Table in #193415:  Part of https://github.com/elastic/kibana/issues/193015. ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
parent
1ba788620e
commit
6f01d6a260
4 changed files with 197 additions and 47 deletions
|
@ -4,12 +4,20 @@ exports[`TableActions getFieldCellActions should render correctly for undefined
|
|||
Array [
|
||||
<ToggleColumn
|
||||
Component={[Function]}
|
||||
isEsqlMode={false}
|
||||
onToggleColumn={[MockFunction]}
|
||||
row={
|
||||
FieldRow {
|
||||
"columnsMeta": undefined,
|
||||
"dataViewField": undefined,
|
||||
"flattenedValue": "flattenedField",
|
||||
"dataViewField": Object {
|
||||
"aggregatable": false,
|
||||
"displayName": "message",
|
||||
"filterable": false,
|
||||
"name": "message",
|
||||
"scripted": false,
|
||||
"type": "string",
|
||||
},
|
||||
"flattenedValue": "test",
|
||||
"isPinned": false,
|
||||
"name": "message",
|
||||
}
|
||||
|
@ -24,12 +32,20 @@ exports[`TableActions getFieldCellActions should render the panels correctly for
|
|||
Array [
|
||||
<FilterExist
|
||||
Component={[Function]}
|
||||
isEsqlMode={false}
|
||||
onFilter={[MockFunction]}
|
||||
row={
|
||||
FieldRow {
|
||||
"columnsMeta": undefined,
|
||||
"dataViewField": undefined,
|
||||
"flattenedValue": "flattenedField",
|
||||
"dataViewField": Object {
|
||||
"aggregatable": false,
|
||||
"displayName": "message",
|
||||
"filterable": false,
|
||||
"name": "message",
|
||||
"scripted": false,
|
||||
"type": "string",
|
||||
},
|
||||
"flattenedValue": "test",
|
||||
"isPinned": false,
|
||||
"name": "message",
|
||||
}
|
||||
|
@ -37,12 +53,20 @@ Array [
|
|||
/>,
|
||||
<ToggleColumn
|
||||
Component={[Function]}
|
||||
isEsqlMode={false}
|
||||
onToggleColumn={[MockFunction]}
|
||||
row={
|
||||
FieldRow {
|
||||
"columnsMeta": undefined,
|
||||
"dataViewField": undefined,
|
||||
"flattenedValue": "flattenedField",
|
||||
"dataViewField": Object {
|
||||
"aggregatable": false,
|
||||
"displayName": "message",
|
||||
"filterable": false,
|
||||
"name": "message",
|
||||
"scripted": false,
|
||||
"type": "string",
|
||||
},
|
||||
"flattenedValue": "test",
|
||||
"isPinned": false,
|
||||
"name": "message",
|
||||
}
|
||||
|
@ -57,12 +81,20 @@ exports[`TableActions getFieldValueCellActions should render the panels correctl
|
|||
Array [
|
||||
<FilterIn
|
||||
Component={[Function]}
|
||||
isEsqlMode={false}
|
||||
onFilter={[MockFunction]}
|
||||
row={
|
||||
FieldRow {
|
||||
"columnsMeta": undefined,
|
||||
"dataViewField": undefined,
|
||||
"flattenedValue": "flattenedField",
|
||||
"dataViewField": Object {
|
||||
"aggregatable": false,
|
||||
"displayName": "message",
|
||||
"filterable": false,
|
||||
"name": "message",
|
||||
"scripted": false,
|
||||
"type": "string",
|
||||
},
|
||||
"flattenedValue": "test",
|
||||
"isPinned": false,
|
||||
"name": "message",
|
||||
}
|
||||
|
@ -70,12 +102,20 @@ Array [
|
|||
/>,
|
||||
<FilterOut
|
||||
Component={[Function]}
|
||||
isEsqlMode={false}
|
||||
onFilter={[MockFunction]}
|
||||
row={
|
||||
FieldRow {
|
||||
"columnsMeta": undefined,
|
||||
"dataViewField": undefined,
|
||||
"flattenedValue": "flattenedField",
|
||||
"dataViewField": Object {
|
||||
"aggregatable": false,
|
||||
"displayName": "message",
|
||||
"filterable": false,
|
||||
"name": "message",
|
||||
"scripted": false,
|
||||
"type": "string",
|
||||
},
|
||||
"flattenedValue": "test",
|
||||
"isPinned": false,
|
||||
"name": "message",
|
||||
}
|
||||
|
|
|
@ -324,12 +324,12 @@ export const DocViewerTable = ({
|
|||
}, [showPagination, curPageIndex, pageSize, onChangePageSize, changePageIndex]);
|
||||
|
||||
const fieldCellActions = useMemo(
|
||||
() => getFieldCellActions({ rows, onFilter: filter, onToggleColumn }),
|
||||
[rows, filter, onToggleColumn]
|
||||
() => getFieldCellActions({ rows, isEsqlMode, onFilter: filter, onToggleColumn }),
|
||||
[rows, isEsqlMode, filter, onToggleColumn]
|
||||
);
|
||||
const fieldValueCellActions = useMemo(
|
||||
() => getFieldValueCellActions({ rows, onFilter: filter }),
|
||||
[rows, filter]
|
||||
() => getFieldValueCellActions({ rows, isEsqlMode, onFilter: filter }),
|
||||
[rows, isEsqlMode, filter]
|
||||
);
|
||||
|
||||
useWindowSize(); // trigger re-render on window resize to recalculate the grid container height
|
||||
|
|
|
@ -11,26 +11,27 @@ import React from 'react';
|
|||
import { getFieldCellActions, getFieldValueCellActions } from './table_cell_actions';
|
||||
import { FieldRow } from './field_row';
|
||||
import { buildDataTableRecord } from '@kbn/discover-utils';
|
||||
import { stubLogstashDataView as dataView } from '@kbn/data-views-plugin/common/data_view.stub';
|
||||
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { dataViewMockWithTimeField } from '@kbn/discover-utils/src/__mocks__';
|
||||
|
||||
describe('TableActions', () => {
|
||||
const rows: FieldRow[] = [
|
||||
const getRows = (fieldName = 'message', fieldValue: unknown = 'test'): FieldRow[] => [
|
||||
new FieldRow({
|
||||
name: 'message',
|
||||
flattenedValue: 'flattenedField',
|
||||
name: fieldName,
|
||||
flattenedValue: fieldValue,
|
||||
hit: buildDataTableRecord(
|
||||
{
|
||||
_ignored: [],
|
||||
_index: 'test',
|
||||
_id: '1',
|
||||
_source: {
|
||||
message: 'test',
|
||||
[fieldName]: fieldValue,
|
||||
},
|
||||
},
|
||||
dataView
|
||||
dataViewMockWithTimeField
|
||||
),
|
||||
dataView,
|
||||
dataView: dataViewMockWithTimeField,
|
||||
fieldFormats: {} as FieldFormatsStart,
|
||||
isPinned: false,
|
||||
columnsMeta: undefined,
|
||||
|
@ -49,23 +50,32 @@ describe('TableActions', () => {
|
|||
describe('getFieldCellActions', () => {
|
||||
it('should render correctly for undefined functions', () => {
|
||||
expect(
|
||||
getFieldCellActions({ rows, onFilter: undefined, onToggleColumn: jest.fn() }).map((item) =>
|
||||
item(EuiCellParams)
|
||||
)
|
||||
getFieldCellActions({
|
||||
rows: getRows(),
|
||||
isEsqlMode: false,
|
||||
onFilter: undefined,
|
||||
onToggleColumn: jest.fn(),
|
||||
}).map((item) => item(EuiCellParams))
|
||||
).toMatchSnapshot();
|
||||
|
||||
expect(
|
||||
getFieldCellActions({ rows, onFilter: undefined, onToggleColumn: undefined }).map((item) =>
|
||||
item(EuiCellParams)
|
||||
)
|
||||
getFieldCellActions({
|
||||
rows: getRows(),
|
||||
isEsqlMode: false,
|
||||
onFilter: undefined,
|
||||
onToggleColumn: undefined,
|
||||
}).map((item) => item(EuiCellParams))
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the panels correctly for defined onFilter function', () => {
|
||||
expect(
|
||||
getFieldCellActions({ rows, onFilter: jest.fn(), onToggleColumn: jest.fn() }).map((item) =>
|
||||
item(EuiCellParams)
|
||||
)
|
||||
getFieldCellActions({
|
||||
rows: getRows(),
|
||||
isEsqlMode: false,
|
||||
onFilter: jest.fn(),
|
||||
onToggleColumn: jest.fn(),
|
||||
}).map((item) => item(EuiCellParams))
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -73,14 +83,72 @@ describe('TableActions', () => {
|
|||
describe('getFieldValueCellActions', () => {
|
||||
it('should render correctly for undefined functions', () => {
|
||||
expect(
|
||||
getFieldValueCellActions({ rows, onFilter: undefined }).map((item) => item(EuiCellParams))
|
||||
getFieldValueCellActions({ rows: getRows(), isEsqlMode: false, onFilter: undefined }).map(
|
||||
(item) => item(EuiCellParams)
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the panels correctly for defined onFilter function', () => {
|
||||
expect(
|
||||
getFieldValueCellActions({ rows, onFilter: jest.fn() }).map((item) => item(EuiCellParams))
|
||||
getFieldValueCellActions({ rows: getRows(), isEsqlMode: false, onFilter: jest.fn() }).map(
|
||||
(item) => item(EuiCellParams)
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should allow filtering in ES|QL mode', () => {
|
||||
const actions = getFieldValueCellActions({
|
||||
rows: getRows('extension'),
|
||||
isEsqlMode: true,
|
||||
onFilter: jest.fn(),
|
||||
}).map((Action, i) => (
|
||||
<Action
|
||||
key={i}
|
||||
{...EuiCellParams}
|
||||
Component={(props: any) => (
|
||||
<div data-test-subj={props['data-test-subj']}>{JSON.stringify(props)}</div>
|
||||
)}
|
||||
/>
|
||||
));
|
||||
render(<>{actions}</>);
|
||||
const filterForProps = JSON.parse(
|
||||
screen.getByTestId('addFilterForValueButton-extension').innerHTML
|
||||
);
|
||||
expect(filterForProps.disabled).toBe(false);
|
||||
expect(filterForProps.title).toBe('Filter for value');
|
||||
const filterOutProps = JSON.parse(
|
||||
screen.getByTestId('addFilterOutValueButton-extension').innerHTML
|
||||
);
|
||||
expect(filterOutProps.disabled).toBe(false);
|
||||
expect(filterOutProps.title).toBe('Filter out value');
|
||||
});
|
||||
|
||||
it('should not allow filtering in ES|QL mode for multivalue fields', () => {
|
||||
const actions = getFieldValueCellActions({
|
||||
rows: getRows('extension', ['foo', 'bar']),
|
||||
isEsqlMode: true,
|
||||
onFilter: jest.fn(),
|
||||
}).map((Action, i) => (
|
||||
<Action
|
||||
key={i}
|
||||
{...EuiCellParams}
|
||||
Component={(props: any) => (
|
||||
<div data-test-subj={props['data-test-subj']}>{JSON.stringify(props)}</div>
|
||||
)}
|
||||
/>
|
||||
));
|
||||
render(<>{actions}</>);
|
||||
const filterForProps = JSON.parse(
|
||||
screen.getByTestId('addFilterForValueButton-extension').innerHTML
|
||||
);
|
||||
expect(filterForProps.disabled).toBe(true);
|
||||
expect(filterForProps.title).toBe('Multivalue filtering is not supported in ES|QL');
|
||||
const filterOutProps = JSON.parse(
|
||||
screen.getByTestId('addFilterOutValueButton-extension').innerHTML
|
||||
);
|
||||
expect(filterOutProps.disabled).toBe(true);
|
||||
expect(filterOutProps.title).toBe('Multivalue filtering is not supported in ES|QL');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,9 +16,10 @@ import { FieldRow } from './field_row';
|
|||
interface TableActionsProps {
|
||||
Component: EuiDataGridColumnCellActionProps['Component'];
|
||||
row: FieldRow | undefined; // as we pass `rows[rowIndex]` it's safer to assume that `row` prop can be undefined
|
||||
isEsqlMode: boolean | undefined;
|
||||
}
|
||||
|
||||
export function isFilterInOutPairDisabled(
|
||||
function isFilterInOutPairDisabled(
|
||||
row: FieldRow | undefined,
|
||||
onFilter: DocViewFilterFn | undefined
|
||||
): boolean {
|
||||
|
@ -58,9 +59,17 @@ export function getFilterInOutPairDisabledWarning(
|
|||
: undefined;
|
||||
}
|
||||
|
||||
export const FilterIn: React.FC<TableActionsProps & { onFilter: DocViewFilterFn | undefined }> = ({
|
||||
const esqlMultivalueFilteringDisabled = i18n.translate(
|
||||
'unifiedDocViewer.docViews.table.esqlMultivalueFilteringDisabled',
|
||||
{
|
||||
defaultMessage: 'Multivalue filtering is not supported in ES|QL',
|
||||
}
|
||||
);
|
||||
|
||||
const FilterIn: React.FC<TableActionsProps & { onFilter: DocViewFilterFn | undefined }> = ({
|
||||
Component,
|
||||
row,
|
||||
isEsqlMode,
|
||||
onFilter,
|
||||
}) => {
|
||||
if (!row) {
|
||||
|
@ -81,12 +90,14 @@ export const FilterIn: React.FC<TableActionsProps & { onFilter: DocViewFilterFn
|
|||
return null;
|
||||
}
|
||||
|
||||
const filteringDisabled = isEsqlMode && Array.isArray(flattenedValue);
|
||||
|
||||
return (
|
||||
<Component
|
||||
data-test-subj={`addFilterForValueButton-${name}`}
|
||||
iconType="plusInCircle"
|
||||
disabled={isFilterInOutPairDisabled(row, onFilter)}
|
||||
title={filterAddLabel}
|
||||
disabled={filteringDisabled || isFilterInOutPairDisabled(row, onFilter)}
|
||||
title={filteringDisabled ? esqlMultivalueFilteringDisabled : filterAddLabel}
|
||||
flush="left"
|
||||
onClick={() => onFilter(dataViewField, flattenedValue, '+')}
|
||||
>
|
||||
|
@ -95,9 +106,10 @@ export const FilterIn: React.FC<TableActionsProps & { onFilter: DocViewFilterFn
|
|||
);
|
||||
};
|
||||
|
||||
export const FilterOut: React.FC<TableActionsProps & { onFilter: DocViewFilterFn | undefined }> = ({
|
||||
const FilterOut: React.FC<TableActionsProps & { onFilter: DocViewFilterFn | undefined }> = ({
|
||||
Component,
|
||||
row,
|
||||
isEsqlMode,
|
||||
onFilter,
|
||||
}) => {
|
||||
if (!row) {
|
||||
|
@ -118,12 +130,14 @@ export const FilterOut: React.FC<TableActionsProps & { onFilter: DocViewFilterFn
|
|||
return null;
|
||||
}
|
||||
|
||||
const filteringDisabled = isEsqlMode && Array.isArray(flattenedValue);
|
||||
|
||||
return (
|
||||
<Component
|
||||
data-test-subj={`addFilterOutValueButton-${name}`}
|
||||
iconType="minusInCircle"
|
||||
disabled={isFilterInOutPairDisabled(row, onFilter)}
|
||||
title={filterOutLabel}
|
||||
disabled={filteringDisabled || isFilterInOutPairDisabled(row, onFilter)}
|
||||
title={filteringDisabled ? esqlMultivalueFilteringDisabled : filterOutLabel}
|
||||
flush="left"
|
||||
onClick={() => onFilter(dataViewField, flattenedValue, '-')}
|
||||
>
|
||||
|
@ -132,7 +146,7 @@ export const FilterOut: React.FC<TableActionsProps & { onFilter: DocViewFilterFn
|
|||
);
|
||||
};
|
||||
|
||||
export function isFilterExistsDisabled(
|
||||
function isFilterExistsDisabled(
|
||||
row: FieldRow | undefined,
|
||||
onFilter: DocViewFilterFn | undefined
|
||||
): boolean {
|
||||
|
@ -165,9 +179,11 @@ export function getFilterExistsDisabledWarning(
|
|||
: undefined;
|
||||
}
|
||||
|
||||
export const FilterExist: React.FC<
|
||||
TableActionsProps & { onFilter: DocViewFilterFn | undefined }
|
||||
> = ({ Component, row, onFilter }) => {
|
||||
const FilterExist: React.FC<TableActionsProps & { onFilter: DocViewFilterFn | undefined }> = ({
|
||||
Component,
|
||||
row,
|
||||
onFilter,
|
||||
}) => {
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
|
@ -198,7 +214,7 @@ export const FilterExist: React.FC<
|
|||
);
|
||||
};
|
||||
|
||||
export const ToggleColumn: React.FC<
|
||||
const ToggleColumn: React.FC<
|
||||
TableActionsProps & {
|
||||
onToggleColumn: ((field: string) => void) | undefined;
|
||||
}
|
||||
|
@ -236,10 +252,12 @@ export const ToggleColumn: React.FC<
|
|||
|
||||
export function getFieldCellActions({
|
||||
rows,
|
||||
isEsqlMode,
|
||||
onFilter,
|
||||
onToggleColumn,
|
||||
}: {
|
||||
rows: FieldRow[];
|
||||
isEsqlMode: boolean | undefined;
|
||||
onFilter?: DocViewFilterFn;
|
||||
onToggleColumn: ((field: string) => void) | undefined;
|
||||
}) {
|
||||
|
@ -247,7 +265,14 @@ export function getFieldCellActions({
|
|||
...(onFilter
|
||||
? [
|
||||
({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => {
|
||||
return <FilterExist row={rows[rowIndex]} Component={Component} onFilter={onFilter} />;
|
||||
return (
|
||||
<FilterExist
|
||||
row={rows[rowIndex]}
|
||||
Component={Component}
|
||||
isEsqlMode={isEsqlMode}
|
||||
onFilter={onFilter}
|
||||
/>
|
||||
);
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
@ -258,6 +283,7 @@ export function getFieldCellActions({
|
|||
<ToggleColumn
|
||||
row={rows[rowIndex]}
|
||||
Component={Component}
|
||||
isEsqlMode={isEsqlMode}
|
||||
onToggleColumn={onToggleColumn}
|
||||
/>
|
||||
);
|
||||
|
@ -269,18 +295,34 @@ export function getFieldCellActions({
|
|||
|
||||
export function getFieldValueCellActions({
|
||||
rows,
|
||||
isEsqlMode,
|
||||
onFilter,
|
||||
}: {
|
||||
rows: FieldRow[];
|
||||
isEsqlMode: boolean | undefined;
|
||||
onFilter?: DocViewFilterFn;
|
||||
}) {
|
||||
return onFilter
|
||||
? [
|
||||
({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => {
|
||||
return <FilterIn row={rows[rowIndex]} Component={Component} onFilter={onFilter} />;
|
||||
return (
|
||||
<FilterIn
|
||||
row={rows[rowIndex]}
|
||||
Component={Component}
|
||||
isEsqlMode={isEsqlMode}
|
||||
onFilter={onFilter}
|
||||
/>
|
||||
);
|
||||
},
|
||||
({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => {
|
||||
return <FilterOut row={rows[rowIndex]} Component={Component} onFilter={onFilter} />;
|
||||
return (
|
||||
<FilterOut
|
||||
row={rows[rowIndex]}
|
||||
Component={Component}
|
||||
isEsqlMode={isEsqlMode}
|
||||
onFilter={onFilter}
|
||||
/>
|
||||
);
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue