Skip to content

Commit

Permalink
[ES|QL] Render a Discover-like table in the assistant instead of a Le…
Browse files Browse the repository at this point in the history
…ns chart (elastic#184106)

## Summary

This PR does 2 things:

- Creates a new plugin that is a wrapper of the unified datatable and is
only for rendering as a table ES|QL results. The UnifiedDatatable
package is good but the consumers need to know all the properties to
understand how to use it and the necessity of displaying in a table the
results of an ES|QL query comes a lot lately. This plugin has only 3
required properties (rows, columns, query) which make it very easy for
the consumers to use it. It also integrates the Row Viewer flyout

- It changes the implementation of the obs ai assistant to render a
Discover like table instead of a Lens table. The Discover-like table is
much better on rendering a table with thousands of columns and is going
to be much more helpful for our users.

The same plugin can be used later for the inline ediitng flyout too in a
dashboard if we want to also display the results of an ES|QL query.

Some screenshots of the new possibilities in the assistant:

- I can see the results of an ES|QL query in a visualization


![meow](https://github.com/elastic/kibana/assets/17003240/27f77ca3-633b-45f2-b935-42c62c184a04)

- I can render my results as a Document view

<img width="880" alt="image"
src="https://github.com/elastic/kibana/assets/17003240/e8034e10-325d-4d9e-b8a5-34d01b0dbd9d">

<img width="1095" alt="image"
src="https://github.com/elastic/kibana/assets/17003240/c8236e65-96aa-4fcb-b7c3-835e2a5665bd">

<img width="955" alt="image"
src="https://github.com/elastic/kibana/assets/17003240/78b1d664-6863-42bf-a337-659143b7683d">


### Checklist

Delete any items that are not applicable to this PR.

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

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
2 people authored and pull[bot] committed Jun 28, 2024
1 parent 084ad74 commit 69c1198
Show file tree
Hide file tree
Showing 30 changed files with 1,066 additions and 105 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ examples/eso_model_version_example @elastic/kibana-security
x-pack/test/encrypted_saved_objects_api_integration/plugins/api_consumer_plugin @elastic/kibana-security
packages/kbn-esql-ast @elastic/kibana-esql
examples/esql_ast_inspector @elastic/kibana-esql
src/plugins/esql_datagrid @elastic/kibana-esql
packages/kbn-esql-utils @elastic/kibana-esql
packages/kbn-esql-validation-autocomplete @elastic/kibana-esql
examples/esql_validation_example @elastic/kibana-esql
Expand Down
1 change: 1 addition & 0 deletions .i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
"coloring": "packages/kbn-coloring/src",
"languageDocumentationPopover": "packages/kbn-language-documentation-popover/src",
"textBasedLanguages": "src/plugins/text_based_languages",
"esqlDataGrid": "src/plugins/esql_datagrid",
"statusPage": "src/legacy/core_plugins/status_page",
"telemetry": ["src/plugins/telemetry", "src/plugins/telemetry_management_section"],
"timelion": ["src/plugins/vis_types/timelion"],
Expand Down
4 changes: 4 additions & 0 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ This API doesn't support angular, for registering angular dev tools, bootstrap a
|Embeddables are React components that manage their own state, can be serialized and deserialized, and return an API that can be used to interact with them imperatively.
|{kib-repo}blob/{branch}/src/plugins/esql_datagrid/README.md[esqlDataGrid]
|Contains a Discover-like table specifically for ES|QL queries:
|{kib-repo}blob/{branch}/src/plugins/es_ui_shared/README.md[esUiShared]
|This plugin contains reusable code in the form of self-contained modules (or libraries). Each of these modules exports a set of functionality relevant to the domain of the module.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@
"@kbn/eso-plugin": "link:x-pack/test/encrypted_saved_objects_api_integration/plugins/api_consumer_plugin",
"@kbn/esql-ast": "link:packages/kbn-esql-ast",
"@kbn/esql-ast-inspector-plugin": "link:examples/esql_ast_inspector",
"@kbn/esql-datagrid": "link:src/plugins/esql_datagrid",
"@kbn/esql-utils": "link:packages/kbn-esql-utils",
"@kbn/esql-validation-autocomplete": "link:packages/kbn-esql-validation-autocomplete",
"@kbn/esql-validation-example-plugin": "link:examples/esql_validation_example",
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pageLoadAssetSize:
embeddable: 87309
embeddableEnhanced: 22107
enterpriseSearch: 50858
esqlDataGrid: 24598
esUiShared: 326654
eventAnnotation: 30000
eventAnnotationListing: 25841
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-unified-data-table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

export { UnifiedDataTable, DataLoadingState } from './src/components/data_table';
export type { UnifiedDataTableProps } from './src/components/data_table';
export type { UnifiedDataTableProps, SortOrder } from './src/components/data_table';
export {
RowHeightSettings,
type RowHeightSettingsProps,
Expand Down
31 changes: 17 additions & 14 deletions packages/kbn-unified-data-table/src/components/data_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export interface UnifiedDataTableProps {
theme: ThemeServiceStart;
fieldFormats: FieldFormatsStart;
uiSettings: IUiSettingsClient;
dataViewFieldEditor: DataViewFieldEditorStart;
dataViewFieldEditor?: DataViewFieldEditorStart;
toastNotifications: ToastsStart;
storage: Storage;
data: DataPublicPluginStart;
Expand Down Expand Up @@ -611,7 +611,7 @@ export const UnifiedDataTable = ({
useNewFieldsApi,
shouldShowFieldHandler,
closePopover: () => dataGridRef.current?.closeCellPopover(),
fieldFormats: services.fieldFormats,
fieldFormats,
maxEntries: maxDocFieldsDisplayed,
externalCustomRenderers,
isPlainRecord,
Expand All @@ -622,7 +622,7 @@ export const UnifiedDataTable = ({
useNewFieldsApi,
shouldShowFieldHandler,
maxDocFieldsDisplayed,
services.fieldFormats,
fieldFormats,
externalCustomRenderers,
isPlainRecord,
]
Expand Down Expand Up @@ -651,18 +651,20 @@ export const UnifiedDataTable = ({
() =>
onFieldEdited
? (fieldName: string) => {
closeFieldEditor.current = services.dataViewFieldEditor.openEditor({
ctx: {
dataView,
},
fieldName,
onSave: async () => {
await onFieldEdited();
},
});
closeFieldEditor.current =
onFieldEdited &&
services?.dataViewFieldEditor?.openEditor({
ctx: {
dataView,
},
fieldName,
onSave: async () => {
await onFieldEdited();
},
});
}
: undefined,
[dataView, onFieldEdited, services.dataViewFieldEditor]
[dataView, onFieldEdited, services?.dataViewFieldEditor]
);

const timeFieldName = dataView.timeFieldName;
Expand Down Expand Up @@ -756,7 +758,8 @@ export const UnifiedDataTable = ({
uiSettings,
toastNotifications,
},
hasEditDataViewPermission: () => dataViewFieldEditor.userPermissions.editIndexPattern(),
hasEditDataViewPermission: () =>
Boolean(dataViewFieldEditor?.userPermissions?.editIndexPattern()),
valueToStringConverter,
onFilter,
editField,
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/esql_datagrid/.i18nrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"prefix": "esqlDataGrid",
"paths": {
"esqlDataGrid": "."
}
}
47 changes: 47 additions & 0 deletions src/plugins/esql_datagrid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# @kbn/esql-datagrid

Contains a Discover-like table specifically for ES|QL queries:
- You have to run the esql query on your application, this is just a UI component
- You pass the columns and rows of the _query response to the table
- The table operates in both Document view and table view mode, define this with the `isTableView` property
- The table offers a built in Row Viewer flyout
- The table offers a rows comparison mode, exactly as Discover

---

### Properties
* rows: ESQLRow[], is the array of values returned by the _query api
* columns: DatatableColumn[], is the array of columns in a kibana compatible format. You can sue the `formatESQLColumns` helper function from the `@kbn/esql-utils` package
* query: AggregateQuery, the ES|QL query in the format of
```json
{
esql: <queryString>
}
```
* flyoutType?: "overlay" | "push", defines the type of flyout for the Row Viewer
* isTableView?: boolean, defines if the table will render as a Document Viewer or a Table View


### How to use it
```tsx
import { getIndexPatternFromESQLQuery, getESQLAdHocDataview, formatESQLColumns } from '@kbn/esql-utils';
import { ESQLDataGrid } from '@kbn/esql-datagrid/public';

/**
Run the _query api to get the datatable with the ES|QL query you want.
This will return a response with columns and values
**/

const indexPattern = getIndexPatternFromESQLQuery(query);
const adHocDataView = getESQLAdHocDataview(indexPattern, dataViewService);
const formattedColumns = formatESQLColumns(columns);

<ESQLDataGrid
rows={values}
columns={formattedColumns}
dataView={adHocDataView}
query={{ esql: query }}
flyoutType="overlay"
isTableView
/>
```
19 changes: 19 additions & 0 deletions src/plugins/esql_datagrid/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../../..',
roots: ['<rootDir>/src/plugins/esql_datagrid'],
coverageDirectory: '<rootDir>/target/kibana-coverage/jest/src/plugins/esql_datagrid',
coverageReporters: ['text', 'html'],
collectCoverageFrom: [
'<rootDir>/src/plugins/esql_datagrid/{common,public,server}/**/*.{js,ts,tsx}',
],
setupFiles: ['jest-canvas-mock'],
};
21 changes: 21 additions & 0 deletions src/plugins/esql_datagrid/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"type": "plugin",
"id": "@kbn/esql-datagrid",
"owner": "@elastic/kibana-esql",
"plugin": {
"id": "esqlDataGrid",
"server": false,
"browser": true,
"requiredPlugins": [
"data",
"uiActions",
"fieldFormats"
],
"requiredBundles": [
"kibanaReact",
"kibanaUtils",
"dataViews",
"unifiedDocViewer"
]
}
}
6 changes: 6 additions & 0 deletions src/plugins/esql_datagrid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/esql-datagrid",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}
58 changes: 58 additions & 0 deletions src/plugins/esql_datagrid/public/create_datagrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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, { lazy } from 'react';
import { EuiLoadingSpinner } from '@elastic/eui';
import type { ESQLRow } from '@kbn/es-types';
import type { AggregateQuery } from '@kbn/es-query';
import { withSuspense } from '@kbn/shared-ux-utility';
import useAsync from 'react-use/lib/useAsync';
import type { DataView } from '@kbn/data-views-plugin/common';
import type { DatatableColumn } from '@kbn/expressions-plugin/common';
import { CellActionsProvider } from '@kbn/cell-actions';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { untilPluginStartServicesReady } from './kibana_services';

interface ESQLDataGridProps {
rows: ESQLRow[];
dataView: DataView;
columns: DatatableColumn[];
query: AggregateQuery;
flyoutType?: 'overlay' | 'push';
isTableView?: boolean;
}

const DataGridLazy = withSuspense(lazy(() => import('./data_grid')));

export const ESQLDataGrid = (props: ESQLDataGridProps) => {
const { loading, value } = useAsync(() => {
const startServicesPromise = untilPluginStartServicesReady();
return Promise.all([startServicesPromise]);
}, []);

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

return (
<KibanaContextProvider
services={{
...deps,
}}
>
<CellActionsProvider getTriggerCompatibleActions={deps.uiActions.getTriggerCompatibleActions}>
<div style={{ height: 500 }}>
<DataGridLazy
data={deps.data}
fieldFormats={deps.fieldFormats}
core={deps.core}
{...props}
/>
</div>
</CellActionsProvider>
</KibanaContextProvider>
);
};
Loading

0 comments on commit 69c1198

Please sign in to comment.