Skip to content

Commit

Permalink
[ES|QL] Improves the authoring of the query and charts (#186875)
Browse files Browse the repository at this point in the history
## Summary

It makes the authoring of the ES|QL query easier by:

- changing the flyout to be resizable
- displaying a tab with the results of the query in the ES|QL datagrid
component.

<img width="1255" alt="image"
src="https://github.com/user-attachments/assets/526509fa-7313-4560-9186-61181b5c575b">


### Checklist

- [ ] 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)
- [ ] [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
- [ ] 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))
- [ ] 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)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
stratoula and kibanamachine authored Jul 30, 2024
1 parent 696190d commit 1bf4fcd
Show file tree
Hide file tree
Showing 19 changed files with 486 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/* eslint-disable max-classes-per-file */

import { EuiFlyout } from '@elastic/eui';
import { EuiFlyout, EuiFlyoutResizable } from '@elastic/eui';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Subject } from 'rxjs';
Expand Down Expand Up @@ -102,11 +102,26 @@ export class FlyoutService {
}
};

render(
<KibanaRenderContextProvider analytics={analytics} i18n={i18n} theme={theme}>
const getWrapper = (children: JSX.Element) => {
return options?.isResizable ? (
<EuiFlyoutResizable
{...options}
onClose={onCloseFlyout}
ref={React.createRef()}
maxWidth={Number(options?.maxWidth)}
>
{children}
</EuiFlyoutResizable>
) : (
<EuiFlyout {...options} onClose={onCloseFlyout}>
<MountWrapper mount={mount} className="kbnOverlayMountWrapper" />
{children}
</EuiFlyout>
);
};

render(
<KibanaRenderContextProvider analytics={analytics} i18n={i18n} theme={theme}>
{getWrapper(<MountWrapper mount={mount} className="kbnOverlayMountWrapper" />)}
</KibanaRenderContextProvider>,
this.targetDomElement
);
Expand Down
5 changes: 3 additions & 2 deletions packages/core/overlays/core-overlays-browser/src/flyout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { EuiFlyoutProps } from '@elastic/eui';
import type { EuiFlyoutProps, EuiFlyoutResizableProps } from '@elastic/eui';
import type { MountPoint, OverlayRef } from '@kbn/core-mount-utils-browser';

/**
Expand All @@ -28,10 +28,11 @@ export interface OverlayFlyoutStart {
/**
* @public
*/
export type OverlayFlyoutOpenOptions = Omit<EuiFlyoutProps, 'onClose'> & {
export type OverlayFlyoutOpenOptions = Omit<EuiFlyoutProps | EuiFlyoutResizableProps, 'onClose'> & {
/**
* EuiFlyout onClose handler.
* If provided the consumer is responsible for calling flyout.close() to close the flyout;
*/
onClose?: (flyout: OverlayRef) => void;
isResizable?: boolean;
};
1 change: 1 addition & 0 deletions packages/kbn-esql-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export {
getESQLQueryColumns,
getESQLQueryColumnsRaw,
getESQLResults,
formatESQLColumns,
getTimeFieldFromESQLQuery,
getStartEndParams,
hasStartEndParams,
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-esql-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export {
getESQLQueryColumns,
getESQLQueryColumnsRaw,
getESQLResults,
formatESQLColumns,
getStartEndParams,
hasStartEndParams,
} from './utils/run_query';
3 changes: 2 additions & 1 deletion src/plugins/esql_datagrid/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"requiredPlugins": [
"data",
"uiActions",
"fieldFormats"
"fieldFormats",
"share",
],
"requiredBundles": [
"kibanaReact",
Expand Down
15 changes: 13 additions & 2 deletions src/plugins/esql_datagrid/public/create_datagrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ interface ESQLDataGridProps {
dataView: DataView;
columns: DatatableColumn[];
query: AggregateQuery;
/**
* Optional parameters
*/
flyoutType?: 'overlay' | 'push';
isTableView?: boolean;
initialColumns?: DatatableColumn[];
fullHeight?: boolean;
initialRowHeight?: number;
controlColumnIds?: string[]; // default: ['openDetails', 'select']
}

const DataGridLazy = withSuspense(lazy(() => import('./data_grid')));
Expand All @@ -35,6 +41,10 @@ export const ESQLDataGrid = (props: ESQLDataGridProps) => {
return Promise.all([startServicesPromise]);
}, []);

const getWrapper = (children: JSX.Element) => {
return props.fullHeight ? <div style={{ height: 500 }}>{children}</div> : <>{children}</>;
};

const deps = value?.[0];
if (loading || !deps) return <EuiLoadingSpinner />;

Expand All @@ -45,14 +55,15 @@ export const ESQLDataGrid = (props: ESQLDataGridProps) => {
}}
>
<CellActionsProvider getTriggerCompatibleActions={deps.uiActions.getTriggerCompatibleActions}>
<div style={{ height: 500 }}>
{getWrapper(
<DataGridLazy
data={deps.data}
fieldFormats={deps.fieldFormats}
core={deps.core}
share={deps.share}
{...props}
/>
</div>
)}
</CellActionsProvider>
</KibanaContextProvider>
);
Expand Down
92 changes: 88 additions & 4 deletions src/plugins/esql_datagrid/public/data_grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@

import React, { useState, useCallback, useMemo } from 'react';
import { zipObject } from 'lodash';
import { UnifiedDataTable, DataLoadingState, type SortOrder } from '@kbn/unified-data-table';
import {
UnifiedDataTable,
DataLoadingState,
type SortOrder,
renderCustomToolbar,
} from '@kbn/unified-data-table';
import { i18n } from '@kbn/i18n';
import { EuiLink, EuiText, EuiIcon } from '@elastic/eui';
import { css } from '@emotion/react';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import type { ESQLRow } from '@kbn/es-types';
import type { DatatableColumn, DatatableColumnMeta } from '@kbn/expressions-plugin/common';
import type { SharePluginStart } from '@kbn/share-plugin/public';
import type { AggregateQuery } from '@kbn/es-query';
import type { DataTableRecord } from '@kbn/discover-utils/types';
import type { DataView } from '@kbn/data-views-plugin/common';
Expand All @@ -24,13 +33,16 @@ interface ESQLDataGridProps {
core: CoreStart;
data: DataPublicPluginStart;
fieldFormats: FieldFormatsStart;
share?: SharePluginStart;
rows: ESQLRow[];
dataView: DataView;
columns: DatatableColumn[];
query: AggregateQuery;
flyoutType?: 'overlay' | 'push';
isTableView?: boolean;
initialColumns?: DatatableColumn[];
initialRowHeight?: number;
controlColumnIds?: string[];
}
type DataTableColumnsMeta = Record<
string,
Expand All @@ -41,13 +53,19 @@ type DataTableColumnsMeta = Record<
>;

const sortOrder: SortOrder[] = [];
const DEFAULT_INITIAL_ROW_HEIGHT = 5;
const DEFAULT_ROWS_PER_PAGE = 10;
const ROWS_PER_PAGE_OPTIONS = [10, 25];

const DataGrid: React.FC<ESQLDataGridProps> = (props) => {
const [expandedDoc, setExpandedDoc] = useState<DataTableRecord | undefined>(undefined);
const [activeColumns, setActiveColumns] = useState<string[]>(
(props.initialColumns || (props.isTableView ? props.columns : [])).map((c) => c.name)
);
const [rowHeight, setRowHeight] = useState<number>(5);
const [rowHeight, setRowHeight] = useState<number>(
props.initialRowHeight ?? DEFAULT_INITIAL_ROW_HEIGHT
);
const [rowsPerPage, setRowsPerPage] = useState(DEFAULT_ROWS_PER_PAGE);

const onSetColumns = useCallback((columns) => {
setActiveColumns(columns);
Expand Down Expand Up @@ -123,9 +141,71 @@ const DataGrid: React.FC<ESQLDataGridProps> = (props) => {
props.fieldFormats,
]);

const discoverLocator = useMemo(() => {
return props.share?.url.locators.get('DISCOVER_APP_LOCATOR');
}, [props.share?.url.locators]);

const renderToolbar = useCallback(
(customToolbarProps) => {
const discoverLink = discoverLocator?.getRedirectUrl({
dataViewSpec: props.dataView.toSpec(),
timeRange: props.data.query.timefilter.timefilter.getTime(),
query: props.query,
columns: activeColumns,
});
return renderCustomToolbar({
...customToolbarProps,
toolbarProps: {
...customToolbarProps.toolbarProps,
hasRoomForGridControls: true,
},
gridProps: {
additionalControls: (
<EuiLink
href={discoverLink}
target="_blank"
color="primary"
css={css`
display: flex;
align-items: center;
`}
external={false}
>
<EuiIcon
type="discoverApp"
size="s"
color="primary"
css={css`
margin-right: 4px;
`}
/>
<EuiText size="xs">
{i18n.translate('esqlDataGrid.openInDiscoverLabel', {
defaultMessage: 'Open in Discover',
})}
</EuiText>
</EuiLink>
),
},
});
},
[
activeColumns,
discoverLocator,
props.data.query.timefilter.timefilter,
props.dataView,
props.query,
]
);

return (
<UnifiedDataTable
columns={activeColumns}
css={css`
.unifiedDataTableToolbar {
padding: 4px 0px;
}
`}
rows={rows}
columnsMeta={columnsMeta}
services={services}
Expand All @@ -134,8 +214,10 @@ const DataGrid: React.FC<ESQLDataGridProps> = (props) => {
loadingState={DataLoadingState.loaded}
dataView={props.dataView}
sampleSizeState={rows.length}
rowsPerPageState={10}
rowsPerPageState={rowsPerPage}
rowsPerPageOptions={ROWS_PER_PAGE_OPTIONS}
onSetColumns={onSetColumns}
onUpdateRowsPerPage={setRowsPerPage}
expandedDoc={expandedDoc}
setExpandedDoc={setExpandedDoc}
showTimeCol
Expand All @@ -146,9 +228,11 @@ const DataGrid: React.FC<ESQLDataGridProps> = (props) => {
maxDocFieldsDisplayed={100}
renderDocumentView={renderDocumentView}
showFullScreenButton={false}
configRowHeight={5}
configRowHeight={DEFAULT_INITIAL_ROW_HEIGHT}
rowHeightState={rowHeight}
onUpdateRowHeight={setRowHeight}
controlColumnIds={props.controlColumnIds}
renderCustomToolbar={discoverLocator ? renderToolbar : undefined}
/>
);
};
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/esql_datagrid/public/kibana_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { CoreStart } from '@kbn/core/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import type { SharePluginStart } from '@kbn/share-plugin/public';

export let core: CoreStart;

Expand All @@ -19,6 +20,7 @@ interface ServiceDeps {
data: DataPublicPluginStart;
uiActions: UiActionsStart;
fieldFormats: FieldFormatsStart;
share?: SharePluginStart;
}

const servicesReady$ = new BehaviorSubject<ServiceDeps | undefined>(undefined);
Expand All @@ -38,13 +40,15 @@ export const setKibanaServices = (
kibanaCore: CoreStart,
data: DataPublicPluginStart,
uiActions: UiActionsStart,
fieldFormats: FieldFormatsStart
fieldFormats: FieldFormatsStart,
share?: SharePluginStart
) => {
core = kibanaCore;
servicesReady$.next({
core,
data,
uiActions,
fieldFormats,
share,
});
};
9 changes: 7 additions & 2 deletions src/plugins/esql_datagrid/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@ import type { Plugin, CoreStart, CoreSetup } from '@kbn/core/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import type { SharePluginStart } from '@kbn/share-plugin/public';
import { setKibanaServices } from './kibana_services';

interface ESQLDataGridPluginStart {
data: DataPublicPluginStart;
uiActions: UiActionsStart;
fieldFormats: FieldFormatsStart;
share?: SharePluginStart;
}
export class ESQLDataGridPlugin implements Plugin<{}, void> {
public setup(_: CoreSetup, {}: {}) {
return {};
}

public start(core: CoreStart, { data, uiActions, fieldFormats }: ESQLDataGridPluginStart): void {
setKibanaServices(core, data, uiActions, fieldFormats);
public start(
core: CoreStart,
{ data, uiActions, fieldFormats, share }: ESQLDataGridPluginStart
): void {
setKibanaServices(core, data, uiActions, fieldFormats, share);
}

public stop() {}
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/esql_datagrid/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"@kbn/unified-doc-viewer-plugin",
"@kbn/core-notifications-browser",
"@kbn/shared-ux-utility",
"@kbn/share-plugin",
"@kbn/i18n",
],
"exclude": [
"target/**/*",
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/lens/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"embeddable",
"fieldFormats",
"charts",
"esqlDataGrid",
"esql",
],
"extraPublicDirs": [
Expand Down
Loading

0 comments on commit 1bf4fcd

Please sign in to comment.