mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Discover] Enable expanded row view (#158623)
## Summary
Part of https://github.com/elastic/kibana/issues/154331
Enables the expanded row view for text based documents for both the
legacy and datagrid modes (the legacy was broken)
<img width="1899" alt="image"
src="edae78a9
-6ef5-43db-ba3d-9019ecc72c57">
Note: I am hiding for now the single document view and surrounding
document view. I think that we should think about it more and if it
makes sense for ESQL. With ESQL if there is no @timestamp I see all my
data in the table. If I want to narrow the results I can use where and
limit. How should the surrounding documents work for a query with where
date field and with llimit? Does it make sense? Possibly not, because
with ESQL I can have the surrounding documents view in my main view bu
just changing the query. So I am hiding them for now, until we find a
good use case for that and decide how we want this to work.
### 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)
- [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
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d13f884ec3
commit
2bee02ffd0
20 changed files with 273 additions and 133 deletions
|
@ -16,6 +16,7 @@ import { DocViewer } from '../../../services/doc_views/components/doc_viewer';
|
|||
import { ElasticRequestState } from '../types';
|
||||
import { useEsDocSearch } from '../../../hooks/use_es_doc_search';
|
||||
import { useDiscoverServices } from '../../../hooks/use_discover_services';
|
||||
import type { DataTableRecord } from '../../../types';
|
||||
|
||||
export interface DocProps {
|
||||
/**
|
||||
|
@ -38,6 +39,10 @@ export interface DocProps {
|
|||
* Discover main view url
|
||||
*/
|
||||
referrer?: string;
|
||||
/**
|
||||
* Records fetched from text based query
|
||||
*/
|
||||
textBasedHits?: DataTableRecord[];
|
||||
}
|
||||
|
||||
export function Doc(props: DocProps) {
|
||||
|
|
|
@ -208,6 +208,7 @@ function DiscoverDocumentsComponent({
|
|||
isLoading={isDataLoading}
|
||||
searchDescription={savedSearch.description}
|
||||
sharedItemTitle={savedSearch.title}
|
||||
isPlainRecord={isPlainRecord}
|
||||
onAddColumn={onAddColumn}
|
||||
onFilter={onAddFilter as DocViewFilterFn}
|
||||
onMoveColumn={onMoveColumn}
|
||||
|
@ -238,7 +239,7 @@ function DiscoverDocumentsComponent({
|
|||
sampleSize={sampleSize}
|
||||
searchDescription={savedSearch.description}
|
||||
searchTitle={savedSearch.title}
|
||||
setExpandedDoc={!isPlainRecord ? setExpandedDoc : undefined}
|
||||
setExpandedDoc={setExpandedDoc}
|
||||
showTimeCol={showTimeCol}
|
||||
settings={grid}
|
||||
onAddColumn={onAddColumn}
|
||||
|
@ -252,6 +253,7 @@ function DiscoverDocumentsComponent({
|
|||
onUpdateRowHeight={onUpdateRowHeight}
|
||||
isSortEnabled={!isPlainRecord}
|
||||
isPlainRecord={isPlainRecord}
|
||||
query={query}
|
||||
rowsPerPageState={rowsPerPage}
|
||||
onUpdateRowsPerPage={onUpdateRowsPerPage}
|
||||
onFieldEdited={onFieldEdited}
|
||||
|
|
|
@ -15,16 +15,12 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.dscDiscoverGrid__textLanguageMode .euiDataGridRowCell.euiDataGridRowCell--firstColumn {
|
||||
padding: $euiSizeXS;
|
||||
}
|
||||
|
||||
.euiDataGridRowCell.euiDataGridRowCell--lastColumn {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.dscDiscoverGrid__documentsMode .euiDataGridRowCell:first-of-type,
|
||||
.dscDiscoverGrid__documentsMode .euiDataGrid--headerShade.euiDataGrid--bordersAll .euiDataGridHeaderCell:first-of-type {
|
||||
.dscDiscoverGrid__table .euiDataGridRowCell:first-of-type,
|
||||
.dscDiscoverGrid__table .euiDataGrid--headerShade.euiDataGrid--bordersAll .euiDataGridHeaderCell:first-of-type {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { SortOrder } from '@kbn/saved-search-plugin/public';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import type { AggregateQuery, Filter, Query } from '@kbn/es-query';
|
||||
import { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import type { ToastsStart, IUiSettingsClient, HttpStart, CoreStart } from '@kbn/core/public';
|
||||
import { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public';
|
||||
|
@ -191,6 +191,10 @@ export interface DiscoverGridProps {
|
|||
* Filters applied by saved search embeddable
|
||||
*/
|
||||
filters?: Filter[];
|
||||
/**
|
||||
* Query applied by KQL bar or text based editor
|
||||
*/
|
||||
query?: Query | AggregateQuery;
|
||||
/**
|
||||
* Saved search id used for links to single doc and surrounding docs in the flyout
|
||||
*/
|
||||
|
@ -224,6 +228,7 @@ export const DiscoverGrid = ({
|
|||
expandedDoc,
|
||||
onAddColumn,
|
||||
filters,
|
||||
query,
|
||||
savedSearchId,
|
||||
onFilter,
|
||||
onRemoveColumn,
|
||||
|
@ -596,11 +601,7 @@ export const DiscoverGrid = ({
|
|||
data-title={searchTitle}
|
||||
data-description={searchDescription}
|
||||
data-document-number={displayedRows.length}
|
||||
className={classnames(
|
||||
className,
|
||||
'dscDiscoverGrid__table',
|
||||
isPlainRecord ? 'dscDiscoverGrid__textLanguageMode' : 'dscDiscoverGrid__documentsMode'
|
||||
)}
|
||||
className={classnames(className, 'dscDiscoverGrid__table')}
|
||||
>
|
||||
<EuiDataGridMemoized
|
||||
aria-describedby={randomId}
|
||||
|
@ -665,6 +666,7 @@ export const DiscoverGrid = ({
|
|||
onAddColumn={onAddColumn}
|
||||
onClose={() => setExpandedDoc(undefined)}
|
||||
setExpandedDoc={setExpandedDoc}
|
||||
query={query}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import React from 'react';
|
||||
import { findTestSubject } from '@elastic/eui/lib/test';
|
||||
import { mountWithIntl } from '@kbn/test-jest-helpers';
|
||||
import type { Query, AggregateQuery } from '@kbn/es-query';
|
||||
import { DiscoverGridFlyout, DiscoverGridFlyoutProps } from './discover_grid_flyout';
|
||||
import { esHits } from '../../__mocks__/es_hits';
|
||||
import { createFilterManagerMock } from '@kbn/data-plugin/public/query/filter_manager/filter_manager.mock';
|
||||
|
@ -40,10 +41,12 @@ describe('Discover flyout', function () {
|
|||
dataView,
|
||||
hits,
|
||||
hitIndex,
|
||||
query,
|
||||
}: {
|
||||
dataView?: DataView;
|
||||
hits?: DataTableRecord[];
|
||||
hitIndex?: number;
|
||||
query?: Query | AggregateQuery;
|
||||
}) => {
|
||||
const onClose = jest.fn();
|
||||
const services = {
|
||||
|
@ -71,6 +74,7 @@ describe('Discover flyout', function () {
|
|||
hits:
|
||||
hits ||
|
||||
esHits.map((entry: EsHitRecord) => buildDataTableRecord(entry, dataView || dataViewMock)),
|
||||
query,
|
||||
onAddColumn: jest.fn(),
|
||||
onClose,
|
||||
onFilter: jest.fn(),
|
||||
|
@ -192,4 +196,14 @@ describe('Discover flyout', function () {
|
|||
findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowRight' });
|
||||
expect(props.setExpandedDoc).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not render single/surrounding views for text based', async () => {
|
||||
const { component } = await mountComponent({
|
||||
query: { sql: 'Select * from indexpattern' },
|
||||
});
|
||||
const singleDocumentView = findTestSubject(component, 'docTableRowAction');
|
||||
expect(singleDocumentView.length).toBeFalsy();
|
||||
const flyoutTitle = findTestSubject(component, 'docTableRowDetailsTitle');
|
||||
expect(flyoutTitle.text()).toBe('Expanded row');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,16 +25,18 @@ import {
|
|||
EuiHideFor,
|
||||
keys,
|
||||
} from '@elastic/eui';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import type { Filter, Query, AggregateQuery } from '@kbn/es-query';
|
||||
import { DocViewer } from '../../services/doc_views/components/doc_viewer/doc_viewer';
|
||||
import { DocViewFilterFn } from '../../services/doc_views/doc_views_types';
|
||||
import { useNavigationProps } from '../../hooks/use_navigation_props';
|
||||
import { useDiscoverServices } from '../../hooks/use_discover_services';
|
||||
import { isTextBasedQuery } from '../../application/main/utils/is_text_based_query';
|
||||
import type { DataTableRecord } from '../../types';
|
||||
|
||||
export interface DiscoverGridFlyoutProps {
|
||||
savedSearchId?: string;
|
||||
filters?: Filter[];
|
||||
query?: Query | AggregateQuery;
|
||||
columns: string[];
|
||||
hit: DataTableRecord;
|
||||
hits?: DataTableRecord[];
|
||||
|
@ -61,6 +63,7 @@ export function DiscoverGridFlyout({
|
|||
columns,
|
||||
savedSearchId,
|
||||
filters,
|
||||
query,
|
||||
onFilter,
|
||||
onClose,
|
||||
onRemoveColumn,
|
||||
|
@ -68,6 +71,7 @@ export function DiscoverGridFlyout({
|
|||
setExpandedDoc,
|
||||
}: DiscoverGridFlyoutProps) {
|
||||
const services = useDiscoverServices();
|
||||
const isPlainRecord = isTextBasedQuery(query);
|
||||
// Get actual hit with updated highlighted searches
|
||||
const actualHit = useMemo(() => hits?.find(({ id }) => id === hit?.id) || hit, [hit, hits]);
|
||||
const pageCount = useMemo<number>(() => (hits ? hits.length : 0), [hits]);
|
||||
|
@ -120,80 +124,88 @@ export function DiscoverGridFlyout({
|
|||
data-test-subj="docTableRowDetailsTitle"
|
||||
>
|
||||
<h2>
|
||||
{i18n.translate('discover.grid.tableRow.detailHeading', {
|
||||
defaultMessage: 'Expanded document',
|
||||
})}
|
||||
{isPlainRecord
|
||||
? i18n.translate('discover.grid.tableRow.textBasedDetailHeading', {
|
||||
defaultMessage: 'Expanded row',
|
||||
})
|
||||
: i18n.translate('discover.grid.tableRow.detailHeading', {
|
||||
defaultMessage: 'Expanded document',
|
||||
})}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
|
||||
<EuiHideFor sizes={['xs', 's', 'm']}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s">
|
||||
<strong>
|
||||
{i18n.translate('discover.grid.tableRow.viewText', {
|
||||
defaultMessage: 'View:',
|
||||
})}
|
||||
</strong>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiHideFor>
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
iconSize="s"
|
||||
iconType="document"
|
||||
flush="left"
|
||||
data-test-subj="docTableRowAction"
|
||||
href={singleDocHref}
|
||||
onClick={onOpenSingleDoc}
|
||||
>
|
||||
{i18n.translate('discover.grid.tableRow.viewSingleDocumentLinkTextSimple', {
|
||||
defaultMessage: 'Single document',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
{dataView.isTimeBased() && dataView.id && (
|
||||
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="none">
|
||||
{!isPlainRecord && (
|
||||
<>
|
||||
<EuiHideFor sizes={['xs', 's', 'm']}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s">
|
||||
<strong>
|
||||
{i18n.translate('discover.grid.tableRow.viewText', {
|
||||
defaultMessage: 'View:',
|
||||
})}
|
||||
</strong>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiHideFor>
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
iconSize="s"
|
||||
iconType="documents"
|
||||
iconType="document"
|
||||
flush="left"
|
||||
onClick={onOpenContextView}
|
||||
href={contextViewHref}
|
||||
data-test-subj="docTableRowAction"
|
||||
href={singleDocHref}
|
||||
onClick={onOpenSingleDoc}
|
||||
>
|
||||
{i18n.translate(
|
||||
'discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple',
|
||||
{
|
||||
defaultMessage: 'Surrounding documents',
|
||||
}
|
||||
)}
|
||||
{i18n.translate('discover.grid.tableRow.viewSingleDocumentLinkTextSimple', {
|
||||
defaultMessage: 'Single document',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
content={i18n.translate(
|
||||
'discover.grid.tableRow.viewSurroundingDocumentsHover',
|
||||
{
|
||||
defaultMessage:
|
||||
'Inspect documents that occurred before and after this document. Only pinned filters remain active in the Surrounding documents view.',
|
||||
}
|
||||
)}
|
||||
type="questionInCircle"
|
||||
color="subdued"
|
||||
position="right"
|
||||
iconProps={{
|
||||
className: 'eui-alignTop',
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{dataView.isTimeBased() && dataView.id && (
|
||||
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
iconSize="s"
|
||||
iconType="documents"
|
||||
flush="left"
|
||||
onClick={onOpenContextView}
|
||||
href={contextViewHref}
|
||||
data-test-subj="docTableRowAction"
|
||||
>
|
||||
{i18n.translate(
|
||||
'discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple',
|
||||
{
|
||||
defaultMessage: 'Surrounding documents',
|
||||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
content={i18n.translate(
|
||||
'discover.grid.tableRow.viewSurroundingDocumentsHover',
|
||||
{
|
||||
defaultMessage:
|
||||
'Inspect documents that occurred before and after this document. Only pinned filters remain active in the Surrounding documents view.',
|
||||
}
|
||||
)}
|
||||
type="questionInCircle"
|
||||
color="subdued"
|
||||
position="right"
|
||||
iconProps={{
|
||||
className: 'eui-alignTop',
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{activePage !== -1 && (
|
||||
<EuiFlexItem data-test-subj={`dscDocNavigationPage-${activePage}`}>
|
||||
|
@ -236,6 +248,7 @@ export function DiscoverGridFlyout({
|
|||
})
|
||||
);
|
||||
}}
|
||||
textBasedHits={isPlainRecord ? hits : undefined}
|
||||
/>
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
|
|
|
@ -132,5 +132,17 @@ describe('Doc table row component', () => {
|
|||
toggleButton.simulate('click');
|
||||
expect(findTestSubject(component, 'docTableRowDetailsTitle').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should hide the single/surrounding views for text based languages', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
isPlainRecord: true,
|
||||
};
|
||||
const component = mountComponent(props);
|
||||
const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn');
|
||||
toggleButton.simulate('click');
|
||||
expect(findTestSubject(component, 'docTableRowDetailsTitle').text()).toBe('Expanded row');
|
||||
expect(findTestSubject(component, 'docTableRowAction').length).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,8 +31,10 @@ export interface TableRowProps {
|
|||
columns: string[];
|
||||
filter: DocViewFilterFn;
|
||||
filters?: Filter[];
|
||||
isPlainRecord?: boolean;
|
||||
savedSearchId?: string;
|
||||
row: DataTableRecord;
|
||||
rows: DataTableRecord[];
|
||||
dataView: DataView;
|
||||
useNewFieldsApi: boolean;
|
||||
shouldShowFieldHandler: ShouldShowFieldInTableHandler;
|
||||
|
@ -43,10 +45,12 @@ export interface TableRowProps {
|
|||
|
||||
export const TableRow = ({
|
||||
filters,
|
||||
isPlainRecord,
|
||||
columns,
|
||||
filter,
|
||||
savedSearchId,
|
||||
row,
|
||||
rows,
|
||||
dataView,
|
||||
useNewFieldsApi,
|
||||
shouldShowFieldHandler,
|
||||
|
@ -212,6 +216,7 @@ export const TableRow = ({
|
|||
columns={columns}
|
||||
filters={filters}
|
||||
savedSearchId={savedSearchId}
|
||||
isPlainRecord={isPlainRecord}
|
||||
>
|
||||
<DocViewer
|
||||
columns={columns}
|
||||
|
@ -220,6 +225,7 @@ export const TableRow = ({
|
|||
dataView={dataView}
|
||||
onAddColumn={onAddColumn}
|
||||
onRemoveColumn={onRemoveColumn}
|
||||
textBasedHits={isPlainRecord ? rows : undefined}
|
||||
/>
|
||||
</TableRowDetails>
|
||||
)}
|
||||
|
|
|
@ -23,6 +23,7 @@ interface TableRowDetailsProps {
|
|||
dataView: DataView;
|
||||
filters?: Filter[];
|
||||
savedSearchId?: string;
|
||||
isPlainRecord?: boolean;
|
||||
}
|
||||
|
||||
export const TableRowDetails = ({
|
||||
|
@ -35,6 +36,7 @@ export const TableRowDetails = ({
|
|||
columns,
|
||||
filters,
|
||||
savedSearchId,
|
||||
isPlainRecord,
|
||||
}: TableRowDetailsProps) => {
|
||||
const { singleDocHref, contextViewHref, onOpenSingleDoc, onOpenContextView } = useNavigationProps(
|
||||
{
|
||||
|
@ -58,55 +60,65 @@ export const TableRowDetails = ({
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xxs" data-test-subj="docTableRowDetailsTitle">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="discover.docTable.tableRow.detailHeading"
|
||||
defaultMessage="Expanded document"
|
||||
/>
|
||||
{isPlainRecord && (
|
||||
<FormattedMessage
|
||||
id="discover.grid.tableRow.textBasedDetailHeading"
|
||||
defaultMessage="Expanded row"
|
||||
/>
|
||||
)}
|
||||
{!isPlainRecord && (
|
||||
<FormattedMessage
|
||||
id="discover.docTable.tableRow.detailHeading"
|
||||
defaultMessage="Expanded document"
|
||||
/>
|
||||
)}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="l" alignItems="center" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
{isTimeBased && (
|
||||
/* eslint-disable-next-line @elastic/eui/href-or-on-click */
|
||||
{!isPlainRecord && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="l" alignItems="center" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
{isTimeBased && (
|
||||
/* eslint-disable-next-line @elastic/eui/href-or-on-click */
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
iconSize="s"
|
||||
iconType="document"
|
||||
flush="left"
|
||||
data-test-subj="docTableRowAction"
|
||||
href={contextViewHref}
|
||||
onClick={onOpenContextView}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="discover.docTable.tableRow.viewSurroundingDocumentsLinkText"
|
||||
defaultMessage="View surrounding documents"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
iconSize="s"
|
||||
iconType="document"
|
||||
flush="left"
|
||||
data-test-subj="docTableRowAction"
|
||||
href={contextViewHref}
|
||||
onClick={onOpenContextView}
|
||||
href={singleDocHref}
|
||||
onClick={onOpenSingleDoc}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="discover.docTable.tableRow.viewSurroundingDocumentsLinkText"
|
||||
defaultMessage="View surrounding documents"
|
||||
id="discover.docTable.tableRow.viewSingleDocumentLinkText"
|
||||
defaultMessage="View single document"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
iconSize="s"
|
||||
iconType="document"
|
||||
flush="left"
|
||||
data-test-subj="docTableRowAction"
|
||||
href={singleDocHref}
|
||||
onClick={onOpenSingleDoc}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="discover.docTable.tableRow.viewSingleDocumentLinkText"
|
||||
defaultMessage="View single document"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
<div data-test-subj="docViewer">{children}</div>
|
||||
</td>
|
||||
|
|
|
@ -32,6 +32,7 @@ export function DiscoverDocTableEmbeddable(renderProps: DocTableEmbeddableProps)
|
|||
searchDescription={renderProps.searchDescription}
|
||||
sharedItemTitle={renderProps.sharedItemTitle}
|
||||
isLoading={renderProps.isLoading}
|
||||
isPlainRecord={renderProps.isPlainRecord}
|
||||
dataTestSubj="embeddedSavedSearchDocTable"
|
||||
DocViewer={DocViewer}
|
||||
/>
|
||||
|
|
|
@ -61,6 +61,11 @@ export interface DocTableProps {
|
|||
* Filters applied by embeddalbe
|
||||
*/
|
||||
filters?: Filter[];
|
||||
/**
|
||||
* Flag which identifies if Discover operates
|
||||
* in text based mode (ESQL)
|
||||
*/
|
||||
isPlainRecord?: boolean;
|
||||
/**
|
||||
* Saved search id
|
||||
*/
|
||||
|
@ -114,6 +119,7 @@ export const DocTableWrapper = forwardRef(
|
|||
render,
|
||||
columns,
|
||||
filters,
|
||||
isPlainRecord,
|
||||
savedSearchId,
|
||||
rows,
|
||||
dataView,
|
||||
|
@ -187,6 +193,8 @@ export const DocTableWrapper = forwardRef(
|
|||
onAddColumn={onAddColumn}
|
||||
onRemoveColumn={onRemoveColumn}
|
||||
DocViewer={DocViewer}
|
||||
isPlainRecord={isPlainRecord}
|
||||
rows={rows}
|
||||
/>
|
||||
));
|
||||
},
|
||||
|
@ -201,6 +209,8 @@ export const DocTableWrapper = forwardRef(
|
|||
onAddColumn,
|
||||
onRemoveColumn,
|
||||
DocViewer,
|
||||
isPlainRecord,
|
||||
rows,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -556,10 +556,13 @@ export class SavedSearchEmbeddable
|
|||
return;
|
||||
}
|
||||
const useLegacyTable = this.services.uiSettings.get(DOC_TABLE_LEGACY);
|
||||
const query = this.savedSearch.searchSource.getField('query');
|
||||
|
||||
const props = {
|
||||
savedSearch: this.savedSearch,
|
||||
searchProps,
|
||||
useLegacyTable,
|
||||
query,
|
||||
};
|
||||
if (searchProps.services) {
|
||||
ReactDOM.render(
|
||||
|
|
|
@ -7,15 +7,17 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { AggregateQuery, Query } from '@kbn/es-query';
|
||||
import { DiscoverGridEmbeddable, DiscoverGridEmbeddableProps } from './saved_search_grid';
|
||||
import { DiscoverDocTableEmbeddable } from '../components/doc_table/create_doc_table_embeddable';
|
||||
import { DocTableEmbeddableProps } from '../components/doc_table/doc_table_embeddable';
|
||||
import { isTextBasedQuery } from '../application/main/utils/is_text_based_query';
|
||||
import { SearchProps } from './saved_search_embeddable';
|
||||
|
||||
interface SavedSearchEmbeddableComponentProps {
|
||||
searchProps: SearchProps;
|
||||
useLegacyTable: boolean;
|
||||
query?: AggregateQuery | Query;
|
||||
}
|
||||
|
||||
const DiscoverDocTableEmbeddableMemoized = React.memo(DiscoverDocTableEmbeddable);
|
||||
|
@ -24,14 +26,22 @@ const DiscoverGridEmbeddableMemoized = React.memo(DiscoverGridEmbeddable);
|
|||
export function SavedSearchEmbeddableComponent({
|
||||
searchProps,
|
||||
useLegacyTable,
|
||||
query,
|
||||
}: SavedSearchEmbeddableComponentProps) {
|
||||
if (useLegacyTable) {
|
||||
return <DiscoverDocTableEmbeddableMemoized {...(searchProps as DocTableEmbeddableProps)} />;
|
||||
const isPlainRecord = isTextBasedQuery(query);
|
||||
return (
|
||||
<DiscoverDocTableEmbeddableMemoized
|
||||
{...(searchProps as DocTableEmbeddableProps)}
|
||||
isPlainRecord={isPlainRecord}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<DiscoverGridEmbeddableMemoized
|
||||
{...(searchProps as DiscoverGridEmbeddableProps)}
|
||||
showFullScreenButton={false}
|
||||
query={query}
|
||||
className="dscDiscoverGrid"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -29,7 +29,7 @@ export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) {
|
|||
>
|
||||
<DataGridMemoized
|
||||
{...props}
|
||||
setExpandedDoc={!props.isPlainRecord ? setExpandedDoc : undefined}
|
||||
setExpandedDoc={setExpandedDoc}
|
||||
expandedDoc={expandedDoc}
|
||||
DocumentView={DiscoverGridFlyout}
|
||||
/>
|
||||
|
|
|
@ -286,4 +286,39 @@ describe('Test of <Doc /> helper / hook', () => {
|
|||
buildDataTableRecord(record),
|
||||
]);
|
||||
});
|
||||
|
||||
test('useEsDocSearch for text based languages', async () => {
|
||||
const dataView = {
|
||||
getComputedFields: () => [],
|
||||
getIndexPattern: () => index,
|
||||
};
|
||||
const props = {
|
||||
id: '1',
|
||||
index: 'index1',
|
||||
dataView,
|
||||
textBasedHits: [
|
||||
{
|
||||
id: '1',
|
||||
raw: { field1: 1, field2: 2 },
|
||||
flattened: { field1: 1, field2: 2 },
|
||||
},
|
||||
],
|
||||
} as unknown as DocProps;
|
||||
|
||||
const hook = renderHook((p: DocProps) => useEsDocSearch(p), {
|
||||
initialProps: props,
|
||||
wrapper: ({ children }) => (
|
||||
<KibanaContextProvider services={services}>{children}</KibanaContextProvider>
|
||||
),
|
||||
});
|
||||
|
||||
expect(hook.result.current.slice(0, 2)).toEqual([
|
||||
ElasticRequestState.Found,
|
||||
{
|
||||
id: '1',
|
||||
raw: { field1: 1, field2: 2 },
|
||||
flattened: { field1: 1, field2: 2 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ export function useEsDocSearch({
|
|||
index,
|
||||
dataView,
|
||||
requestSource,
|
||||
textBasedHits,
|
||||
}: DocProps): [ElasticRequestState, DataTableRecord | null, () => void] {
|
||||
const [status, setStatus] = useState(ElasticRequestState.Loading);
|
||||
const [hit, setHit] = useState<DataTableRecord | null>(null);
|
||||
|
@ -65,8 +66,16 @@ export function useEsDocSearch({
|
|||
}, [id, index, dataView, data.search, useNewFieldsApi, requestSource]);
|
||||
|
||||
useEffect(() => {
|
||||
requestData();
|
||||
}, [requestData]);
|
||||
if (textBasedHits) {
|
||||
const selectedHit = textBasedHits?.find((r) => r.id === id);
|
||||
if (selectedHit) {
|
||||
setStatus(ElasticRequestState.Found);
|
||||
setHit(selectedHit);
|
||||
}
|
||||
} else {
|
||||
requestData();
|
||||
}
|
||||
}, [id, requestData, textBasedHits]);
|
||||
|
||||
return [status, hit, requestData];
|
||||
}
|
||||
|
|
|
@ -262,22 +262,25 @@ export class DiscoverPlugin
|
|||
defaultMessage: 'JSON',
|
||||
}),
|
||||
order: 20,
|
||||
component: ({ hit, dataView }) => (
|
||||
<React.Suspense
|
||||
fallback={
|
||||
<DeferredSpinner>
|
||||
<EuiSkeletonText />
|
||||
</DeferredSpinner>
|
||||
}
|
||||
>
|
||||
<SourceViewer
|
||||
index={hit.raw._index}
|
||||
id={hit.raw._id}
|
||||
dataView={dataView}
|
||||
hasLineNumbers
|
||||
/>
|
||||
</React.Suspense>
|
||||
),
|
||||
component: ({ hit, dataView, query, textBasedHits }) => {
|
||||
return (
|
||||
<React.Suspense
|
||||
fallback={
|
||||
<DeferredSpinner>
|
||||
<EuiSkeletonText />
|
||||
</DeferredSpinner>
|
||||
}
|
||||
>
|
||||
<SourceViewer
|
||||
index={hit.raw._index}
|
||||
id={hit.raw._id ?? hit.id}
|
||||
dataView={dataView}
|
||||
textBasedHits={textBasedHits}
|
||||
hasLineNumbers
|
||||
/>
|
||||
</React.Suspense>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
|
|
|
@ -16,6 +16,7 @@ import { DataView } from '@kbn/data-views-plugin/public';
|
|||
import { useDiscoverServices } from '../../../../hooks/use_discover_services';
|
||||
import { JSONCodeEditorCommonMemoized } from '../../../../components/json_code_editor/json_code_editor_common';
|
||||
import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE } from '../../../../../common';
|
||||
import type { DataTableRecord } from '../../../../types';
|
||||
import { useEsDocSearch } from '../../../../hooks/use_es_doc_search';
|
||||
import { ElasticRequestState } from '../../../../application/doc/types';
|
||||
import { getHeight } from './get_height';
|
||||
|
@ -24,6 +25,7 @@ interface SourceViewerProps {
|
|||
id: string;
|
||||
index: string;
|
||||
dataView: DataView;
|
||||
textBasedHits?: DataTableRecord[];
|
||||
hasLineNumbers: boolean;
|
||||
width?: number;
|
||||
}
|
||||
|
@ -40,6 +42,7 @@ export const DocViewerSource = ({
|
|||
dataView,
|
||||
width,
|
||||
hasLineNumbers,
|
||||
textBasedHits,
|
||||
}: SourceViewerProps) => {
|
||||
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor>();
|
||||
const [editorHeight, setEditorHeight] = useState<number>();
|
||||
|
@ -52,6 +55,7 @@ export const DocViewerSource = ({
|
|||
index,
|
||||
dataView,
|
||||
requestSource: useNewFieldsApi,
|
||||
textBasedHits,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
|
||||
import type { AggregateQuery, Query } from '@kbn/es-query';
|
||||
import { DataTableRecord } from '../../types';
|
||||
import { IgnoredReason } from '../../utils/get_ignored_reason';
|
||||
|
||||
|
@ -29,6 +30,8 @@ export interface DocViewRenderProps {
|
|||
hit: DataTableRecord;
|
||||
dataView: DataView;
|
||||
columns?: string[];
|
||||
query?: Query | AggregateQuery;
|
||||
textBasedHits?: DataTableRecord[];
|
||||
filter?: DocViewFilterFn;
|
||||
onAddColumn?: (columnName: string) => void;
|
||||
onRemoveColumn?: (columnName: string) => void;
|
||||
|
|
|
@ -77,7 +77,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
expect(await testSubjects.exists('unifiedHistogramQueryHits')).to.be(true);
|
||||
expect(await testSubjects.exists('discoverAlertsButton')).to.be(false);
|
||||
expect(await testSubjects.exists('shareTopNavButton')).to.be(true);
|
||||
expect(await testSubjects.exists('docTableExpandToggleColumn')).to.be(false);
|
||||
expect(await testSubjects.exists('docTableExpandToggleColumn')).to.be(true);
|
||||
expect(await testSubjects.exists('dataGridColumnSortingButton')).to.be(false);
|
||||
expect(await testSubjects.exists('fieldListFiltersFieldTypeFilterToggle')).to.be(true);
|
||||
await testSubjects.click('field-@message-showDetails');
|
||||
|
@ -97,7 +97,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
// here Lens suggests a heatmap so it is rendered
|
||||
expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true);
|
||||
expect(await testSubjects.exists('heatmapChart')).to.be(true);
|
||||
const cell = await dataGrid.getCellElement(0, 3);
|
||||
const cell = await dataGrid.getCellElement(0, 4);
|
||||
expect(await cell.getVisibleText()).to.be('2269');
|
||||
});
|
||||
|
||||
|
@ -110,7 +110,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await monacoEditor.setCodeEditorValue(testQuery);
|
||||
await testSubjects.click('querySubmitButton');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
let cell = await dataGrid.getCellElement(0, 3);
|
||||
let cell = await dataGrid.getCellElement(0, 4);
|
||||
expect(await cell.getVisibleText()).to.be('2269');
|
||||
await PageObjects.timePicker.setAbsoluteRange(
|
||||
'Sep 19, 2015 @ 06:31:44.000',
|
||||
|
@ -120,7 +120,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
expect(await testSubjects.exists('discoverNoResults')).to.be(true);
|
||||
await PageObjects.timePicker.setDefaultAbsoluteRange();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
cell = await dataGrid.getCellElement(0, 3);
|
||||
cell = await dataGrid.getCellElement(0, 4);
|
||||
expect(await cell.getVisibleText()).to.be('2269');
|
||||
});
|
||||
|
||||
|
@ -135,7 +135,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await testSubjects.click('querySubmitButton');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
const cell = await dataGrid.getCellElement(0, 3);
|
||||
const cell = await dataGrid.getCellElement(0, 4);
|
||||
expect(await cell.getVisibleText()).to.be('2269');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue