mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Discover][EuiDataGrid] Add document selector (#94804)
Co-authored-by: Ryan Keairns <rkeairns@chef.io>
This commit is contained in:
parent
73ccf7844a
commit
8cce4805d4
11 changed files with 537 additions and 11 deletions
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ReactWrapper } from 'enzyme';
|
||||
import { EuiCopy } from '@elastic/eui';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { findTestSubject } from '@elastic/eui/lib/test';
|
||||
import { esHits } from '../../../__mocks__/es_hits';
|
||||
import { indexPatternMock } from '../../../__mocks__/index_pattern';
|
||||
import { mountWithIntl } from '@kbn/test/jest';
|
||||
import { DiscoverGrid, DiscoverGridProps } from './discover_grid';
|
||||
import { uiSettingsMock } from '../../../__mocks__/ui_settings';
|
||||
import { DiscoverServices } from '../../../build_services';
|
||||
import { ElasticSearchHit } from '../../doc_views/doc_views_types';
|
||||
import { getDocId } from './discover_grid_document_selection';
|
||||
|
||||
function getProps() {
|
||||
const servicesMock = {
|
||||
uiSettings: uiSettingsMock,
|
||||
} as DiscoverServices;
|
||||
return {
|
||||
ariaLabelledBy: '',
|
||||
columns: [],
|
||||
indexPattern: indexPatternMock,
|
||||
isLoading: false,
|
||||
expandedDoc: undefined,
|
||||
onAddColumn: jest.fn(),
|
||||
onFilter: jest.fn(),
|
||||
onRemoveColumn: jest.fn(),
|
||||
onResize: jest.fn(),
|
||||
onSetColumns: jest.fn(),
|
||||
onSort: jest.fn(),
|
||||
rows: esHits,
|
||||
sampleSize: 30,
|
||||
searchDescription: '',
|
||||
searchTitle: '',
|
||||
services: servicesMock,
|
||||
setExpandedDoc: jest.fn(),
|
||||
settings: {},
|
||||
showTimeCol: true,
|
||||
sort: [],
|
||||
useNewFieldsApi: true,
|
||||
};
|
||||
}
|
||||
|
||||
function getComponent() {
|
||||
return mountWithIntl(<DiscoverGrid {...getProps()} />);
|
||||
}
|
||||
|
||||
function getSelectedDocNr(component: ReactWrapper<DiscoverGridProps>) {
|
||||
const gridSelectionBtn = findTestSubject(component, 'dscGridSelectionBtn');
|
||||
if (!gridSelectionBtn.length) {
|
||||
return 0;
|
||||
}
|
||||
const selectedNr = gridSelectionBtn.getDOMNode().getAttribute('data-selected-documents');
|
||||
return Number(selectedNr);
|
||||
}
|
||||
|
||||
function getDisplayedDocNr(component: ReactWrapper<DiscoverGridProps>) {
|
||||
const gridSelectionBtn = findTestSubject(component, 'discoverDocTable');
|
||||
if (!gridSelectionBtn.length) {
|
||||
return 0;
|
||||
}
|
||||
const selectedNr = gridSelectionBtn.getDOMNode().getAttribute('data-document-number');
|
||||
return Number(selectedNr);
|
||||
}
|
||||
|
||||
async function toggleDocSelection(
|
||||
component: ReactWrapper<DiscoverGridProps>,
|
||||
document: ElasticSearchHit
|
||||
) {
|
||||
act(() => {
|
||||
const docId = getDocId(document);
|
||||
findTestSubject(component, `dscGridSelectDoc-${docId}`).simulate('change');
|
||||
});
|
||||
component.update();
|
||||
}
|
||||
|
||||
describe('DiscoverGrid', () => {
|
||||
describe('Document selection', () => {
|
||||
let component: ReactWrapper<DiscoverGridProps>;
|
||||
beforeEach(() => {
|
||||
component = getComponent();
|
||||
});
|
||||
|
||||
test('no documents are selected initially', async () => {
|
||||
expect(getSelectedDocNr(component)).toBe(0);
|
||||
expect(getDisplayedDocNr(component)).toBe(5);
|
||||
});
|
||||
|
||||
test('Allows selection/deselection of multiple documents', async () => {
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
expect(getSelectedDocNr(component)).toBe(1);
|
||||
await toggleDocSelection(component, esHits[1]);
|
||||
expect(getSelectedDocNr(component)).toBe(2);
|
||||
await toggleDocSelection(component, esHits[1]);
|
||||
expect(getSelectedDocNr(component)).toBe(1);
|
||||
});
|
||||
|
||||
test('deselection of all selected documents', async () => {
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
await toggleDocSelection(component, esHits[1]);
|
||||
expect(getSelectedDocNr(component)).toBe(2);
|
||||
findTestSubject(component, 'dscGridSelectionBtn').simulate('click');
|
||||
findTestSubject(component, 'dscGridClearSelectedDocuments').simulate('click');
|
||||
expect(getSelectedDocNr(component)).toBe(0);
|
||||
});
|
||||
|
||||
test('showing only selected documents and undo selection', async () => {
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
await toggleDocSelection(component, esHits[1]);
|
||||
expect(getSelectedDocNr(component)).toBe(2);
|
||||
findTestSubject(component, 'dscGridSelectionBtn').simulate('click');
|
||||
findTestSubject(component, 'dscGridShowSelectedDocuments').simulate('click');
|
||||
expect(getDisplayedDocNr(component)).toBe(2);
|
||||
findTestSubject(component, 'dscGridSelectionBtn').simulate('click');
|
||||
component.update();
|
||||
findTestSubject(component, 'dscGridShowAllDocuments').simulate('click');
|
||||
expect(getDisplayedDocNr(component)).toBe(5);
|
||||
});
|
||||
|
||||
test('showing only selected documents and remove filter deselecting each doc manually', async () => {
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
findTestSubject(component, 'dscGridSelectionBtn').simulate('click');
|
||||
findTestSubject(component, 'dscGridShowSelectedDocuments').simulate('click');
|
||||
expect(getDisplayedDocNr(component)).toBe(1);
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
expect(getDisplayedDocNr(component)).toBe(5);
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
expect(getDisplayedDocNr(component)).toBe(5);
|
||||
});
|
||||
|
||||
test('copying selected documents to clipboard', async () => {
|
||||
await toggleDocSelection(component, esHits[0]);
|
||||
findTestSubject(component, 'dscGridSelectionBtn').simulate('click');
|
||||
expect(component.find(EuiCopy).prop('textToCopy')).toMatchInlineSnapshot(
|
||||
`"[{\\"_index\\":\\"i\\",\\"_id\\":\\"1\\",\\"_score\\":1,\\"_type\\":\\"_doc\\",\\"_source\\":{\\"date\\":\\"2020-20-01T12:12:12.123\\",\\"message\\":\\"test1\\",\\"bytes\\":20}}]"`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -37,6 +37,7 @@ import { defaultPageSize, gridStyle, pageSizeArr, toolbarVisibility } from './co
|
|||
import { DiscoverServices } from '../../../build_services';
|
||||
import { getDisplayedColumns } from '../../helpers/columns';
|
||||
import { KibanaContextProvider } from '../../../../../kibana_react/public';
|
||||
import { DiscoverGridDocumentToolbarBtn, getDocId } from './discover_grid_document_selection';
|
||||
|
||||
interface SortObj {
|
||||
id: string;
|
||||
|
@ -158,14 +159,27 @@ export const DiscoverGrid = ({
|
|||
sort,
|
||||
useNewFieldsApi,
|
||||
}: DiscoverGridProps) => {
|
||||
const [selectedDocs, setSelectedDocs] = useState<string[]>([]);
|
||||
const [isFilterActive, setIsFilterActive] = useState(false);
|
||||
const displayedColumns = getDisplayedColumns(columns, indexPattern);
|
||||
const defaultColumns = displayedColumns.includes('_source');
|
||||
const displayedRows = useMemo(() => {
|
||||
if (!rows) {
|
||||
return [];
|
||||
}
|
||||
if (!isFilterActive || selectedDocs.length === 0) {
|
||||
return rows;
|
||||
}
|
||||
return rows.filter((row) => {
|
||||
return selectedDocs.includes(getDocId(row));
|
||||
});
|
||||
}, [rows, selectedDocs, isFilterActive]);
|
||||
|
||||
/**
|
||||
* Pagination
|
||||
*/
|
||||
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: defaultPageSize });
|
||||
const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]);
|
||||
const rowCount = useMemo(() => (displayedRows ? displayedRows.length : 0), [displayedRows]);
|
||||
const pageCount = useMemo(() => Math.ceil(rowCount / pagination.pageSize), [
|
||||
rowCount,
|
||||
pagination,
|
||||
|
@ -207,11 +221,11 @@ export const DiscoverGrid = ({
|
|||
() =>
|
||||
getRenderCellValueFn(
|
||||
indexPattern,
|
||||
rows,
|
||||
rows ? rows.map((hit) => indexPattern.flattenHit(hit)) : [],
|
||||
displayedRows,
|
||||
displayedRows ? displayedRows.map((hit) => indexPattern.flattenHit(hit)) : [],
|
||||
useNewFieldsApi
|
||||
),
|
||||
[rows, indexPattern, useNewFieldsApi]
|
||||
[displayedRows, indexPattern, useNewFieldsApi]
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -240,6 +254,20 @@ export const DiscoverGrid = ({
|
|||
]);
|
||||
const lead = useMemo(() => getLeadControlColumns(), []);
|
||||
|
||||
const additionalControls = useMemo(
|
||||
() =>
|
||||
selectedDocs.length ? (
|
||||
<DiscoverGridDocumentToolbarBtn
|
||||
isFilterActive={isFilterActive}
|
||||
rows={rows!}
|
||||
selectedDocs={selectedDocs}
|
||||
setSelectedDocs={setSelectedDocs}
|
||||
setIsFilterActive={setIsFilterActive}
|
||||
/>
|
||||
) : null,
|
||||
[selectedDocs, isFilterActive, rows, setIsFilterActive]
|
||||
);
|
||||
|
||||
if (!rowCount) {
|
||||
return (
|
||||
<div className="euiDataGrid__noResults">
|
||||
|
@ -257,10 +285,17 @@ export const DiscoverGrid = ({
|
|||
value={{
|
||||
expanded: expandedDoc,
|
||||
setExpanded: setExpandedDoc,
|
||||
rows: rows || [],
|
||||
rows: displayedRows,
|
||||
onFilter,
|
||||
indexPattern,
|
||||
isDarkMode: services.uiSettings.get('theme:darkMode'),
|
||||
selectedDocs,
|
||||
setSelectedDocs: (newSelectedDocs) => {
|
||||
setSelectedDocs(newSelectedDocs);
|
||||
if (isFilterActive && newSelectedDocs.length === 0) {
|
||||
setIsFilterActive(false);
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<span
|
||||
|
@ -269,6 +304,7 @@ export const DiscoverGrid = ({
|
|||
data-shared-item=""
|
||||
data-title={searchTitle}
|
||||
data-description={searchDescription}
|
||||
data-document-number={displayedRows.length}
|
||||
>
|
||||
<KibanaContextProvider services={{ uiSettings: services.uiSettings }}>
|
||||
<EuiDataGridMemoized
|
||||
|
@ -294,8 +330,12 @@ export const DiscoverGrid = ({
|
|||
? {
|
||||
...toolbarVisibility,
|
||||
showColumnSelector: false,
|
||||
additionalControls,
|
||||
}
|
||||
: {
|
||||
...toolbarVisibility,
|
||||
additionalControls,
|
||||
}
|
||||
: toolbarVisibility
|
||||
}
|
||||
/>
|
||||
</KibanaContextProvider>
|
||||
|
@ -335,7 +375,7 @@ export const DiscoverGrid = ({
|
|||
<DiscoverGridFlyout
|
||||
indexPattern={indexPattern}
|
||||
hit={expandedDoc}
|
||||
hits={rows}
|
||||
hits={displayedRows}
|
||||
// if default columns are used, dont make them part of the URL - the context state handling will take care to restore them
|
||||
columns={defaultColumns ? [] : displayedColumns}
|
||||
onFilter={onFilter}
|
||||
|
|
|
@ -25,6 +25,8 @@ describe('Discover cell actions ', function () {
|
|||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
|
@ -50,6 +52,8 @@ describe('Discover cell actions ', function () {
|
|||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
|
|
|
@ -14,6 +14,7 @@ import { DiscoverGridSettings } from './types';
|
|||
import { IndexPattern } from '../../../../../data/common/index_patterns/index_patterns';
|
||||
import { buildCellActions } from './discover_grid_cell_actions';
|
||||
import { getSchemaByKbnType } from './discover_grid_schema';
|
||||
import { SelectButton } from './discover_grid_document_selection';
|
||||
|
||||
export function getLeadControlColumns() {
|
||||
return [
|
||||
|
@ -31,6 +32,20 @@ export function getLeadControlColumns() {
|
|||
),
|
||||
rowCellRender: ExpandButton,
|
||||
},
|
||||
{
|
||||
id: 'select',
|
||||
width: 32,
|
||||
rowCellRender: SelectButton,
|
||||
headerCellRender: () => (
|
||||
<EuiScreenReaderOnly>
|
||||
<span>
|
||||
{i18n.translate('discover.selectColumnHeader', {
|
||||
defaultMessage: 'Select column',
|
||||
})}
|
||||
</span>
|
||||
</EuiScreenReaderOnly>
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ export interface GridContext {
|
|||
onFilter: DocViewFilterFn;
|
||||
indexPattern: IndexPattern;
|
||||
isDarkMode: boolean;
|
||||
selectedDocs: string[];
|
||||
setSelectedDocs: (selected: string[]) => void;
|
||||
}
|
||||
|
||||
const defaultContext = ({} as unknown) as GridContext;
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { mountWithIntl } from '@kbn/test/jest';
|
||||
import { findTestSubject } from '@elastic/eui/lib/test';
|
||||
import {
|
||||
DiscoverGridDocumentToolbarBtn,
|
||||
getDocId,
|
||||
SelectButton,
|
||||
} from './discover_grid_document_selection';
|
||||
import { esHits } from '../../../__mocks__/es_hits';
|
||||
import { indexPatternMock } from '../../../__mocks__/index_pattern';
|
||||
import { DiscoverGridContext } from './discover_grid_context';
|
||||
|
||||
describe('document selection', () => {
|
||||
describe('getDocId', () => {
|
||||
test('doc with custom routing', () => {
|
||||
const doc = {
|
||||
_id: 'test-id',
|
||||
_index: 'test-indices',
|
||||
_routing: 'why-not',
|
||||
};
|
||||
expect(getDocId(doc)).toMatchInlineSnapshot(`"test-indices::test-id::why-not"`);
|
||||
});
|
||||
test('doc without custom routing', () => {
|
||||
const doc = {
|
||||
_id: 'test-id',
|
||||
_index: 'test-indices',
|
||||
};
|
||||
expect(getDocId(doc)).toMatchInlineSnapshot(`"test-indices::test-id::"`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SelectButton', () => {
|
||||
test('is not checked', () => {
|
||||
const contextMock = {
|
||||
expanded: undefined,
|
||||
setExpanded: jest.fn(),
|
||||
rows: esHits,
|
||||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
<DiscoverGridContext.Provider value={contextMock}>
|
||||
<SelectButton rowIndex={0} />
|
||||
</DiscoverGridContext.Provider>
|
||||
);
|
||||
|
||||
const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::');
|
||||
expect(checkBox.props().checked).toBeFalsy();
|
||||
});
|
||||
|
||||
test('is checked', () => {
|
||||
const contextMock = {
|
||||
expanded: undefined,
|
||||
setExpanded: jest.fn(),
|
||||
rows: esHits,
|
||||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: ['i::1::'],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
<DiscoverGridContext.Provider value={contextMock}>
|
||||
<SelectButton rowIndex={0} />
|
||||
</DiscoverGridContext.Provider>
|
||||
);
|
||||
|
||||
const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::');
|
||||
expect(checkBox.props().checked).toBeTruthy();
|
||||
});
|
||||
|
||||
test('adding a selection', () => {
|
||||
const contextMock = {
|
||||
expanded: undefined,
|
||||
setExpanded: jest.fn(),
|
||||
rows: esHits,
|
||||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
<DiscoverGridContext.Provider value={contextMock}>
|
||||
<SelectButton rowIndex={0} />
|
||||
</DiscoverGridContext.Provider>
|
||||
);
|
||||
|
||||
const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::');
|
||||
checkBox.simulate('change');
|
||||
expect(contextMock.setSelectedDocs).toHaveBeenCalledWith(['i::1::']);
|
||||
});
|
||||
test('removing a selection', () => {
|
||||
const contextMock = {
|
||||
expanded: undefined,
|
||||
setExpanded: jest.fn(),
|
||||
rows: esHits,
|
||||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: ['i::1::'],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
<DiscoverGridContext.Provider value={contextMock}>
|
||||
<SelectButton rowIndex={0} />
|
||||
</DiscoverGridContext.Provider>
|
||||
);
|
||||
|
||||
const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::');
|
||||
checkBox.simulate('change');
|
||||
expect(contextMock.setSelectedDocs).toHaveBeenCalledWith([]);
|
||||
});
|
||||
});
|
||||
describe('DiscoverGridDocumentToolbarBtn', () => {
|
||||
test('it renders a button clickable button', () => {
|
||||
const props = {
|
||||
isFilterActive: false,
|
||||
rows: esHits,
|
||||
selectedDocs: ['i::1::'],
|
||||
setIsFilterActive: jest.fn(),
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
const component = mountWithIntl(<DiscoverGridDocumentToolbarBtn {...props} />);
|
||||
const button = findTestSubject(component, 'dscGridSelectionBtn');
|
||||
expect(button.length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import React, { useCallback, useState, useContext, useMemo } from 'react';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiContextMenuItem,
|
||||
EuiContextMenuPanel,
|
||||
EuiCopy,
|
||||
EuiPopover,
|
||||
EuiCheckbox,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import classNames from 'classnames';
|
||||
import { ElasticSearchHit } from '../../doc_views/doc_views_types';
|
||||
import { DiscoverGridContext } from './discover_grid_context';
|
||||
|
||||
/**
|
||||
* Returning a generated id of a given ES document, since `_id` can be the same
|
||||
* when using different indices and shard routing
|
||||
*/
|
||||
export const getDocId = (doc: ElasticSearchHit & { _routing?: string }) => {
|
||||
const routing = doc._routing ? doc._routing : '';
|
||||
return [doc._index, doc._id, routing].join('::');
|
||||
};
|
||||
export const SelectButton = ({ rowIndex }: { rowIndex: number }) => {
|
||||
const ctx = useContext(DiscoverGridContext);
|
||||
const doc = useMemo(() => ctx.rows[rowIndex], [ctx.rows, rowIndex]);
|
||||
const id = useMemo(() => getDocId(doc), [doc]);
|
||||
const checked = useMemo(() => ctx.selectedDocs.includes(id), [ctx.selectedDocs, id]);
|
||||
|
||||
return (
|
||||
<EuiCheckbox
|
||||
id={id}
|
||||
label=""
|
||||
checked={checked}
|
||||
data-test-subj={`dscGridSelectDoc-${id}`}
|
||||
onChange={() => {
|
||||
if (checked) {
|
||||
const newSelection = ctx.selectedDocs.filter((docId) => docId !== id);
|
||||
ctx.setSelectedDocs(newSelection);
|
||||
} else {
|
||||
ctx.setSelectedDocs([...ctx.selectedDocs, id]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export function DiscoverGridDocumentToolbarBtn({
|
||||
isFilterActive,
|
||||
rows,
|
||||
selectedDocs,
|
||||
setIsFilterActive,
|
||||
setSelectedDocs,
|
||||
}: {
|
||||
isFilterActive: boolean;
|
||||
rows: ElasticSearchHit[];
|
||||
selectedDocs: string[];
|
||||
setIsFilterActive: (value: boolean) => void;
|
||||
setSelectedDocs: (value: string[]) => void;
|
||||
}) {
|
||||
const [isSelectionPopoverOpen, setIsSelectionPopoverOpen] = useState(false);
|
||||
|
||||
const getMenuItems = useCallback(() => {
|
||||
return [
|
||||
isFilterActive ? (
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="dscGridShowAllDocuments"
|
||||
key="showAllDocuments"
|
||||
icon="eye"
|
||||
onClick={() => {
|
||||
setIsSelectionPopoverOpen(false);
|
||||
setIsFilterActive(false);
|
||||
}}
|
||||
>
|
||||
<FormattedMessage id="discover.showAllDocuments" defaultMessage="Show all documents" />
|
||||
</EuiContextMenuItem>
|
||||
) : (
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="dscGridShowSelectedDocuments"
|
||||
key="showSelectedDocuments"
|
||||
icon="eye"
|
||||
onClick={() => {
|
||||
setIsSelectionPopoverOpen(false);
|
||||
setIsFilterActive(true);
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="discover.showSelectedDocumentsOnly"
|
||||
defaultMessage="Show selected documents only"
|
||||
/>
|
||||
</EuiContextMenuItem>
|
||||
),
|
||||
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="dscGridClearSelectedDocuments"
|
||||
key="clearSelection"
|
||||
icon="cross"
|
||||
onClick={() => {
|
||||
setIsSelectionPopoverOpen(false);
|
||||
setSelectedDocs([]);
|
||||
setIsFilterActive(false);
|
||||
}}
|
||||
>
|
||||
<FormattedMessage id="discover.clearSelection" defaultMessage="Clear selection" />
|
||||
</EuiContextMenuItem>,
|
||||
<EuiCopy
|
||||
key="copyJsonWrapper"
|
||||
data-test-subj="dscGridCopySelectedDocumentsJSON"
|
||||
textToCopy={
|
||||
rows ? JSON.stringify(rows.filter((row) => selectedDocs.includes(getDocId(row)))) : ''
|
||||
}
|
||||
>
|
||||
{(copy) => (
|
||||
<EuiContextMenuItem key="copyJSON" icon="copyClipboard" onClick={copy}>
|
||||
<FormattedMessage
|
||||
id="discover.copyToClipboardJSON"
|
||||
defaultMessage="Copy documents to clipboard (JSON)"
|
||||
/>
|
||||
</EuiContextMenuItem>
|
||||
)}
|
||||
</EuiCopy>,
|
||||
];
|
||||
}, [
|
||||
isFilterActive,
|
||||
rows,
|
||||
selectedDocs,
|
||||
setIsFilterActive,
|
||||
setIsSelectionPopoverOpen,
|
||||
setSelectedDocs,
|
||||
]);
|
||||
|
||||
return (
|
||||
<EuiPopover
|
||||
closePopover={() => setIsSelectionPopoverOpen(false)}
|
||||
isOpen={isSelectionPopoverOpen}
|
||||
panelPaddingSize="none"
|
||||
button={
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
color="text"
|
||||
iconType="documents"
|
||||
onClick={() => setIsSelectionPopoverOpen(true)}
|
||||
data-selected-documents={selectedDocs.length}
|
||||
data-test-subj="dscGridSelectionBtn"
|
||||
isSelected={isFilterActive}
|
||||
className={classNames({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
euiDataGrid__controlBtn: true,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'euiDataGrid__controlBtn--active': isFilterActive,
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="discover.selectedDocumentsNumber"
|
||||
defaultMessage="{nr} documents selected"
|
||||
values={{ nr: selectedDocs.length }}
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
>
|
||||
{isSelectionPopoverOpen && <EuiContextMenuPanel items={getMenuItems()} />}
|
||||
</EuiPopover>
|
||||
);
|
||||
}
|
|
@ -23,6 +23,8 @@ describe('Discover grid view button ', function () {
|
|||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
|
@ -49,6 +51,8 @@ describe('Discover grid view button ', function () {
|
|||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
|
@ -75,6 +79,8 @@ describe('Discover grid view button ', function () {
|
|||
onFilter: jest.fn(),
|
||||
indexPattern: indexPatternMock,
|
||||
isDarkMode: false,
|
||||
selectedDocs: [],
|
||||
setSelectedDocs: jest.fn(),
|
||||
};
|
||||
|
||||
const component = mountWithIntl(
|
||||
|
|
|
@ -47,12 +47,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('are added when a cell filter is clicked', async function () {
|
||||
await find.clickByCssSelector(`[role="gridcell"]:nth-child(3)`);
|
||||
await find.clickByCssSelector(`[role="gridcell"]:nth-child(4)`);
|
||||
// needs a short delay between becoming visible & being clickable
|
||||
await PageObjects.common.sleep(250);
|
||||
await find.clickByCssSelector(`[data-test-subj="filterOutButton"]`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await find.clickByCssSelector(`[role="gridcell"]:nth-child(3)`);
|
||||
await find.clickByCssSelector(`[role="gridcell"]:nth-child(4)`);
|
||||
await PageObjects.common.sleep(250);
|
||||
await find.clickByCssSelector(`[data-test-subj="filterForButton"]`);
|
||||
const filterCount = await filterBar.getFilterCount();
|
||||
|
|
|
@ -68,7 +68,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.discover.waitUntilSearchingHasFinished();
|
||||
|
||||
await retry.waitFor('first cell contains expected timestamp', async () => {
|
||||
const cell = await dataGrid.getCellElement(1, 2);
|
||||
const cell = await dataGrid.getCellElement(1, 3);
|
||||
const text = await cell.getVisibleText();
|
||||
return text === expectedTimeStamp;
|
||||
});
|
||||
|
|
|
@ -168,7 +168,7 @@ export function DataGridProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
const textArr = [];
|
||||
let idx = 0;
|
||||
for (const cell of result) {
|
||||
if (idx > 0) {
|
||||
if (idx > 1) {
|
||||
textArr.push(await cell.getVisibleText());
|
||||
}
|
||||
idx++;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue